EnqueueMessage() private méthode

private EnqueueMessage ( NetOutgoingMessage msg, NetDeliveryMethod method, int sequenceChannel ) : NetSendResult
msg NetOutgoingMessage
method NetDeliveryMethod
sequenceChannel int
Résultat NetSendResult
        /// <summary>
        /// Send a message to a specific connection
        /// </summary>
        /// <param name="msg">The message to send</param>
        /// <param name="recipient">The recipient connection</param>
        /// <param name="method">How to deliver the message</param>
        /// <param name="sequenceChannel">Sequence channel within the delivery method</param>
        public NetSendResult SendMessage(NetOutgoingMessage msg, NetConnection recipient, NetDeliveryMethod method, int sequenceChannel)
        {
            if (msg == null)
                throw new ArgumentNullException("msg");
            if (recipient == null)
                throw new ArgumentNullException("recipient");

            NetException.Assert(
                ((method != NetDeliveryMethod.Unreliable && method != NetDeliveryMethod.ReliableUnordered) ||
                ((method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered) && sequenceChannel == 0)),
                "Delivery method " + method + " cannot use sequence channels other than 0!"
            );

            NetException.Assert(method != NetDeliveryMethod.Unknown, "Bad delivery method!");

            if (msg.m_isSent)
                throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");

            int len = msg.LengthBytes;
            if (len <= m_configuration.MaximumTransmissionUnit)
            {
                Interlocked.Increment(ref msg.m_recyclingCount);
                return recipient.EnqueueMessage(msg, method, sequenceChannel);
            }
            else
            {
                // message must be fragmented!
                SendFragmentedMessage(msg, new NetConnection[] { recipient }, method, sequenceChannel);
                return NetSendResult.Queued; // could be different for each connection; Queued is "most true"
            }
        }
Exemple #2
0
        /// <summary>
        /// Send a message to a specific connection
        /// </summary>
        /// <param name="msg">The message to send</param>
        /// <param name="recipient">The recipient connection</param>
        /// <param name="method">How to deliver the message</param>
        /// <param name="sequenceChannel">Sequence channel within the delivery method</param>
        public NetSendResult SendMessage(NetOutgoingMessage msg, NetConnection recipient, NetDeliveryMethod method, int sequenceChannel)
        {
            if (msg == null)
                throw new ArgumentNullException("msg");
            if (recipient == null)
                throw new ArgumentNullException("recipient");
            if (sequenceChannel >= NetConstants.NetChannelsPerDeliveryMethod)
                throw new ArgumentOutOfRangeException("sequenceChannel");

            NetException.Assert(
                ((method != NetDeliveryMethod.Unreliable && method != NetDeliveryMethod.ReliableUnordered) ||
                ((method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered) && sequenceChannel == 0)),
                "Delivery method " + method + " cannot use sequence channels other than 0!"
            );

            NetException.Assert(method != NetDeliveryMethod.Unknown, "Bad delivery method!");

            if (msg.m_isSent)
                throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
            msg.m_isSent = true;

            int len = NetConstants.UnfragmentedMessageHeaderSize + msg.LengthBytes; // headers + length, faster than calling msg.GetEncodedSize
            if (len <= recipient.m_currentMTU)
            {
                Interlocked.Increment(ref msg.m_recyclingCount);
                return recipient.EnqueueMessage(msg, method, sequenceChannel);
            }
            else
            {
                // message must be fragmented!
                SendFragmentedMessage(msg, new NetConnection[] { recipient }, method, sequenceChannel);
                return NetSendResult.Queued; // could be different for each connection; Queued is "most true"
            }
        }
