private void SendQueuedOutOfBandMessages()
 {
     if (m_unsentOutOfBandMessages.Count > 0)
     {
         while (m_unsentOutOfBandMessages.Count > 0)
         {
             NetBuffer       buf = m_unsentOutOfBandMessages.Dequeue();
             NetworkEndPoint ep  = m_unsentOutOfBandRecipients.Dequeue();
             DoSendOutOfBandMessage(buf, ep);
         }
     }
 }
예제 #2
0
        /// <summary>
        /// Reads all packets and create messages
        /// </summary>
        protected void BaseHeartbeat(double now)
        {
            if (!m_isBound)
            {
                return;
            }

            // discovery
            m_discovery.Heartbeat(now);

            // hole punching
            if (m_holePunches != null)
            {
                if (now > m_lastHolePunch + NetConstants.HolePunchingFrequency)
                {
                    if (m_holePunches.Count <= 0)
                    {
                        m_holePunches = null;
                    }
                    else
                    {
                        IPEndPoint dest = m_holePunches[0];
                        m_holePunches.RemoveAt(0);
                        NotifyApplication(NetMessageType.DebugMessage, "Sending hole punch to " + dest, null);
                        NetConnection.SendPing(this, dest, now);
                        if (m_holePunches.Count < 1)
                        {
                            m_holePunches = null;
                        }
                        m_lastHolePunch = now;
                    }
                }
            }

            // Send queued system messages
            if (m_susmQueue.Count > 0)
            {
                lock (m_susmQueue)
                {
                    while (m_susmQueue.Count > 0)
                    {
                        SUSystemMessage su = m_susmQueue.Dequeue();
                        SendSingleUnreliableSystemMessage(su.Type, su.Data, su.Destination, su.UseBroadcast);
                    }
                }
            }

            // Send out-of-band messages
            if (m_unsentOutOfBandMessages.Count > 0)
            {
                lock (m_unsentOutOfBandMessages)
                {
                    while (m_unsentOutOfBandMessages.Count > 0)
                    {
                        NetBuffer  buf = m_unsentOutOfBandMessages.Dequeue();
                        IPEndPoint ep  = m_unsentOutOfBandRecipients.Dequeue();
                        DoSendOutOfBandMessage(buf, ep);
                    }
                }
            }

            try
            {
#if DEBUG
                SendDelayedPackets(now);
#endif

                while (true)
                {
                    if (m_socket == null || m_socket.Available < 1)
                    {
                        return;
                    }
                    m_receiveBuffer.Reset();

                    int bytesReceived = 0;
                    try
                    {
                        bytesReceived = m_socket.ReceiveFrom(m_receiveBuffer.Data, 0, m_receiveBuffer.Data.Length, SocketFlags.None, ref m_senderRemote);
                    }
                    catch (SocketException)
                    {
                        // no good response to this yet
                        return;
                    }
                    if (bytesReceived < 1)
                    {
                        return;
                    }
                    if (bytesReceived > 0)
                    {
                        m_statistics.CountPacketReceived(bytesReceived);
                    }
                    m_receiveBuffer.LengthBits = bytesReceived * 8;

                    //LogVerbose("Read packet: " + bytesReceived + " bytes");

                    IPEndPoint ipsender = (IPEndPoint)m_senderRemote;

                    NetConnection sender = GetConnection(ipsender);
                    if (sender != null)
                    {
                        sender.m_statistics.CountPacketReceived(bytesReceived, now);
                    }

                    // create messages from packet
                    while (m_receiveBuffer.Position < m_receiveBuffer.LengthBits)
                    {
                        int beginPosition = m_receiveBuffer.Position;

                        // read message header
                        IncomingNetMessage msg = CreateIncomingMessage();
                        msg.m_sender = sender;
                        msg.ReadFrom(m_receiveBuffer, ipsender);

                        // statistics
                        if (sender != null)
                        {
                            sender.m_statistics.CountMessageReceived(msg.m_type, msg.m_sequenceChannel, (m_receiveBuffer.Position - beginPosition) / 8, now);
                        }

                        // handle message
                        HandleReceivedMessage(msg, ipsender);
                    }
                }
            }
            catch (SocketException sex)
            {
                if (sex.ErrorCode == 10054)
                {
                    // forcibly closed; but m_senderRemote is unreliable, we can't trust it!
                    //NetConnection conn = GetConnection((IPEndPoint)m_senderRemote);
                    //HandleConnectionForciblyClosed(conn, sex);
                    return;
                }
            }
            catch (Exception ex)
            {
                throw new NetException("ReadPacket() exception", ex);
            }
        }
