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