/// <summary> /// NetManager constructor /// </summary> /// <param name="listener">Network events listener</param> /// <param name="maxConnections">Maximum connections (incoming and outcoming)</param> public NetManager(INetEventListener listener, int maxConnections) { _logicThread = new Thread(UpdateLogic) { Name = "LogicThread", IsBackground = true }; _socket = new NetSocket(ReceiveLogic); _netEventListener = listener; _netEventsQueue = new SwitchQueue <NetEvent>(); _netEventsPool = new Stack <NetEvent>(); NetPacketPool = new NetPacketPool(); NatPunchModule = new NatPunchModule(this); Statistics = new NetStatistics(); _peers = new NetPeerCollection(maxConnections); _connectingPeers = new HashSet <NetEndPoint>(); _maxConnections = maxConnections; _updateTimeFilter = new long[3]; // Precreate all needed Merge Packets for (int i = 0; i < maxConnections * 3; ++i) { NetPacket p = NetPacketPool.Get(PacketProperty.Sequenced, 0, NetConstants.MaxPacketSize); p.Recycle(); } }
//from user thread, our thread, or recv? private void SendPacket(NetPacket packet) { NetUtils.DebugWrite("[RS]Packet: " + packet.Property); switch (packet.Property) { case PacketProperty.ReliableUnordered: if (NetManager.EnableReliableUnorderedChannel) { getReliableUnorderedChannel(packet.Channel).AddToQueue(packet); } break; case PacketProperty.Sequenced: if (NetManager.EnableSequencedChannel) { getSequencedChannel(packet.Channel).AddToQueue(packet); } break; case PacketProperty.ReliableOrdered: if (NetManager.EnableReliableOrderedChannel) { getReliableOrderedChannel(packet.Channel).AddToQueue(packet); } break; case PacketProperty.Unreliable: if (NetManager.EnableSimpleChannel) { getSimpleChannel(packet.Channel).AddToQueue(packet); } break; case PacketProperty.ReliableSequenced: //getReliableSequencedChannel(packet.Channel).AddToQueue(packet); break; case PacketProperty.MtuCheck: //Must check result for MTU fix if (!_netManager.SendRawAndRecycle(packet, _remoteEndPoint)) { _finishMtu = true; } break; case PacketProperty.AckReliable: case PacketProperty.AckReliableOrdered: case PacketProperty.Ping: case PacketProperty.Pong: case PacketProperty.MtuOk: SendRawData(packet); packet.Recycle(); break; default: throw new InvalidPacketException("Unknown packet property: " + packet.Property); } }
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); } return; case PacketProperty.DiscoveryResponse: { var netEvent = CreateEvent(NetEventType.DiscoveryResponse); netEvent.RemoteEndPoint = remoteEndPoint; netEvent.DataReader.SetSource(packet); EnqueueEvent(netEvent); } return; case PacketProperty.UnconnectedMessage: if (UnconnectedMessagesEnabled) { var netEvent = CreateEvent(NetEventType.ReceiveUnconnected); netEvent.RemoteEndPoint = remoteEndPoint; netEvent.DataReader.SetSource(packet); EnqueueEvent(netEvent); } return; case PacketProperty.NatIntroduction: case PacketProperty.NatIntroductionRequest: case PacketProperty.NatPunchMessage: { if (NatPunchEnabled) { NatPunchModule.ProcessMessage(remoteEndPoint, packet); } 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) { //Old or incorrect disconnect packet.Recycle(); return; } 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) { return; } 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); } packet.Recycle(); return; default: netPeer.ProcessPacket(packet); return; } 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); } } } }
//Process incoming packet internal void ProcessPacket(NetPacket packet) { _timeSinceLastPacket = 0; NetUtils.DebugWrite("[RR]PacketProperty: {0}", packet.Property); switch (packet.Property) { case PacketProperty.ConnectRequest: //response with connect long newId = BitConverter.ToInt64(packet.RawData, NetConstants.RequestConnectIdIndex); NetUtils.DebugWrite("ConnectRequest LastId: {0}, NewId: {1}, EP: {2}", _connectId, newId, _remoteEndPoint); if (newId > _connectId) { _connectId = newId; } SendConnectAccept(); packet.Recycle(); break; case PacketProperty.Merged: int pos = 0; while (pos < packet.GetDataSize()) { ushort size = BitConverter.ToUInt16(packet.RawData, pos); pos += sizeof(ushort); NetPacket mergedPacket = _packetPool.GetAndRead(packet.RawData, pos, size); if (mergedPacket == null) { packet.Recycle(); break; } pos += size; ProcessPacket(mergedPacket); } break; //If we get ping, send pong case PacketProperty.Ping: if (NetUtils.RelativeSequenceNumber(packet.Sequence, _remotePingSequence) < 0) { packet.Recycle(); break; } NetUtils.DebugWrite("[PP]Ping receive, send pong"); _remotePingSequence = packet.Sequence; packet.Recycle(); //send _pingMustSend = true; break; //If we get pong, calculate ping time and rtt case PacketProperty.Pong: if (NetUtils.RelativeSequenceNumber(packet.Sequence, _pingSequence) < 0) { packet.Recycle(); break; } _pingSequence = packet.Sequence; long rtt = NetTime.NowMs - _pingTimeStart; UpdateRoundTripTime(rtt); NetUtils.DebugWrite("[PP]Ping: {0}", rtt); packet.Recycle(); break; //Process ack case PacketProperty.AckReliable: getReliableUnorderedChannel(packet.Channel).ProcessAck(packet); packet.Recycle(); break; case PacketProperty.AckReliableOrdered: getReliableOrderedChannel(packet.Channel).ProcessAck(packet); packet.Recycle(); break; //Process in order packets case PacketProperty.Sequenced: if (getSequencedChannel(packet.Channel).ProcessPacket(packet) == false) { packet.Recycle(); } break; case PacketProperty.ReliableUnordered: if (getReliableUnorderedChannel(packet.Channel).ProcessPacket(packet) == false) { packet.Recycle(); } break; case PacketProperty.ReliableOrdered: if (getReliableOrderedChannel(packet.Channel).ProcessPacket(packet) == false) { packet.Recycle(); } break; case PacketProperty.ReliableSequenced: getReliableSequencedChannel(packet.Channel).ProcessPacket(packet); break; //Simple packet without acks case PacketProperty.Unreliable: AddIncomingPacket(packet); return; case PacketProperty.MtuCheck: case PacketProperty.MtuOk: ProcessMtuPacket(packet); break; case PacketProperty.ShutdownOk: _connectionState = ConnectionState.Disconnected; break; default: NetUtils.DebugWriteError("Error! Unexpected packet type: " + packet.Property); break; } }
internal void AddIncomingPacket(NetPacket p) { if (p.IsFragmented) { NetUtils.DebugWrite("Fragment. Id: {0}, Part: {1}, Total: {2}", p.FragmentId, p.FragmentPart, p.FragmentsTotal); //Get needed array from dictionary ushort packetFragId = p.FragmentId; IncomingFragments incomingFragments; if (!_holdedFragments.TryGetValue(packetFragId, out incomingFragments)) { incomingFragments = new IncomingFragments { Fragments = new NetPacket[p.FragmentsTotal] }; _holdedFragments.Add(packetFragId, incomingFragments); } //Cache var fragments = incomingFragments.Fragments; //Error check if (p.FragmentPart >= fragments.Length || fragments[p.FragmentPart] != null) { p.Recycle(); NetUtils.DebugWriteError("Invalid fragment packet"); return; } //Fill array fragments[p.FragmentPart] = p; //Increase received fragments count incomingFragments.ReceivedCount++; //Increase total size incomingFragments.TotalSize += p.GetDataSize(); //Check for finish if (incomingFragments.ReceivedCount != fragments.Length) { return; } NetUtils.DebugWrite("Received all fragments!"); NetPacket resultingPacket = _packetPool.Get(p.Property, 0, incomingFragments.TotalSize); int resultingPacketOffset = 0; int firstFragmentSize = fragments[0].GetDataSize(); for (int i = 0; i < incomingFragments.ReceivedCount; i++) { //Create resulting big packet int fragmentSize = fragments[i].GetDataSize(); Buffer.BlockCopy( fragments[i].RawData, 0, resultingPacket.RawData, resultingPacketOffset + firstFragmentSize * i, fragmentSize); //Free memory fragments[i].Recycle(); fragments[i] = null; } //Send to process _netManager.ReceiveFromPeer(resultingPacket, _remoteEndPoint); //Clear memory //_packetPool.Recycle(resultingPacket); _holdedFragments.Remove(packetFragId); } else //Just simple packet { _netManager.ReceiveFromPeer(p, _remoteEndPoint); //_packetPool.Recycle(p); } }