예제 #3
0
        internal void SendUnsentMessages(double now)
        {
            // Add any acknowledges to unsent messages
            if (m_acknowledgesToSend.Count > 0)
            {
                if (m_unsentMessages.Count < 1)
                {
                    // Wait before sending acknowledges?
                    if (m_ackMaxDelayTime > 0.0f)
                    {
                        if (m_ackWithholdingStarted == 0.0)
                        {
                            m_ackWithholdingStarted = now;
                        }
                        else
                        {
                            if (now - m_ackWithholdingStarted < m_ackMaxDelayTime)
                            {
                                return;                                 // don't send (only) acks just yet
                            }
                            // send acks "explicitly" ie. without any other message being sent
                            m_ackWithholdingStarted = 0.0;
                        }
                    }
                }

                // create ack messages and add to m_unsentMessages
                CreateAckMessages();
            }

            if (m_unsentMessages.Count < 1)
            {
                return;
            }

            // throttling
            float throttle     = m_owner.m_config.ThrottleBytesPerSecond;
            float maxSendBytes = float.MaxValue;

            if (throttle > 0)
            {
                double frameLength = now - m_lastSentUnsentMessages;

                //int wasDebt = (int)m_throttleDebt;
                if (m_throttleDebt > 0)
                {
                    m_throttleDebt -= (float)(frameLength * (double)m_owner.m_config.ThrottleBytesPerSecond);
                }
                //int nowDebt = (int)m_throttleDebt;
                //if (nowDebt != wasDebt)
                //	LogWrite("THROTTLE worked off -" + (nowDebt - wasDebt) + " bytes = " + m_throttleDebt);

                m_lastSentUnsentMessages = now;

                maxSendBytes = throttle - m_throttleDebt;
                if (maxSendBytes < 0)
                {
                    return;                     // throttling; no bytes allowed to be sent
                }
            }

            int  mtu           = m_owner.Configuration.MaximumTransmissionUnit;
            bool useCoalescing = m_owner.Configuration.UseMessageCoalescing;

            int       messagesInPacket = 0;
            NetBuffer sendBuffer       = m_owner.m_sendBuffer;

            sendBuffer.Reset();
            while (m_unsentMessages.Count > 0)
            {
                OutgoingNetMessage msg   = m_unsentMessages.Peek();
                int estimatedMessageSize = msg.m_data.LengthBytes + 5;

                // check if this message fits the throttle window
                if (estimatedMessageSize > maxSendBytes)                 // TODO: Allow at last one message if no debt
                {
                    break;
                }

                // need to send packet and start a new one?
                if (messagesInPacket > 0)
                {
                    if (!useCoalescing || (sendBuffer.LengthBytes + estimatedMessageSize > mtu))
                    {
                        m_owner.SendPacket(m_remoteEndPoint);
                        int sendLen = sendBuffer.LengthBytes;
                        m_statistics.CountPacketSent(sendLen);
                        //LogWrite("THROTTLE Send packet +" + sendLen + " bytes = " + m_throttleDebt + " (maxSendBytes " + maxSendBytes + " estimated " + estimatedMessageSize + ")");
                        m_throttleDebt += sendLen;
                        sendBuffer.Reset();
                    }
                }

                if (msg.m_sequenceNumber == -1)
                {
                    AssignSequenceNumber(msg);
                }

                // pop and encode message
                m_unsentMessages.Dequeue();
                int pre = sendBuffer.m_bitLength;
                msg.m_data.m_readPosition = 0;
                msg.Encode(sendBuffer);

                int encLen = (sendBuffer.m_bitLength - pre) / 8;
                m_statistics.CountMessageSent(msg, encLen);
                maxSendBytes -= encLen;

                if (msg.m_sequenceChannel >= NetChannel.ReliableUnordered)
                {
                    // reliable; store message (incl. buffer)
                    msg.m_numSent++;
                    StoreMessage(now, msg);
                }
                else
                {
                    // not reliable, don't store - recycle...
                    NetBuffer b = msg.m_data;
                    b.m_refCount--;

                    msg.m_data = null;

                    // ... unless someone else is using the buffer
                    if (b.m_refCount <= 0)
                    {
                        m_owner.RecycleBuffer(b);
                    }

                    //m_owner.m_messagePool.Push(msg);
                }
                messagesInPacket++;
            }

            // send current packet
            if (messagesInPacket > 0)
            {
                m_owner.SendPacket(m_remoteEndPoint);
                int sendLen = sendBuffer.LengthBytes;
                m_statistics.CountPacketSent(sendLen);
                //LogWrite("THROTTLE Send packet +" + sendLen + " bytes = " + m_throttleDebt);
                m_throttleDebt += sendLen;
            }
        }
