BytesToHoldBits() public static method

Returns how many bytes are required to hold a certain number of bits
public static BytesToHoldBits ( int numBits ) : int
numBits int
return int
Example #1
0
        /// <summary>
        /// Reads the specified number of bits into a preallocated array
        /// </summary>
        /// <param name="into">The destination array</param>
        /// <param name="offset">The offset where to start writing in the destination array</param>
        /// <param name="numberOfBits">The number of bits to read</param>
        public void ReadBits(byte[] into, int offset, int numberOfBits)
        {
            NetException.Assert(m_bitLength - m_readPosition >= numberOfBits, c_readOverflowError);
            NetException.Assert(offset + NetUtility.BytesToHoldBits(numberOfBits) <= into.Length);

            int numberOfWholeBytes = numberOfBits / 8;
            int extraBits          = numberOfBits - (numberOfWholeBytes * 8);

            NetBitWriter.ReadBytes(m_data, numberOfWholeBytes, m_readPosition, into, offset);
            m_readPosition += (8 * numberOfWholeBytes);

            if (extraBits > 0)
            {
                into[offset + numberOfWholeBytes] = ReadByte(extraBits);
            }

            return;
        }
        public override bool Decrypt(NetIncomingMessage msg)
        {
            int unEncLenBits = (int)msg.ReadUInt32();

            var ms = new MemoryStream(msg.m_data, 4, msg.LengthBytes - 4);
            var cs = GetDecryptStream(ms);

            var result = m_peer.GetStorage(unEncLenBits);

            cs.Read(result, 0, NetUtility.BytesToHoldBits(unEncLenBits));
            cs.Close();

            // TODO: recycle existing msg

            msg.m_data      = result;
            msg.m_bitLength = unEncLenBits;

            return(true);
        }
        public override bool Decrypt(NetIncomingMessage msg)
        {
            try
            {
                var memoryStream        = new MemoryStream(msg.m_data);
                var plaintextBitsBuffer = new byte[sizeof(int)];
                if (sizeof(int) != memoryStream.Read(plaintextBitsBuffer, 0, sizeof(int)))
                {
                    throw new Exception();
                }

                var plaintextBits = BitConverter.ToInt32(plaintextBitsBuffer, 0);

                if (!m_decryptorProvider.Pop(out var cryptoTransform))
                {
                    return(false);
                }

                var cs = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Read);

                var byteLen   = NetUtility.BytesToHoldBits(plaintextBits);
                var result    = m_peer.GetStorage(byteLen << 3);
                var bytesRead = cs.Read(result, 0, byteLen);

                cs.Close();

                // Recycle existing data buffer
                m_peer.Recycle(msg.m_data);

                msg.m_data         = result;
                msg.m_bitLength    = plaintextBits;
                msg.m_readPosition = 0;

                return(true);
            } catch
            {
#if DEBUG
                Debugger.Break();
#endif
                throw;
            }
        }
        /// <summary>
        /// Encrypt this message using the XTEA algorithm; no more writing can be done before sending it
        /// </summary>
        public void Encrypt(NetXtea tea)
        {
            // need blocks of 8 bytes
            WritePadBits();
            int blocksNeeded = (m_bitLength + 63) / 64;
            int missingBits  = (blocksNeeded * 64) - m_bitLength;
            int missingBytes = NetUtility.BytesToHoldBits(missingBits);

            for (int i = 0; i < missingBytes; i++)
            {
                Write((byte)0);
            }

            byte[] result = new byte[m_data.Length];
            for (int i = 0; i < blocksNeeded; i++)
            {
                tea.EncryptBlock(m_data, (i * 8), result, (i * 8));
            }
            m_data = result;
        }
Example #5
0
        public override bool Decrypt(NetIncomingMessage msg)
        {
            int unEncLenBits = (int)msg.ReadUInt32();

            var ms = new MemoryStream(msg.m_data, 4, msg.LengthBytes - 4);
            var cs = new CryptoStream(ms, m_algorithm.CreateDecryptor(), CryptoStreamMode.Read);

            var byteLen = NetUtility.BytesToHoldBits(unEncLenBits);
            var result  = m_peer.GetStorage(byteLen);

            cs.Read(result, 0, byteLen);
            cs.Close();

            // TODO: recycle existing msg

            msg.m_data         = result;
            msg.m_bitLength    = unEncLenBits;
            msg.m_readPosition = 0;

            return(true);
        }