Exemple #3
0
        /// <summary>
        /// Send a message to a list of connections
        /// </summary>
        /// <param name="msg">The message to send</param>
        /// <param name="recipients">The list of recipients to send to</param>
        /// <param name="method">How to deliver the message</param>
        /// <param name="sequenceChannel">Sequence channel within the delivery method</param>
        public void SendMessage(NetOutgoingMessage msg, List <NetConnection> recipients, NetDeliveryMethod method, int sequenceChannel)
        {
            if (msg == null)
            {
                throw new ArgumentNullException("msg");
            }
            if (recipients == null)
            {
                throw new ArgumentNullException("recipients");
            }
            if (recipients.Count < 1)
            {
                throw new NetException("recipients must contain at least one item");
            }
            if (method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered)
            {
                NetException.Assert(sequenceChannel == 0, "Delivery method " + method + " cannot use sequence channels other than 0!");
            }
            if (msg.m_isSent)
            {
                throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
            }

            int mtu = GetMTU(recipients);

            msg.m_isSent = true;

            int len = msg.GetEncodedSize();

            if (len <= mtu)
            {
                Interlocked.Add(ref msg.m_recyclingCount, recipients.Count);
                int ct = recipients.Count;
                for (int i = 0; i < ct; ++i)
                {
                    NetConnection conn = recipients[i];
                    if (conn == null)
                    {
                        Interlocked.Decrement(ref msg.m_recyclingCount);
                        continue;
                    }
                    NetSendResult res = conn.EnqueueMessage(msg, method, sequenceChannel);
                    if (res != NetSendResult.Queued && res != NetSendResult.Sent)
                    {
                        Interlocked.Decrement(ref msg.m_recyclingCount);
                    }
                }
            }
            else
            {
                // message must be fragmented!
                SendFragmentedMessage(msg, recipients, method, sequenceChannel);
            }

            return;
        }
Exemple #4
0
        /// <summary>
        /// Sends message to server
        /// </summary>
        public NetSendResult Send(NetOutgoingMessage msg, NetDeliveryMethod method = NetDeliveryMethod.ReliableOrdered, int sequenceChannel = 0)
        {
            NetConnection serverConnection = ServerConnection;

            if (serverConnection == null)
            {
                LogWarning("Cannot send message, no server connection!");
                Recycle(msg);
                return(NetSendResult.FailedNotConnected);
            }

            if (msg == null)
            {
                throw new ArgumentNullException("msg");
            }
            if (sequenceChannel >= NetConstants.NetChannelsPerDeliveryMethod)
            {
                throw new ArgumentOutOfRangeException("sequenceChannel");
            }

            NetException.Assert(
                ((method != NetDeliveryMethod.Unreliable && method != NetDeliveryMethod.ReliableUnordered) ||
                 ((method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered) && sequenceChannel == 0)),
                "Delivery method " + method + " cannot use sequence channels other than 0!"
                );

            NetException.Assert(method != NetDeliveryMethod.Unknown, "Bad delivery method!");

            if (msg.m_isSent)
            {
                throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
            }
            msg.m_isSent = true;

            Network.Statistics.UploadedBytes         += (uint)msg.LengthBytes;
            Network.Statistics.uploadBytesPerSecLast += (uint)msg.LengthBytes;

            bool suppressFragmentation = (method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.UnreliableSequenced) && m_configuration.UnreliableSizeBehaviour != NetUnreliableSizeBehaviour.NormalFragmentation;

            int len = NetConstants.UnfragmentedMessageHeaderSize + msg.LengthBytes; // headers + length, faster than calling msg.GetEncodedSize

            if (len <= serverConnection.m_currentMTU || suppressFragmentation)
            {
                Interlocked.Increment(ref msg.m_recyclingCount);
                return(serverConnection.EnqueueMessage(msg, method, sequenceChannel));
            }
            else
            {
                // message must be fragmented!
                if (serverConnection.m_status != NetConnectionStatus.Connected)
                {
                    return(NetSendResult.FailedNotConnected);
                }
                return(SendFragmentedMessage(msg, new NetConnection[] { serverConnection }, method, sequenceChannel));
            }
        }
