Пример #1
0
        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);
        }
        // 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;
            }
        }
Пример #3
0
        public void TestScenario()
        {
            var peer = TestHelper.CreatePeer();
            NetOutgoingMessage msg = peer.CreateMessage();

            msg.Write(false);
            msg.Write(-3, 6);
            msg.Write(42);
            msg.Write("duke of earl");
            msg.Write((byte)43);
            msg.Write((ushort)44);
            msg.Write(UInt64.MaxValue, 64);
            msg.Write(true);

            msg.WritePadBits();

            int bcnt = 0;

            msg.Write(567845.0f);
            msg.WriteVariableInt32(2115998022);
            msg.Write(46.0);
            msg.Write((ushort)14, 9);
            bcnt += msg.WriteVariableInt32(-47);
            msg.WriteVariableInt32(470000);
            msg.WriteVariableUInt32(48);
            bcnt += msg.WriteVariableInt64(-49);

            if (bcnt != 2)
            {
                throw new NetException("WriteVariable* wrote too many bytes!");
            }

            byte[] data = msg.Data;

            NetIncomingMessage inc = TestHelper.CreateIncomingMessage(data, msg.LengthBits);

            StringBuilder bdr = new StringBuilder();

            bdr.Append(inc.ReadBoolean());
            bdr.Append(inc.ReadInt32(6));
            bdr.Append(inc.ReadInt32());

            string strResult;
            bool   ok = inc.ReadString(out strResult);

            if (ok == false)
            {
                throw new NetException("Read/write failure");
            }
            bdr.Append(strResult);

            bdr.Append(inc.ReadByte());

            if (inc.PeekUInt16() != (ushort)44)
            {
                throw new NetException("Read/write failure");
            }

            bdr.Append(inc.ReadUInt16());

            if (inc.PeekUInt64(64) != UInt64.MaxValue)
            {
                throw new NetException("Read/write failure");
            }

            bdr.Append(inc.ReadUInt64());
            bdr.Append(inc.ReadBoolean());

            inc.SkipPadBits();

            bdr.Append(inc.ReadSingle());
            bdr.Append(inc.ReadVariableInt32());
            bdr.Append(inc.ReadDouble());
            bdr.Append(inc.ReadUInt32(9));
            bdr.Append(inc.ReadVariableInt32());
            bdr.Append(inc.ReadVariableInt32());
            bdr.Append(inc.ReadVariableUInt32());
            bdr.Append(inc.ReadVariableInt64());

            if (bdr.ToString().Equals("False-342duke of earl434418446744073709551615True56784521159980224614-4747000048-49"))
            {
                Console.WriteLine("Read/write tests OK");
            }
            else
            {
                throw new NetException("Read/write tests FAILED!");
            }

            msg = peer.CreateMessage();

            NetOutgoingMessage tmp = peer.CreateMessage();

            tmp.Write((int)42, 14);

            msg.Write(tmp);
            msg.Write(tmp);

            if (msg.LengthBits != tmp.LengthBits * 2)
            {
                throw new NetException("NetOutgoingMessage.Write(NetOutgoingMessage) failed!");
            }

            tmp = peer.CreateMessage();

            Test test = new Test();

            test.Number = 42;
            test.Name   = "Hallon";
            test.Age    = 8.2f;

            tmp.WriteAllFields(test, BindingFlags.Public | BindingFlags.Instance);

            data = tmp.Data;

            inc = TestHelper.CreateIncomingMessage(data, tmp.LengthBits);

            Test readTest = new Test();

            inc.ReadAllFields(readTest, BindingFlags.Public | BindingFlags.Instance);

            NetException.Assert(readTest.Number == 42);
            NetException.Assert(readTest.Name == "Hallon");
            NetException.Assert(readTest.Age == 8.2f);

            // test aligned WriteBytes/ReadBytes
            msg = peer.CreateMessage();
            byte[] tmparr = new byte[] { 5, 6, 7, 8, 9 };
            msg.Write(tmparr);

            inc = TestHelper.CreateIncomingMessage(msg.Data, msg.LengthBits);
            byte[] result = inc.ReadBytes(tmparr.Length);

            for (int i = 0; i < tmparr.Length; i++)
            {
                if (tmparr[i] != result[i])
                {
                    throw new Exception("readbytes fail");
                }
            }
        }
Пример #4
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;
        }
