示例#1
0
        protected override void HandleConnectionReady(IPEndPoint from)
        {
            if (connectingMessengers.Remove(from))
            {
                // Complete the connection process
                NetConnection conn = new NetConnection(from, this);

                if (!Connections.TryAdd(from, conn))
                {
                    NetLogger.LogError("An error occured trying to add a NetConnection! IP: {0}", from);
                }
                else
                {
                    NetLogger.LogImportant("Client successfully connected from {0}", from);
                    newConnections.Enqueue(conn);
                }
            }
            else
            {
                NetLogger.LogWarning("ConnectionReady sent from non-connecting client @ {0}!", from);
                AddWatchedConnection(from, "connection ready from non-connecting client");
            }

            base.HandleConnectionReady(from);
        }
 void HandleInboundPacket(NetInboundPacket packet)
 {
     if (IsPingPacket(packet.Type))
     {
         HandlePingPacket(packet);
     }
     else if (packet.Type == NetPacketType.AckResponse)
     {
         // Handle ack
         ushort ackid = packet.ReadUInt16();
         if (NetLogger.LogAcks)
         {
             NetLogger.LogVerbose("[ACK] Received {0} from {1}", ackid, packet.Sender);
         }
         packet.Sender.HandleAck(ackid);
     }
     else if (packet.Type == NetPacketType.Custom)
     {
         receivedPackets.Enqueue(packet);
     }
     else if (packet.Type == NetPacketType.Disconnected)
     {
         string reason         = packet.ReadString();
         bool   lostConnection = packet.ReadBool();
         packet.Sender.Disconnect(reason, lostConnection);
     }
     else if (IsRemotePacket(packet.Type))
     {
         HandleRemotePacket(packet);
     }
     else
     {
         NetLogger.LogWarning("Invalid packet sent from {0}. Type: {1}", packet.Sender, packet.Type);
     }
 }