Exemple #5
0
        /// <summary>
        /// Send a message to a specific connection
        /// </summary>
        /// <param name="msg">The message to send</param>
        /// <param name="recipient">The recipient connection</param>
        /// <param name="method">How to deliver the message</param>
        /// <param name="sequenceChannel">Sequence channel within the delivery method</param>
        public NetSendResult SendMessage(NetOutgoingMessage msg, NetConnection recipient, NetDeliveryMethod method, int sequenceChannel)
        {
            if (msg == null)
            {
                throw new ArgumentNullException("msg");
            }
            if (recipient == null)
            {
                throw new ArgumentNullException("recipient");
            }
            if (sequenceChannel >= NetConstants.NetChannelsPerDeliveryMethod)
            {
                throw new ArgumentOutOfRangeException("sequenceChannel");
            }

            NetException.Assert(
                ((method != NetDeliveryMethod.Unreliable && method != NetDeliveryMethod.ReliableUnordered) ||
                 ((method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered) && sequenceChannel == 0)),
                "Delivery method " + method + " cannot use sequence channels other than 0!"
                );

            NetException.Assert(method != NetDeliveryMethod.Unknown, "Bad delivery method!");

            if (msg.m_isSent)
            {
                throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
            }
            msg.m_isSent = true;

            bool suppressFragmentation = (method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.UnreliableSequenced) && m_configuration.UnreliableSizeBehaviour != NetUnreliableSizeBehaviour.NormalFragmentation;

            int len = NetConstants.UnfragmentedMessageHeaderSize + msg.LengthBytes;             // headers + length, faster than calling msg.GetEncodedSize

            if (len <= recipient.m_currentMTU || suppressFragmentation)
            {
                Interlocked.Increment(ref msg.m_recyclingCount);
                return(recipient.EnqueueMessage(msg, method, sequenceChannel));
            }
            else
            {
                // message must be fragmented!
                if (recipient.m_status != NetConnectionStatus.Connected)
                {
                    return(NetSendResult.FailedNotConnected);
                }
                // return SendFragmentedMessage(msg, new NetConnection[] { recipient }, method, sequenceChannel);
                var tmp = ConnectionListPool.Rent();
                tmp.Add(recipient);
                var result = SendFragmentedMessage(msg, tmp, method, sequenceChannel);
                ConnectionListPool.Return(tmp);
                return(result);
            }
        }