Пример #5
0
        internal void Heartbeat(double now, uint frameCounter)
        {
            m_peer.VerifyNetworkThread();

            NetException.Assert(m_status != NetConnectionStatus.InitiatedConnect && m_status != NetConnectionStatus.RespondedConnect);

            if ((frameCounter % m_infrequentEventsSkipFrames) == 0)
            {
                if (now > m_timeoutDeadline)
                {
                    //
                    // connection timed out
                    //
                    m_peer.LogVerbose("Connection timed out at " + now + " deadline was " + m_timeoutDeadline);
                    ExecuteDisconnect("Connection timed out", true);
                    return;
                }

                // send ping?
                if (m_status == NetConnectionStatus.Connected)
                {
                    if (now > m_sentPingTime + m_peer.m_configuration.m_pingInterval)
                    {
                        SendPing();
                    }

                    // handle expand mtu
                    MTUExpansionHeartbeat(now);
                }

                if (m_disconnectRequested)
                {
                    ExecuteDisconnect(m_disconnectMessage, m_disconnectReqSendBye);
                    return;
                }
            }

            bool connectionReset;             // TODO: handle connection reset

            //
            // Note: at this point m_sendBufferWritePtr and m_sendBufferNumMessages may be non-null; resends may already be queued up
            //

            byte[] sendBuffer = m_peer.m_sendBuffer;
            int    mtu        = m_currentMTU;

            if ((frameCounter % m_messageCoalesceFrames) == 0)             // coalesce a few frames
            {
                //
                // send ack messages
                //
                while (m_queuedOutgoingAcks.Count > 0)
                {
                    int acks = (mtu - (m_sendBufferWritePtr + 5)) / 3;                     // 3 bytes per actual ack
                    if (acks > m_queuedOutgoingAcks.Count)
                    {
                        acks = m_queuedOutgoingAcks.Count;
                    }

                    NetException.Assert(acks > 0);

                    m_sendBufferNumMessages++;

                    // write acks header
                    sendBuffer[m_sendBufferWritePtr++] = (byte)NetMessageType.Acknowledge;
                    sendBuffer[m_sendBufferWritePtr++] = 0;       // no sequence number
                    sendBuffer[m_sendBufferWritePtr++] = 0;       // no sequence number
                    int len = (acks * 3) * 8;                     // bits
                    sendBuffer[m_sendBufferWritePtr++] = (byte)len;
                    sendBuffer[m_sendBufferWritePtr++] = (byte)(len >> 8);

                    // write acks
                    for (int i = 0; i < acks; i++)
                    {
                        NetTuple <NetMessageType, int> tuple;
                        m_queuedOutgoingAcks.TryDequeue(out tuple);

                        //m_peer.LogVerbose("Sending ack for " + tuple.Item1 + "#" + tuple.Item2);

                        sendBuffer[m_sendBufferWritePtr++] = (byte)tuple.Item1;
                        sendBuffer[m_sendBufferWritePtr++] = (byte)tuple.Item2;
                        sendBuffer[m_sendBufferWritePtr++] = (byte)(tuple.Item2 >> 8);
                    }

                    if (m_queuedOutgoingAcks.Count > 0)
                    {
                        // send packet and go for another round of acks
                        NetException.Assert(m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0);
                        m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndPoint, m_sendBufferNumMessages, out connectionReset);
                        m_statistics.PacketSent(m_sendBufferWritePtr, 1);
                        m_sendBufferWritePtr    = 0;
                        m_sendBufferNumMessages = 0;
                    }
                }

                //
                // Parse incoming acks (may trigger resends)
                //
                NetTuple <NetMessageType, int> incAck;
                while (m_queuedIncomingAcks.TryDequeue(out incAck))
                {
                    //m_peer.LogVerbose("Received ack for " + acktp + "#" + seqNr);
                    NetSenderChannelBase chan = m_sendChannels[(int)incAck.Item1 - 1];

                    // If we haven't sent a message on this channel there is no reason to ack it
                    if (chan == null)
                    {
                        continue;
                    }

                    chan.ReceiveAcknowledge(now, incAck.Item2);
                }
            }

            //
            // send queued messages
            //
            if (m_peer.m_executeFlushSendQueue)
            {
                for (int i = m_sendChannels.Length - 1; i >= 0; i--)                    // Reverse order so reliable messages are sent first
                {
                    var channel = m_sendChannels[i];
                    NetException.Assert(m_sendBufferWritePtr < 1 || m_sendBufferNumMessages > 0);
                    if (channel != null)
                    {
                        channel.SendQueuedMessages(now);
                        if (channel.NeedToSendMessages())
                        {
                            m_peer.m_needFlushSendQueue = true;                             // failed to send all queued sends; likely a full window - need to try again
                        }
                    }
                    NetException.Assert(m_sendBufferWritePtr < 1 || m_sendBufferNumMessages > 0);
                }
            }

            //
            // Put on wire data has been written to send buffer but not yet sent
            //
            if (m_sendBufferWritePtr > 0)
            {
                m_peer.VerifyNetworkThread();
                NetException.Assert(m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0);
                m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndPoint, m_sendBufferNumMessages, out connectionReset);
                m_statistics.PacketSent(m_sendBufferWritePtr, m_sendBufferNumMessages);
                m_sendBufferWritePtr    = 0;
                m_sendBufferNumMessages = 0;
            }
        }
