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); } }
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); }