/// <summary> /// Called when a packet has been received. /// </summary> /// <param name="numBytes">The number of bytes received</param> /// <remarks>This function parses the incoming data into individual packets and then calls the appropriate handler.</remarks> protected override void OnReceive(int numBytes) { //This is the first received packet ... if (Version == eClientVersion.VersionNotChecked) { //Disconnect if the packet seems wrong if (numBytes < 17) // 17 is correct bytes count for 0xF4 packet { if (log.IsWarnEnabled) { log.WarnFormat("Disconnected {0} in login phase because wrong packet size {1}", TcpEndpoint, numBytes); log.Warn("numBytes=" + numBytes); log.Warn(Marshal.ToHexDump("packet buffer:", _pBuf, 0, numBytes)); } GameServer.Instance.Disconnect(this); return; } int version; /// <summary> /// The First Packet Format Change after 1.115c /// If "numbytes" is below 19 we have a pre-1.115c packet ! /// </summary> if (numBytes < 19) { //Currently, the version is sent with the first packet, no //matter what packet code it is version = (_pBuf[12] * 100) + (_pBuf[13] * 10) + _pBuf[14]; // we force the versionning: 200 correspond to 1.100 (1100) // thus we could handle logically packets with version number based on the client version if (version >= 200) version += 900; } else { // post 1.115c // first byte is major (1), second byte is minor (1), third byte is version (15) // revision (c) is also coded in ascii after that, then a build number appear using two bytes (0x$$$$) version = _pBuf[11] * 1000 + _pBuf[12] * 100 + _pBuf[13]; } eClientVersion ver; IPacketLib lib = AbstractPacketLib.CreatePacketLibForVersion(version, this, out ver); if (lib == null) { Version = eClientVersion.VersionUnknown; if (log.IsWarnEnabled) log.Warn(TcpEndpointAddress + " client Version " + version + " not handled on this server!"); GameServer.Instance.Disconnect(this); } else { log.Info("Incoming connection from " + TcpEndpointAddress + " using client version " + version); Version = ver; Out = lib; PacketProcessor = new PacketProcessor(this); } } if (Version != eClientVersion.VersionUnknown) { m_packetProcessor.ReceiveBytes(numBytes); } }
/// <summary> /// Called when a packet has been received. /// </summary> /// <param name="numBytes">The number of bytes received</param> /// <remarks>This function parses the incoming data into individual packets and then calls the appropriate handler.</remarks> protected override void OnReceive(int numBytes) { //This is the first received packet ... if (Version == eClientVersion.VersionNotChecked) { //Disconnect if the packet seems wrong if (numBytes < 17) // 17 is correct bytes count for 0xF4 packet { if (log.IsWarnEnabled) { log.WarnFormat("Disconnected {0} in login phase because wrong packet size {1}", TcpEndpoint, numBytes); log.Warn("numBytes=" + numBytes); log.Warn(Marshal.ToHexDump("packet buffer:", _pBuf, 0, numBytes)); } GameServer.Instance.Disconnect(this); return; } //Currently, the version is sent with the first packet, no //matter what packet code it is int version = (_pBuf[12] * 100) + (_pBuf[13] * 10) + _pBuf[14]; // we force the versionning: 200 correspond to 1.100 (1100) // thus we could handle logically packets with version number based on the client version if (version >= 200) version += 900; eClientVersion ver; IPacketLib lib = AbstractPacketLib.CreatePacketLibForVersion(version, this, out ver); if (lib == null) { Version = eClientVersion.VersionUnknown; if (log.IsErrorEnabled) log.Error(TcpEndpoint + " Client Version " + version + " not handled in this server!"); GameServer.Instance.Disconnect(this); } else { Version = ver; Out = lib; PacketProcessor = new PacketProcessor(this); } } if (Version != eClientVersion.VersionUnknown) { m_packetProcessor.ReceiveBytes(numBytes); } }
/// <summary> /// Callback method for async sends /// </summary> /// <param name="ar"></param> protected static void AsyncTcpSendCallback(IAsyncResult ar) { if (ar == null) { if (log.IsErrorEnabled) log.Error("AsyncSendCallback: ar == null"); return; } var client = (GameClient) ar.AsyncState; try { PacketProcessor pakProc = client.PacketProcessor; Queue<byte[]> q = pakProc.m_tcpQueue; int sent = 0; if (client.IsConnected) sent = client.Socket.EndSend(ar); int dataLength = 0; byte[] data = pakProc.m_tcpSendBuffer; if (data == null) return; lock (((ICollection)q).SyncRoot) { if (q.Count > 0) { // log.WarnFormat("async sent {0} bytes, sending queued packets count: {1}", sent, q.Count); dataLength = CombineTCPPackets(data, q); } if (dataLength <= 0) { // log.WarnFormat("async sent {0} bytes", sent); pakProc.m_sendingTcp = false; return; } } int start = Environment.TickCount; client.Socket.BeginSend(data, 0, dataLength, SocketFlags.None, m_asyncTcpCallback, client); int took = Environment.TickCount - start; if (took > 100 && log.IsWarnEnabled) log.WarnFormat("AsyncTcpSendCallback.BeginSend took {0}ms! (TCP to client: {1})", took, client.ToString()); } catch (ObjectDisposedException ex) { log.Error("Packet processor: ObjectDisposedException", ex); GameServer.Instance.Disconnect(client); } catch (SocketException ex) { log.Error("Packet processor: SocketException", ex); GameServer.Instance.Disconnect(client); } catch (Exception ex) { // assure that no exception is thrown into the upper layers and interrupt game loops! if (log.IsErrorEnabled) log.Error("AsyncSendCallback. client: " + client, ex); GameServer.Instance.Disconnect(client); } }
/// <summary> /// Callback method for async sends /// </summary> /// <param name="ar"></param> protected static void AsyncTcpSendCallback(IAsyncResult ar) { if (ar == null) { if (Log.IsErrorEnabled) { Log.Error("AsyncSendCallback: ar == null"); } return; } var client = (GameClient)ar.AsyncState; try { PacketProcessor pakProc = client.PacketProcessor; Queue <byte[]> q = pakProc._tcpQueue; if (client.IsConnected) { client.Socket.EndSend(ar); } int count = 0; byte[] data = pakProc._tcpSendBuffer; if (data == null) { return; } lock (((ICollection)q).SyncRoot) { if (q.Count > 0) { count = CombinePackets(data, q, client); } if (count <= 0) { pakProc._sendingTcp = false; return; } } int start = Environment.TickCount; client.Socket.BeginSend(data, 0, count, SocketFlags.None, AsyncTcpCallback, client); int took = Environment.TickCount - start; if (took > 100 && Log.IsWarnEnabled) { Log.Warn($"AsyncTcpSendCallback.BeginSend took {took}ms! (TCP to client: {client})"); } } catch (ObjectDisposedException ex) { Log.Error("Packet processor: ObjectDisposedException", ex); GameServer.Instance.Disconnect(client); } catch (SocketException ex) { Log.Error("Packet processor: SocketException", ex); GameServer.Instance.Disconnect(client); } catch (Exception ex) { // assure that no exception is thrown into the upper layers and interrupt game loops! if (Log.IsErrorEnabled) { Log.Error($"AsyncSendCallback. client: {client}", ex); } GameServer.Instance.Disconnect(client); } }