예제 #1
0
        /// <summary>
        /// Client connected. Establish SSL, do handshake and validate client before accepting it.
        /// </summary>
        /// <param name="r"></param>
        void ClientAccepted(IAsyncResult r)
        {
            // Continue listening
            try
            {
                listener.BeginAcceptTcpClient(ClientAccepted, null);
            }
            catch (Exception ex)
            {
                if (IsListening)
                {
                    Logger.Log($"Failed to continue listening... " + ex.GetDetailedMessage(), Logger.LogSeverity.Debug);
                }
                return;
            }

            // Start accepting client
            var client = listener.EndAcceptTcpClient(r);

            Logger.Log($"Client connecting from {client.Client.RemoteEndPoint}...", Logger.LogSeverity.Debug);

            if (plugins?.Invoke(p => p.OnClientConnecting(client), true) == false)
            {
                // reject client
                Logger.Log("Client rejected by plugin.", Logger.LogSeverity.Debug);
                client.ProperlyClose();
                return;
            }

            // Create client object
            var wc = new WorkerClient(client);

            // Start handshake
            try
            {
                var stream = client.GetStream();

                Logger.Log($"Establishing secure connection to {client.Client.RemoteEndPoint}...", Logger.LogSeverity.Debug);
                // setup SSL here
                var sslstream = SecurityUtils.ServerEstablishSSL(stream, certificate);

                wc.MesssageHandler = new NetworkMessageHandler <NetworkMessage>(sslstream, m => ClientMessageReceived(wc, m));
                wc.MesssageHandler.ExceptionThrown += (a, b) =>
                {
                    wc.MesssageHandler.Dispose();

                    if (wc.Online)
                    {
                        wc.Online = false;
                        ClientLeft?.Invoke(wc, null);

                        Logger.Log($"Client disconnected from {wc.RemoteEndpoint}! ({wc.Id})");

                        // ignore certain common errors
                        if (!IgnoreError(b))
                        {
                            Logger.Log(b.GetDetailedMessage(), Logger.LogSeverity.Debug);
                        }
                    }
                };

                Logger.Log($"Validating {client.Client.RemoteEndPoint}...", Logger.LogSeverity.Debug);

                wc.Id = SecurityUtils.DoHandshake(wc.MesssageHandler, passwordHash, false, null,
                                                  id => Clients.Count(x => x.Id == id) > 0,
                                                  id =>
                {
                    var c = Clients.Where(x => x.Id == id).FirstOrDefault();
                    if (c == null)
                    {
                        return(false);               // generate new Id if client doesn't exist
                    }
                    if (c.Online == true)
                    {
                        return(false);                      // worker already online with this Id, generate new Id
                    }
                    // worker with this Id is offline, assume this is that worker
                    return(true);
                });

                wc.HandshakeCompleted = true;
            }
            catch (Exception ex)
            {
                Logger.Log($"Rejected client from {wc.RemoteEndpoint}. " + ex.Message, Logger.LogSeverity.Warning);
                Logger.Log(ex.GetDetailedMessage(), Logger.LogSeverity.Debug);

                try
                {
                    wc.MesssageHandler.SendMessage(new NetworkMessage(NetworkMessageType.Reject));
                }
                catch { }

                client.ProperlyClose();
                return;
            }

            wc.Online        = true;
            wc.LastConnected = DateTime.Now;

            // try get existing client
            var ewc = Clients.Where(x => x.Id == wc.Id).FirstOrDefault();

            // Accept valid client
            Logger.Log($"Accepted {(ewc == null ? "new" : "existing")} client from {client.Client.RemoteEndPoint}. ({wc.Id})");
            lock (Clients)
            {
                // if client doesn't exist yet, add it - otherwise replace existing client
                if (ewc == null)
                {
                    Clients.Add(wc);
                }
                else
                {
                    var index = Clients.IndexOf(ewc);

                    Clients[index] = wc;
                }
            }

            plugins?.Invoke(p => p.OnClientConnect(wc.Client, wc.Id));

            // send configuration
            wc.MesssageHandler.SendMessage(new NetworkMessage(NetworkMessageType.ConfigUpdate, WorkerConfig));

            // send client limit
            wc.MesssageHandler.SendMessage(new NetworkMessage(
                                               NetworkMessageType.WorkLimitUpdate, config.ClientWorkLimit));

            ClientJoined?.Invoke(wc, ewc != null);
        }
예제 #2
0
 private void OnClientLeft(RailController client)
 {
     ClientLeft?.Invoke(client);
 }