Example #1
0
        /// <summary>
        ///     Called when a new server connects to this server.
        /// </summary>
        /// <param name="connection">The new connection.</param>
        internal void HandleNewConnection(NetworkServerConnection connection)
        {
            //TODO make configurable
            PendingDownstreamRemoteServer server = new PendingDownstreamRemoteServer(connection, 10000, HandleServerReady, HandleServerDroppedBeforeReady, logger);

            lock (pendingDownstreamServers)
                pendingDownstreamServers.Add(server);

            connection.StartListening();

            logger.Trace($"New server connected, awaiting identification [{connection.RemoteEndPoints.Format()}].");
        }
        /// <summary>
        ///     Creates a new remote server.
        /// </summary>
        /// <param name="connection">The connection to the server.</param>
        /// <param name="timeoutMs">The number of milliseconds to wait before timing out.</param>
        /// <param name="ready">Delegate invoked if the connection is dropped.</param>
        /// <param name="dropped">Delegate invoked if the remote server identifies itself.</param>
        /// <param name="logger">The logger to use.</param>
        internal PendingDownstreamRemoteServer(NetworkServerConnection connection, int timeoutMs, Action <PendingDownstreamRemoteServer, ushort> ready, Action <PendingDownstreamRemoteServer> dropped, Logger logger)
        {
            this.Connection = connection;
            this.Ready      = ready;
            this.Dropped    = dropped;
            this.logger     = logger;

            connection.MessageReceived += MessageReceivedHandler;
            connection.Disconnected    += DisconnectedHandler;

            // Wait until we get a message with their ID
            timer = new System.Threading.Timer((_) => DropConnection(), null, timeoutMs, Timeout.Infinite);
        }
        /// <summary>
        ///     Sets the connection being used by this remote server.
        /// </summary>
        /// <param name="pendingServer">The connection to switch to.</param>
        internal void SetConnection(PendingDownstreamRemoteServer pendingServer)
        {
            if (connection != null)
            {
                connection.MessageReceived -= MessageReceivedHandler;
                connection.Disconnected    -= DisconnectedHandler;
            }

            connection = pendingServer.Connection;

            // Switch out message received handler from the pending server
            connection.MessageReceived = MessageReceivedHandler;
            connection.Disconnected    = DisconnectedHandler;

            EventHandler <ServerConnectedEventArgs> handler = ServerConnected;

            if (handler != null)
            {
                void DoServerConnectedEvent()
                {
                    long startTimestamp = Stopwatch.GetTimestamp();

                    try
                    {
                        handler?.Invoke(this, new ServerConnectedEventArgs(this));
                    }
                    catch (Exception e)
                    {
                        serverConnectedEventFailuresCounter.Increment();

                        logger.Error("A plugin encountered an error whilst handling the ServerConnected event. The server will still be connected. (See logs for exception)", e);
                    }

                    double time = (double)(Stopwatch.GetTimestamp() - startTimestamp) / Stopwatch.Frequency;

                    serverConnectedEventTimeHistogram.Report(time);
                }

                threadHelper.DispatchIfNeeded(DoServerConnectedEvent);
            }

            // Handle all messages that had queued
            foreach (PendingDownstreamRemoteServer.QueuedMessage queuedMessage in pendingServer.GetQueuedMessages())
            {
                HandleMessage(queuedMessage.Message, queuedMessage.SendMode);

                queuedMessage.Message.Dispose();
            }
        }
Example #4
0
        /// <summary>
        ///     Registers a new connection to the server.
        /// </summary>
        /// <param name="connection">The new connection.</param>
        protected void RegisterConnection(NetworkServerConnection connection)
        {
            Action <NetworkServerConnection> handler = RegisteredConnection;

            if (handler != null)
            {
                handler.Invoke(connection);
            }
            else
            {
                Logger.Error("A connection was registered by the network listener while no hooks were subscribed to handle the registration. The connection has been dropped. This suggests the network listener is erroneously accepting connections before the StartListening() method has been called.");

                connection.Disconnect();
            }
        }
        /// <summary>
        ///     Called when a new client connects.
        /// </summary>
        /// <param name="connection">The new client.</param>
        internal void HandleNewConnection(NetworkServerConnection connection)
        {
            //Allocate ID and add to list
            ushort id;

            try
            {
                id = ReserveID();
            }
            catch (InvalidOperationException)
            {
                logger.Info($"New client could not be connected as there were no IDs available to allocate to them [{connection.RemoteEndPoints.Format()}].");

                connection.Disconnect();

                return;
            }


            Client client;

            try
            {
                client = Client.Create(
                    connection,
                    id,
                    this,
                    threadHelper,
                    clientLogger
#if PRO
                    , clientMetricsCollector
#endif
                    );
            }
            catch (Exception e)
            {
                logger.Error("An exception ocurred while connecting a client. The client has been dropped.", e);

                connection.Disconnect();

                DeallocateID(id, out int _);

                return;
            }

            AllocateIDToClient(id, client, out int noClients);

            // TODO if a client sends immediately after connecting then the message will be missed as the Connected event has not yet fired

            connection.Client = client;

            logger.Info($"New client [{client.ID}] connected [{client.RemoteEndPoints.Format()}].");
#if PRO
            clientsConnectedGauge.Report(noClients);
#endif

            //Inform plugins of the new connection
            EventHandler <ClientConnectedEventArgs> handler = ClientConnected;
            if (handler != null)
            {
                threadHelper.DispatchIfNeeded(
                    delegate()
                {
#if PRO
                    long startTimestamp = Stopwatch.GetTimestamp();
#endif
                    try
                    {
                        handler.Invoke(this, new ClientConnectedEventArgs(client));
                    }
                    catch (Exception e)
                    {
                        logger.Error("A plugin encountered an error whilst handling the ClientConnected event. The client will be disconnected. (See logs for exception)", e);

                        client.DropConnection();

#if PRO
                        clientConnectedEventFailuresCounter.Increment();
#endif
                        return;
                    }

#if PRO
                    double time = (double)(Stopwatch.GetTimestamp() - startTimestamp) / Stopwatch.Frequency;
                    clientConnectedEventTimeHistogram.Report(time);
#endif
                },
                    (_) => client.StartListening()
                    );
            }
        }