示例#3
0
 protected override void HandleConnectionRequest(NetConnectionRequest request)
 {
     // Check if the password is correct and if there is room
     if (Connections.Count < config.MaxConnections && (config.Password == null || config.Password == request.Password))
     {
         if (!connectingMessengers.Add(request.EndPoint))
         {
             NetLogger.LogWarning("Connection request from already connecting client @ {0}! (or an error occured)", request.EndPoint);
         }
         else
         {
             // Send approval
             NetOutboundPacket approvalPacket = new NetOutboundPacket(NetDeliveryMethod.Unreliable,
                                                                      NetPacketType.ConnectionApproved);
             SendInternalPacket(approvalPacket, request.EndPoint);
         }
     }
     else
     {
         // Send denial
         NetOutboundPacket denialPacket = new NetOutboundPacket(NetDeliveryMethod.Unreliable,
                                                                NetPacketType.ConnectionDenied);
         denialPacket.Write((byte)(Connections.Count < config.MaxConnections ? NetDenialReason.InvalidPassword : NetDenialReason.ServerFull));
         SendInternalPacket(denialPacket, request.EndPoint);
     }
 }
 /// <summary>
 /// Resizes the byte array.
 /// </summary>
 /// <param name="data">The byte array to resize.</param>
 /// <param name="newSize">The new size of the byte array.</param>
 public static void ResizeData(ref byte[] data, int newSize)
 {
     if (newSize < NetBuffer.MaxLength)
     {
         Array.Resize <byte>(ref data, newSize);
     }
     else
     {
         // This really should never happen
         NetLogger.LogWarning("Could not resize buffer, buffer is too long!");
     }
 }
        public void AddIgnoredConnection(IPEndPoint endPoint, string reason, int ignoreTimeMilliseconds)
        {
            NetLogger.LogWarning("[IGNORE:{0}:{1}ms] {2}", endPoint, ignoreTimeMilliseconds, reason);

            IgnoredConnection ignored = new IgnoredConnection(endPoint, ignoreTimeMilliseconds);

            ignoredConnections.TryAdd(endPoint, ignored);

            TrackedConnection temp;

            trackedConnections.TryRemove(endPoint, out temp);
        }
        protected void AddWatchedConnection(IPEndPoint endPoint, string reason)
        {
            if (ignoredConnections.ContainsKey(endPoint))
            {
                return;
            }

            TrackedConnection tracked;

            if (trackedConnections.TryGetValue(endPoint, out tracked))
            {
                tracked.PacketsFrom++;
                tracked.Accumulator++;
            }
            else
            {
                tracked = new TrackedConnection(endPoint);
                if (trackedConnections.TryAdd(endPoint, tracked))
                {
                    NetLogger.LogWarning("[WATCH:{0}] {1}", endPoint, reason);
                }
            }
        }
        void AddRecentPing(int ping)
        {
            // Add the new ping
            recentPings[avgPingI++] = ping;

            // If we've reached the end of one ping collection
            if (avgPingI == recentPings.Length)
            {
                // Average the pings we collected
                AverageRecentPings();
                avgPingI = 0;

                // If we are calculating the base ping as well, set it
                if (baseAvgPing == -1)
                {
                    if (NetLogger.LogFlowControl)
                    {
                        NetLogger.LogVerbose("[FlowControl] Base Ping for {0} set to {1}", EndPoint, lastAvgPing);
                    }
                    baseAvgPing = lastAvgPing;
                }
                else if (NetTime.Now - sendRateSwitchCooldown >= 0)
                {
                    // If the ping increased too much, drop the send rate
                    if (lastAvgPing - baseAvgPing > 80)
                    {
                        sendRateDropped = true;
                        if (!config.DontApplyPingControl)
                        {
                            if (!NetLogger.IgnoreSendRateChanges)
                            {
                                NetLogger.LogWarning("[FlowControl] Dropped send rate for {0}", EndPoint);
                            }
                            chunkSendDelay = droppedSendRate[0];
                            PacketSendRate = droppedSendRate[1];
                        }
                        sendRateSwitchCooldown = NetTime.Now + sendRateSwitchCooldownDelay;
                    }
                    // If the ping returned to normal, try increasing the send rate
                    else if (sendRateDropped && lastAvgPing - baseAvgPing < 80)
                    {
                        sendRateDropped = false;
                        if (!config.DontApplyPingControl)
                        {
                            if (!NetLogger.IgnoreSendRateChanges)
                            {
                                NetLogger.Log("[FlowControl] Send rate set to normal for {0}", EndPoint);
                            }
                            chunkSendDelay = normalSendRate[0];
                            PacketSendRate = normalSendRate[1];
                        }
                        sendRateSwitchCooldown = NetTime.Now + sendRateSwitchCooldownDelay;
                    }
                    // If the average ping dropped, see if we can lower the base ping
                    else if (!sendRateDropped && lastAvgPing - baseAvgPing < -20)
                    {
                        if (NetLogger.LogFlowControl)
                        {
                            NetLogger.LogVerbose("[FlowControl] Attempting to increase base ping for {0}...", EndPoint);
                        }
                        RecalculateBasePing();
                    }
                }
            }
        }
        bool HandlePartial(ref NetInboundPacket packet)
        {
            // Read the partials header (6 bytes)
            ushort partialId   = packet.ReadUInt16();
            byte   index       = packet.ReadByte();
            byte   numPartials = packet.ReadByte();
            ushort partialSize = packet.ReadUInt16();

            PartialPacket partial;

            // See if the partial already exists
            if (!packet.Sender.Partials.TryGetValue(partialId, out partial))
            {
                // Since the partial doesn't exist, create one.
                if (!packet.Sender.Partials.TryAdd(partialId,
                                                   partial = new PartialPacket(packet.Sender, partialId, numPartials, partialSize)))
                {
                    //NetLogger.LogError("[Partial:{0}:{1}] Failed to add new partial!", packet.Sender.EndPoint, partialId);
                    //return false;

                    // TODO: See if theres a better way to handle this partial packet concurrency issue

                    // If for some reason, two partials are processed simultaneously,
                    // and it tried adding two packets at once,
                    // we'll just grab the packet created by the other and move on.
                    partial = packet.Sender.Partials[partialId];
                }
                else
                {
                    if (NetLogger.LogPartials)
                    {
                        NetLogger.LogVerbose("[Partial:{0}:{1}] Starting new; NumPackets: {2}; PacketSize: {3}b",
                                             packet.Sender, partialId, numPartials, partialSize);
                    }
                }
            }

            // Add the current partial
            if (partial.AddPacket(index, packet.ReadBytes(partialSize)))
            {
                if (NetLogger.LogPartials)
                {
                    NetLogger.LogVerbose("[Partial:{0}:{1}] Adding index: {2}; PacketsLeft: {3}",
                                         packet.Sender, partialId, index, partial.numPartials - partial.numPartialsReceived);
                }

                // Check if the partial is complete
                if (partial.numPartialsReceived >= partial.numPartials)
                {
                    // Remove the partial from the connections queue
                    if (packet.Sender.Partials.TryRemove(partial.id, out partial))
                    {
                        // Save the old sender
                        NetConnection sender = packet.Sender;
                        // Construct the final packet
                        packet = partial.Construct(packet);
                        // Reset the packets parameters
                        packet.ReadOnly = true;

                        if (NetLogger.LogPartials)
                        {
                            NetLogger.LogVerbose("[Partial:{0}:{1}] Constructed final partial; FullSize: {2}b",
                                                 sender, partialId, packet.Length);
                        }

                        // Process the partial like a physical packet
                        packet.position = 0;
                        if (packet.ReadHeader())
                        {
                            if (packet.isEncrypted)
                            {
                                NetEncryption.DecryptPacket(packet);
                            }
                            if (packet.isCompressed)
                            {
                                NetCompressor.Decompress(packet);
                            }

                            // Update the stats
                            packet.Sender.PartialPacketReceived(numPartials);

                            // Tell the caller this partial is ready!
                            return(true);
                        }
                        else
                        {
                            // Bad stuff happened
                            NetLogger.LogWarning("[Partial:{0}:{1}] Constructed partial packet had invalid header!",
                                                 sender, partialId);
                            return(false);
                        }
                    }
                    else
                    {
                        NetLogger.LogError("[Partial:{0}:{1}] Failed to remove completed partial!",
                                           packet.Sender, partialId);
                    }
                }
            }

            // Tell the caller this partial is not complete
            return(false);
        }
        void PacketReceived(byte[] data, IPEndPoint sender, bool parentWasChunk = false)
        {
            NetInboundPacketBase packet;
            NetInboundPacket     connectionyPacket = null;
            bool connectionless;

            NetConnection senderConn;

            if (Connections.TryGetValue(sender, out senderConn))
            {
                connectionless = false;
                packet         = connectionyPacket = new NetInboundPacket(senderConn, data);

                if (!parentWasChunk)
                {
                    senderConn.PhysicalPacketReceived();
                }
                else
                {
                    senderConn.PacketReceived();
                }
            }
            else
            {
                connectionless = true;
                packet         = new NetConnectionlessInboundPacket(sender, data);
            }

            if (packet.ReadHeader())
            {
                if (packet.isChunked)
                {
                    byte[][] chunks = packet.GetChunked();
                    for (int i = 0; i < chunks.Length; i++)
                    {
                        PacketReceived(chunks[i], sender, true);
                    }
                }
                else
                {
                    if (packet.Type == NetPacketType.MTUTest)
                    {
                        return;
                    }

                    if (ignoredConnections.Count > 0 && ignoredConnections.ContainsKey(sender))
                    {
                        return;
                    }

                    bool packetAlreadyReceived = connectionless ? false : !connectionyPacket.Sender.TryHandlePacket(packet.Id);

                    if (NetLogger.LogPacketReceives && !IsPingPacket(packet.Type) && !packetAlreadyReceived)
                    {
                        NetLogger.LogVerbose("[Inbound:{0}] {1}", sender, packet.ToInternalString());
                    }

                    if (packet.isReliable && !connectionless)
                    {
                        ReplyAck(connectionyPacket, sender);
                    }
                    else if (packet.isReliable && connectionless)
                    {
                        AddWatchedConnection(sender, "Sent reliable connectionless packet");
                    }

                    if (packetAlreadyReceived)
                    {
                        if (NetLogger.LogAlreadyHandledPackets)
                        {
                            NetLogger.LogWarning("[DUPLICATE PACKET:{0}] Ignoring packet {1}", sender, packet.Id);
                        }

                        return;
                    }

                    if (packet.isEncrypted)
                    {
                        NetEncryption.DecryptPacket(packet);
                    }

                    if (packet.isCompressed)
                    {
                        NetCompressor.Decompress(packet);
                    }

                    if (packet.isPartial)
                    {
                        if (connectionyPacket == null)
                        {
                            AddWatchedConnection(sender, "Sent connectionless partial packet");
                            return;
                        }

                        if (!HandlePartial(ref connectionyPacket))
                        {
                            // Partial is not complete yet, so just return
                            return;
                        }
                        else
                        {
                            // Partial is complete, so overrite the current
                            // packet with the completed packet.
                            packet = connectionyPacket;
                        }
                    }

                    if (connectionless)
                    {
                        HandleConnectionlessInboundPacket((NetConnectionlessInboundPacket)packet);
                    }
                    else
                    {
                        HandleInboundPacket((NetInboundPacket)packet);
                    }
                }
            }
            else
            {
                AddWatchedConnection(sender, "Sent packet with invalid signature");
            }
        }
        internal bool Heartbeat(int now)
        {
            if (ignorePing)
            {
                lastPingResponse = now;
            }

            // Check if any reliable non-ordered packet is needed to be resent
            foreach (ReliablePacket packet in reliableOutboundPacketQueue.Values)
            {
                if (now - packet.LastSendAttempt >= config.AckAwaitDelay + Stats.Ping)
                {
                    Stats.PacketsLost++;
                    if (NetLogger.LogReliableResends)
                    {
                        NetLogger.LogWarning("[Resending Packet] [{0}:{1}:{2}]",
                                             packet.Packet.Id, packet.Packet.Type, packet.Packet.DeliveryMethod);
                    }
                    AddPacketToChunkQueue(packet.Packet); // Assume packet was lost and resend
                }
            }

            // Check if the current ordered reliable packet is needed to be resent
            ReliablePacket orderedPacket;

            if (reliableOrderedOutboundPacketQueue.TryPeek(out orderedPacket) &&
                now - orderedPacket.LastSendAttempt >= config.AckAwaitDelay + Stats.Ping)
            {
                if (orderedPacket.LastSendAttempt != 0 && NetLogger.LogReliableResends)
                {
                    Stats.PacketsLost++;
                    NetLogger.LogWarning("[Resending Packet] [{0}:{1}:{2}]",
                                         orderedPacket.Packet.Id, orderedPacket.Packet.Type,
                                         orderedPacket.Packet.DeliveryMethod);
                }

                // If the the next packet exists, and it took too long for an ack,
                // assume the packet was lost and resend
                AddPacketToChunkQueue(orderedPacket.Packet);
            }

            // Ping
            // Check for timeout
            if (now - lastPingResponse >= config.ConnectionTimeout)
            {
                // We lost connection so return false to indicate the heartbeat failed
                return(false);
            }

            // Ping connection
            if (now - lastPingRequest >= config.PingDelay)
            {
                Ping();
            }

            // Run flow control checks
            FlowControlHeartbeat(NetTime.Now);

            // Check if its time to send the chunk
            if ((now - lastChunkSend >= chunkSendDelay || currentChunkSize >= maxChunkSize) &&
                physicalPacketsSentInLastSecond < PacketSendRate)
            {
                SendChunk();
            }

            // TODO: Fix overflow warning. The warning is currently incorrect as it assumes all packets are sent in chunks.
            // Game packets sent on specific tickrates disable chunking so that nothing delays the packets further, which can
            // sometimes allow more packets to be sent than our "send rate" when combined with normal packets that are chunked.

            // Log warning if this connection gets overflowed
            //if (physicalPacketsSentInLastSecond >= PacketSendRate)
            //    NetLogger.LogWarning("[OVERFLOW:{2}] Packets Sent Last Second: {0}, SendRate: {1}",
            //        physicalPacketsSentInLastSecond, PacketSendRate, EndPoint);

            // Reset packets per second calculation
            if (now - packetPerSecondLastReset >= 1000)
            {
                Stats.PhysicalPacketsSentPerSecond = physicalPacketsSentInLastSecond;
                Stats.PacketsSentPerSecond         = packetsSentInLastSecond;
                physicalPacketsSentInLastSecond    = 0;
                packetsSentInLastSecond            = 0;
                packetPerSecondLastReset           = now;
            }
            if (now - packetsRecPerSecondLastReset >= 1000)
            {
                Stats.PhysicalPacketsReceivedPerSecond = physicalPacketsReceivedInLastSecond;
                Stats.PacketsReceivedPerSecond         = packetsReceivedInLastSecond;
                packetsReceivedInLastSecond            = 0;
                physicalPacketsReceivedInLastSecond    = 0;
                packetsRecPerSecondLastReset           = now;
            }

            // Heartbeat was successful
            return(true);
        }