/// <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); }
private void OnClientLeft(RailController client) { ClientLeft?.Invoke(client); }