Exemple #6
0
        /// <summary>
        /// Send a message to a specific connection
        /// </summary>
        /// <param name="msg">The message to send</param>
        /// <param name="recipient">The recipient connection</param>
        /// <param name="method">How to deliver the message</param>
        /// <param name="sequenceChannel">Sequence channel within the delivery method</param>
        public NetSendResult SendMessage(NetOutgoingMessage msg, NetConnection recipient, NetDeliveryMethod method, int sequenceChannel)
        {
            if (msg == null)
            {
                throw new ArgumentNullException("msg");
            }
            if (recipient == null)
            {
                throw new ArgumentNullException("recipient");
            }
            if (sequenceChannel >= NetConstants.NetChannelsPerDeliveryMethod)
            {
                throw new ArgumentOutOfRangeException("sequenceChannel");
            }

            NetException.Assert(
                ((method != NetDeliveryMethod.Unreliable && method != NetDeliveryMethod.ReliableUnordered) ||
                 ((method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered) && sequenceChannel == 0)),
                "Delivery method " + method + " cannot use sequence channels other than 0!"
                );

            NetException.Assert(method != NetDeliveryMethod.Unknown, "Bad delivery method!");

            if (msg.m_isSent)
            {
                throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
            }
            msg.m_isSent = true;

            int len = NetConstants.UnfragmentedMessageHeaderSize + msg.LengthBytes;             // headers + length, faster than calling msg.GetEncodedSize

            if (len <= recipient.m_currentMTU)
            {
                Interlocked.Increment(ref msg.m_recyclingCount);
                return(recipient.EnqueueMessage(msg, method, sequenceChannel));
            }
            else
            {
                // message must be fragmented!
                if (recipient.m_status != NetConnectionStatus.Connected)
                {
                    return(NetSendResult.FailedNotConnected);
                }
                SendFragmentedMessage(msg, new NetConnection[] { recipient }, method, sequenceChannel);
                return(NetSendResult.Queued);                // could be different for each connection; Queued is "most true"
            }
        }
        /// <summary>
        /// Send a message to a specific connection.
        /// </summary>
        /// <param name="message">The message to send</param>
        /// <param name="recipient">The recipient connection</param>
        /// <param name="method">How to deliver the message</param>
        /// <param name="sequenceChannel">Sequence channel within the delivery method</param>
        public NetSendResult SendMessage(
            NetOutgoingMessage message, NetConnection recipient, NetDeliveryMethod method, int sequenceChannel)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }
            if (recipient == null)
            {
                throw new ArgumentNullException(nameof(recipient));
            }

            NetConstants.AssertValidDeliveryChannel(
                method, sequenceChannel, nameof(method), nameof(sequenceChannel));

            message.AssertNotSent(nameof(message));
            message._isSent = true;

            bool suppressFragmentation =
                (method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.UnreliableSequenced) &&
                Configuration.UnreliableSizeBehaviour != NetUnreliableSizeBehaviour.NormalFragmentation;

            if (suppressFragmentation || message.GetEncodedSize() <= recipient.CurrentMTU)
            {
                Interlocked.Increment(ref message._recyclingCount);
                return(recipient.EnqueueMessage(message, method, sequenceChannel).Result);
            }
            else
            {
                // message must be fragmented!
                if (recipient.Status != NetConnectionStatus.Connected)
                {
                    return(NetSendResult.FailedNotConnected);
                }

                List <NetConnection> recipients = NetConnectionListPool.Rent(1);
                try
                {
                    recipients.Add(recipient);
                    return(SendFragmentedMessage(message, recipients, method, sequenceChannel));
                }
                finally
                {
                    NetConnectionListPool.Return(recipients);
                }
            }
        }
        /// <summary>
        /// Send a message to a specific connection
        /// </summary>
        /// <param name="msg">The message to send</param>
        /// <param name="recipient">The recipient connection</param>
        /// <param name="method">How to deliver the message</param>
        /// <param name="sequenceChannel">Sequence channel within the delivery method</param>
        public NetSendResult SendMessage(NetOutgoingMessage msg, NetConnection recipient, NetDeliveryMethod method, int sequenceChannel)
        {
            if (msg == null)
            {
                throw new ArgumentNullException("msg");
            }
            if (recipient == null)
            {
                throw new ArgumentNullException("recipient");
            }

            NetException.Assert(
                ((method != NetDeliveryMethod.Unreliable && method != NetDeliveryMethod.ReliableUnordered) ||
                 ((method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered) && sequenceChannel == 0)),
                "Delivery method " + method + " cannot use sequence channels other than 0!"
                );

            NetException.Assert(method != NetDeliveryMethod.Unknown, "Bad delivery method!");

            if (msg.m_isSent)
            {
                throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
            }

            int len = msg.LengthBytes;

            if (len <= m_configuration.MaximumTransmissionUnit)
            {
                Interlocked.Increment(ref msg.m_recyclingCount);
                return(recipient.EnqueueMessage(msg, method, sequenceChannel));
            }
            else
            {
                // message must be fragmented!
                SendFragmentedMessage(msg, new NetConnection[] { recipient }, method, sequenceChannel);
                return(NetSendResult.Queued);                // could be different for each connection; Queued is "most true"
            }
        }
        // on user thread
        private async ValueTask <NetSendResult> SendFragmentedMessageAsync(
            PipeReader reader,
            NetConnection recipient,
            int sequenceChannel,
            CancellationToken cancellationToken)
        {
            int group = GetNextFragmentGroup();

            (NetSendResult Result, NetSenderChannel?) SendChunk(NetOutgoingMessage chunk)
            {
                return(recipient.EnqueueMessage(chunk, NetDeliveryMethod.ReliableOrdered, sequenceChannel));
            }

            NetSendResult finalResult;
            Exception?    exception = null;

            try
            {
                ReadResult readResult;
                do
                {
                    readResult = await reader.ReadAsync(cancellationToken).ConfigureAwait(false);

                    if (readResult.IsCanceled)
                    {
                        NetOutgoingMessage cancelChunk = CreateStreamChunk(0, group, NetStreamFragmentType.Cancelled);
                        finalResult = SendChunk(cancelChunk).Result;
                        break;
                    }

                    ReadOnlySequence <byte> buffer = readResult.Buffer;

                    int mtu           = recipient.CurrentMTU;
                    int bytesPerChunk = NetFragmentationHelper.GetBestChunkSize(group, (int)buffer.Length, mtu);

                    while (buffer.Length > 0)
                    {
                        long chunkLength         = Math.Min(buffer.Length, bytesPerChunk);
                        NetOutgoingMessage chunk = CreateStreamChunk((int)chunkLength, group, NetStreamFragmentType.Data);
                        foreach (ReadOnlyMemory <byte> memory in buffer.Slice(0, chunkLength))
                        {
                            chunk.Write(memory.Span);
                        }
                        buffer = buffer.Slice(chunkLength);

                        LidgrenException.Assert(chunk.GetEncodedSize() <= mtu);
                        Interlocked.Add(ref chunk._recyclingCount, 1);

                        var(result, channel) = SendChunk(chunk);
                        if (result == NetSendResult.Queued)
                        {
                            await channel !.WaitForIdleAsync(millisecondsTimeout: 10000, cancellationToken);
                        }
                        else if (result != NetSendResult.Sent)
                        {
                            NetOutgoingMessage cancelChunk = CreateStreamChunk(0, group, NetStreamFragmentType.Cancelled);
                            finalResult = SendChunk(cancelChunk).Result;
                            reader.CancelPendingRead();
                            break;
                        }
                    }

                    reader.AdvanceTo(readResult.Buffer.End);
                }while (!readResult.IsCompleted);

                NetOutgoingMessage endChunk = CreateStreamChunk(0, group, NetStreamFragmentType.EndOfStream);
                finalResult = SendChunk(endChunk).Result;
            }
            catch (Exception ex)
            {
                exception = ex;

                NetOutgoingMessage errorChunk = CreateStreamChunk(0, group, NetStreamFragmentType.ServerError);
                finalResult = SendChunk(errorChunk).Result;
            }

            await reader.CompleteAsync(exception).ConfigureAwait(false);

            return(finalResult);
        }
