private NetIncomingMessage TryHandleInboundMessage() { Debug.Assert(mPeer != null, "mPeer != null"); if (!mPeer.ReadMessage(out var message)) { return(null); } var connection = message.SenderConnection; var lidgrenId = connection?.RemoteUniqueIdentifier ?? -1; var lidgrenIdHex = BitConverter.ToString(BitConverter.GetBytes(lidgrenId)); switch (message.MessageType) { case NetIncomingMessageType.Data: //Log.Diagnostic($"{message.MessageType}: {message}"); return(message); case NetIncomingMessageType.StatusChanged: Debug.Assert(mGuidLookup != null, "mGuidLookup != null"); Debug.Assert(mNetwork != null, "mNetwork != null"); switch (connection?.Status ?? NetConnectionStatus.None) { case NetConnectionStatus.None: case NetConnectionStatus.InitiatedConnect: case NetConnectionStatus.ReceivedInitiation: case NetConnectionStatus.RespondedAwaitingApproval: case NetConnectionStatus.RespondedConnect: Log.Diagnostic($"{message.MessageType}: {message} [{connection?.Status}]"); break; case NetConnectionStatus.Disconnecting: Log.Debug($"{message.MessageType}: {message} [{connection?.Status}]"); break; case NetConnectionStatus.Connected: { LidgrenConnection intersectConnection; if (!mNetwork.Configuration.IsServer) { intersectConnection = mNetwork.FindConnection <LidgrenConnection>(Guid.Empty); if (intersectConnection == null) { Log.Error("Bad state, no connection found."); mNetwork.Disconnect("client_connection_missing"); connection?.Disconnect("client_connection_missing"); break; } FireHandler( OnConnectionApproved, nameof(OnConnectionApproved), this, new ConnectionEventArgs { NetworkStatus = NetworkStatus.Connecting, Connection = intersectConnection } ); Debug.Assert(connection != null, "connection != null"); var approval = (ApprovalPacket)mCeras.Deserialize(connection.RemoteHailMessage.Data); if (!intersectConnection.HandleApproval(approval)) { mNetwork.Disconnect(NetworkStatus.HandshakeFailure.ToString()); connection.Disconnect(NetworkStatus.HandshakeFailure.ToString()); break; } if (!(mNetwork is ClientNetwork clientNetwork)) { throw new InvalidOperationException(); } clientNetwork.AssignGuid(approval.Guid); Debug.Assert(mGuidLookup != null, "mGuidLookup != null"); mGuidLookup.Add(connection.RemoteUniqueIdentifier, Guid.Empty); } else { Log.Diagnostic($"{message.MessageType}: {message} [{connection?.Status}]"); if (!mGuidLookup.TryGetValue(lidgrenId, out var guid)) { Log.Error($"Unknown client connected ({lidgrenIdHex})."); connection?.Disconnect("server_unknown_client"); break; } intersectConnection = mNetwork.FindConnection <LidgrenConnection>(guid); } if (OnConnected != null) { intersectConnection?.HandleConnected(); } FireHandler( OnConnected, nameof(OnConnected), this, new ConnectionEventArgs { NetworkStatus = NetworkStatus.Online, Connection = intersectConnection } ); } break; case NetConnectionStatus.Disconnected: { Debug.Assert(connection != null, "connection != null"); Log.Debug($"{message.MessageType}: {message} [{connection.Status}]"); var result = (NetConnectionStatus)message.ReadByte(); var reason = message.ReadString(); NetworkStatus networkStatus; try { switch (reason) { //Lidgren won't accept a connection with a bad version and sends this message back so we need to manually handle it case "Wrong application identifier!": networkStatus = NetworkStatus.VersionMismatch; break; case "Connection timed out": networkStatus = NetworkStatus.Quitting; break; case "Failed to establish connection - no response from remote host": networkStatus = NetworkStatus.Offline; break; default: networkStatus = (NetworkStatus)Enum.Parse(typeof(NetworkStatus), reason ?? "<null>", true); break; } } catch (Exception exception) { Log.Diagnostic(exception); networkStatus = NetworkStatus.Unknown; } HandleConnectionEvent disconnectHandler; string disconnectHandlerName; switch (networkStatus) { case NetworkStatus.HandshakeFailure: case NetworkStatus.ServerFull: case NetworkStatus.VersionMismatch: case NetworkStatus.Failed: disconnectHandler = OnConnectionDenied; disconnectHandlerName = nameof(OnConnectionDenied); break; case NetworkStatus.Connecting: case NetworkStatus.Online: case NetworkStatus.Offline: case NetworkStatus.Quitting: case NetworkStatus.Unknown: disconnectHandler = OnDisconnected; disconnectHandlerName = nameof(OnDisconnected); break; default: throw new ArgumentOutOfRangeException(); } if (!mGuidLookup.TryGetValue(lidgrenId, out var guid)) { Log.Debug($"Unknown client disconnected ({lidgrenIdHex})."); FireHandler(disconnectHandler, disconnectHandlerName, this, new ConnectionEventArgs { NetworkStatus = networkStatus }); break; } var client = mNetwork.FindConnection(guid); if (client != null) { client.HandleDisconnected(); FireHandler(disconnectHandler, disconnectHandlerName, this, new ConnectionEventArgs { Connection = client, NetworkStatus = NetworkStatus.Offline }); mNetwork.RemoveConnection(client); } mGuidLookup.Remove(connection.RemoteUniqueIdentifier); } break; default: throw new ArgumentOutOfRangeException(); } break; case NetIncomingMessageType.UnconnectedData: OnUnconnectedMessage?.Invoke(mPeer, message); Log.Diagnostic($"Net Incoming Message: {message.MessageType}: {message}"); break; case NetIncomingMessageType.ConnectionApproval: { try { var hail = (HailPacket)mCeras.Deserialize(message.Data); Debug.Assert(SharedConstants.VersionData != null, "SharedConstants.VERSION_DATA != null"); Debug.Assert(hail.VersionData != null, "hail.VersionData != null"); if (!SharedConstants.VersionData.SequenceEqual(hail.VersionData)) { Log.Error($"Bad version detected, denying connection [{lidgrenIdHex}]."); connection?.Deny(NetworkStatus.VersionMismatch.ToString()); break; } if (OnConnectionApproved == null) { Log.Error($"No handlers for OnConnectionApproved, denying connection [{lidgrenIdHex}]."); connection?.Deny(NetworkStatus.Failed.ToString()); break; } /* Approving connection from here-on. */ var aesKey = new byte[32]; mRng?.GetNonZeroBytes(aesKey); var client = new LidgrenConnection(mNetwork, connection, aesKey, hail.RsaParameters); if (!OnConnectionRequested(this, client)) { Log.Warn($"Connection blocked due to ban or ip filter!"); connection?.Deny(NetworkStatus.Failed.ToString()); break; } Debug.Assert(mNetwork != null, "mNetwork != null"); if (!mNetwork.AddConnection(client)) { Log.Error($"Failed to add the connection."); connection?.Deny(NetworkStatus.Failed.ToString()); break; } Debug.Assert(mGuidLookup != null, "mGuidLookup != null"); Debug.Assert(connection != null, "connection != null"); mGuidLookup.Add(connection.RemoteUniqueIdentifier, client.Guid); Debug.Assert(mPeer != null, "mPeer != null"); var approval = new ApprovalPacket(client.Rsa, hail.HandshakeSecret, aesKey, client.Guid); var approvalMessage = mPeer.CreateMessage(); approvalMessage.Data = approval.Data; approvalMessage.LengthBytes = approvalMessage.Data.Length; connection.Approve(approvalMessage); OnConnectionApproved(this, new ConnectionEventArgs { Connection = client, NetworkStatus = NetworkStatus.Online }); } catch { connection?.Deny(NetworkStatus.Failed.ToString()); } break; } case NetIncomingMessageType.VerboseDebugMessage: Log.Diagnostic($"Net Incoming Message: {message.MessageType}: {message.ReadString()}"); break; case NetIncomingMessageType.DebugMessage: Log.Debug($"Net Incoming Message: {message.MessageType}: {message.ReadString()}"); break; case NetIncomingMessageType.WarningMessage: Log.Warn($"Net Incoming Message: {message.MessageType}: {message.ReadString()}"); break; case NetIncomingMessageType.ErrorMessage: case NetIncomingMessageType.Error: Log.Error($"Net Incoming Message: {message.MessageType}: {message.ReadString()}"); break; case NetIncomingMessageType.Receipt: Log.Info($"Net Incoming Message: {message.MessageType}: {message.ReadString()}"); break; case NetIncomingMessageType.DiscoveryRequest: case NetIncomingMessageType.DiscoveryResponse: case NetIncomingMessageType.NatIntroductionSuccess: case NetIncomingMessageType.ConnectionLatencyUpdated: Log.Diagnostic($"Net Incoming Message: {message.MessageType}: {message}"); break; default: throw new ArgumentOutOfRangeException(); } return(null); }
private NetIncomingMessage TryHandleInboundMessage() { Debug.Assert(mPeer != null, "mPeer != null"); if (!mPeer.ReadMessage(out var message)) { return(null); } var connection = message.SenderConnection; var lidgrenId = connection?.RemoteUniqueIdentifier ?? -1; var lidgrenIdHex = BitConverter.ToString(BitConverter.GetBytes(lidgrenId)); switch (message.MessageType) { case NetIncomingMessageType.Data: //Log.Diagnostic($"{message.MessageType}: {message}"); return(message); case NetIncomingMessageType.StatusChanged: Debug.Assert(mGuidLookup != null, "mGuidLookup != null"); Debug.Assert(mNetwork != null, "mNetwork != null"); switch (connection?.Status ?? NetConnectionStatus.None) { case NetConnectionStatus.None: case NetConnectionStatus.InitiatedConnect: case NetConnectionStatus.ReceivedInitiation: case NetConnectionStatus.RespondedAwaitingApproval: case NetConnectionStatus.RespondedConnect: Log.Diagnostic($"{message.MessageType}: {message} [{connection?.Status}]"); break; case NetConnectionStatus.Disconnecting: Log.Debug($"{message.MessageType}: {message} [{connection?.Status}]"); break; case NetConnectionStatus.Connected: { LidgrenConnection intersectConnection; if (!mNetwork.Configuration.IsServer) { intersectConnection = mNetwork.FindConnection <LidgrenConnection>(Guid.Empty); if (intersectConnection == null) { Log.Error("Bad state, no connection found."); mNetwork.Disconnect("client_connection_missing"); connection?.Disconnect("client_connection_missing"); break; } FireHandler( OnConnectionApproved, nameof(OnConnectionApproved), this, intersectConnection ); Debug.Assert(connection != null, "connection != null"); var approval = (ApprovalPacket)mCeras.Deserialize(connection.RemoteHailMessage.Data); if (!intersectConnection.HandleApproval(approval)) { mNetwork?.Disconnect("bad_handshake_secret"); connection.Disconnect("bad_handshake_secret"); break; } var clientNetwork = mNetwork as ClientNetwork; if (clientNetwork == null) { throw new InvalidOperationException(); } clientNetwork.AssignGuid(approval.Guid); Debug.Assert(mGuidLookup != null, "mGuidLookup != null"); mGuidLookup.Add(connection.RemoteUniqueIdentifier, Guid.Empty); } else { Log.Diagnostic($"{message.MessageType}: {message} [{connection?.Status}]"); if (!mGuidLookup.TryGetValue(lidgrenId, out var guid)) { Log.Error($"Unknown client connected ({lidgrenIdHex})."); connection?.Disconnect("server_unknown_client"); break; } intersectConnection = mNetwork.FindConnection <LidgrenConnection>(guid); } if (OnConnected != null) { intersectConnection?.HandleConnected(); } FireHandler(OnConnected, nameof(OnConnected), this, intersectConnection); } break; case NetConnectionStatus.Disconnected: { Debug.Assert(connection != null, "connection != null"); Log.Debug($"{message.MessageType}: {message} [{connection.Status}]"); var result = (NetConnectionStatus)message.ReadByte(); var reason = message.ReadString(); HandleConnectionEvent disconnectHandler; string disconnectHandlerName; switch (reason) { case RejectBadHail: case RejectBadVersion: case RejectServerError: disconnectHandler = OnConnectionDenied; disconnectHandlerName = nameof(OnConnectionDenied); break; default: disconnectHandler = OnDisconnected; disconnectHandlerName = nameof(OnDisconnected); break; } if (!mGuidLookup.TryGetValue(lidgrenId, out var guid)) { Log.Debug($"Unknown client disconnected ({lidgrenIdHex})."); FireHandler(disconnectHandler, disconnectHandlerName, this, null); break; } var client = mNetwork.FindConnection(guid); if (client != null) { client.HandleDisconnected(); FireHandler(disconnectHandler, disconnectHandlerName, this, client); mNetwork.RemoveConnection(client); } mGuidLookup.Remove(connection.RemoteUniqueIdentifier); } break; default: throw new ArgumentOutOfRangeException(); } break; case NetIncomingMessageType.UnconnectedData: OnUnconnectedMessage?.Invoke(mPeer, message); Log.Diagnostic($"Net Incoming Message: {message.MessageType}: {message}"); break; case NetIncomingMessageType.ConnectionApproval: { var hail = (HailPacket)mCeras.Deserialize(message.Data); Debug.Assert(SharedConstants.VersionData != null, "SharedConstants.VERSION_DATA != null"); Debug.Assert(hail.VersionData != null, "hail.VersionData != null"); if (!SharedConstants.VersionData.SequenceEqual(hail.VersionData)) { Log.Error($"Bad version detected, denying connection [{lidgrenIdHex}]."); connection?.Deny(RejectBadVersion); break; } if (OnConnectionApproved == null) { Log.Error($"No handlers for OnConnectionApproved, denying connection [{lidgrenIdHex}]."); connection?.Deny(RejectServerError); break; } /* Approving connection from here-on. */ var aesKey = new byte[32]; mRng?.GetNonZeroBytes(aesKey); var client = new LidgrenConnection(mNetwork, connection, aesKey, hail.RsaParameters); if (!OnConnectionRequested(this, client)) { Log.Warn($"Connection blocked due to ban or ip filter!"); connection?.Deny(RejectServerError); break; } Debug.Assert(mNetwork != null, "mNetwork != null"); if (!mNetwork.AddConnection(client)) { Log.Error($"Failed to add the connection."); connection?.Deny(RejectServerError); break; } Debug.Assert(mGuidLookup != null, "mGuidLookup != null"); Debug.Assert(connection != null, "connection != null"); mGuidLookup.Add(connection.RemoteUniqueIdentifier, client.Guid); Debug.Assert(mPeer != null, "mPeer != null"); var approval = new ApprovalPacket(client.Rsa, hail.HandshakeSecret, aesKey, client.Guid); var approvalMessage = mPeer.CreateMessage(); approvalMessage.Data = approval.Data; approvalMessage.LengthBytes = approvalMessage.Data.Length; connection.Approve(approvalMessage); OnConnectionApproved(this, client); break; } case NetIncomingMessageType.VerboseDebugMessage: Log.Diagnostic($"Net Incoming Message: {message.MessageType}: {message.ReadString()}"); break; case NetIncomingMessageType.DebugMessage: Log.Debug($"Net Incoming Message: {message.MessageType}: {message.ReadString()}"); break; case NetIncomingMessageType.WarningMessage: Log.Warn($"Net Incoming Message: {message.MessageType}: {message.ReadString()}"); break; case NetIncomingMessageType.ErrorMessage: case NetIncomingMessageType.Error: Log.Error($"Net Incoming Message: {message.MessageType}: {message.ReadString()}"); break; case NetIncomingMessageType.Receipt: Log.Info($"Net Incoming Message: {message.MessageType}: {message.ReadString()}"); break; case NetIncomingMessageType.DiscoveryRequest: case NetIncomingMessageType.DiscoveryResponse: case NetIncomingMessageType.NatIntroductionSuccess: case NetIncomingMessageType.ConnectionLatencyUpdated: Log.Diagnostic($"Net Incoming Message: {message.MessageType}: {message}"); break; default: throw new ArgumentOutOfRangeException(); } return(null); }