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();
            cs.Dispose();

            // TODO: recycle existing msg

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

            return(true);
        }
        // remoteWindowStart is remote expected sequence number; everything below this has arrived properly
        // seqNr is the actual nr received
        public override NetSocketResult ReceiveAcknowledge(TimeSpan now, int seqNr)
        {
            if (!_doFlowControl)
            {
                // we have no use for acks on this channel since we don't respect the window anyway
                _connection.Peer.LogWarning(new NetLogMessage(NetLogCode.SuppressedUnreliableAck, endPoint: _connection));
                return(new NetSocketResult(true, false));
            }

            // late (dupe), on time or early ack?
            int relate = NetUtility.RelativeSequenceNumber(seqNr, _windowStart);

            if (relate < 0)
            {
                //m_connection.m_peer.LogDebug("Received late/dupe ack for #" + seqNr);
                return(new NetSocketResult(true, false)); // late/duplicate ack
            }

            if (relate == 0)
            {
                //m_connection.m_peer.LogDebug("Received right-on-time ack for #" + seqNr);

                // ack arrived right on time
                LidgrenException.Assert(seqNr == _windowStart);

                _receivedAcks[_windowStart] = false;
                _windowStart = NetUtility.PowOf2Mod(_windowStart + 1, NetConstants.SequenceNumbers);
                return(new NetSocketResult(true, false));
            }

            // Advance window to this position
            _receivedAcks[seqNr] = true;

            while (_windowStart != seqNr)
            {
                _receivedAcks[_windowStart] = false;
                _windowStart = NetUtility.PowOf2Mod(_windowStart + 1, NetConstants.SequenceNumbers);
            }

            return(new NetSocketResult(true, false));
        }
        internal override void ReceiveMessage(NetIncomingMessage message)
        {
            int nr = message.m_sequenceNumber;

            int relate = NetUtility.RelativeSequenceNumber(nr, m_windowStart);

            // ack no matter what
            m_connection.QueueAck(message.m_receivedMessageType, nr);

            if (relate == 0)
            {
                // Log("Received message #" + message.SequenceNumber + " right on time");

                //
                // excellent, right on time
                //

                AdvanceWindow();
                m_peer.ReleaseMessage(message);
                return;
            }

            if (relate < 0)
            {
                m_peer.LogVerbose("Received message #" + message.m_sequenceNumber + " DROPPING LATE or DUPE");
                return;
            }

            // relate > 0 = early message
            if (relate > m_windowSize)
            {
                // too early message!
                m_peer.LogDebug("Received " + message + " TOO EARLY! Expected " + m_windowStart);
                return;
            }

            // ok
            m_windowStart = (m_windowStart + relate) % NetConstants.NumSequenceNumbers;
            m_peer.ReleaseMessage(message);
            return;
        }
