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); } }
internal bool SendDataToSocket(byte[] data, IPEndPoint receivingEndPoint, bool mtuTest = false) { try { //NetLogger.LogVerbose("Sending {0} byte packet to {1}", data.Length, receivingEndPoint); // If this is an MTU test we don't want to automatically fragment the packet socket.DontFragment = mtuTest; // Try and send the data socket.SendTo(data, receivingEndPoint); //socket.Send(data, data.Length, receivingEndPoint); return(true); } catch (SocketException e) { // Ignore error reporting if this was an MTU test if (!mtuTest) { NetLogger.LogError("[ERROR] Failed to send packet to {0}! {1}", receivingEndPoint, e); } return(false); } finally { // Reset just incase socket.DontFragment = false; } }
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); } }
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); }
RemoteChannelBase GetRemoteChannelFromPacket(RemoteChannelType type, ushort channelId) { RemoteChannel channel; StateRemoteChannel stateChannel; if (type == RemoteChannelType.Core) { return((channelId == GlobalChannel.Id) ? GlobalChannel : HiddenChannel); } else if (type == RemoteChannelType.State) { if (!StateChannels.TryGetValue(channelId, out stateChannel)) { NetLogger.LogError("Failed to retreive state channel of id {0}, it doesn't exist!", channelId); } return(stateChannel); } else { if (!Channels.TryGetValue(channelId, out channel)) { NetLogger.LogError("Failed to retreive channel of id {0}, it doesn't exist!", channelId); } return(channel); } }
public bool Start(IPEndPoint endPoint, IPEndPoint receiveEndPoint = null) { if (IsRunning) { throw new NetException(string.Format("{0} is already running!", GetType().Name)); } try { IsRunning = true; // Create the socket and setup endpoints CreateSocket(endPoint, receiveEndPoint); // Log success NetLogger.LogImportant("Started DashNet v3.0"); //NetLogger.LogImportant("{1} bound to {0}, listening on {2}", BoundEndPoint, GetType().Name, ReceiveEndPoint); NetLogger.LogImportant("{1} bound to {0}", BoundEndPoint, GetType().Name); NetLogger.LogImportant("{1} receiving on {0}", ReceiveEndPoint, GetType().Name); // Start the network loop CreateStartThread(); return(true); } catch (SocketException e) { IsRunning = false; NetLogger.LogError("Could not start Messenger, {0}", e.SocketErrorCode); return(false); } }
/// <summary> /// Sends a packet to the connection. /// </summary> /// <param name="packet">The packet to send.</param> public void SendPacket(NetOutboundPacket packet) { if (packet.HasId) { throw new NetException( "Cannot send packet twice, please create a new packet or clone this one before sending another time."); } // Remove the packets padding packet.RemovePadding(); // Setup the packet and make it ready for sending SetupOutboundPacket(packet); // Write the packet's header and set it's Id WriteOutboundPacketHeader(packet); // Check if this packet needs to be split into a partial if (MTU > 0 && packet.Length > MTU && !packet.isPartial) { // Split the packet into partials NetOutboundPacket[] partials = SplitPacketIntoPartials(packet); for (int i = 0; i < partials.Length; i++) { // Send the partials as seperate packets SendPacket(partials[i]); } // Stop handling the too large packet return; } // Handle the sending based on delivery method if (packet.DeliveryMethod == NetDeliveryMethod.Unreliable) { // No extra work needed, just place in outbound queue AddPacketToChunkQueue(packet); } else if (packet.DeliveryMethod == NetDeliveryMethod.Reliable) { // Create the reliable packet handler and add it to the reliable queue ReliablePacket reliablePacket = new ReliablePacket(packet); if (!reliableOutboundPacketQueue.TryAdd(packet.Id, reliablePacket)) { NetLogger.LogError("Failed to add packet to the reliable outbound queue. Id: {0}, Type: {1}, DeliveryMethod: {2}", packet.Id, packet.Type, packet.DeliveryMethod); } // Attempt first send AddPacketToChunkQueue(packet); } else if (packet.DeliveryMethod == NetDeliveryMethod.ReliableOrdered) { // Create the reliable packet handler and add it to the ordered reliable queue ReliablePacket reliablePacket = new ReliablePacket(packet); reliableOrderedOutboundPacketQueue.Enqueue(reliablePacket); } }
/// <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); }
NetConnection RemoveConnection(IPEndPoint endpoint) { // Remove it from the normal connection list NetConnection temp; if (!Connections.TryRemove(endpoint, out temp)) { NetLogger.LogError("Failed to remove NetConnection from Connections. IP: {0}", endpoint); } return(temp); }
void ReplyAck(NetInboundPacket packet, IPEndPoint sender) { // Create the ack packet NetOutboundPacket ack = new NetOutboundPacket(NetDeliveryMethod.Unreliable, 3); ack.Type = NetPacketType.AckResponse; ack.Write(packet.Id); // Write the id if (NetLogger.LogAcks) { NetLogger.LogVerbose("[ACK] Replying {0} to {1}", packet.Id, packet.Sender); } // And send packet.Sender.SendPacket(ack); }
NetOutboundPacket[] SplitPacketIntoPartials(NetOutboundPacket packet) { packet.position = 0; // Calculate the number of packets to split it into, // and each of their sizes int numPackets = (int)Math.Ceiling((double)(packet.Length) / (MTU - 12)); int newPacketSize = MTU - 12; int packetChunkIndex = 0; ushort id = nextPartialId++; NetOutboundPacket[] partialPackets = new NetOutboundPacket[numPackets]; for (byte i = 0; i < numPackets; i++) { int packetSize = Math.Min(newPacketSize, packet.Length - packetChunkIndex); // Create the new partial NetOutboundPacket partial = packet.Clone(true); partial.isPartial = true; partial.Encrypt = false; partial.Compression = NetPacketCompression.None; partial.Clear(6 + packetSize); // Write the partial header partial.Write(id); partial.Write(i); partial.Write((byte)numPackets); partial.Write((ushort)packetSize); // Write the data allocated to this partial partial.WriteBytes(packet.ReadBytes(packetChunkIndex, packetSize)); // Add it to the list of partials partialPackets[i] = partial; packetChunkIndex += packetSize; } if (NetLogger.LogPartials) { NetLogger.LogVerbose("[Partial] Split Packet into {0} parts; Size: {1}b, Original Size: {2}b", numPackets, newPacketSize, packet.Length); } return(partialPackets); }
void HandleRemoteEvent(NetInboundPacket packet, RemoteChannelBase channel) { // Attempt to locate the event string eventName = packet.ReadString(); RemoteEvent evt; if (channel.Events.TryGetValue(eventName, out evt)) { // Call the event ushort numArgs = packet.ReadUInt16(); evt(packet.Sender, packet, numArgs); } else { NetLogger.LogError("Remote Event \"{0}\" was fired on a {1} channel with the id {2}, but it doesn't exist!", eventName, channel.Type, channel.Id); } }
internal void SendInternalPacket(NetOutboundPacket packet, IPEndPoint to) { packet.RemovePadding(); packet.SetId(AllocatePacketId()); if (packet.Type == NetPacketType.ConnectionRequest) { NetEncryption.EncryptPacket(packet); } packet.PrependHeader(); if (NetLogger.LogPacketSends && !IsPingPacket(packet.Type)) { NetLogger.LogVerbose("[Outbound:{0}] {1}", to, packet.ToInternalString()); } SendDataToSocket(packet.data, to, false); }
bool CallFunc(string functionName, NetConnection onConnection, RemoteFunctionCallback callback, RemoteFlag flags, NetDeliveryMethod deliveryMethod, NetBuffer data, ushort numArgs) { // Allocate Id ushort callbackId = GetNextCallbackId(); // Create the function packet NetOutboundPacket funcPacket = new NetOutboundPacket(deliveryMethod); funcPacket.Type = NetPacketType.RemoteFunction; // Handle the flags funcPacket.Encrypt = flags.HasFlag(RemoteFlag.Encrypt); if (flags.HasFlag(RemoteFlag.DontCompress)) { funcPacket.Compression = NetPacketCompression.None; } funcPacket.SendImmediately = flags.HasFlag(RemoteFlag.SendImmediately); // Write the function header funcPacket.Write((byte)Type); funcPacket.Write(Id); funcPacket.Write(functionName); funcPacket.Write(callbackId); funcPacket.Write(numArgs); // Write the data for the function funcPacket.WriteBytes(data.data, 0, data.Length); // Add the waiting function for the return value callback if (WaitingFunctions.TryAdd(callbackId, callback)) { // Send the event packet onConnection.SendPacket(funcPacket); return(true); } else { NetLogger.LogError("Failed to call function {0}, this function is already in the middle of being called!", functionName); return(false); } }
void HandleRemoteFunctionResponse(NetInboundPacket packet, RemoteChannelBase channel) { // Attempt to locate the function callback string funcName = packet.ReadString(); ushort callbackId = packet.ReadUInt16(); RemoteFunctionCallback callback; if (channel.WaitingFunctions.TryGetValue(callbackId, out callback)) { // Call the callback (hehe) callback(packet.Sender, packet); // Remove the callback from the waiting list channel.WaitingFunctions.TryRemove(callbackId, out callback); } else { NetLogger.LogError( "Received a Remote Function Response for function {0} on channel {1}, but we do not have a callback!", funcName, channel.Id); } }
void TryMarkReliablePacket(NetOutboundPacket packet) { // If this packet is reliable, mark is as a new send if (packet.DeliveryMethod == NetDeliveryMethod.Reliable) { ReliablePacket reliablePacket; if (reliableOutboundPacketQueue.TryGetValue(packet.Id, out reliablePacket)) { reliablePacket.LastSendAttempt = NetTime.Now; reliablePacket.SendAttempts++; } else { // Could be from a connection issue NetLogger.LogError("Reliable packet was attempted to be sent, but it doesnt exist in the queue! Id: {0}", packet.Id); } } else if (packet.DeliveryMethod == NetDeliveryMethod.ReliableOrdered) { ReliablePacket reliablePacket; // Try and get the current ordered packet if (reliableOrderedOutboundPacketQueue.TryPeek(out reliablePacket)) { // Only set if it really is the first if (packet.Id == reliablePacket.Packet.Id) { reliablePacket.LastSendAttempt = NetTime.Now; reliablePacket.SendAttempts++; } else { // Bad news if it is not the current NetLogger.LogError("ReliableOrdered packet was attempted to be sent, without being first in queue! Id: {0}", packet.Id); } } } }
void AddPacketToChunkQueue(NetOutboundPacket packet) { // If it is reliable we need to mark it as a new send TryMarkReliablePacket(packet); // Log send if (NetLogger.LogPacketSends && CanLogSend(packet.Type) && !IsPingPacket(packet.Type)) { NetLogger.LogVerbose("[Outbound:{0}] {1}", EndPoint, packet.ToInternalString()); } // Send packet or add it to queue if (packet.SendImmediately) { // Just send it if needed SendPacketToSocket(packet); // Send } else { // Try to add the packet to the chunked queue if (!packetChunkQueue.Add(packet)) { NetLogger.LogError( "Failed to add packet to the chunk queue. Id: {0}, Type: {1}, DeliveryMethod: {2}, Duplicate Id Added: {3}", packet.Id, packet.Type, packet.DeliveryMethod, packetChunkQueue.Contains(packet)); } else { // Increment the chunks current size currentChunkSize += packet.Length; // If the chunk is too big, send it before any other chunks are added if (currentChunkSize >= maxChunkSize) { SendChunk(); } } } }
void HandleRemoteFunction(NetInboundPacket packet, RemoteChannelBase channel) { // Attempt to locate the function string funcName = packet.ReadString(); RemoteFunction func; if (channel.Functions.TryGetValue(funcName, out func)) { // Get the callback id ushort callbackId = packet.ReadUInt16(); // Call the event ushort numArgs = packet.ReadUInt16(); NetBuffer returnValue = func(packet.Sender, packet, numArgs); // Send the response NetOutboundPacket funcResponse = new NetOutboundPacket(NetDeliveryMethod.Reliable); funcResponse.Type = NetPacketType.RemoteFunctionResponse; funcResponse.Encrypt = packet.isEncrypted; // Write the normal remote header funcResponse.Write((byte)channel.Type); funcResponse.Write(channel.Id); funcResponse.Write(funcName); funcResponse.Write(callbackId); // Write the return value funcResponse.WriteBytes(returnValue.data, 0, returnValue.Length); // Send the response packet.Sender.SendPacket(funcResponse); } else { NetLogger.LogError("Remote Function \"{0}\" was invoked on a {1} channel with the id {2}, but it doesn't exist!", funcName, channel.Type, channel.Id); } }
internal void HandleAck(ushort ackId) { ReliablePacket temp; // Try removing from both queues bool reliableSuccess = reliableOutboundPacketQueue.TryRemove(ackId, out temp); bool orderedSuccess = reliableOrderedOutboundPacketQueue.TryPeek(out temp); // If this is the first in the ordered queue, dequeue it if (orderedSuccess && temp.Packet.Id == ackId) { orderedSuccess = reliableOrderedOutboundPacketQueue.TryDequeue(out temp); } else { orderedSuccess = false; // Reset to false incase the id didn't match } // If we couldn't find the packet in either queue, then log it as an error if (!reliableSuccess && !orderedSuccess && NetLogger.LogAlreadyHandledAcks) { NetLogger.LogError("[ACK:{0}] Received already handled (or non-existant) ack! Id: {1}", EndPoint, ackId); } }
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); } } }
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 MTUHeartbeat(int now) { if (mtu_status == MTUStatus.Unset) { // Prep next MTU test mtu_status = MTUStatus.Setting; nextMTUTest = now + MTU_UnsetTry_Delay + 1.5f + Stats.Ping; if (NetLogger.LogFlowControl) { NetLogger.LogVerbose("[FlowControl] Expanding MTU for {0}...", EndPoint); } } else if (now >= nextMTUTest) { if (mtu_status == MTUStatus.Setting) { // Try and send an MTU packet if (lastMTUTest < NetMessenger.MAX_UDP_PACKET_SIZE && TrySendMTU(lastMTUTest)) { // If it succeeds then continue lastMTUTest = (int)(lastMTUTest * MTU_TryInc); now += MTU_UnsetTry_Delay; } else { // If it fails, set the MTU and stop trying to expand it if (lastMTUTest > NetMessenger.MAX_UDP_PACKET_SIZE) { lastMTUTest = NetMessenger.MAX_UDP_PACKET_SIZE; } // Use 75% of the MTU as the max chunk size, and cap it at 5000 bytes. maxChunkSize = (int)Math.Min(MaxUDP_MTU, lastMTUTest * 0.75f); MTU = maxChunkSize; Stats.MTU = MTU; MTUEventNeedsCall = true; if (NetLogger.LogFlowControl) { NetLogger.LogVerbose("[FlowControl] MTU for {0} set to {1}", EndPoint, MTU); } mtu_status = MTUStatus.Set; now += MTU_SetTry_Delay; } } // No need. /*else if (status == MTUStatus.Set) * { * int tryExpandAmount = Math.Min((int)(lastMTUTest * MTU_TryInc), MaxUDP_MTU); * * if (TrySendMTU(tryExpandAmount)) * { * lastMTUTest = (int)(lastMTUTest * MTU_TryInc); * now += MTU_UnsetTry_Delay; * MTU_Status = MTUStatus.Setting; * NetLogger.LogVerbose("Expanding MTU further for {0}...", EndPoint); * } * else * now += MTU_SetTry_Delay; * }*/ } }
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(); } } } }
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); }
void Heartbeat() { if (socket.Available >= NetOutboundPacket.PacketHeaderSize) { try { // Read the packet PacketState state = new PacketState(ReceiveEndPoint, new byte[READ_BUFFER_SIZE]); //socket.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, // ref state.Sender, PacketReceived, state); //NetLogger.LogImportant("Awaiting data from {0}...", state.Sender); state.BytesReceived = socket.ReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.Sender); //byte[] data = socket.Receive(ref state.Sender); //state.Buffer = data; //NetLogger.LogVerbose("Got {0} byte packet from {1}", br, state.Sender); if (!config.SimulatePacketLoss || packetLossRandom.NextDouble() <= 1f - config.SimulatedPacketLossChance) { if (config.SimulateLatency) { delayedReceivedPackets.Enqueue(new DelayedInboundPacket(state, NetTime.Now + config.SimulatedLatencyAmount)); } else { PacketReceived(state); } } } catch (SocketException e) { if (e.SocketErrorCode != SocketError.ConnectionReset) { NetLogger.LogError("SocketErrorCode: {0}", e.SocketErrorCode.ToString()); NetLogger.LogError(e); } } } if (delayedReceivedPackets.Count > 0) { DelayedInboundPacket delayedPacket; while (delayedReceivedPackets.Count > 0 && delayedReceivedPackets.TryPeek(out delayedPacket)) { if (delayedPacket.QueueAfter > NetTime.Now) { break; } if (delayedReceivedPackets.TryDequeue(out delayedPacket)) { PacketReceived(delayedPacket.Packet); } } } foreach (NetConnection conn in Connections.Values) { // Attempt to run the connections heartbeat if (!conn.Heartbeat(NetTime.Now)) { NetLogger.Log("Connection {0} timed out!", conn); // The heartbeat failed which means the connection timed out conn.Disconnect("Lost Connection", true); } } foreach (TrackedConnection conn in trackedConnections.Values) { if (conn.IsFlooding()) { int ignoreTime; if (lastIgnoreLengths.TryGetValue(conn.EndPoint, out ignoreTime)) { ignoreTime *= 2; } else { ignoreTime = 10000; } AddIgnoredConnection(conn.EndPoint, string.Format("Sent {0} invalid packets in the last second, {1} total.", conn.PacketsFrom, conn.Accumulator), ignoreTime); } else if (NetTime.Now >= conn.StopTrackingAt && conn.PacketsFrom == 0) { TrackedConnection temp; if (trackedConnections.TryRemove(conn.EndPoint, out temp)) { NetLogger.Log("[WATCH] No longer watching {0} for excessive invalid packets", conn.EndPoint); } } } foreach (IgnoredConnection conn in ignoredConnections.Values) { if (NetTime.Now >= conn.AcknowledgeAt) { IgnoredConnection temp; if (ignoredConnections.TryRemove(conn.EndPoint, out temp)) { NetLogger.Log("[IGNORE] No longer ignoring {0}...", conn.EndPoint); lastIgnoreLengths[conn.EndPoint] = conn.IgnoreTime; } } } }
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"); } }
protected override void HandleConnectionDisconnected(NetConnection connection, string reason, bool connectionLost) { NetLogger.Log("Client disconnected: {0}", reason); newConnectionsLost.Enqueue(new LostConnection(connection, reason, connectionLost)); }
void SendChunk() { lastChunkSend = NetTime.Now; // If theres nothing to send, don't bother! if (packetChunkQueue.Count == 0) { return; } // Safely grab the packets NetOutboundPacket[] packetsToChunk = packetChunkQueue.ToArrayAndClear(); currentChunkSize = 0; // Reset size if (packetsToChunk == null) { NetLogger.LogError("Failed to convert packetChunkQueue to an array!"); // Cannot continue return; } // If there is only one packet to send, // then don't create a chunk, just send it to // save cpu and bandwidth. if (packetsToChunk.Length == 1) { TryMarkReliablePacket(packetsToChunk[0]); SendPacketToSocket(packetsToChunk[0]); } else // Otherwise send it as a chunk { // Log the sends packetsSentInLastSecond += packetsToChunk.Length; Stats.PacketsSent += packetsToChunk.Length; // Create the packet NetOutboundPacket chunkPacket = new NetOutboundPacket(NetDeliveryMethod.Unreliable, 2 + (packetsToChunk.Length * 2) + currentChunkSize); chunkPacket.isChunked = true; // Write the header, the number of chunked packets chunkPacket.Write((ushort)packetsToChunk.Length); // Write each packet for (int i = 0; i < packetsToChunk.Length; i++) { NetOutboundPacket packet = packetsToChunk[i]; // If it is reliable we need to mark it as a new send TryMarkReliablePacket(packet); // Write packet chunkPacket.Write((ushort)packet.Length); // Size chunkPacket.WriteBytes(packet.data, 0, packet.Length); // Packet Data } // Setup header //SetupOutboundPacket(chunkPacket); WriteOutboundPacketHeader(chunkPacket); // And Send SendPacketToSocket(chunkPacket); } }