예제 #4
0
        internal void Heartbeat(double now)
        {
            if (m_status == NetConnectionStatus.Disconnected)
            {
                return;
            }

            //CongestionHeartbeat(now);

            // drain messages from application into main unsent list
            lock (m_lockedUnsentMessages)
            {
                OutgoingNetMessage lm;
                while ((lm = m_lockedUnsentMessages.Dequeue()) != null)
                {
                    m_unsentMessages.Enqueue(lm);
                }
            }

            if (m_status == NetConnectionStatus.Connecting)
            {
                if (now - m_handshakeInitiated > m_owner.Configuration.HandshakeAttemptRepeatDelay)
                {
                    if (m_handshakeAttempts >= m_owner.Configuration.HandshakeAttemptsMaxCount)
                    {
                        Disconnect("No answer from remote host", 0, false, true);
                        return;
                    }
                    m_handshakeAttempts++;
                    if (m_isInitiator)
                    {
                        m_owner.LogWrite("Re-sending Connect", this);
                        Connect();
                    }
                    else
                    {
                        m_owner.LogWrite("Re-sending ConnectResponse", this);
                        m_handshakeInitiated = now;

                        OutgoingNetMessage response = m_owner.CreateSystemMessage(NetSystemType.ConnectResponse);
                        if (m_localHailData != null)
                        {
                            response.m_data.Write(m_localHailData);
                        }
                        m_unsentMessages.Enqueue(response);
                    }
                }
            }
            else if (m_status == NetConnectionStatus.Connected)
            {
                // send ping?
                CheckPing(now);
            }

            if (m_requestDisconnect)
            {
                InitiateDisconnect();
            }

            if (now > m_futureClose)
            {
                FinalizeDisconnect();
            }

            // Resend all packets that has reached a mature age
            ResendMessages(now);

            // send all unsent messages
            SendUnsentMessages(now);
        }
        public bool ReadMessage(
            NetBuffer intoBuffer,
            out NetMessageType type,
            out NetConnection sender,
            out NetworkEndPoint senderEndPoint,
            out NetChannel channel,
            out double localTimeRecv)
        {
            if (intoBuffer == null)
            {
                throw new ArgumentNullException("intoBuffer");
            }

            if (m_receivedMessages.Count < 1)
            {
                type           = NetMessageType.None;
                sender         = null;
                senderEndPoint = NetworkEndPoint.unassigned;
                channel        = NetChannel.Unreliable;
                localTimeRecv  = 0;
                return(false);
            }

            IncomingNetMessage msg = m_receivedMessages.Dequeue();

            if (msg == null)
            {
                type           = NetMessageType.None;
                sender         = null;
                senderEndPoint = NetworkEndPoint.unassigned;
                channel        = NetChannel.Unreliable;
                localTimeRecv  = 0;
                return(false);
            }

            senderEndPoint = msg.m_senderEndPoint;
            sender         = msg.m_sender;
            localTimeRecv  = NetTime.Now;            // TODO: this is a ugly hack, should instead get value when reading from socket. Merging/switching to Speedgren will solve that.
            channel        = msg.m_sequenceChannel;

            // recycle NetMessage object
            var content = msg.m_data;

            msg.m_data = null;
            type       = msg.m_msgType;

            if (content == null)
            {
                intoBuffer.m_bitLength    = 0;
                intoBuffer.m_readPosition = 0;
                return(true);
            }

            // swap content of buffers
            byte[] tmp = intoBuffer.Data;
            intoBuffer.Data = content.Data;
            content.Data    = tmp;

            // set correct values for returning value (ignore the other, it's being recycled anyway)
            intoBuffer.m_bitLength    = content.m_bitLength;
            intoBuffer.m_readPosition = 0;

            // recycle buffer
            RecycleBuffer(content);

            return(true);
        }