public static NetServerInfo DecodeResponse(NetMessage msg, IPEndPoint ep) { if (msg == null) { throw new ArgumentNullException("msg"); } NetServerInfo info = new NetServerInfo(); info.NumConnected = msg.ReadUInt16(); info.MaxConnections = msg.ReadUInt16(); info.ServerName = msg.ReadString(); info.RemoteEndpoint = ep; return(info); }
internal void HandlePong(double now, NetMessage pongMessage) { int nr = pongMessage.ReadByte(6); if (nr != m_pingNrInProgress) { m_connection.Parent.Log.Warning("Pong received for wrong ping; received " + nr + " expecting " + m_pingNrInProgress); return; } double roundtrip = now - m_lastSentPing; // spike, or can we use this roundtrip? double avgRT = pongMessage.Sender.AverageRoundtripTime; if (roundtrip > avgRT * 2.0) { // must be spike m_connection.Parent.Log.Verbose("Not adjusting clock due lag spike... (rt " + NetUtil.SecToMil(roundtrip) + " avg " + NetUtil.SecToMil(avgRT) + ")"); } else { ushort val = pongMessage.ReadUInt16(); int curOffset = m_connection.RemoteClockOffset; int foundOffset = NetTime.CalculateOffset(now, val, roundtrip); int res = NetTime.MergeOffsets(curOffset, foundOffset); int rtMillis = (int)(roundtrip * 1000.0); if (res != curOffset) { //m_connection.Parent.Log.Verbose("Ping: " + rtMillis + " Local: " + NetTime.Encoded(now) + " CurOffset: " + curOffset + " Remote: " + val + " NewOffset: " + res + " (adjusted " + (res - curOffset) + ")"); m_connection.Parent.Log.Verbose("Roundtrip: " + rtMillis + " ms; Ajusted remote offset " + (res - curOffset) + " ms"); m_connection.RemoteClockOffset = res; } } AddRoundtrip((float)roundtrip); if (m_connection.Parent is NetServer) { // server is authorative on settings optimizing roundtrip numbers m_connection.Configuration.OptimizeSettings(m_averageRoundtrip); SendOptimizeInfo(m_averageRoundtrip); } return; }
internal override void HandlePacket(NetBuffer buffer, int bytesReceived, IPEndPoint senderEndpoint) { double now = NetTime.Now; NetConnection sender = FindConnection(senderEndpoint); if (sender != null) { sender.m_lastHeardFromRemote = now; if (sender.m_encryption.SymmetricEncryptionKeyBytes != null) { bool ok = sender.m_encryption.DecryptSymmetric(buffer); if (!ok) { Log.Warning("Failed to decrypt packet from client " + sender); return; } } } try { NetMessage response; int messagesReceived = 0; int usrMessagesReceived = 0; int ackMessagesReceived = 0; while (buffer.ReadBitsLeft > 7) { NetMessage msg = NetMessage.Decode(buffer); if (msg == null) { break; // done } messagesReceived++; msg.Sender = sender; switch (msg.m_type) { case NetMessageType.Acknowledge: case NetMessageType.AcknowledgeBitField: if (sender == null) { Log.Warning("Received Ack from not-connected source!"); } else { //Log.Debug("Received ack " + msg.SequenceChannel + "|" + msg.SequenceNumber); sender.ReceiveAcknowledge(msg); ackMessagesReceived++; } break; case NetMessageType.Handshake: NetHandshakeType tp = (NetHandshakeType)msg.ReadByte(); if (tp == NetHandshakeType.ConnectResponse) { Log.Warning("Received ConnectResponse?!"); } else if (tp == NetHandshakeType.Connect) { if (sender == null) { NetHandshake.HandleConnect(msg, this, senderEndpoint); } else { // resend response NetHandshake.SendConnectResponse(this, sender, senderEndpoint); Log.Verbose("Redundant Connect received; resending response"); } } else if (tp == NetHandshakeType.ConnectionEstablished) { if (sender == null) { Log.Warning("Received ConnectionEstablished, but no sender connection?!"); } else { float rt = (float)(now - sender.m_firstSentHandshake); sender.m_ping.Initialize(rt); ushort remoteValue = msg.ReadUInt16(); sender.RemoteClockOffset = NetTime.CalculateOffset(now, remoteValue, rt); Log.Verbose("Reinitializing remote clock offset to " + sender.RemoteClockOffset + " ms (roundtrip " + NetUtil.SecToMil(rt) + " ms)"); if (sender.Status == NetConnectionStatus.Connected) { Log.Verbose("Redundant ConnectionEstablished received"); } else { Log.Debug("Connection established"); sender.SetStatus(NetConnectionStatus.Connected, "Connected by established"); } } } else { // disconnected if (sender == null) { Log.Warning("Disconnected received from unconnected source: " + senderEndpoint); return; } string reason = msg.ReadString(); sender.Disconnected(reason); } break; case NetMessageType.Discovery: Log.Debug("Answering discovery response from " + senderEndpoint); response = NetDiscovery.EncodeResponse(this); SendSingleMessageAtOnce(response, null, senderEndpoint); break; case NetMessageType.PingPong: if (sender == null) { return; } bool isPong = msg.ReadBoolean(); bool isOptimizeInfo = msg.ReadBoolean(); if (isOptimizeInfo) { // DON'T handle optimizeinfo... only clients should adapt to server ping info } else if (isPong) { if (sender.Status == NetConnectionStatus.Connected) { sender.m_ping.HandlePong(now, msg); } } else { NetPing.ReplyPong(msg, sender); // send pong } break; case NetMessageType.User: case NetMessageType.UserFragmented: usrMessagesReceived++; if (sender == null) { Log.Warning("User message received from unconnected source: " + senderEndpoint); return; // don't handle user messages from unconnected sources } if (sender.Status == NetConnectionStatus.Connecting) { sender.SetStatus(NetConnectionStatus.Connected, "Connected by user message"); } sender.ReceiveMessage(now, msg); break; default: Log.Warning("Bad message type: " + msg); break; } } if (sender != null) { NetStatistics stats = sender.Statistics; stats.PacketsReceived++; stats.MessagesReceived += messagesReceived; stats.UserMessagesReceived += usrMessagesReceived; stats.AckMessagesReceived += ackMessagesReceived; stats.BytesReceived += bytesReceived; } } catch (Exception ex) { Log.Error("Failed to parse packet correctly; read/write mismatch? " + ex); } }
internal static void HandleConnect(NetMessage connectMsg, NetServer server, IPEndPoint senderEndpoint) { NetMessage response; if (server.NumConnected >= server.Configuration.MaximumConnections) { // server full response = new NetMessage(NetMessageType.Handshake, "Server full".Length + 1); response.Write((byte)NetHandshakeType.Disconnected); response.Write("Server full"); server.SendSingleMessageAtOnce(response, null, senderEndpoint); return; } ushort remoteNow = connectMsg.ReadUInt16(); //server.Log.Debug("Setting remote clock based on guess of 50 ms lag..."); int remoteClockOffset = NetTime.CalculateOffset(NetTime.Now, remoteNow, 0.05); // assume 50ms... // read symmetric key int encSymKeyLen = connectMsg.ReadUInt16(); byte[] encSymKey = null; if (encSymKeyLen > 0) { encSymKey = connectMsg.ReadBytes(encSymKeyLen); } // read custom data int cdLen = (int)connectMsg.Read7BitEncodedUInt(); byte[] customData = null; if (cdLen > 0) { customData = connectMsg.ReadBytes(cdLen); } string failReason = null; bool ok = server.ApproveConnection(senderEndpoint, customData, out failReason); if (!ok) { if (!string.IsNullOrEmpty(failReason)) { // send disconnect reason; unencrypted, client can handle it because status is connecting response = new NetMessage(NetMessageType.Handshake, failReason.Length + 3); response.Write((byte)NetHandshakeType.Disconnected); response.Write(failReason); server.SendSingleMessageAtOnce(response, null, senderEndpoint); } // connection not approved return; } NetConnection connection = server.AddConnection(senderEndpoint, remoteClockOffset); if (connection == null) { return; // uh oh } if (encSymKeyLen > 0) { byte[] symKey = connection.m_encryption.DecryptRSA(encSymKey); if (symKey == null) { // send disconnect unencrypted, client can handle it because status is connecting string bye = "RSA failed; are you using correct public key?"; response = new NetMessage(NetMessageType.Handshake, bye.Length + 3); response.Write((byte)NetHandshakeType.Disconnected); response.Write(bye); server.SendSingleMessageAtOnce(response, null, senderEndpoint); server.Log.Warning("Failed to decrypt RSA encrypted symmetric key from " + senderEndpoint); return; } connection.m_encryption.SetSymmetricKey(symKey); server.Log.Debug("Received Connect containing key: " + Convert.ToBase64String(symKey)); } else { if (server.Configuration.UsesEncryption) { server.Log.Warning("Client tried to connect without encryption from " + senderEndpoint); // denied response = new NetMessage(NetMessageType.Handshake, "Encryption required".Length + 1); response.Write((byte)NetHandshakeType.Disconnected); response.Write("Encryption required"); server.SendSingleMessageAtOnce(response, null, senderEndpoint); return; } server.Log.Debug("Received Connect - using unencrypted connection!"); } // send connect response int bytesSent = SendConnectResponse(server, connection, senderEndpoint); if (connection != null) { // account for connectresponse connection.Statistics.PacketsSent++; connection.Statistics.MessagesSent++; connection.Statistics.BytesSent += bytesSent; } }
internal static void HandleConnect(NetMessage connectMsg, NetServer server, IPEndPoint senderEndpoint) { NetMessage response; if (server.NumConnected >= server.Configuration.MaximumConnections) { // server full response = new NetMessage(NetMessageType.Handshake, "Server full".Length + 1); response.Write((byte)NetHandshakeType.Disconnected); response.Write("Server full"); server.SendSingleMessageAtOnce(response, null, senderEndpoint); return; } ushort remoteNow = connectMsg.ReadUInt16(); //server.Log.Debug("Setting remote clock based on guess of 50 ms lag..."); int remoteClockOffset = NetTime.CalculateOffset(NetTime.Now, remoteNow, 0.05); // assume 50ms... // read symmetric key int encSymKeyLen = connectMsg.ReadUInt16(); byte[] encSymKey = null; if (encSymKeyLen > 0) encSymKey = connectMsg.ReadBytes(encSymKeyLen); // read custom data int cdLen = (int)connectMsg.Read7BitEncodedUInt(); byte[] customData = null; if (cdLen > 0) customData = connectMsg.ReadBytes(cdLen); string failReason = null; bool ok = server.ApproveConnection(senderEndpoint, customData, out failReason); if (!ok) { if (!string.IsNullOrEmpty(failReason)) { // send disconnect reason; unencrypted, client can handle it because status is connecting response = new NetMessage(NetMessageType.Handshake, failReason.Length + 3); response.Write((byte)NetHandshakeType.Disconnected); response.Write(failReason); server.SendSingleMessageAtOnce(response, null, senderEndpoint); } // connection not approved return; } NetConnection connection = server.AddConnection(senderEndpoint, remoteClockOffset); if (connection == null) return; // uh oh if (encSymKeyLen > 0) { byte[] symKey = connection.m_encryption.DecryptRSA(encSymKey); if (symKey == null) { // send disconnect unencrypted, client can handle it because status is connecting string bye = "RSA failed; are you using correct public key?"; response = new NetMessage(NetMessageType.Handshake, bye.Length + 3); response.Write((byte)NetHandshakeType.Disconnected); response.Write(bye); server.SendSingleMessageAtOnce(response, null, senderEndpoint); server.Log.Warning("Failed to decrypt RSA encrypted symmetric key from " + senderEndpoint); return; } connection.m_encryption.SetSymmetricKey(symKey); server.Log.Debug("Received Connect containing key: " + Convert.ToBase64String(symKey)); } else { if (server.Configuration.UsesEncryption) { server.Log.Warning("Client tried to connect without encryption from " + senderEndpoint); // denied response = new NetMessage(NetMessageType.Handshake, "Encryption required".Length + 1); response.Write((byte)NetHandshakeType.Disconnected); response.Write("Encryption required"); server.SendSingleMessageAtOnce(response, null, senderEndpoint); return; } server.Log.Debug("Received Connect - using unencrypted connection!"); } // send connect response int bytesSent = SendConnectResponse(server, connection, senderEndpoint); if (connection != null) { // account for connectresponse connection.Statistics.PacketsSent++; connection.Statistics.MessagesSent++; connection.Statistics.BytesSent += bytesSent; } }
public static NetServerInfo DecodeResponse(NetMessage msg, IPEndPoint ep) { if (msg == null) throw new ArgumentNullException("msg"); NetServerInfo info = new NetServerInfo(); info.NumConnected = msg.ReadUInt16(); info.MaxConnections = msg.ReadUInt16(); info.ServerName = msg.ReadString(); info.RemoteEndpoint = ep; return info; }