private void DataReceived(byte[] reusableBuffer, int count, NetEndPoint remoteEndPoint) { #if STATS_ENABLED Statistics.PacketsReceived++; Statistics.BytesReceived += (uint)count; #endif //Try read packet NetPacket packet = NetPacketPool.GetAndRead(reusableBuffer, 0, count); if (packet == null) { NetUtils.DebugWriteError("[NM] DataReceived: bad!"); return; } //Check unconnected switch (packet.Property) { case PacketProperty.DiscoveryRequest: if (DiscoveryEnabled) { var netEvent = CreateEvent(NetEventType.DiscoveryRequest); netEvent.RemoteEndPoint = remoteEndPoint; netEvent.DataReader.SetSource(packet); EnqueueEvent(netEvent); packet.Recycle(); } return; case PacketProperty.DiscoveryResponse: { var netEvent = CreateEvent(NetEventType.DiscoveryResponse); netEvent.RemoteEndPoint = remoteEndPoint; netEvent.DataReader.SetSource(packet); EnqueueEvent(netEvent); packet.Recycle(); } return; case PacketProperty.UnconnectedMessage: if (UnconnectedMessagesEnabled) { var netEvent = CreateEvent(NetEventType.ReceiveUnconnected); netEvent.RemoteEndPoint = remoteEndPoint; netEvent.DataReader.SetSource(packet); EnqueueEvent(netEvent); packet.Recycle(); } return; case PacketProperty.NatIntroduction: case PacketProperty.NatIntroductionRequest: case PacketProperty.NatPunchMessage: { if (NatPunchEnabled) { NatPunchModule.ProcessMessage(remoteEndPoint, packet); } packet.Recycle(); return; } } //Check normal packets NetPeer netPeer; //lock (_peers) { _peers.TryGetValue(remoteEndPoint, out netPeer); } if (netPeer != null && netPeer.ConnectionState != ConnectionState.Disconnected) { switch (packet.Property) { case PacketProperty.Disconnect: if (netPeer.ConnectionState == ConnectionState.InProgress || netPeer.ConnectionState == ConnectionState.Connected) { if (BitConverter.ToInt64(packet.RawData, 0) == netPeer.ConnectId) { var netEvent = CreateEvent(NetEventType.Disconnect); netEvent.Peer = netPeer; netEvent.DataReader.SetSource(packet.RawData, sizeof(long), packet.GetDataSize() - sizeof(long)); netEvent.DisconnectReason = DisconnectReason.RemoteConnectionClose; EnqueueEvent(netEvent); } } break; case PacketProperty.ShutdownOk: if (netPeer.ConnectionState == ConnectionState.ShutdownRequested) { netPeer.ProcessPacket(packet); NetUtils.DebugWriteForce(ConsoleColor.Cyan, "[NM] ShutdownOK!"); } break; case PacketProperty.ConnectAccept: if (netPeer.ProcessConnectAccept(packet)) { var connectEvent = CreateEvent(NetEventType.Connect); connectEvent.Peer = netPeer; EnqueueEvent(connectEvent); } break; default: netPeer.ProcessPacket(packet); break; } packet.Recycle(); return; } //Unacked shutdown if (packet.Property == PacketProperty.Disconnect) { byte[] data = { (byte)PacketProperty.ShutdownOk }; SendRaw(data, 0, 1, remoteEndPoint); return; } if (packet.Property == PacketProperty.ConnectRequest && packet.Size >= 12) { lock (_connectingPeers) { if (_connectingPeers.Contains(remoteEndPoint)) { return; } } int peersCount = GetPeersCount(ConnectionState.Connected | ConnectionState.InProgress); if (peersCount < _maxConnections) { int protoId = BitConverter.ToInt32(packet.RawData, 0); if (protoId != NetConstants.ProtocolId) { NetUtils.DebugWrite(ConsoleColor.Cyan, "[NM] Peer connect reject. Invalid protocol ID: " + protoId); return; } //Getting new id for peer long connectionId = BitConverter.ToInt64(packet.RawData, sizeof(int)); // Read data and create request var reader = new NetDataReader(null, 0, 0); if (packet.GetDataSize() > sizeof(int) + sizeof(long)) { reader.SetSource(packet.RawData, sizeof(int) + sizeof(long), packet.GetDataSize() - sizeof(int) - sizeof(long)); } lock (_connectingPeers) { _connectingPeers.Add(remoteEndPoint); } var netEvent = CreateEvent(NetEventType.ConnectionRequest); netEvent.ConnectionRequest = new ConnectionRequest(connectionId, remoteEndPoint, reader, OnConnectionSolved); if (String.IsNullOrEmpty(PasscodeKey) == true) { EnqueueEvent(netEvent); } else { netEvent.ConnectionRequest.AcceptIfKey(PasscodeKey); OnConnectionSolved(netEvent.ConnectionRequest); } } } }
//Update function private void UpdateLogic() { long startNowMs = NetTime.NowMs; long timeout = startNowMs + UpdateTime; if (_receiveBuffer == null) { _receiveBuffer = NetPacketPool.Get(PacketProperty.Sequenced, 0, NetConstants.MaxPacketSize); } //while (true) { #if DEBUG if (SimulateLatency) { var time = DateTime.UtcNow; lock (_pingSimulationList) { for (int i = 0; i < _pingSimulationList.Count; i++) { var incomingData = _pingSimulationList[i]; if (incomingData.TimeWhenGet <= time) { DataReceived(incomingData.Data, incomingData.Data.Length, incomingData.EndPoint); _pingSimulationList.RemoveAt(i); i--; } } } } #endif #if STATS_ENABLED ulong totalPacketLoss = 0; #endif // Flush disconnection first //lock (_peers) { //Process acks for (int i = 0; i < _peers.Count; i++) { NetPeer netPeer = _peers[i]; netPeer.Update(UpdateTime); #if STATS_ENABLED totalPacketLoss += netPeer.Statistics.PacketLoss; #endif } //Process ping for (int i = 0; i < _peers.Count; i++) { _peers[i].ProcessPong(UpdateTime); } } #if STATS_ENABLED Statistics.PacketLoss = totalPacketLoss; #endif _socket.Receive(false, _receiveBuffer.RawData); _socket.Receive(true, _receiveBuffer.RawData); PollEvents(); long currentNowMs = NetTime.NowMs; int remainingTime = (int)(timeout - currentNowMs); Thread.Sleep(remainingTime > 0 ? remainingTime : 0); currentNowMs = NetTime.NowMs; long elapsedNowMs = currentNowMs - startNowMs; startNowMs = currentNowMs; AvgUpdateTime = (long)((elapsedNowMs * 6.0f + _updateTimeFilter[0] * 3.0f + _updateTimeFilter[1] * 2.0f + _updateTimeFilter[2] * 1.0f) / 12.0f); _updateTimeFilter[2] = _updateTimeFilter[1]; _updateTimeFilter[1] = _updateTimeFilter[0]; _updateTimeFilter[0] = elapsedNowMs; //break; } }