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 override void HandlePacket(NetBuffer buffer, int bytesReceived, IPEndPoint sender) { double now = NetTime.Now; try { NetMessage msg; if (m_serverConnection == null || m_serverConnection.Status == NetConnectionStatus.Disconnected) { // // unconnected packet // msg = NetMessage.Decode(buffer); if (msg == null) { Log.Warning("Malformed NetMessage?"); return; // malformed? } Log.Verbose("Received unconnected message: " + msg); // discovery response? if (msg.m_type == NetMessageType.Discovery) { NetServerInfo info = NetDiscovery.DecodeResponse(msg, sender); if (ServerDiscovered != null) { ServerDiscovered(this, new NetServerDiscoveredEventArgs(info)); } return; } if (m_serverConnection != null && sender.Equals(m_serverConnection.RemoteEndpoint)) { // we have m_serverConnection, but status is disconnected Log.Warning("Received " + buffer.LengthBytes + " from server; but we're disconnected!"); return; } Log.Warning("Received " + buffer.LengthBytes + " bytes from non-server source: " + sender + "(server is " + m_serverConnection.RemoteEndpoint + ")"); return; } // decrypt in place if (m_serverConnection.m_encryption.SymmetricEncryptionKeyBytes != null) { byte[] savedBuffer = null; if (m_serverConnection.Status == NetConnectionStatus.Connecting) { // special case; save buffer in case we get unencrypted response savedBuffer = new byte[buffer.LengthBytes]; Array.Copy(buffer.Data, 0, savedBuffer, 0, buffer.LengthBytes); } bool ok = m_serverConnection.m_encryption.DecryptSymmetric(buffer); if (!ok) { // failed to decrypt; drop this packet UNLESS we're in a connecting state, // in which case the server may want to tell us something if (m_serverConnection.Status == NetConnectionStatus.Connecting) { // ok let this one thru unencrypted Array.Copy(savedBuffer, buffer.Data, savedBuffer.Length); } else { Log.Warning("Failed to decrypt packet from server!"); return; } } } m_serverConnection.m_lastHeardFromRemote = now; int messagesReceived = 0; int usrMessagesReceived = 0; int ackMessagesReceived = 0; while (buffer.ReadBitsLeft > 7) { msg = NetMessage.Decode(buffer); if (msg == null) { break; // done } messagesReceived++; msg.Sender = m_serverConnection; switch (msg.m_type) { case NetMessageType.Handshake: NetHandshakeType tp = (NetHandshakeType)msg.ReadByte(); if (tp == NetHandshakeType.Connect || tp == NetHandshakeType.ConnectionEstablished) { Log.Warning("Client received " + tp + "?!"); } else if (tp == NetHandshakeType.ConnectResponse) { if (m_serverConnection.Status != NetConnectionStatus.Connecting) { Log.Verbose("Received redundant ConnectResponse!"); break; } // Log.Debug("ConnectResponse received"); m_serverConnection.SetStatus(NetConnectionStatus.Connected, "Connected"); Log.Info("Connected to " + m_serverConnection.RemoteEndpoint); // initialize ping to now - m_firstSentConnect float initRoundtrip = (float)(now - m_serverConnection.m_firstSentHandshake); m_serverConnection.m_ping.Initialize(initRoundtrip); ushort remoteValue = msg.ReadUInt16(); m_serverConnection.RemoteClockOffset = NetTime.CalculateOffset(now, remoteValue, initRoundtrip); Log.Verbose("Initializing remote clock offset to " + m_serverConnection.RemoteClockOffset + " ms (roundtrip " + NetUtil.SecToMil(initRoundtrip) + " ms)"); NetMessage established = new NetMessage(NetMessageType.Handshake, 3); established.Write((byte)NetHandshakeType.ConnectionEstablished); established.WriteSendStamp(); SendSingleMessageAtOnce(established, m_serverConnection, m_serverConnection.RemoteEndpoint); } else { // Disconnected string reason = msg.ReadString(); m_serverConnection.SetStatus(NetConnectionStatus.Disconnected, reason); } break; case NetMessageType.Acknowledge: //Log.Debug("Received ack " + msg.SequenceChannel + "|" + msg.SequenceNumber); m_serverConnection.ReceiveAcknowledge(msg); ackMessagesReceived++; break; case NetMessageType.PingPong: bool isPong = msg.ReadBoolean(); bool isOptimizeInfo = msg.ReadBoolean(); if (isOptimizeInfo) { m_serverConnection.m_ping.HandleOptimizeInfo(now, msg); } else if (isPong) { if (m_serverConnection.Status == NetConnectionStatus.Connected) { m_serverConnection.m_ping.HandlePong(now, msg); } } else { NetPing.ReplyPong(msg, m_serverConnection); } break; case NetMessageType.User: case NetMessageType.UserFragmented: //Log.Debug("User message received; " + msg.m_buffer.LengthBytes + " bytes"); m_serverConnection.ReceiveMessage(now, msg); usrMessagesReceived++; break; case NetMessageType.Discovery: NetServerInfo info = NetDiscovery.DecodeResponse(msg, sender); if (ServerDiscovered != null) { ServerDiscovered(this, new NetServerDiscoveredEventArgs(info)); } break; default: Log.Warning("Client received " + msg.m_type + "?!"); break; } } // add statistics NetStatistics stats = m_serverConnection.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); } }