Exemple #4
0
        // may be on user thread
        private NetSenderChannelBase CreateSenderChannel(NetMessageType tp)
        {
            NetSenderChannelBase chan;

            lock (m_sendChannels)
            {
                NetDeliveryMethod method = NetUtility.GetDeliveryMethod(tp);
                int sequenceChannel      = (int)tp - (int)method;

                int channelSlot = (int)method - 1 + sequenceChannel;
                if (m_sendChannels[channelSlot] != null)
                {
                    // we were pre-empted by another call to this method
                    chan = m_sendChannels[channelSlot];
                }
                else
                {
                    switch (method)
                    {
                    case NetDeliveryMethod.Unreliable:
                    case NetDeliveryMethod.UnreliableSequenced:
                        chan = new NetUnreliableSenderChannel(this, NetUtility.GetWindowSize(method), method);
                        break;

                    case NetDeliveryMethod.ReliableOrdered:
                        chan = new NetReliableSenderChannel(this, NetUtility.GetWindowSize(method));
                        break;

                    case NetDeliveryMethod.Unknown:
                    case NetDeliveryMethod.ReliableSequenced:
                    case NetDeliveryMethod.ReliableUnordered:
                    default:
                        chan = new NetReliableSenderChannel(this, NetUtility.GetWindowSize(method));
                        break;
                    }
                    m_sendChannels[channelSlot] = chan;
                }
            }

            return(chan);
        }
        private NetReceiverChannelBase CreateReceiverChannel(NetMessageType tp)
        {
            m_peer.VerifyNetworkThread();

            // create receiver channel
            NetReceiverChannelBase chan;
            NetDeliveryMethod      method = NetUtility.GetDeliveryMethod(tp);

            switch (method)
            {
            case NetDeliveryMethod.Unreliable:
                chan = new NetUnreliableUnorderedReceiver(this);
                break;

            case NetDeliveryMethod.ReliableOrdered:
                chan = new NetReliableOrderedReceiver(this, NetConstants.ReliableOrderedWindowSize);
                break;

            case NetDeliveryMethod.UnreliableSequenced:
                chan = new NetUnreliableSequencedReceiver(this);
                break;

            case NetDeliveryMethod.ReliableUnordered:
                chan = new NetReliableUnorderedReceiver(this, NetConstants.ReliableOrderedWindowSize);
                break;

            case NetDeliveryMethod.ReliableSequenced:
                chan = new NetReliableSequencedReceiver(this, NetConstants.ReliableSequencedWindowSize);
                break;

            default:
                throw new NetException("Unhandled NetDeliveryMethod!");
            }

            int channelSlot = (int)tp - 1;

            NetException.Assert(m_receiveChannels[channelSlot] == null);
            m_receiveChannels[channelSlot] = chan;

            return(chan);
        }
        internal void Discover(NetPeer peer)
        {
#if !DOTNETCORE
            string str =
                "M-SEARCH * HTTP/1.1\r\n" +
                "HOST: 239.255.255.250:1900\r\n" +
                "ST:upnp:rootdevice\r\n" +
                "MAN:\"ssdp:discover\"\r\n" +
                "MX:3\r\n\r\n";

            m_discoveryResponseDeadline = NetTime.Now + 6.0;             // arbitrarily chosen number, router gets 6 seconds to respond
            m_status = UPnPStatus.Discovering;

            byte[] arr = System.Text.Encoding.UTF8.GetBytes(str);

            m_peer.LogDebug("Attempting UPnP discovery");
            peer.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
            peer.RawSend(arr, 0, arr.Length, new NetEndPoint(NetUtility.GetBroadcastAddress(), 1900));
            peer.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false);
#endif
        }
        /// <summary>
        /// Send a message to an unconnected host.
        /// </summary>
        public void SendUnconnectedMessage(NetOutgoingMessage message, ReadOnlySpan <char> host, int port)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            message.AssertNotSent(nameof(message));
            AssertValidUnconnectedLength(message);

            IPAddress?address = NetUtility.Resolve(host);

            if (address == null)
            {
                throw new LidgrenException("Failed to resolve " + host.ToString());
            }

            IPEndPoint recipient = new(address, port);

            SendUnconnectedMessageCore(message, recipient);
        }
Exemple #8
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);
        }
Exemple #9
0
        // remoteWindowStart is remote expected sequence number; everything below this has arrived properly
        // seqNr is the actual nr received
        internal override void ReceiveAcknowledge(double now, int seqNr)
        {
            if (m_doFlowControl == false)
            {
                // we have no use for acks on this channel since we don't respect the window anyway
                m_connection.m_peer.LogVerbose("SuppressUnreliableUnorderedAcks sender/receiver mismatch!");
                return;
            }

            // late (dupe), on time or early ack?
            int relate = NetUtility.RelativeSequenceNumber(seqNr, m_windowStart);

            if (relate < 0)
            {
                //m_connection.m_peer.LogDebug("Received late/dupe ack for #" + seqNr);
                return;                 // late/duplicate ack
            }

            if (relate == 0)
            {
                //m_connection.m_peer.LogDebug("Received right-on-time ack for #" + seqNr);

                // ack arrived right on time
                NetException.Assert(seqNr == m_windowStart);

                m_receivedAcks[m_windowStart] = false;
                m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers;

                return;
            }

            // Advance window to this position
            m_receivedAcks[seqNr] = true;

            while (m_windowStart != seqNr)
            {
                m_receivedAcks[m_windowStart] = false;
                m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers;
            }
        }