Example #6
0
        private void Heartbeat()
        {
            VerifyNetworkThread();

            double dnow = NetTime.Now;
            float  now  = (float)dnow;

            double delta = dnow - m_lastHeartbeat;

            int maxCHBpS = 1250 - m_connections.Count;

            if (maxCHBpS < 250)
            {
                maxCHBpS = 250;
            }
            if (delta > (1.0 / (double)maxCHBpS))             // max connection heartbeats/second max
            {
                m_frameCounter++;
                m_lastHeartbeat = dnow;

                // do handshake heartbeats
                if ((m_frameCounter % 3) == 0)
                {
                    foreach (var kvp in m_handshakes)
                    {
                        NetConnection conn = kvp.Value as NetConnection;
#if DEBUG
                        // sanity check
                        if (kvp.Key != kvp.Key)
                        {
                            LogWarning("Sanity fail! Connection in handshake list under wrong key!");
                        }
#endif
                        conn.UnconnectedHeartbeat(now);
                        if (conn.m_status == NetConnectionStatus.Connected || conn.m_status == NetConnectionStatus.Disconnected)
                        {
#if DEBUG
                            // sanity check
                            if (conn.m_status == NetConnectionStatus.Disconnected && m_handshakes.ContainsKey(conn.RemoteEndpoint))
                            {
                                LogWarning("Sanity fail! Handshakes list contained disconnected connection!");
                                m_handshakes.Remove(conn.RemoteEndpoint);
                            }
#endif
                            break;                             // collection has been modified
                        }
                    }
                }

#if DEBUG
                SendDelayedPackets();
#endif

                // update m_executeFlushSendQueue
                if (m_configuration.m_autoFlushSendQueue)
                {
                    m_executeFlushSendQueue = true;
                }

                // do connection heartbeats
                lock (m_connections)
                {
                    foreach (NetConnection conn in m_connections)
                    {
                        conn.Heartbeat(now, m_frameCounter);
                        if (conn.m_status == NetConnectionStatus.Disconnected)
                        {
                            //
                            // remove connection
                            //
                            m_connections.Remove(conn);
                            m_connectionLookup.Remove(conn.RemoteEndpoint);
                            break;                             // can't continue iteration here
                        }
                    }
                }
                m_executeFlushSendQueue = false;

                // send unsent unconnected messages
                NetTuple <IPEndPoint, NetOutgoingMessage> unsent;
                while (m_unsentUnconnectedMessages.TryDequeue(out unsent))
                {
                    NetOutgoingMessage om = unsent.Item2;

                    bool connReset;
                    int  len = om.Encode(m_sendBuffer, 0, 0);
                    SendPacket(len, unsent.Item1, 1, out connReset);

                    Interlocked.Decrement(ref om.m_recyclingCount);
                    if (om.m_recyclingCount <= 0)
                    {
                        Recycle(om);
                    }
                }
            }

            //
            // read from socket
            //
            if (m_socket == null)
            {
                return;
            }

            if (!m_socket.Poll(1000, SelectMode.SelectRead))             // wait up to 1 ms for data to arrive
            {
                return;
            }

            //if (m_socket == null || m_socket.Available < 1)
            //	return;

            do
            {
                int bytesReceived = 0;
                try
                {
                    bytesReceived = m_socket.ReceiveFrom(m_receiveBuffer, 0, m_receiveBuffer.Length, SocketFlags.None, ref m_senderRemote);
                }
                catch (SocketException sx)
                {
                    if (sx.SocketErrorCode == SocketError.ConnectionReset)
                    {
                        // connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable"
                        // we should shut down the connection; but m_senderRemote seemingly cannot be trusted, so which connection should we shut down?!
                        // So, what to do?
                        LogWarning("ConnectionReset");
                        return;
                    }

                    LogWarning(sx.ToString());
                    return;
                }

                if (bytesReceived < NetConstants.HeaderByteSize)
                {
                    return;
                }

                //LogVerbose("Received " + bytesReceived + " bytes");

                IPEndPoint ipsender = (IPEndPoint)m_senderRemote;

                if (ipsender.Port == 1900)
                {
                    // UPnP response
                    try
                    {
                        string resp = System.Text.Encoding.ASCII.GetString(m_receiveBuffer, 0, bytesReceived);
                        if (resp.Contains("upnp:rootdevice"))
                        {
                            resp = resp.Substring(resp.ToLower().IndexOf("location:") + 9);
                            resp = resp.Substring(0, resp.IndexOf("\r")).Trim();
                            m_upnp.ExtractServiceUrl(resp);
                            return;
                        }
                    }
                    catch { }
                }

                NetConnection sender = null;
                m_connectionLookup.TryGetValue(ipsender, out sender);

                double receiveTime = NetTime.Now;
                //
                // parse packet into messages
                //
                int numMessages = 0;
                int ptr         = 0;
                while ((bytesReceived - ptr) >= NetConstants.HeaderByteSize)
                {
                    // decode header
                    //  8 bits - NetMessageType
                    //  1 bit  - Fragment?
                    // 15 bits - Sequence number
                    // 16 bits - Payload length in bits

                    numMessages++;

                    NetMessageType tp = (NetMessageType)m_receiveBuffer[ptr++];

                    byte low  = m_receiveBuffer[ptr++];
                    byte high = m_receiveBuffer[ptr++];

                    bool   isFragment     = ((low & 1) == 1);
                    ushort sequenceNumber = (ushort)((low >> 1) | (((int)high) << 7));

                    ushort payloadBitLength  = (ushort)(m_receiveBuffer[ptr++] | (m_receiveBuffer[ptr++] << 8));
                    int    payloadByteLength = NetUtility.BytesToHoldBits(payloadBitLength);

                    if (bytesReceived - ptr < payloadByteLength)
                    {
                        LogWarning("Malformed packet; stated payload length " + payloadByteLength + ", remaining bytes " + (bytesReceived - ptr));
                        return;
                    }

                    try
                    {
                        NetException.Assert(tp <NetMessageType.Unused1 || tp> NetMessageType.Unused29);

                        if (tp >= NetMessageType.LibraryError)
                        {
                            if (sender != null)
                            {
                                sender.ReceivedLibraryMessage(tp, ptr, payloadByteLength);
                            }
                            else
                            {
                                ReceivedUnconnectedLibraryMessage(receiveTime, ipsender, tp, ptr, payloadByteLength);
                            }
                        }
                        else
                        {
                            if (sender == null && !m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.UnconnectedData))
                            {
                                return;                                 // dropping unconnected message since it's not enabled
                            }
                            NetIncomingMessage msg = CreateIncomingMessage(NetIncomingMessageType.Data, payloadByteLength);
                            msg.m_isFragment          = isFragment;
                            msg.m_receiveTime         = receiveTime;
                            msg.m_sequenceNumber      = sequenceNumber;
                            msg.m_receivedMessageType = tp;
                            msg.m_senderConnection    = sender;
                            msg.m_senderEndpoint      = ipsender;
                            msg.m_bitLength           = payloadBitLength;
                            Buffer.BlockCopy(m_receiveBuffer, ptr, msg.m_data, 0, payloadByteLength);
                            if (sender != null)
                            {
                                if (tp == NetMessageType.Unconnected)
                                {
                                    // We're connected; but we can still send unconnected messages to this peer
                                    msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData;
                                    ReleaseMessage(msg);
                                }
                                else
                                {
                                    // connected application (non-library) message
                                    sender.ReceivedMessage(msg);
                                }
                            }
                            else
                            {
                                // at this point we know the message type is enabled
                                // unconnected application (non-library) message
                                msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData;
                                ReleaseMessage(msg);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        LogError("Packet parsing error: " + ex.Message + " from " + ipsender);
                    }
                    ptr += payloadByteLength;
                }

                m_statistics.PacketReceived(bytesReceived, numMessages);
                if (sender != null)
                {
                    sender.m_statistics.PacketReceived(bytesReceived, numMessages);
                }
            } while (m_socket.Available > 0);
        }
        private void HandleReleasedFragment(NetIncomingMessage im)
        {
            VerifyNetworkThread();

            //
            // read fragmentation header and combine fragments
            //
            int group;
            int totalBits;
            int chunkByteSize;
            int chunkNumber;
            int ptr = NetFragmentationHelper.ReadHeader(
                im.m_data, 0,
                out group,
                out totalBits,
                out chunkByteSize,
                out chunkNumber
                );

            NetException.Assert(im.LengthBytes > ptr);

            NetException.Assert(group > 0);
            NetException.Assert(totalBits > 0);
            NetException.Assert(chunkByteSize > 0);

            int totalBytes     = NetUtility.BytesToHoldBits((int)totalBits);
            int totalNumChunks = totalBytes / chunkByteSize;

            if (totalNumChunks * chunkByteSize < totalBytes)
            {
                totalNumChunks++;
            }

            NetException.Assert(chunkNumber < totalNumChunks);

            if (chunkNumber >= totalNumChunks)
            {
                LogWarning("Index out of bounds for chunk " + chunkNumber + " (total chunks " + totalNumChunks + ")");
                return;
            }

            Dictionary <int, ReceivedFragmentGroup> groups;

            if (!m_receivedFragmentGroups.TryGetValue(im.SenderConnection, out groups))
            {
                groups = new Dictionary <int, ReceivedFragmentGroup>();
                m_receivedFragmentGroups[im.SenderConnection] = groups;
            }

            ReceivedFragmentGroup info;

            if (!groups.TryGetValue(group, out info))
            {
                info                = new ReceivedFragmentGroup();
                info.Data           = new byte[totalBytes];
                info.ReceivedChunks = new NetBitVector(totalNumChunks);
                groups[group]       = info;
            }

            info.ReceivedChunks[chunkNumber] = true;
            //info.LastReceived = (float)NetTime.Now;

            // copy to data
            int offset = (chunkNumber * chunkByteSize);

            Buffer.BlockCopy(im.m_data, ptr, info.Data, offset, im.LengthBytes - ptr);

            int cnt = info.ReceivedChunks.Count();

            //LogVerbose("Found fragment #" + chunkNumber + " in group " + group + " offset " + offset + " of total bits " + totalBits + " (total chunks done " + cnt + ")");

            LogVerbose("Received fragment " + chunkNumber + " of " + totalNumChunks + " (" + cnt + " chunks received)");

            if (info.ReceivedChunks.Count() == totalNumChunks)
            {
                // Done! Transform this incoming message
                im.m_data       = info.Data;
                im.m_bitLength  = (int)totalBits;
                im.m_isFragment = false;

                LogVerbose("Fragment group #" + group + " fully received in " + totalNumChunks + " chunks (" + totalBits + " bits)");
                groups.Remove(group);

                ReleaseMessage(im);
            }
            else
            {
                // data has been copied; recycle this incoming message
                Recycle(im);
            }

            return;
        }
Example #8
0
        private void ReceiveSocketData(double now)
        {
            int bytesReceived = m_socket.ReceiveFrom(m_receiveBuffer, 0, m_receiveBuffer.Length, SocketFlags.None, ref m_senderRemote);

            if (bytesReceived < NetConstants.HeaderByteSize)
            {
                return;
            }

            //LogVerbose("Received " + bytesReceived + " bytes");

            var ipsender = (NetEndPoint)m_senderRemote;

            if (m_upnp != null && now < m_upnp.m_discoveryResponseDeadline && bytesReceived > 32)
            {
                // is this an UPnP response?
                string resp = System.Text.Encoding.UTF8.GetString(m_receiveBuffer, 0, bytesReceived);
                if (resp.Contains("upnp:rootdevice") || resp.Contains("UPnP/1.0"))
                {
                    try
                    {
                        resp = resp.Substring(resp.ToLower().IndexOf("location:") + 9);
                        resp = resp.Substring(0, resp.IndexOf("\r")).Trim();
                        m_upnp.ExtractServiceUrl(resp);
                        return;
                    }
                    catch (Exception ex)
                    {
                        LogDebug("Failed to parse UPnP response: " + ex.ToString());

                        // don't try to parse this packet further
                        return;
                    }
                }
            }

            NetConnection sender = null;

            m_connectionLookup.TryGetValue(ipsender, out sender);

            //
            // parse packet into messages
            //
            int numMessages  = 0;
            int numFragments = 0;
            int ptr          = 0;

            while ((bytesReceived - ptr) >= NetConstants.HeaderByteSize)
            {
                // decode header
                //  8 bits - NetMessageType
                //  1 bit  - Fragment?
                // 15 bits - Sequence number
                // 16 bits - Payload length in bits

                numMessages++;

                NetMessageType tp = (NetMessageType)m_receiveBuffer[ptr++];

                byte low  = m_receiveBuffer[ptr++];
                byte high = m_receiveBuffer[ptr++];

                bool   isFragment     = ((low & 1) == 1);
                ushort sequenceNumber = (ushort)((low >> 1) | (((int)high) << 7));

                if (isFragment)
                {
                    numFragments++;
                }

                ushort payloadBitLength  = (ushort)(m_receiveBuffer[ptr++] | (m_receiveBuffer[ptr++] << 8));
                int    payloadByteLength = NetUtility.BytesToHoldBits(payloadBitLength);

                if (bytesReceived - ptr < payloadByteLength)
                {
                    LogWarning("Malformed packet; stated payload length " + payloadByteLength + ", remaining bytes " + (bytesReceived - ptr));
                    return;
                }

                if (tp >= NetMessageType.Unused1 && tp <= NetMessageType.Unused29)
                {
                    ThrowOrLog("Unexpected NetMessageType: " + tp);
                    return;
                }

                try
                {
                    if (tp >= NetMessageType.LibraryError)
                    {
                        if (sender != null)
                        {
                            sender.ReceivedLibraryMessage(tp, ptr, payloadByteLength);
                        }
                        else
                        {
                            ReceivedUnconnectedLibraryMessage(now, ipsender, tp, ptr, payloadByteLength);
                        }
                    }
                    else
                    {
                        if (sender == null && !m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.UnconnectedData))
                        {
                            return;                             // dropping unconnected message since it's not enabled
                        }
                        NetIncomingMessage msg = CreateIncomingMessage(NetIncomingMessageType.Data, payloadByteLength);
                        msg.m_isFragment          = isFragment;
                        msg.m_receiveTime         = now;
                        msg.m_sequenceNumber      = sequenceNumber;
                        msg.m_receivedMessageType = tp;
                        msg.m_senderConnection    = sender;
                        msg.m_senderEndPoint      = ipsender;
                        msg.m_bitLength           = payloadBitLength;

                        Buffer.BlockCopy(m_receiveBuffer, ptr, msg.m_data, 0, payloadByteLength);
                        if (sender != null)
                        {
                            if (tp == NetMessageType.Unconnected)
                            {
                                // We're connected; but we can still send unconnected messages to this peer
                                msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData;
                                ReleaseMessage(msg);
                            }
                            else
                            {
                                // connected application (non-library) message
                                sender.ReceivedMessage(msg);
                            }
                        }
                        else
                        {
                            // at this point we know the message type is enabled
                            // unconnected application (non-library) message
                            msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData;
                            ReleaseMessage(msg);
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogError("Packet parsing error: " + ex.Message + " from " + ipsender);
                }
                ptr += payloadByteLength;
            }

            m_statistics.PacketReceived(bytesReceived, numMessages, numFragments);
            if (sender != null)
            {
                sender.m_statistics.PacketReceived(bytesReceived, numMessages, numFragments);
            }
        }
Example #9
0
        private void Heartbeat()
        {
            VerifyNetworkThread();

            double now   = NetTime.Now;
            double delta = now - m_lastHeartbeat;

            int maxCHBpS = 1250 - m_connections.Count;

            if (maxCHBpS < 250)
            {
                maxCHBpS = 250;
            }
            if (delta > (1.0 / (double)maxCHBpS) || delta < 0.0)             // max connection heartbeats/second max
            {
                m_frameCounter++;
                m_lastHeartbeat = now;

                // do handshake heartbeats
                if ((m_frameCounter % 3) == 0)
                {
                    foreach (var kvp in m_handshakes)
                    {
                        NetConnection conn = kvp.Value as NetConnection;
#if DEBUG
                        // sanity check
                        if (kvp.Key != kvp.Key)
                        {
                            LogWarning("Sanity fail! Connection in handshake list under wrong key!");
                        }
#endif
                        conn.UnconnectedHeartbeat(now);
                        if (conn.m_status == NetConnectionStatus.Connected || conn.m_status == NetConnectionStatus.Disconnected)
                        {
#if DEBUG
                            // sanity check
                            if (conn.m_status == NetConnectionStatus.Disconnected && m_handshakes.ContainsKey(conn.RemoteEndPoint))
                            {
                                LogWarning("Sanity fail! Handshakes list contained disconnected connection!");
                                m_handshakes.Remove(conn.RemoteEndPoint);
                            }
#endif
                            break;                             // collection has been modified
                        }
                    }
                }

#if DEBUG
                SendDelayedPackets();
#endif

                // update m_executeFlushSendQueue
                if (m_configuration.m_autoFlushSendQueue && m_needFlushSendQueue == true)
                {
                    m_executeFlushSendQueue = true;
                    m_needFlushSendQueue    = false;                  // a race condition to this variable will simply result in a single superfluous call to FlushSendQueue()
                }

                // do connection heartbeats
                lock (m_connections)
                {
                    for (int i = m_connections.Count - 1; i >= 0; i--)
                    {
                        var conn = m_connections[i];
                        conn.Heartbeat(now, m_frameCounter);
                        if (conn.m_status == NetConnectionStatus.Disconnected)
                        {
                            //
                            // remove connection
                            //
                            m_connections.RemoveAt(i);
                            m_connectionLookup.Remove(conn.RemoteEndPoint);
                        }
                    }
                }
                m_executeFlushSendQueue = false;

                // send unsent unconnected messages
                NetTuple <NetEndPoint, NetOutgoingMessage> unsent;
                while (m_unsentUnconnectedMessages.TryDequeue(out unsent))
                {
                    NetOutgoingMessage om = unsent.Item2;

                    int len = om.Encode(m_sendBuffer, 0, 0);

                    Interlocked.Decrement(ref om.m_recyclingCount);
                    if (om.m_recyclingCount <= 0)
                    {
                        Recycle(om);
                    }

                    bool connReset;
                    SendPacket(len, unsent.Item1, 1, out connReset);
                }
            }

            if (m_upnp != null)
            {
                m_upnp.CheckForDiscoveryTimeout();
            }

            //
            // read from socket
            //
            if (m_socket == null)
            {
                return;
            }

            if (!m_socket.Poll(1000, SelectMode.SelectRead))             // wait up to 1 ms for data to arrive
            {
                return;
            }

            //if (m_socket == null || m_socket.Available < 1)
            //	return;

            // update now
            now = NetTime.Now;

            do
            {
                int bytesReceived = 0;
                try
                {
                    bytesReceived = m_socket.ReceiveFrom(m_receiveBuffer, 0, m_receiveBuffer.Length, SocketFlags.None, ref m_senderRemote);
                    //UnityEngine.Debug.Log($"recv from {m_senderRemote}, bytes {bytesReceived}, local {m_socket.LocalEndPoint}");
                }
                catch (SocketException sx)
                {
                    switch (sx.SocketErrorCode)
                    {
                    case SocketError.ConnectionReset:
                        // connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable"
                        // we should shut down the connection; but m_senderRemote seemingly cannot be trusted, so which connection should we shut down?!
                        // So, what to do?
                        LogWarning("ConnectionReset");
                        return;

                    case SocketError.NotConnected:
                        // socket is unbound; try to rebind it (happens on mobile when process goes to sleep)
                        BindSocket(true);
                        return;

                    default:
                        LogWarning("Socket exception: " + sx.ToString());
                        return;
                    }
                }

                if (bytesReceived < NetConstants.HeaderByteSize)
                {
                    return;
                }

                //LogVerbose("Received " + bytesReceived + " bytes");

                var ipsender = (NetEndPoint)m_senderRemote;

                if (m_upnp != null && now < m_upnp.m_discoveryResponseDeadline && bytesReceived > 32)
                {
                    // is this an UPnP response?
                    string resp = System.Text.Encoding.UTF8.GetString(m_receiveBuffer, 0, bytesReceived);
                    if (resp.Contains("upnp:rootdevice") || resp.Contains("UPnP/1.0"))
                    {
                        try
                        {
                            resp = resp.Substring(resp.ToLower().IndexOf("location:") + 9);
                            resp = resp.Substring(0, resp.IndexOf("\r")).Trim();
                            m_upnp.ExtractServiceUrl(resp);
                            return;
                        }
                        catch (Exception ex)
                        {
                            LogDebug("Failed to parse UPnP response: " + ex.ToString());

                            // don't try to parse this packet further
                            return;
                        }
                    }
                }

                NetConnection sender = null;
                m_connectionLookup.TryGetValue(ipsender, out sender);

                //
                // parse packet into messages
                //
                int numMessages  = 0;
                int numFragments = 0;
                int ptr          = 0;
                while ((bytesReceived - ptr) >= NetConstants.HeaderByteSize)
                {
                    // decode header
                    //  8 bits - NetMessageType
                    //  1 bit  - Fragment?
                    // 15 bits - Sequence number
                    // 16 bits - Payload length in bits

                    numMessages++;

                    NetMessageType tp = (NetMessageType)m_receiveBuffer[ptr++];

                    byte low  = m_receiveBuffer[ptr++];
                    byte high = m_receiveBuffer[ptr++];

                    bool   isFragment     = ((low & 1) == 1);
                    ushort sequenceNumber = (ushort)((low >> 1) | (((int)high) << 7));

                    if (isFragment)
                    {
                        numFragments++;
                    }

                    ushort payloadBitLength  = (ushort)(m_receiveBuffer[ptr++] | (m_receiveBuffer[ptr++] << 8));
                    int    payloadByteLength = NetUtility.BytesToHoldBits(payloadBitLength);

                    if (bytesReceived - ptr < payloadByteLength)
                    {
                        LogWarning("Malformed packet; stated payload length " + payloadByteLength + ", remaining bytes " + (bytesReceived - ptr));
                        return;
                    }

                    if (tp >= NetMessageType.Unused1 && tp <= NetMessageType.Unused29)
                    {
                        ThrowOrLog("Unexpected NetMessageType: " + tp);
                        return;
                    }

                    try
                    {
                        if (tp >= NetMessageType.LibraryError)
                        {
                            if (sender != null)
                            {
                                sender.ReceivedLibraryMessage(tp, ptr, payloadByteLength);
                            }
                            else
                            {
                                ReceivedUnconnectedLibraryMessage(now, ipsender, tp, ptr, payloadByteLength);
                            }
                        }
                        else
                        {
                            if (sender == null && !m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.UnconnectedData))
                            {
                                return;                                 // dropping unconnected message since it's not enabled
                            }
                            NetIncomingMessage msg = CreateIncomingMessage(NetIncomingMessageType.Data, payloadByteLength);
                            msg.m_isFragment          = isFragment;
                            msg.m_receiveTime         = now;
                            msg.m_sequenceNumber      = sequenceNumber;
                            msg.m_receivedMessageType = tp;
                            msg.m_senderConnection    = sender;
                            msg.m_senderEndPoint      = ipsender;
                            msg.m_bitLength           = payloadBitLength;

                            Buffer.BlockCopy(m_receiveBuffer, ptr, msg.m_data, 0, payloadByteLength);
                            if (sender != null)
                            {
                                if (tp == NetMessageType.Unconnected)
                                {
                                    // We're connected; but we can still send unconnected messages to this peer
                                    msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData;
                                    ReleaseMessage(msg);
                                }
                                else
                                {
                                    // connected application (non-library) message
                                    sender.ReceivedMessage(msg);
                                }
                            }
                            else
                            {
                                // at this point we know the message type is enabled
                                // unconnected application (non-library) message
                                msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData;
                                ReleaseMessage(msg);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        LogError("Packet parsing error: " + ex.Message + " from " + ipsender);
                    }
                    ptr += payloadByteLength;
                }

                m_statistics.PacketReceived(bytesReceived, numMessages, numFragments);
                if (sender != null)
                {
                    sender.m_statistics.PacketReceived(bytesReceived, numMessages, numFragments);
                }
            } while (m_socket.Available > 0);
        }
Example #10
0
        internal int Encode(byte[] intoBuffer, int ptr, int sequenceNumber)
        {
            // NOTE: I had to change the header format so it won't collide with multiplexed STUN on the same socket
            //       and I made it big-endian for consistency's sake. -AR
            //
            //  <- MSB                                                     LSB ->
            //   0                   1                   2                   3
            //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
            //  V-+-+-+-+-+-+-+-V-+-+-+-+-+-+-+-V-+-+-+-+-+-+-+-V-+-+-+-+-+-+-+-V
            //  |1|F| Sequence Number           |NetMessageType |  Length bits...
            //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            //  ...             |
            //  +-+-+-+-+-+-+-+-+
            //
            // IMPORTANT: The packet format is also encoded elsewhere, to send NetMessageType.Acknowledge (see NetConnection.cs)
            //

            intoBuffer[ptr++] = (byte)(((sequenceNumber >> 8) & 0x3F) | (m_fragmentGroup == 0 ? 0x80 : 0xC0));
            intoBuffer[ptr++] = (byte)sequenceNumber;

            intoBuffer[ptr++] = (byte)m_messageType;

            if (m_fragmentGroup == 0)
            {
                intoBuffer[ptr++] = (byte)(m_bitLength >> 8);
                intoBuffer[ptr++] = (byte)m_bitLength;


                int byteLen = NetUtility.BytesToHoldBits(m_bitLength);
                if (byteLen > 0)
                {
                    Buffer.BlockCopy(m_data, 0, intoBuffer, ptr, byteLen);
                    ptr += byteLen;
                }
            }
            else
            {
                int wasPtr = ptr;
                intoBuffer[ptr++] = (byte)(m_bitLength >> 8);
                intoBuffer[ptr++] = (byte)m_bitLength;


                //
                // write fragmentation header
                //
                ptr = NetFragmentationHelper.WriteHeader(intoBuffer, ptr, m_fragmentGroup, m_fragmentGroupTotalBits, m_fragmentChunkByteSize, m_fragmentChunkNumber);
                int hdrLen = ptr - wasPtr - 2;

                // update length
                int realBitLength = m_bitLength + (hdrLen * 8);
                intoBuffer[wasPtr]     = (byte)(realBitLength >> 8);
                intoBuffer[wasPtr + 1] = (byte)realBitLength;

                int byteLen = NetUtility.BytesToHoldBits(m_bitLength);
                if (byteLen > 0)
                {
                    Buffer.BlockCopy(m_data, (int)(m_fragmentChunkNumber * m_fragmentChunkByteSize), intoBuffer, ptr, byteLen);
                    ptr += byteLen;
                }
            }

            NetException.Assert(ptr > 0);
            return(ptr);
        }
        internal int Encode(byte[] intoBuffer, int ptr, long connectionId, int sequenceNumber)
        {
            //  8 bits - NetMessageType
            // 64 bits - Connection ID
            //  1 bit  - Fragment?
            // 15 bits - Sequence number
            // 16 bits - Payload length in bits

            intoBuffer[ptr++] = (byte)m_messageType;
            intoBuffer[ptr++] = (byte)((connectionId >> 56) & 0xFF);
            intoBuffer[ptr++] = (byte)((connectionId >> 48) & 0xFF);
            intoBuffer[ptr++] = (byte)((connectionId >> 40) & 0xFF);
            intoBuffer[ptr++] = (byte)((connectionId >> 32) & 0xFF);
            intoBuffer[ptr++] = (byte)((connectionId >> 24) & 0xFF);
            intoBuffer[ptr++] = (byte)((connectionId >> 16) & 0xFF);
            intoBuffer[ptr++] = (byte)((connectionId >> 8) & 0xFF);
            intoBuffer[ptr++] = (byte)((connectionId) & 0xFF);
            byte low = (byte)((sequenceNumber << 1) | (m_fragmentGroup == 0 ? 0 : 1));

            intoBuffer[ptr++] = low;
            intoBuffer[ptr++] = (byte)(sequenceNumber >> 7);

            if (m_fragmentGroup == 0)
            {
                intoBuffer[ptr++] = (byte)m_bitLength;
                intoBuffer[ptr++] = (byte)(m_bitLength >> 8);

                int byteLen = NetUtility.BytesToHoldBits(m_bitLength);
                if (byteLen > 0)
                {
                    Buffer.BlockCopy(m_data, 0, intoBuffer, ptr, byteLen);
                    ptr += byteLen;
                }
            }
            else
            {
                int wasPtr = ptr;
                intoBuffer[ptr++] = (byte)m_bitLength;
                intoBuffer[ptr++] = (byte)(m_bitLength >> 8);

                //
                // write fragmentation header
                //
                ptr = NetFragmentationHelper.WriteHeader(intoBuffer, ptr, m_fragmentGroup, m_fragmentGroupTotalBits, m_fragmentChunkByteSize, m_fragmentChunkNumber);
                int hdrLen = ptr - wasPtr - 2;

                // update length
                int realBitLength = m_bitLength + (hdrLen * 8);
                intoBuffer[wasPtr]     = (byte)realBitLength;
                intoBuffer[wasPtr + 1] = (byte)(realBitLength >> 8);

                int byteLen = NetUtility.BytesToHoldBits(m_bitLength);
                if (byteLen > 0)
                {
                    Buffer.BlockCopy(m_data, (int)(m_fragmentChunkNumber * m_fragmentChunkByteSize), intoBuffer, ptr, byteLen);
                    ptr += byteLen;
                }
            }

            NetException.Assert(ptr > 0);
            return(ptr);
        }