private void ReceiveCallback(IAsyncResult ar) { UdpClient listener = (UdpClient) ar.AsyncState; // Check if we already closed the server if (listener.Client == null) return; // WSAECONNRESET: // The virtual circuit was reset by the remote side executing a hard or abortive close. // The application should close the socket; it is no longer usable. On a UDP-datagram socket // this error indicates a previous send operation resulted in an ICMP Port Unreachable message. // Note the spocket settings on creation of the server. It makes us ignore these resets. IPEndPoint senderEndpoint = new IPEndPoint(0, 0); Byte[] receiveBytes = null; try { receiveBytes = listener.EndReceive(ar, ref senderEndpoint); } catch (Exception e) { Log.Error("Unexpected end of transmission?", e); if (listener.Client != null) { try { listener.BeginReceive(ReceiveCallback, listener); } catch (ObjectDisposedException dex) { Log.Error("Unexpected end of transmission?", dex); } } return; } if (receiveBytes.Length != 0) { listener.BeginReceive(ReceiveCallback, listener); ServerInfo.AvailableBytes = listener.Available; ServerInfo.NumberOfPacketsInPerSecond++; ServerInfo.TotalPacketSizeIn += receiveBytes.Length; try { if (!GreylistManager.IsWhitelisted(senderEndpoint.Address) && GreylistManager.IsBlacklisted(senderEndpoint.Address)) return; if (GreylistManager.IsGreylisted(senderEndpoint.Address)) return; ProcessMessage(receiveBytes, senderEndpoint); } catch (Exception e) { //Log.Warn(string.Format("Process message error from: {0}", senderEndpoint.Address), e); } } else { //Log.Error("Unexpected end of transmission?"); } }
private void HandleRakNetMessage(IPEndPoint senderEndpoint, OpenConnectionRequest1 incoming) { if (!GreylistManager.AcceptConnection(senderEndpoint)) { var noFree = NoFreeIncomingConnections.CreateObject(); var bytes = noFree.Encode(); noFree.PutPool(); TraceSend(noFree); SendData(bytes, senderEndpoint, new object()); return; } if (Log.IsDebugEnabled) { Log.DebugFormat("New connection from: {0} {1}", senderEndpoint.Address, senderEndpoint.Port); } lock (_playerSessions) { // Already connecting, then this is just a duplicate if (_connectionAttemps.ContainsKey(senderEndpoint)) { DateTime created; _connectionAttemps.TryGetValue(senderEndpoint, out created); if (DateTime.UtcNow < created + TimeSpan.FromSeconds(3)) { return; } _connectionAttemps.TryRemove(senderEndpoint, out created); } if (!_connectionAttemps.TryAdd(senderEndpoint, DateTime.UtcNow)) { return; } } var packet = OpenConnectionReply1.CreateObject(); packet.serverGuid = 12345; packet.mtuSize = incoming.mtuSize; packet.serverHasSecurity = 0; var data = packet.Encode(); packet.PutPool(); TraceSend(packet); SendData(data, senderEndpoint, new object()); }
private void Receive(object state) { var listener = (UdpClient)state; while (true) { // Check if we already closed the server if (listener.Client == null) { return; } // WSAECONNRESET: // The virtual circuit was reset by the remote side executing a hard or abortive close. // The application should close the socket; it is no longer usable. On a UDP-datagram socket // this error indicates a previous send operation resulted in an ICMP Port Unreachable message. // Note the spocket settings on creation of the server. It makes us ignore these resets. IPEndPoint senderEndpoint = null; try { ReadOnlyMemory <byte> receiveBytes = listener.Receive(ref senderEndpoint); //UdpReceiveResult result = listener.ReceiveAsync().Result; //senderEndpoint = result.RemoteEndPoint; //byte[] receiveBytes = result.Buffer; Interlocked.Increment(ref ServerInfo.NumberOfPacketsInPerSecond); Interlocked.Add(ref ServerInfo.TotalPacketSizeInPerSecond, receiveBytes.Length); if (receiveBytes.Length != 0) { _receiveThreadPool.QueueUserWorkItem(() => { try { if (!GreylistManager.IsWhitelisted(senderEndpoint.Address) && GreylistManager.IsBlacklisted(senderEndpoint.Address)) { return; } if (GreylistManager.IsGreylisted(senderEndpoint.Address)) { return; } ProcessMessage(this, receiveBytes, senderEndpoint); } catch (Exception e) { Log.Warn($"Process message error from: {senderEndpoint.Address}", e); } }); } else { Log.Warn("Unexpected end of transmission?"); continue; } } catch (SocketException e) { if (e.ErrorCode != 10004) { Log.Error("Unexpected end of receive", e); } if (listener.Client != null) { continue; } return; } } }
private void HandleRakNetMessage(byte[] receiveBytes, IPEndPoint senderEndpoint, byte msgId) { DefaultMessageIdTypes msgIdType = (DefaultMessageIdTypes)msgId; // Increase fast, decrease slow on 1s ticks. if (ServerInfo.NumberOfPlayers < ServerInfo.PlayerSessions.Count) { ServerInfo.NumberOfPlayers = ServerInfo.PlayerSessions.Count; } // Shortcut to reply fast, and no parsing if (msgIdType == DefaultMessageIdTypes.ID_OPEN_CONNECTION_REQUEST_1) { if (!GreylistManager.AcceptConnection(senderEndpoint.Address)) { var noFree = NoFreeIncomingConnections.CreateObject(); var bytes = noFree.Encode(); noFree.PutPool(); TraceSend(noFree); SendData(bytes, senderEndpoint); Interlocked.Increment(ref ServerInfo.NumberOfDeniedConnectionRequestsPerSecond); return; } } Package message = null; try { try { message = PackageFactory.CreatePackage(msgId, receiveBytes, "raknet"); } catch (Exception) { message = null; } if (message == null) { GreylistManager.Blacklist(senderEndpoint.Address); Log.ErrorFormat("Receive bad packet with ID: {0} (0x{0:x2}) {2} from {1}", msgId, senderEndpoint.Address, (DefaultMessageIdTypes)msgId); return; } TraceReceive(message); switch (msgIdType) { case DefaultMessageIdTypes.ID_UNCONNECTED_PING: case DefaultMessageIdTypes.ID_UNCONNECTED_PING_OPEN_CONNECTIONS: { HandleRakNetMessage(senderEndpoint, (UnconnectedPing)message); break; } case DefaultMessageIdTypes.ID_OPEN_CONNECTION_REQUEST_1: { HandleRakNetMessage(senderEndpoint, (OpenConnectionRequest1)message); break; } case DefaultMessageIdTypes.ID_OPEN_CONNECTION_REQUEST_2: { HandleRakNetMessage(senderEndpoint, (OpenConnectionRequest2)message); break; } default: GreylistManager.Blacklist(senderEndpoint.Address); Log.ErrorFormat("Receive unexpected packet with ID: {0} (0x{0:x2}) {2} from {1}", msgId, senderEndpoint.Address, (DefaultMessageIdTypes)msgId); break; } } finally { if (message != null) { message.PutPool(); } } }
private void ProcessMessage(byte[] receiveBytes, IPEndPoint senderEndpoint) { byte msgId = receiveBytes[0]; if (msgId == 0xFE) { Log.InfoFormat("A query detected from: {0}", senderEndpoint.Address); HandleQuery(receiveBytes, senderEndpoint); } else if (msgId <= (byte)DefaultMessageIdTypes.ID_USER_PACKET_ENUM) { HandleRakNetMessage(receiveBytes, senderEndpoint, msgId); } else { PlayerNetworkSession playerSession; if (!_playerSessions.TryGetValue(senderEndpoint, out playerSession)) { //Log.DebugFormat("Receive MCPE message 0x{1:x2} without session {0}", senderEndpoint.Address, msgId); //if (!_badPacketBans.ContainsKey(senderEndpoint.Address)) //{ // _badPacketBans.Add(senderEndpoint.Address, true); //} return; } if (playerSession.MessageHandler == null) { Log.ErrorFormat("Receive MCPE message 0x{1:x2} without message handler {0}. Session removed.", senderEndpoint.Address, msgId); _playerSessions.TryRemove(senderEndpoint, out playerSession); //if (!_badPacketBans.ContainsKey(senderEndpoint.Address)) //{ // _badPacketBans.Add(senderEndpoint.Address, true); //} return; } if (playerSession.Evicted) { return; } playerSession.LastUpdatedTime = DateTime.UtcNow; DatagramHeader header = new DatagramHeader(receiveBytes[0]); if (!header.isACK && !header.isNAK && header.isValid) { if (receiveBytes[0] == 0xa0) { throw new Exception("Receive ERROR, NAK in wrong place"); } ConnectedPackage package = ConnectedPackage.CreateObject(); try { package.Decode(receiveBytes); } catch (Exception e) { playerSession.Disconnect("Bad package received from client."); Log.Warn($"Bad packet {receiveBytes[0]}\n{Package.HexDump(receiveBytes)}", e); GreylistManager.Blacklist(senderEndpoint.Address); return; } // IF reliable code below is enabled, useItem start sending doubles // for some unknown reason. //Reliability reliability = package._reliability; //if (reliability == Reliability.Reliable // || reliability == Reliability.ReliableSequenced // || reliability == Reliability.ReliableOrdered // ) { EnqueueAck(playerSession, package._datagramSequenceNumber); //if (Log.IsDebugEnabled) Log.Debug("ACK on #" + package._datagramSequenceNumber.IntValue()); } HandleConnectedPackage(playerSession, package); package.PutPool(); } else if (header.isACK && header.isValid) { HandleAck(playerSession, receiveBytes); } else if (header.isNAK && header.isValid) { HandleNak(playerSession, receiveBytes); } else if (!header.isValid) { Log.Warn("!!!! ERROR, Invalid header !!!!!"); } } }
private void HandleRakNetMessage(byte[] receiveBytes, IPEndPoint senderEndpoint, byte msgId) { DefaultMessageIdTypes msgIdType = (DefaultMessageIdTypes)msgId; Package message = null; try { try { message = PackageFactory.CreatePackage(msgId, receiveBytes); } catch (Exception) { message = null; } if (message == null) { GreylistManager.Blacklist(senderEndpoint.Address); Log.ErrorFormat("Receive bad packet with ID: {0} (0x{0:x2}) {2} from {1}", msgId, senderEndpoint.Address, (DefaultMessageIdTypes)msgId); return; } TraceReceive(message); switch (msgIdType) { case DefaultMessageIdTypes.ID_UNCONNECTED_PING: case DefaultMessageIdTypes.ID_UNCONNECTED_PING_OPEN_CONNECTIONS: { HandleRakNetMessage(senderEndpoint, (UnconnectedPing)message); break; } case DefaultMessageIdTypes.ID_OPEN_CONNECTION_REQUEST_1: { HandleRakNetMessage(senderEndpoint, (OpenConnectionRequest1)message); break; } case DefaultMessageIdTypes.ID_OPEN_CONNECTION_REQUEST_2: { HandleRakNetMessage(senderEndpoint, (OpenConnectionRequest2)message); break; } default: GreylistManager.Blacklist(senderEndpoint.Address); Log.ErrorFormat("Receive unexpected packet with ID: {0} (0x{0:x2}) {2} from {1}", msgId, senderEndpoint.Address, (DefaultMessageIdTypes)msgId); break; } } finally { if (message != null) { message.PutPool(); } } }