Exemple #10
0
        /// <summary>
        /// Add a forwarding rule to the router using UPnP
        /// </summary>
        public bool ForwardPort(int port, string description)
        {
            if (!CheckAvailability())
            {
                return(false);
            }

            IPAddress mask;
            var       client = NetUtility.GetMyAddress(out mask);

            if (client == null)
            {
                return(false);
            }

            try
            {
                XmlDocument xdoc = SOAPRequest(m_serviceUrl,
                                               "<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:" + m_serviceName + ":1\">" +
                                               "<NewRemoteHost></NewRemoteHost>" +
                                               "<NewExternalPort>" + port.ToString() + "</NewExternalPort>" +
                                               "<NewProtocol>" + ProtocolType.Udp.ToString().ToUpper() + "</NewProtocol>" +
                                               "<NewInternalPort>" + port.ToString() + "</NewInternalPort>" +
                                               "<NewInternalClient>" + client.ToString() + "</NewInternalClient>" +
                                               "<NewEnabled>1</NewEnabled>" +
                                               "<NewPortMappingDescription>" + description + "</NewPortMappingDescription>" +
                                               "<NewLeaseDuration>0</NewLeaseDuration>" +
                                               "</u:AddPortMapping>",
                                               "AddPortMapping");

                m_peer.LogDebug("Sent UPnP port forward request");
                System.Threading.Thread.Sleep(50);
            }
            catch (Exception ex)
            {
                m_peer.LogWarning("UPnP port forward failed: " + ex.Message);
                return(false);
            }
            return(true);
        }
        /// <summary>
        /// Encodes a <see cref="NetBitArray"/> to this buffer.
        /// </summary>
        public static void Write(this IBitBuffer buffer, NetBitArray bitArray)
        {
            buffer.WriteVar(bitArray.Length);

            ReadOnlySpan <uint> values = bitArray.GetBuffer().Span;
            int bitsLeft = NetUtility.PowOf2Mod(bitArray.Length, NetBitArray.BitsPerElement);

            if (bitsLeft == 0)
            {
                for (int i = 0; i < values.Length; i++)
                {
                    buffer.Write(values[i]);
                }
            }
            else
            {
                for (int i = 0; i < values.Length - 1; i++)
                {
                    buffer.Write(values[i]);
                }

                uint last = values[^ 1];
Exemple #12
0
        /// <summary>
        /// Add a forwarding rule to the router using UPnP
        /// </summary>
        public bool ForwardPort(int port, string description)
        {
            //if (!CheckAvailability())
            //	return false;

            IPAddress mask;
            var       client = NetUtility.GetMyAddress(out mask);

            if (client == null)
            {
                client = NetUtility.GetBroadcastAddress();
            }
            //return false;

            try
            {
                SOAPRequest(m_serviceUrl,
                            "<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:" + m_serviceName + ":1\">" +
                            "<NewRemoteHost></NewRemoteHost>" +
                            "<NewExternalPort>" + port.ToString() + "</NewExternalPort>" +
                            "<NewProtocol>" + ProtocolType.Udp.ToString().ToUpper(System.Globalization.CultureInfo.InvariantCulture) + "</NewProtocol>" +
                            "<NewInternalPort>" + port.ToString() + "</NewInternalPort>" +
                            "<NewInternalClient>" + client.ToString() + "</NewInternalClient>" +
                            "<NewEnabled>1</NewEnabled>" +
                            "<NewPortMappingDescription>" + description + "</NewPortMappingDescription>" +
                            "<NewLeaseDuration>0</NewLeaseDuration>" +
                            "</u:AddPortMapping>",
                            "AddPortMapping");

                m_peer.LogDebug("Sent UPnP port forward request");
                NetUtility.Sleep(50);
            }
            catch (Exception ex)
            {
                m_peer.LogWarning("UPnP port forward failed: " + ex.Message);
                return(false);
            }
            return(true);
        }
Exemple #13
0
        /// <summary>
        /// Add a forwarding rule to the router using UPnP
        /// </summary>
        public bool ForwardPort(int port, string description)
        {
            if (m_serviceUrl == null && !m_discoveryComplete.WaitOne(c_discoveryTimeOutMillis))
            {
                return(false);
            }

            IPAddress mask;
            var       client = NetUtility.GetMyAddress(out mask);

            if (client == null)
            {
                return(false);
            }

            try
            {
                SOAPRequest(m_serviceUrl,
                            "<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" +
                            "<NewRemoteHost></NewRemoteHost><NewExternalPort>" + port.ToString() + "</NewExternalPort>" +
                            "<NewProtocol>" + ProtocolType.Udp.ToString().ToUpper() + "</NewProtocol>" +
                            "<NewInternalPort>" + port.ToString() + "</NewInternalPort>" +
                            "<NewInternalClient>" + client.ToString() + "</NewInternalClient>" +
                            "<NewEnabled>1</NewEnabled>" +
                            "<NewPortMappingDescription>" + description + "</NewPortMappingDescription>" +
                            "<NewLeaseDuration>0</NewLeaseDuration>" +
                            "</u:AddPortMapping>",
                            "AddPortMapping");

                m_peer.LogDebug("Sent UPnP port forward request");
                System.Threading.Thread.Sleep(50);
            }
            catch (Exception ex)
            {
                m_peer.LogWarning("UPnP port forward failed: " + ex.Message);
                return(false);
            }
            return(true);
        }
Exemple #14
0
        /// <summary>
        /// Reads all fields with the specified binding of the object in alphabetical order using reflection
        /// </summary>
        public void ReadAllProperties(object target, BindingFlags flags)
        {
            if (target == null)
            {
                throw new ArgumentNullException("target");
            }

            Type tp = target.GetType();

            PropertyInfo[] fields = tp.GetProperties(flags);
            NetUtility.SortMembersList(fields);
            foreach (PropertyInfo fi in fields)
            {
                object value;

                // find read method
                MethodInfo readMethod;
                if (s_readMethods.TryGetValue(fi.PropertyType, out readMethod))
                {
                    // read value
                    value = readMethod.Invoke(this, null);

                    // set the value

//#if UNITY_WEBPLAYER || UNITY_4_5
//					var setMethod = fi.GetSetMethod();
//#else
                    //var setMethod = fi.SetMethod;
//#endif

                    var setMethod = fi.GetSetMethod();

                    if (setMethod != null)
                    {
                        setMethod.Invoke(target, new object[] { value });
                    }
                }
            }
        }
Exemple #15
0
        /// <summary>
        /// Reads a string
        /// </summary>
        public string ReadString()
        {
            int byteLen = (int)ReadVariableUInt32();

            if (byteLen == 0)
            {
                return(String.Empty);
            }

            NetUtility.Assert(m_bitLength - m_readPosition >= (byteLen * 8), c_readOverflowError);

            if ((m_readPosition & 7) == 0)
            {
                // read directly
                string retval = System.Text.Encoding.UTF8.GetString(Data, m_readPosition >> 3, byteLen);
                m_readPosition += (8 * byteLen);
                return(retval);
            }

            byte[] bytes = ReadBytes(byteLen);
            return(System.Text.Encoding.UTF8.GetString(bytes, 0, bytes.Length));
        }
		private void InitializeNetwork()
		{
			lock (m_initializeLock)
			{
				m_configuration.Lock();

				if (m_status == NetPeerStatus.Running)
					return;

				if (m_configuration.m_enableUPnP)
					m_upnp = new NetUPnP(this);

				InitializePools();

				m_releasedIncomingMessages.Clear();
				m_unsentUnconnectedMessages.Clear();
				m_handshakes.Clear();

				// bind to socket
				BindSocket(false);

				m_receiveBuffer = new byte[m_configuration.ReceiveBufferSize];
				m_sendBuffer = new byte[m_configuration.SendBufferSize];
				m_readHelperMessage = new NetIncomingMessage(NetIncomingMessageType.Error);
				m_readHelperMessage.m_data = m_receiveBuffer;

				byte[] macBytes = NetUtility.GetMacAddressBytes();

				var boundEp = m_socket.LocalEndPoint as NetEndPoint;
				byte[] epBytes = BitConverter.GetBytes(boundEp.GetHashCode());
				byte[] combined = new byte[epBytes.Length + macBytes.Length];
				Array.Copy(epBytes, 0, combined, 0, epBytes.Length);
				Array.Copy(macBytes, 0, combined, epBytes.Length, macBytes.Length);
				m_uniqueIdentifier = BitConverter.ToInt64(NetUtility.ComputeSHAHash(combined), 0);

				m_status = NetPeerStatus.Running;
			}
		}
Exemple #17
0
        /// <summary>
        /// Reads all fields with the specified binding of the object in alphabetical order using reflection
        /// </summary>
        public void ReadAllProperties(object target, BindingFlags flags)
        {
            if (target == null)
            {
                throw new ArgumentNullException("target");
            }

            Type tp = target.GetType();

            PropertyInfo[] fields = tp.GetProperties(flags);
            NetUtility.SortMembersList(fields);
            foreach (PropertyInfo fi in fields)
            {
                object value;

                // find read method
                MethodInfo readMethod;
                if (s_readMethods.TryGetValue(fi.PropertyType, out readMethod))
                {
                    // read value
                    value = readMethod.Invoke(this, null);

                    // set the value
#if UNITY_WEBPLAYER || UNITY_4_5
                    var setMethod = fi.GetSetMethod();
#else
                    //This must be changed to the above as this cannot be done in .Net 3.5
                    //Reflection is not too fancy in 3.5
                    //Previous: var setMethod = fi.SetMethod;
                    var setMethod = fi.GetSetMethod();
#endif
                    if (setMethod != null)
                    {
                        setMethod.Invoke(target, new object[] { value });
                    }
                }
            }
        }
Exemple #18
0
        /// <summary>
        /// Binds to socket and spawns the networking thread
        /// </summary>
        public void Start()
        {
            if (m_status != NetPeerStatus.NotRunning)
            {
                // already running! Just ignore...
                LogVerbose("Start() called on already running NetPeer - ignoring.");
                return;
            }

            m_status = NetPeerStatus.Starting;

            // fix network thread name
            if (m_configuration.NetworkThreadName == "Lidgren network thread")
            {
                int pc = Interlocked.Increment(ref s_initializedPeersCount);
                m_configuration.NetworkThreadName = "Lidgren network thread " + pc.ToString();
            }

            InitializeNetwork();

            // start network thread
            m_networkThread              = new Thread(new ThreadStart(NetworkLoop));
            m_networkThread.Name         = m_configuration.NetworkThreadName;
            m_networkThread.IsBackground = true;
            m_networkThread.Start();

#if ENABLE_UPNP
            // send upnp discovery
            if (m_upnp != null)
            {
                m_upnp.Discover(this);
            }
#endif

            // allow some time for network thread to start up in case they call Connect() or UPnP calls immediately
            NetUtility.Sleep(50);
        }
Exemple #19
0
        /// <summary>
        /// Writes all properties with specified binding in alphabetical order using reflection
        /// </summary>
        public void WriteAllProperties(object ob, BindingFlags flags)
        {
            if (ob == null)
            {
                return;
            }
            Type tp = ob.GetType();

            PropertyInfo[] fields = tp.GetProperties(flags);
            NetUtility.SortMembersList(fields);

            foreach (PropertyInfo fi in fields)
            {
                MethodInfo getMethod = fi.GetGetMethod((flags & BindingFlags.NonPublic) == BindingFlags.NonPublic);
                object     value     = getMethod.Invoke(ob, null);

                // find the appropriate Write method
                MethodInfo writeMethod;
                if (s_writeMethods.TryGetValue(fi.PropertyType, out writeMethod))
                {
                    writeMethod.Invoke(this, new object[] { value });
                }
            }
        }
        /// <summary>
        /// Emit a discovery signal to all hosts on your subnet
        /// </summary>
        public void DiscoverLocalPeers(int serverPort)
        {
            NetOutgoingMessage um = CreateMessage(0);

            um.m_messageType = NetMessageType.Discovery;
            Interlocked.Increment(ref um.m_recyclingCount);

            m_unsentUnconnectedMessages.Enqueue(new NetTuple <NetEndPoint, long, NetOutgoingMessage>(new NetEndPoint(NetUtility.GetBroadcastAddress(), serverPort), 0, um));
        }
Exemple #21
0
 /// <summary>
 /// Create a connection to a remote endpoint
 /// </summary>
 public NetConnection Connect(string host, int port, NetOutgoingMessage hailMessage)
 {
     return(Connect(new IPEndPoint(NetUtility.Resolve(host, NetGameConfiguration.NetAddressFamily), port), hailMessage));
 }
Exemple #22
0
 /// <summary>
 /// Create a connection to a remote endpoint
 /// </summary>
 public NetConnection Connect(string host, int port)
 {
     return(Connect(new IPEndPoint(NetUtility.Resolve(host, NetGameConfiguration.NetAddressFamily), port), null));
 }
Exemple #23
0
        internal override void ReceiveMessage(NetIncomingMessage message)
        {
            int relate = NetUtility.RelativeSequenceNumber(message.m_sequenceNumber, m_windowStart);

            // ack no matter what
            m_connection.QueueAck(message.m_receivedMessageType, message.m_sequenceNumber);

            if (relate == 0)
            {
                // Log("Received message #" + message.SequenceNumber + " right on time");

                //
                // excellent, right on time
                //
                //m_peer.LogVerbose("Received RIGHT-ON-TIME " + message);

                AdvanceWindow();
                m_peer.ReleaseMessage(message);

                // release withheld messages
                int nextSeqNr = (message.m_sequenceNumber + 1) % NetConstants.NumSequenceNumbers;

                while (m_earlyReceived[nextSeqNr % m_windowSize])
                {
                    message = m_withheldMessages[nextSeqNr % m_windowSize];
                    NetException.Assert(message != null);

                    // remove it from withheld messages
                    m_withheldMessages[nextSeqNr % m_windowSize] = null;

                    m_peer.LogVerbose("Releasing withheld message #" + message);

                    m_peer.ReleaseMessage(message);

                    AdvanceWindow();
                    nextSeqNr++;
                }

                return;
            }

            if (relate < 0)
            {
                // duplicate
                m_connection.m_statistics.MessageDropped();
                m_peer.LogVerbose("Received message #" + message.m_sequenceNumber + " DROPPING DUPLICATE");
                return;
            }

            // relate > 0 = early message
            if (relate > m_windowSize)
            {
                // too early message!
                m_connection.m_statistics.MessageDropped();
                m_peer.LogDebug("Received " + message + " TOO EARLY! Expected " + m_windowStart);
                return;
            }

            m_earlyReceived.Set(message.m_sequenceNumber % m_windowSize, true);
            m_peer.LogVerbose("Received " + message + " WITHHOLDING, waiting for " + m_windowStart);
            m_withheldMessages[message.m_sequenceNumber % m_windowSize] = message;
        }
        private void InitializeNetwork()
        {
            lock (m_initializeLock)
            {
                m_configuration.Lock();

                if (m_status == NetPeerStatus.Running)
                {
                    return;
                }

                if (m_configuration.m_enableUPnP)
                {
                    m_upnp = new NetUPnP(this);
                }

                InitializePools();

                m_releasedIncomingMessages.Clear();
                m_unsentUnconnectedMessages.Clear();
                m_handshakes.Clear();

                // bind to socket
                IPEndPoint iep = null;

                iep = new IPEndPoint(m_configuration.LocalAddress, m_configuration.Port);
                EndPoint ep = (EndPoint)iep;

                m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                m_socket.ReceiveBufferSize = m_configuration.ReceiveBufferSize;
                m_socket.SendBufferSize    = m_configuration.SendBufferSize;
                m_socket.Blocking          = false;
                m_socket.Bind(ep);

                try
                {
                    const uint IOC_IN            = 0x80000000;
                    const uint IOC_VENDOR        = 0x18000000;
                    uint       SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
                    m_socket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
                }
                catch
                {
                    // ignore; SIO_UDP_CONNRESET not supported on this platform
                }

                IPEndPoint boundEp = m_socket.LocalEndPoint as IPEndPoint;
                LogDebug("Socket bound to " + boundEp + ": " + m_socket.IsBound);
                m_listenPort = boundEp.Port;

                m_receiveBuffer            = new byte[m_configuration.ReceiveBufferSize];
                m_sendBuffer               = new byte[m_configuration.SendBufferSize];
                m_readHelperMessage        = new NetIncomingMessage(NetIncomingMessageType.Error);
                m_readHelperMessage.m_data = m_receiveBuffer;

                byte[] macBytes = new byte[8];
                NetRandom.Instance.NextBytes(macBytes);

#if IS_MAC_AVAILABLE
                try
                {
                    System.Net.NetworkInformation.PhysicalAddress pa = NetUtility.GetMacAddress();
                    if (pa != null)
                    {
                        macBytes = pa.GetAddressBytes();
                        LogVerbose("Mac address is " + NetUtility.ToHexString(macBytes));
                    }
                    else
                    {
                        LogWarning("Failed to get Mac address");
                    }
                }
                catch (NotSupportedException)
                {
                    // not supported; lets just keep the random bytes set above
                }
#endif
                byte[] epBytes  = BitConverter.GetBytes(boundEp.GetHashCode());
                byte[] combined = new byte[epBytes.Length + macBytes.Length];
                Array.Copy(epBytes, 0, combined, 0, epBytes.Length);
                Array.Copy(macBytes, 0, combined, epBytes.Length, macBytes.Length);
                m_uniqueIdentifier = BitConverter.ToInt64(SHA1.Create().ComputeHash(combined), 0);

                m_status = NetPeerStatus.Running;
            }
        }
        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);
        }
