public void SendSessionStats(EQPacket<SessionStats> statsPacket) { SessionStats sessStats = statsPacket.PacketStruct; // new SessionStats(); ulong packsRecv = statsPacket.PacketStruct.PacketsRecieved; sessStats.PacketsRecieved = statsPacket.PacketStruct.PacketsSent; sessStats.PacketsSent = packsRecv; EQPacket<SessionStats> sessStatsPacket = new EQPacket<SessionStats>(ProtocolOpCode.SessionStatResponse, sessStats, _ipe); _nonSeqQueue.Enqueue(sessStatsPacket); uint avgDelta = RawEQPacket.NetToHostOrder(sessStats.AverageDelta); if (avgDelta > 0) { _rateThreshold = RATE_BASE / (int)avgDelta; _decayRate = DECAY_BASE / (int)avgDelta; //_log.DebugFormat("Adjusting data rate to thresh {0}, decay {1} based on avg delta {2}", _rateThreshold, _decayRate, avgDelta); } }
// Process the different protocol packet types private void ProcessRecvPacket(RawEQPacket packet, Client client) { if (packet.RawOpCode > 0x00ff) // Check for application level packet { //_log.Debug("OPCode above 0x00ff."); packet.RawOpCode = (ushort)IPAddress.NetworkToHostOrder((short)packet.RawOpCode); // orig code says opcode byte order is backwards in this case ApplicationPacketReceived(new EQRawApplicationPacket(packet), client); // Handled by specialized server type return; } int subPacketLen = 0, processed = 0; switch (packet.OpCode) { case ProtocolOpCode.None: _log.Error("Protocol OpCode found not set during packet processing... please fix."); break; case ProtocolOpCode.SessionRequest: // Check for existing client - may be getting blitzed w/ session requests if (client.SessionId != 0 && client.ConnectionState == ConnectionState.Established) { _log.Warn("Recv a sessionRequest for an existing open client."); break; } bool add = (client.SessionId == 0); // handles case of existing clients that aren't connected (no need to re-add) EQPacket<SessionRequest> sessReqPacket = new EQPacket<SessionRequest>(packet); lock (client.syncRoot) { client.SessionId = (UInt32)IPAddress.NetworkToHostOrder((int)sessReqPacket.PacketStruct.SessionId); client.MaxLength = (UInt32)IPAddress.NetworkToHostOrder((int)sessReqPacket.PacketStruct.MaxLength); client.Key = 0x11223344; client.ConnectionState = ConnectionState.Established; //_log.Debug(string.Format("Received Session Request: session {0} maxlength {1}", client.SessionId, client.MaxLength)); PreSendSessionResponse(client); } if (add) { _clientListLock.EnterWriteLock(); try { _clients.Add(client.IPEndPoint.ToString(), client); _log.InfoFormat("New client connecting from {0}", client.IPEndPoint.ToString()); } finally { _clientListLock.ExitWriteLock(); } } break; case ProtocolOpCode.SessionResponse: _log.Warn("Received unhandled SessionResponse OPCode"); break; case ProtocolOpCode.Combined: while (processed < packet.GetPayload().Length) { subPacketLen = Buffer.GetByte(packet.GetPayload(), processed); //_log.Debug("Extracting combined packet of length " + subPacketLen); byte[] embBytes = new byte[subPacketLen]; Buffer.BlockCopy(packet.GetPayload(), processed + 1, embBytes, 0, subPacketLen); RawEQPacket embPacket = new RawEQPacket(client.IPEndPoint, embBytes); ProcessRecvPacket(embPacket, client); processed += subPacketLen + 1; } break; case ProtocolOpCode.SessionDisconnect: lock (client.syncRoot) { switch (client.ConnectionState) { case ConnectionState.Established: _log.Debug("Received client initiated disconnect"); lock (client.syncRoot) client.ConnectionState = ConnectionState.Closed; //client.SendDisconnect(ConnectionState.Closed); break; case ConnectionState.Closing: _log.Debug("Received disconnect during a pending close"); lock (client.syncRoot) client.SendDisconnect(ConnectionState.Closed); break; case ConnectionState.Closed: case ConnectionState.Disconnecting: // This is never sent back... handling a different way _log.Debug("Received expected disconnect"); lock (client.syncRoot) client.ConnectionState = ConnectionState.Closed; break; } } break; case ProtocolOpCode.KeepAlive: lock (client.syncRoot) client.NonSequencedQueue.Enqueue(new RawEQPacket(client.IPEndPoint, packet.RawPacketData)); _log.Debug("Received and replied to a KeepAlive"); break; case ProtocolOpCode.SessionStatRequest: EQPacket<SessionStats> statsPacket = new EQPacket<SessionStats>(packet); //_log.DebugFormat("Received Stats: {0} packets recv, {1} packets sent, Deltas: local {2}, ({3} <- {4} -> {5}) remote {6}", // RawEQPacket.NetToHostOrder(statsPacket.PacketStruct.PacketsRecieved), RawEQPacket.NetToHostOrder(statsPacket.PacketStruct.PacketsRecieved), RawEQPacket.NetToHostOrder(statsPacket.PacketStruct.LastLocalDelta), // RawEQPacket.NetToHostOrder(statsPacket.PacketStruct.LowDelta), RawEQPacket.NetToHostOrder(statsPacket.PacketStruct.AverageDelta), // RawEQPacket.NetToHostOrder(statsPacket.PacketStruct.HighDelta), RawEQPacket.NetToHostOrder(statsPacket.PacketStruct.LastRemoteDelta)); lock (client.syncRoot) client.SendSessionStats(statsPacket); break; case ProtocolOpCode.SessionStatResponse: _log.Debug("Received SessionStatResponse OPCode, ignoring"); break; case ProtocolOpCode.Packet: ushort seqNum = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(packet.GetPayload(), 0)); // get seq num //_log.Debug(string.Format("Received Data Packet: session {0} sequence {1}", client.SessionId, seqNum)); // TODO: figure out the locking strategy here // determine the packet sequence if (seqNum > client.NextInSeq) { _log.DebugFormat("Recv future data packet - expected {0} but got {1}", client.NextInSeq, seqNum); lock (client.syncRoot) { client.DataPackets.Remove(seqNum); client.DataPackets.Add(seqNum, packet); // shove into the deferred packet list } } else if (seqNum < client.NextInSeq) { //_log.DebugFormat("Recv duplicate data packet - expected {0} but got {1}", client.NextInSeq, seqNum); client.SendOutOfOrderAck(seqNum); } else { // Received packet w/ expected seq lock (client.syncRoot) { client.DataPackets.Remove(seqNum); // Remove if it was previously queued as a future packet client.SetNextAckToSend(seqNum); // sequenced packets must be ack'd } // check for embedded OP_AppCombined (0x19) ProtocolOpCode embOp = (ProtocolOpCode)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(packet.GetPayload(), 2)); if (embOp == ProtocolOpCode.AppCombined) { //_log.Debug("Found and extracted an embedded packet in a data packet"); byte[] embBytes = new byte[packet.GetPayload().Length - 4]; // snip the data packet sequence num & AppCombined OpCode Buffer.BlockCopy(packet.GetPayload(), 4, embBytes, 0, packet.GetPayload().Length - 4); RawEQPacket embPacket = new RawEQPacket(ProtocolOpCode.AppCombined, embBytes, client.IPEndPoint); ProcessRecvPacket(embPacket, client); } else { // Needs to be handled by specialized server, let's get us an app packet going byte[] appBytes = new byte[packet.GetPayload().Length - 2]; // snip the data packet sequence num Buffer.BlockCopy(packet.GetPayload(), 2, appBytes, 0, packet.GetPayload().Length - 2); ApplicationPacketReceived(new EQRawApplicationPacket(client.IPEndPoint, appBytes), client); } } break; case ProtocolOpCode.Fragment: ushort fragSeqNum = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(packet.GetPayload(), 0)); if (fragSeqNum > client.NextInSeq) { _log.DebugFormat("Recv future fragment - expected {0} but got {1}", client.NextInSeq, fragSeqNum); lock (client.syncRoot) client.DataPackets.Add(fragSeqNum, packet); // shove into the deferred data packet list } else if (fragSeqNum < client.NextInSeq) { //_log.DebugFormat("Recv duplicate data fragment - expected {0} but got {1}", client.NextInSeq, fragSeqNum); client.SendOutOfOrderAck(fragSeqNum); } else { // Received packet w/ expected seq BasePacket bigPacket = null; lock (client.syncRoot) { client.DataPackets.Remove(fragSeqNum); // Remove if it was previously queued as a future packet client.SetNextAckToSend(fragSeqNum); if (client.OversizedBuffer != null) { // copy this round's fragment into the oversized buffer Buffer.BlockCopy(packet.GetPayload(), 2, client.OversizedBuffer, client.OversizedOffset, packet.GetPayload().Length - 2); client.OversizedOffset += packet.GetPayload().Length - 2; //_log.DebugFormat("Recv fragment - seq {0} now at {1}", fragSeqNum, client.OversizedBuffer.Length / client.OversizedOffset); if (client.OversizedOffset == client.OversizedBuffer.Length) { // I totally don't get this first comparison (shouldn't we be looking in the oversized buffer), but ok... if (Buffer.GetByte(packet.GetPayload(), 2) == 0x00 && Buffer.GetByte(packet.GetPayload(), 3) == 0x19) bigPacket = new RawEQPacket(packet.ClientIPE, client.OversizedBuffer); else bigPacket = new EQRawApplicationPacket(client.IPEndPoint, client.OversizedBuffer); client.OversizedBuffer = null; client.OversizedOffset = 0; //_log.Debug("Completed combined oversized packet."); } } else { uint oversizedLen = (uint)IPAddress.NetworkToHostOrder((int)BitConverter.ToUInt32(packet.GetPayload(), 2)); client.OversizedBuffer = new byte[oversizedLen]; // initialize the oversized packet buffer Buffer.BlockCopy(packet.GetPayload(), 6, client.OversizedBuffer, 0, packet.GetPayload().Length - 6); client.OversizedOffset = packet.GetPayload().Length - 6; //_log.DebugFormat("Recv initial fragment packet - total size: {0} fragment len: {1}", oversizedLen, packet.GetPayload().Length - 6); } } if (bigPacket is RawEQPacket) ProcessRecvPacket(bigPacket as RawEQPacket, client); else if(bigPacket is EQRawApplicationPacket) ApplicationPacketReceived(bigPacket as EQRawApplicationPacket, client); } break; case ProtocolOpCode.OutOfOrderAck: _log.Debug("Received OutOfOrderAck OPCode"); break; case ProtocolOpCode.Ack: ushort ackSeqNum = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(packet.GetPayload(), 0)); // get seq num lock (client.syncRoot) client.AckPackets(ackSeqNum); break; case ProtocolOpCode.AppCombined: //_log.Debug("Processing App Combined packet: " + BitConverter.ToString(packet.RawPacketData)); processed = 0; EQRawApplicationPacket appPacket = null; while (processed < packet.GetPayload().Length) { appPacket = null; subPacketLen = Buffer.GetByte(packet.GetPayload(), processed); if (subPacketLen != 0xff) { //_log.Debug("Extracting App Combined packet of length " + subPacketLen); byte[] appBytes = new byte[subPacketLen]; Buffer.BlockCopy(packet.GetPayload(), processed + 1, appBytes, 0, subPacketLen); appPacket = new EQRawApplicationPacket(client.IPEndPoint, appBytes); processed += (subPacketLen + 1); } else { subPacketLen = IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(packet.GetPayload(), processed + 1)); //_log.Debug("Extracting App Combined packet of length " + subPacketLen); byte[] appBytes = new byte[subPacketLen]; Buffer.BlockCopy(packet.GetPayload(), processed + 3, appBytes, 0, subPacketLen); appPacket = new EQRawApplicationPacket(client.IPEndPoint, appBytes); processed += (subPacketLen + 3); } ApplicationPacketReceived(appPacket, client); } break; case ProtocolOpCode.OutOfSession: _log.Debug("Received OutOfSession OPCode, ignoring"); break; default: _log.Warn("Received Unknown Protocol OPCode: " + (ushort)packet.OpCode); break; } }
public void SendSessionResponse(SessionFormat format) { // re-init the client's queues (might have recv this packet again before the writer had a chance to send the session response (eliminates a race)) ClearQueues(); SessionResponse sessResp = new SessionResponse(); sessResp.SessionId = (UInt32)IPAddress.HostToNetworkOrder((int)_sessionId); sessResp.MaxLength = (UInt32)IPAddress.HostToNetworkOrder((int)_maxLen); sessResp.CRCLength = 2; sessResp.Format = (byte)format; sessResp.Key = (UInt32)IPAddress.HostToNetworkOrder((int)_key); EQPacket<SessionResponse> sessRespPacket = new EQPacket<SessionResponse>(ProtocolOpCode.SessionResponse, sessResp, _ipe); //_log.DebugFormat("Sending SessionResponse to client: session: {0}, maxlen: {1}, key: {2}", _sessionId, _maxLen, _key); _nonSeqQueue.Enqueue(sessRespPacket); }