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);
            }
        }
Example #2
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);
        }
        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);
            }
        }