Exemple #26
0
        private void ExecutePeerShutdown()
        {
            VerifyNetworkThread();

            LogDebug("Shutting down...");

            // disconnect and make one final heartbeat
            var list = new List <NetConnection>(m_handshakes.Count + m_connections.Count);

            lock (m_connections)
            {
                foreach (var conn in m_connections)
                {
                    if (conn != null)
                    {
                        list.Add(conn);
                    }
                }
            }

            lock (m_handshakes)
            {
                foreach (var hs in m_handshakes.Values)
                {
                    if (hs != null && list.Contains(hs) == false)
                    {
                        list.Add(hs);
                    }
                }
            }

            // shut down connections
            foreach (NetConnection conn in list)
            {
                conn.Shutdown(m_shutdownReason);
            }

            FlushDelayedPackets();

            // one final heartbeat, will send stuff and do disconnect
            Heartbeat();

            NetUtility.Sleep(10);

            lock (m_initializeLock)
            {
                try
                {
                    if (m_socket != null)
                    {
                        try
                        {
                            m_socket.Shutdown(SocketShutdown.Receive);
                        }
                        catch (Exception ex)
                        {
                            LogDebug("Socket.Shutdown exception: " + ex.ToString());
                        }

                        try
                        {
                            m_socket.Close(2);                             // 2 seconds timeout
                        }
                        catch (Exception ex)
                        {
                            LogDebug("Socket.Close exception: " + ex.ToString());
                        }
                    }
                }
                finally
                {
                    m_socket = null;
                    m_status = NetPeerStatus.NotRunning;
                    LogDebug("Shutdown complete");

                    // wake up any threads waiting for server shutdown
                    if (m_messageReceivedEvent != null)
                    {
                        m_messageReceivedEvent.Set();
                    }
                }

                m_lastSocketBind = float.MinValue;
                m_receiveBuffer  = null;
                m_sendBuffer     = null;
                m_unsentUnconnectedMessages.Clear();
                m_connections.Clear();
                m_connectionLookup.Clear();
                m_handshakes.Clear();
            }

            return;
        }
        // remoteWindowStart is remote expected sequence number; everything below this has arrived properly
        // seqNr is the actual nr received
        internal override void ReceiveAcknowledge(float now, int seqNr)
        {
            // late (dupe), on time or early ack?
            int relate = NetUtility.RelativeSequenceNumber(seqNr, m_windowStart);

            if (relate < 0)
            {
                //m_connection.m_peer.LogDebug("Received late/dupe ack for #" + seqNr);
                return; // late/duplicate ack
            }

            if (relate == 0)
            {
                //m_connection.m_peer.LogDebug("Received right-on-time ack for #" + seqNr);

                // ack arrived right on time
                NetException.Assert(seqNr == m_windowStart);

                m_receivedAcks[m_windowStart] = false;
                DestoreMessage(m_windowStart % m_windowSize);
                m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers;

                // advance window if we already have early acks
                while (m_receivedAcks.Get(m_windowStart))
                {
                    //m_connection.m_peer.LogDebug("Using early ack for #" + m_windowStart + "...");
                    m_receivedAcks[m_windowStart] = false;
                    DestoreMessage(m_windowStart % m_windowSize);

                    NetException.Assert(m_storedMessages[m_windowStart % m_windowSize].Message == null); // should already be destored
                    m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers;
                    //m_connection.m_peer.LogDebug("Advancing window to #" + m_windowStart);
                }

                return;
            }

            //
            // early ack... (if it has been sent!)
            //
            // If it has been sent either the m_windowStart message was lost
            // ... or the ack for that message was lost
            //

            //m_connection.m_peer.LogDebug("Received early ack for #" + seqNr);

            int sendRelate = NetUtility.RelativeSequenceNumber(seqNr, m_sendStart);

            if (sendRelate <= 0)
            {
                // yes, we've sent this message - it's an early (but valid) ack
                if (m_receivedAcks[seqNr])
                {
                    // we've already destored/been acked for this message
                }
                else
                {
                    m_receivedAcks[seqNr] = true;
                }
            }
            else if (sendRelate > 0)
            {
                // This is a bug in Lidgren (that I don't have time to mess around with) (-AR)
                // Disconnecting causes the channel to Reset() (resets pending sequence number), but somehow we still receive acks.
                // (Status gets set to Disconnected after the Reset, but seems to all be on the network thread, so not a race condition)
                if (m_connection == null || m_connection.m_status == NetConnectionStatus.Disconnected)
                {
                    return; // Let's not call NetException.Assert!
                }
                // uh... we haven't sent this message yet? Weird, dupe or error...
                NetException.Assert(false, "Got ack for message not yet sent?");
                return;
            }

            // Ok, lets resend all missing acks
            int rnr = seqNr;

            do
            {
                rnr--;
                if (rnr < 0)
                {
                    rnr = NetConstants.NumSequenceNumbers - 1;
                }

                if (m_receivedAcks[rnr])
                {
                    // m_connection.m_peer.LogDebug("Not resending #" + rnr + " (since we got ack)");
                }
                else
                {
                    int slot = rnr % m_windowSize;
                    NetException.Assert(m_storedMessages[slot].Message != null);
                    if (m_storedMessages[slot].NumSent == 1)
                    {
                        // just sent once; resend immediately since we found gap in ack sequence
                        NetOutgoingMessage rmsg = m_storedMessages[slot].Message;
                        //m_connection.m_peer.LogVerbose("Resending #" + rnr + " (" + rmsg + ")");

                        if (now - m_storedMessages[slot].LastSent < (m_resendDelay * 0.35f))
                        {
                            // already resent recently
                        }
                        else
                        {
                            m_storedMessages[slot].LastSent = now;
                            m_storedMessages[slot].NumSent++;
                            m_connection.m_statistics.MessageResent(MessageResendReason.HoleInSequence);
                            m_connection.QueueSendMessage(rmsg, rnr);
                        }
                    }
                }
            } while (rnr != m_windowStart);
        }
