func (server *SServer) WaitConnections(duration time.Duration) {
	log.Infof("Waiting for %v connections to complete", server.ConnectionsCounter())
	server.connectionManager.Wait()
}
WaitConnections waits until connection complete or stops them after duration time.
package common
import (
	"context"
	"errors"
	"github.com/cossacklabs/acra/utils"
	"io"
	"net"
	url_ "net/url"
	"os"
	"sync"
	"syscall"
	"time"
	"github.com/cossacklabs/acra/decryptor/base"
	"github.com/cossacklabs/acra/logging"
	"github.com/cossacklabs/acra/network"
	"github.com/prometheus/client_golang/prometheus"
	log "github.com/sirupsen/logrus"
	"go.opencensus.io/trace"
)
type SServer struct {
	config                *Config
	listenerACRA          net.Listener
	listenerAPI           net.Listener
	connectionManager     *network.ConnectionManager
	listeners             []net.Listener
	errorSignalChannel    chan os.Signal
	restartSignalsChannel chan os.Signal
	proxyFactory          base.ProxyFactory
	backgroundWorkersSync sync.WaitGroup
	stopListenersSignal   chan bool
}
var ErrWaitTimeout = errors.New("timeout")
func NewServer(config *Config, proxyFactory base.ProxyFactory, errorChan chan os.Signal, restarChan chan os.Signal) (server *SServer, err error) {
	return &SServer{
		config:                config,
		connectionManager:     network.NewConnectionManager(),
		errorSignalChannel:    errorChan,
		restartSignalsChannel: restarChan,
		proxyFactory:          proxyFactory,
		stopListenersSignal:   make(chan bool),
	}, nil
}
func (server *SServer) Close() {
	log.Debugln("Closing server listeners..")
	var err error
	for _, listener := range server.listeners {
		listener = network.UnwrapSafeCloseListener(listener)
		switch listener.(type) {
		case *net.TCPListener:
			err = listener.(*net.TCPListener).Close()
			if err != nil {
				log.WithError(err).Infoln("TCPListener.Close()")
				continue
			}
		case *net.UnixListener:
			err = listener.(*net.UnixListener).Close()
			if err != nil {
				log.WithError(err).Infoln("UnixListener.Close()")
				continue
			}
			url, err2 := url_.Parse(server.config.GetAcraConnectionString())
			if err2 != nil {
				log.WithError(err2).Warningln("UnixListener.Close  url_.Parse")
			}
			if _, err := os.Stat(url.Path); err == nil {
				err3 := os.Remove(url.Path)
				if err3 != nil {
					log.WithError(err3).Warningf("UnixListener.Close  file.Remove(%s)", url.Path)
				}
			}
		default:
			if err = listener.Close(); err != nil {
				log.WithError(err).Warningln("Error on closing listener")
			}
		}
	}
	if err != nil {
		log.WithError(err).Infoln("server.Close()")
	}
	if err := server.connectionManager.CloseConnections(); err != nil {
		log.WithField(logging.FieldKeyEventCode, logging.EventCodeErrorCantCloseConnectionToService).WithError(err).Errorln("Error on close connections")
	}
	log.Debugln("Closed server listeners")
}
func (server *SServer) addListener(listener net.Listener) {
	server.listeners = append(server.listeners, listener)
}
type callbackData struct {
	connectionType string
	funcName       string
	callbackFunc   func(context.Context, []byte, net.Conn)
}
func (server *SServer) handleConnection(ctx context.Context, clientID []byte, connection net.Conn) {
	logger := logging.NewLoggerWithTrace(ctx)
	logging.SetLoggerToContext(ctx, logger)
	clientSession, err := NewClientSession(ctx, server.config, connection)
	if err != nil {
		logger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorCantInitClientSession).
			Errorln("Can't initialize client session")
		if closeErr := connection.Close(); closeErr != nil {
			logger.WithError(closeErr).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorCantCloseConnection).
				Errorln("Can't close connection")
		}
		return
	}
	server.handleClientSession(clientID, clientSession)
}
func (server *SServer) handleClientSession(clientID []byte, clientSession *ClientSession) {
	sessionLogger := clientSession.Logger()
	sessionLogger.Infof("Handle client's connection")
	clientProxyErrorCh := make(chan error, 1)
	dbProxyErrorCh := make(chan error, 1)
	sessionLogger.Debugf("Connecting to db")
	err := clientSession.ConnectToDb()
	if err != nil {
		sessionLogger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorCantConnectToDB).
			Errorln("Can't connect to db")
		sessionLogger.Debugln("Close connection with acra-connector")
		err = clientSession.ClientConnection().Close()
		if err != nil {
			sessionLogger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorCantCloseConnectionToService).
				Errorln("Error with closing connection to acra-connector")
		}
		return
	}
	proxy, err := server.proxyFactory.New(clientID, clientSession)
	if err != nil {
		sessionLogger.WithError(err).Errorln("Can't create new proxy for connection")
		return
	}
	server.backgroundWorkersSync.Add(1)
	go func() {
		defer server.backgroundWorkersSync.Done()
		proxy.ProxyClientConnection(clientProxyErrorCh)
	}()
	server.backgroundWorkersSync.Add(1)
	go func() {
		defer server.backgroundWorkersSync.Done()
		proxy.ProxyDatabaseConnection(dbProxyErrorCh)
	}()
	var channelToWait chan error
	const (
		acraDbSide     = "AcraServer<->Database"
		clientAcraSide = "Client/Connector<->Database"
	)
	var interruptSide string
	select {
	case err = <-dbProxyErrorCh:
		sessionLogger.Debugln("Stop to proxy Database -> AcraServer")
		interruptSide = acraDbSide
		channelToWait = clientProxyErrorCh
	case err = <-clientProxyErrorCh:
		interruptSide = clientAcraSide
		sessionLogger.Debugln("Stop to proxy AcraServer -> Client")
		channelToWait = dbProxyErrorCh
	}
	sessionLogger = sessionLogger.WithField("interrupt_side", interruptSide)
	if err == io.EOF {
		sessionLogger.Debugln("EOF connection closed")
	} else if err == nil {
		sessionLogger.Debugln("Err == nil from proxy goroutine")
	} else if netErr, ok := err.(net.Error); ok {
		sessionLogger.WithError(netErr).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorGeneralConnectionProcessing).
			Errorln("Network error")
	} else if opErr, ok := err.(*net.OpError); ok {
		sessionLogger.WithError(opErr).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorGeneralConnectionProcessing).Errorln("Network error")
	} else {
		sessionLogger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorGeneralConnectionProcessing).Errorln("Unexpected error")
	}
	sessionLogger.Infof("Closing client's connection")
	clientSession.Close()
	sessionLogger.WithError(<-channelToWait).Debugln("Second proxy goroutine stopped")
	sessionLogger.Infoln("Finished processing client's connection")
}
func (server *SServer) processConnection(connection net.Conn, callback *callbackData) {
	connectionCounter.WithLabelValues(callback.connectionType).Inc()
	timer := prometheus.NewTimer(prometheus.ObserverFunc(connectionProcessingTimeHistogram.WithLabelValues(callback.connectionType).Observe))
	defer timer.ObserveDuration()
	ctx := logging.SetTraceStatus(context.Background(), server.config.TraceToLog)
	wrapCtx, wrapSpan := trace.StartSpan(ctx, "WrapServer", server.config.GetTraceOptions()...)
	logger := logging.NewLoggerWithTrace(wrapCtx)
	wrappedConnection, clientID, err := server.config.ConnectionWrapper.WrapServer(wrapCtx, connection)
	if err != nil {
		logger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorCantWrapConnection).
			Errorln("Can't wrap connection from acra-connector")
		if closeErr := connection.Close(); closeErr != nil {
			logger.WithError(closeErr).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorCantCloseConnection).
				Errorln("Can't close connection")
		}
		wrapSpan.End()
		return
	}
	logger = logger.WithField("client_id", string(clientID))
	wrapSpan.End()
	var span *trace.Span
	if server.config.WithConnector() {
		logger.Debugln("Read trace")
		spanContext, err := network.ReadTrace(wrappedConnection)
		if err != nil {
			log.WithField(logging.FieldKeyEventCode, logging.EventCodeErrorTracingCantReadTrace).WithError(err).Errorln("Can't read trace from AcraConnector")
			return
		}
		ctx, span = trace.StartSpanWithRemoteParent(wrapCtx, callback.funcName, spanContext, server.config.GetTraceOptions()...)
	} else {
		ctx, span = trace.StartSpan(wrapCtx, callback.funcName, server.config.GetTraceOptions()...)
	}
	ctx = logging.SetLoggerToContext(ctx, logger)
	span.AddAttributes(trace.BoolAttribute("from_connector", server.config.WithConnector()))
	defer span.End()
	wrapSpanContext := wrapSpan.SpanContext()
	span.AddLink(trace.Link{TraceID: wrapSpanContext.TraceID, SpanID: wrapSpanContext.SpanID, Type: trace.LinkTypeParent})
	callback.callbackFunc(ctx, clientID, wrappedConnection)
}
func (server *SServer) start(parentContext context.Context, listener net.Listener, callback *callbackData, logger *log.Entry, errCh chan<- error) {
	logger.Infof("Start listening connections")
	for {
		select {
		case <-parentContext.Done():
			return
		default:
			break
		}
		connection, err := listener.Accept()
		if err != nil {
			select {
			case <-server.stopListenersSignal:
			default:
				if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
					logger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorConnectionDroppedByTimeout).
						Errorln("Stop accepting new connections due net.Timeout")
				} else {
					logger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorCantAcceptNewConnections).
						Errorln("Can't accept new connection")
				}
				errCh <- err
			}
			return
		}
		if len(connection.RemoteAddr().String()) == 1 {
			logger.Infof("Got new connection to AcraServer: %v", connection.LocalAddr())
		} else {
			logger.Infof("Got new connection to AcraServer: %v", connection.RemoteAddr())
		}
		server.backgroundWorkersSync.Add(1)
		go func() {
			defer server.backgroundWorkersSync.Done()
			_ = server.connectionManager.AddConnection(connection)
			server.processConnection(connection, callback)
			_ = server.connectionManager.RemoveConnection(connection)
		}()
	}
}
func (server *SServer) ListenerAcra() net.Listener {
	return server.listenerACRA
}
func (server *SServer) ListenerAPI() net.Listener {
	return server.listenerAPI
}
func (server *SServer) waitForExitTimeout() {
	if utils.WaitWithTimeout(&server.backgroundWorkersSync, utils.DefaultWaitGroupTimeoutDuration) {
		log.Errorf("Couldn't stop all background goroutines spawned by readerServer. Exited by timeout")
	}
}
func (server *SServer) Start(parentContext context.Context) {
	logger := log.WithFields(log.Fields{"connection_string": server.config.GetAcraConnectionString(), "from_descriptor": false})
	logger.Infoln("Create listener")
	var listener, err = network.Listen(server.config.GetAcraConnectionString())
	if err != nil {
		logger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorCantStartListenConnections).
			Errorln("Can't start listen connections")
		server.errorSignalChannel <- syscall.SIGTERM
		return
	}
	server.listenerACRA = listener
	server.addListener(listener)
	server.run(parentContext, listener, &callbackData{funcName: "handleConnection", connectionType: dbConnectionType, callbackFunc: server.handleConnection}, logger)
}
func (server *SServer) StartFromFileDescriptor(parentContext context.Context, fd uintptr) {
	logger := log.WithFields(log.Fields{"connection_string": server.config.GetAcraConnectionString(), "from_descriptor": true})
	file := os.NewFile(fd, "/tmp/acra-server")
	if file == nil {
		logger.WithField(logging.FieldKeyEventCode, logging.EventCodeErrorCreateFileFromDescriptor).Errorln("Can't create new file from descriptor for acra listener")
		server.errorSignalChannel <- syscall.SIGTERM
		return
	}
	listenerFile, err := net.FileListener(file)
	if err != nil {
		logger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorCantOpenFileByDescriptor).
			Errorln("System error: can't start listen for file descriptor")
		server.errorSignalChannel <- syscall.SIGTERM
		return
	}
	listenerWithFileDescriptor, ok := listenerFile.(network.ListenerWithFileDescriptor)
	if !ok {
		logger.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorFileDescriptionIsNotValid).
			Errorf("System error: file descriptor %d is not a valid socket", fd)
		server.errorSignalChannel <- syscall.SIGTERM
		return
	}
	server.listenerACRA = listenerWithFileDescriptor
	server.addListener(listenerWithFileDescriptor)
	server.run(parentContext, listenerWithFileDescriptor, &callbackData{funcName: "handleConnection", connectionType: dbConnectionType, callbackFunc: server.handleConnection}, logger)
}
func stopAcceptConnections(listener network.DeadlineListener) (err error) {
	if listener != nil {
		err = listener.SetDeadline(time.Now())
		if err != nil {
			log.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorCantStopListenConnections).
				Errorln("Unable to SetDeadLine for listener")
		}
	} else {
		log.Warningln("Can't set deadline for server listener")
	}
	return
}
func (server *SServer) StopListeners() {
	close(server.stopListenersSignal)
	var err error
	var deadlineListener network.DeadlineListener
	log.Debugln("Stopping listeners")
	for _, listener := range server.listeners {
		deadlineListener, err = network.CastListenerToDeadline(listener)
		if err != nil {
			log.WithError(err).Warningln("Listener doesn't support deadlines")
			continue
		}
		if err = stopAcceptConnections(deadlineListener); err != nil {
			log.WithError(err).Warningln("Can't set deadline for listener")
		}
	}
}