Exemple #10
0
        // on user thread
        private void SendFragmentedMessage(NetOutgoingMessage msg, IList <NetConnection> recipients, NetDeliveryMethod method, int sequenceChannel)
        {
            // Note: this group id is PER SENDING/NetPeer; ie. same id is sent to all recipients;
            // this should be ok however; as long as recipients differentiate between same id but different sender
            int group = Interlocked.Increment(ref m_lastUsedFragmentGroup);

            if (group >= NetConstants.MaxFragmentationGroups)
            {
                // @TODO: not thread safe; but in practice probably not an issue
                m_lastUsedFragmentGroup = 1;
                group = 1;
            }
            msg.m_fragmentGroup = group;

            // do not send msg; but set fragmentgroup in case user tries to recycle it immediately

            // create fragmentation specifics
            int totalBytes = msg.LengthBytes;

            // determine minimum mtu for all recipients
            int mtu           = GetMTU(recipients);
            int bytesPerChunk = NetFragmentationHelper.GetBestChunkSize(group, totalBytes, mtu);

            int numChunks = totalBytes / bytesPerChunk;

            if (numChunks * bytesPerChunk < totalBytes)
            {
                numChunks++;
            }

            int bitsPerChunk = bytesPerChunk * 8;
            int bitsLeft     = msg.LengthBits;

            for (int i = 0; i < numChunks; i++)
            {
                NetOutgoingMessage chunk = CreateMessage(mtu);

                chunk.m_bitLength              = (bitsLeft > bitsPerChunk ? bitsPerChunk : bitsLeft);
                chunk.m_data                   = msg.m_data;
                chunk.m_fragmentGroup          = group;
                chunk.m_fragmentGroupTotalBits = totalBytes * 8;
                chunk.m_fragmentChunkByteSize  = bytesPerChunk;
                chunk.m_fragmentChunkNumber    = i;

                NetException.Assert(chunk.m_bitLength != 0);
                NetException.Assert(chunk.GetEncodedSize() < mtu);

                Interlocked.Add(ref chunk.m_recyclingCount, recipients.Count);

                int ct = recipients.Count;
                for (int ix = 0; ix < ct; ++ix)
                {
                    NetConnection recipient = recipients[ix];
                    recipient.EnqueueMessage(chunk, method, sequenceChannel);
                }

                bitsLeft -= bitsPerChunk;
            }

            return;
        }