Exemple #28
0
 /// <summary>
 /// Create a connection to a remote endpoint
 /// </summary>
 public NetConnection Connect(string host, int port, NetOutgoingMessage hailMessage)
 {
     return(Connect(new NetEndPoint(NetUtility.Resolve(host), port), hailMessage));
 }
Exemple #29
0
 /// <summary>
 /// Create a connection to a remote endpoint
 /// </summary>
 public NetConnection Connect(string host, int port)
 {
     return(Connect(new NetEndPoint(NetUtility.Resolve(host), port), null));
 }
        // remoteWindowStart is remote expected sequence number; everything below this has arrived properly
        // seqNr is the actual nr received
        internal override void ReceiveAcknowledge(double now, int seqNr)
        {
            // late (dupe), on time or early ack?
            int relate = NetUtility.RelativeSequenceNumber(seqNr, m_windowStart);

            if (relate < 0)
            {
                //m_connection.m_peer.LogDebug("Received late/dupe ack for #" + seqNr);
                return;                 // late/duplicate ack
            }

            if (relate == 0)
            {
                //m_connection.m_peer.LogDebug("Received right-on-time ack for #" + seqNr);

                // ack arrived right on time
                NetException.Assert(seqNr == m_windowStart);

                bool resetTimeout;
                m_receivedAcks[m_windowStart] = false;
                DestoreMessage(now, m_windowStart % m_windowSize, out resetTimeout);
                m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers;

                // advance window if we already have early acks
                while (m_receivedAcks.Get(m_windowStart))
                {
                    //m_connection.m_peer.LogDebug("Using early ack for #" + m_windowStart + "...");
                    m_receivedAcks[m_windowStart] = false;
                    bool rt;
                    DestoreMessage(now, m_windowStart % m_windowSize, out rt);
                    resetTimeout |= rt;

                    NetException.Assert(m_storedMessages[m_windowStart % m_windowSize].Message == null);                     // should already be destored
                    m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers;
                    //m_connection.m_peer.LogDebug("Advancing window to #" + m_windowStart);
                }
                if (resetTimeout)
                {
                    m_connection.ResetTimeout(now);
                }
                return;
            }

            //
            // early ack... (if it has been sent!)
            //
            // If it has been sent either the m_windowStart message was lost
            // ... or the ack for that message was lost
            //

            //m_connection.m_peer.LogDebug("Received early ack for #" + seqNr);

            int sendRelate = NetUtility.RelativeSequenceNumber(seqNr, m_sendStart);

            if (sendRelate <= 0)
            {
                // yes, we've sent this message - it's an early (but valid) ack
                if (m_receivedAcks[seqNr])
                {
                    // we've already destored/been acked for this message
                }
                else
                {
                    m_receivedAcks[seqNr] = true;
                }
            }
            else if (sendRelate > 0)
            {
                // uh... we haven't sent this message yet? Weird, dupe or error...
                NetException.Assert(false, "Got ack for message not yet sent?");
                return;
            }

            // Ok, lets resend all missing acks
            int rnr = seqNr;

            do
            {
                rnr--;
                if (rnr < 0)
                {
                    rnr = NetConstants.NumSequenceNumbers - 1;
                }

                if (m_receivedAcks[rnr])
                {
                    // m_connection.m_peer.LogDebug("Not resending #" + rnr + " (since we got ack)");
                }
                else
                {
                    int slot = rnr % m_windowSize;
                    NetException.Assert(m_storedMessages[slot].Message != null);
                    if (m_storedMessages[slot].NumSent == 1)
                    {
                        // just sent once; resend immediately since we found gap in ack sequence
                        NetOutgoingMessage rmsg = m_storedMessages[slot].Message;
                        //m_connection.m_peer.LogVerbose("Resending #" + rnr + " (" + rmsg + ")");

                        if (now - m_storedMessages[slot].LastSent < (m_resendDelay * 0.35))
                        {
                            // already resent recently
                        }
                        else
                        {
                            m_storedMessages[slot].LastSent = now;
                            m_storedMessages[slot].NumSent++;
                            m_connection.m_statistics.MessageResent(MessageResendReason.HoleInSequence);
                            Interlocked.Increment(ref rmsg.m_recyclingCount);                             // increment this since it's being decremented in QueueSendMessage
                            m_connection.QueueSendMessage(rmsg, rnr);
                        }
                    }
                }
            } while (rnr != m_windowStart);
        }