Пример #6
0
        public static void Run(NetPeer peer)
        {
            NetOutgoingMessage msg = peer.CreateMessage();

            msg.Write(false);
            msg.Write(-3, 6);
            msg.Write(42);
            msg.Write("duke of earl");
            msg.Write((byte)43);
            msg.Write((ushort)44);
            msg.Write(true);

            msg.WritePadBits();

            int bcnt = 0;

            msg.Write(45.0f);
            msg.Write(46.0);
            bcnt += msg.WriteVariableInt32(-47);
            msg.WriteVariableInt32(470000);
            msg.WriteVariableUInt32(48);
            bcnt += msg.WriteVariableInt64(-49);

            if (bcnt != 2)
            {
                throw new NetException("WriteVariable* wrote too many bytes!");
            }

            byte[] data = msg.PeekDataBuffer();

            NetIncomingMessage inc = Program.CreateIncomingMessage(data, msg.LengthBits);

            StringBuilder bdr = new StringBuilder();

            bdr.Append(inc.ReadBoolean());
            bdr.Append(inc.ReadInt32(6));
            bdr.Append(inc.ReadInt32());
            bdr.Append(inc.ReadString());
            bdr.Append(inc.ReadByte());

            if (inc.PeekUInt16() != (ushort)44)
            {
                throw new NetException("Read/write failure");
            }

            bdr.Append(inc.ReadUInt16());
            bdr.Append(inc.ReadBoolean());

            inc.SkipPadBits();

            bdr.Append(inc.ReadSingle());
            bdr.Append(inc.ReadDouble());
            bdr.Append(inc.ReadVariableInt32());
            bdr.Append(inc.ReadVariableInt32());
            bdr.Append(inc.ReadVariableUInt32());
            bdr.Append(inc.ReadVariableInt64());

            if (bdr.ToString().Equals("False-342duke of earl4344True4546-4747000048-49"))
            {
                Console.WriteLine("Read/write tests OK");
            }
            else
            {
                throw new NetException("Read/write tests FAILED!");
            }

            msg = peer.CreateMessage();

            NetOutgoingMessage tmp = peer.CreateMessage();

            tmp.Write((int)42, 14);

            msg.Write(tmp);
            msg.Write(tmp);

            if (msg.LengthBits != tmp.LengthBits * 2)
            {
                throw new NetException("NetOutgoingMessage.Write(NetOutgoingMessage) failed!");
            }

            tmp = peer.CreateMessage();

            Test test = new Test();

            test.Number = 42;
            test.Name   = "Hallon";
            test.Age    = 8.2f;

            tmp.WriteAllFields(test, BindingFlags.Public | BindingFlags.Instance);

            data = tmp.PeekDataBuffer();

            inc = Program.CreateIncomingMessage(data, tmp.LengthBits);

            Test readTest = new Test();

            inc.ReadAllFields(readTest, BindingFlags.Public | BindingFlags.Instance);

            NetException.Assert(readTest.Number == 42);
            NetException.Assert(readTest.Name == "Hallon");
            NetException.Assert(readTest.Age == 8.2f);

            // test aligned WriteBytes/ReadBytes
            msg = peer.CreateMessage();
            byte[] tmparr = new byte[] { 5, 6, 7, 8, 9 };
            msg.Write(tmparr);

            inc = Program.CreateIncomingMessage(msg.PeekDataBuffer(), msg.LengthBits);
            byte[] result = inc.ReadBytes(tmparr.Length);

            for (int i = 0; i < tmparr.Length; i++)
            {
                if (tmparr[i] != result[i])
                {
                    throw new Exception("readbytes fail");
                }
            }
        }