/// <summary>
 /// This sends a network message with a message ID on the connection. This message is sent on channel zero, which by default is the reliable channel.
 /// </summary>
 /// <typeparam name="T">The message type to unregister.</typeparam>
 /// <param name="msg">The message to send.</param>
 /// <param name="channelId">The transport layer channel to send on.</param>
 /// <returns></returns>
 public virtual bool Send <T>(T msg, int channelId = Channels.DefaultReliable) where T : IMessageBase
 {
     // pack message and send
     byte[] message = MessagePacker.Pack(msg);
     NetworkDiagnostics.OnSend(msg, channelId, message.Length, 1);
     return(SendBytes(message, channelId));
 }
示例#2
0
        private static NetworkMessageDelegate MessageHandler <T>(Action <INetworkConnection, T> handler)
            where T : IMessageBase, new()
        {
            void AdapterFunction(INetworkConnection conn, NetworkReader reader, int channelId)
            {
                // protect against DOS attacks if attackers try to send invalid
                // data packets to crash the server/client. there are a thousand
                // ways to cause an exception in data handling:
                // - invalid headers
                // - invalid message ids
                // - invalid data causing exceptions
                // - negative ReadBytesAndSize prefixes
                // - invalid utf8 strings
                // - etc.
                //
                // let's catch them all and then disconnect that connection to avoid
                // further attacks.
                T message = default(T) != null ? default : new T();

                            try
                            {
                                message.Deserialize(reader);
                            }
                            finally
                            {
                                NetworkDiagnostics.OnReceive(message, channelId, reader.Length);
                            }

                            handler(conn, message);
            }

            return(AdapterFunction);
        }
示例#3
0
        public static void Send <T>(IEnumerable <INetworkConnection> connections, T msg, int channelId = Channels.DefaultReliable) where T : IMessageBase
        {
            using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
            {
                // pack message into byte[] once
                MessagePacker.Pack(msg, writer);
                var segment = writer.ToArraySegment();
                int count   = 0;

                foreach (INetworkConnection conn in connections)
                {
                    if (conn is NetworkConnection networkConnection)
                    {
                        // send to all connections, but don't wait for them
                        _ = networkConnection.SendAsync(segment, channelId);
                    }
                    else
                    {
                        _ = conn.SendAsync(msg, channelId);
                    }
                    count++;
                }

                NetworkDiagnostics.OnSend(msg, channelId, segment.Count, count);
            }
        }
        /// <summary>
        /// Sends a message, but notify when it is delivered or lost
        /// </summary>
        /// <typeparam name="T">type of message to send</typeparam>
        /// <param name="msg">message to send</param>
        /// <param name="token">a arbitrary object that the sender will receive with their notification</param>
        public void SendNotify <T>(T msg, object token, byte channelId = (byte)Channels.Unreliable)
        {
            if (sendWindow.Count == WINDOW_SIZE)
            {
                NotifyLost?.Invoke(this, token);
                return;
            }

            using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
            {
                var notifyPacket = new NotifyPacket
                {
                    Sequence        = (ushort)sequencer.Next(),
                    ReceiveSequence = receiveSequence,
                    AckMask         = receiveMask
                };

                sendWindow.Enqueue(new PacketEnvelope
                {
                    Sequence = notifyPacket.Sequence,
                    Token    = token
                });

                MessagePacker.Pack(notifyPacket, writer);
                MessagePacker.Pack(msg, writer);
                NetworkDiagnostics.OnSend(msg, channelId, writer.Length, 1);
                SendAsync(writer.ToArraySegment(), channelId).Forget();
            }
        }
示例#5
0
        internal static NetworkMessageDelegate MessageHandler <T>(Action <NetworkConnection, T> handler) where T : IMessageBase, new() => networkMessage =>
        {
            // protect against DOS attacks if attackers try to send invalid
            // data packets to crash the server/client. there are a thousand
            // ways to cause an exception in data handling:
            // - invalid headers
            // - invalid message ids
            // - invalid data causing exceptions
            // - negative ReadBytesAndSize prefixes
            // - invalid utf8 strings
            // - etc.
            //
            // let's catch them all and then disconnect that connection to avoid
            // further attacks.
            T message = default;
            try
            {
                message = networkMessage.ReadMessage <T>();
            }
            catch (Exception exception)
            {
                Debug.LogError("Closed connection: " + networkMessage.conn.connectionId + ". This can happen if the other side accidentally (or an attacker intentionally) sent invalid data. Reason: " + exception);
                networkMessage.conn.Disconnect();
                return;
            }
            finally
            {
                // TODO: Figure out the correct channel
                NetworkDiagnostics.OnReceive(message, -1, networkMessage.reader.Length);
            }

            handler(networkMessage.conn, message);
        };
示例#6
0
        internal static NetworkMessageDelegate WrapHandler <T, C>(Action <C, T> handler, bool requireAuthentication)
            where T : struct, NetworkMessage
            where C : NetworkConnection
        => (conn, reader, channelId) =>
        {
            // protect against DOS attacks if attackers try to send invalid
            // data packets to crash the server/client. there are a thousand
            // ways to cause an exception in data handling:
            // - invalid headers
            // - invalid message ids
            // - invalid data causing exceptions
            // - negative ReadBytesAndSize prefixes
            // - invalid utf8 strings
            // - etc.
            //
            // let's catch them all and then disconnect that connection to avoid
            // further attacks.
            T message = default;
            try
            {
                if (requireAuthentication && !conn.isAuthenticated)
                {
                    // message requires authentication, but the connection was not authenticated
                    Debug.LogWarning($"Closing connection: {conn}. Received message {typeof(T)} that required authentication, but the user has not authenticated yet");
                    conn.Disconnect();
                    return;
                }

                //Debug.Log($"ConnectionRecv {conn} msgType:{typeof(T)} content:{BitConverter.ToString(reader.buffer.Array, reader.buffer.Offset, reader.buffer.Count)}");

                // if it is a value type, just use default(T)
                // otherwise allocate a new instance
                message = reader.Read <T>();
            }
            catch (Exception exception)
            {
                Debug.LogError($"Closed connection: {conn}. This can happen if the other side accidentally (or an attacker intentionally) sent invalid data. Reason: {exception}");
                conn.Disconnect();
                return;
            }
            finally
            {
                // TODO: Figure out the correct channel
                NetworkDiagnostics.OnReceive(message, channelId, reader.Length);
            }

            // user handler exception should not stop the whole server
            try
            {
                // user implemented handler
                handler((C)conn, message);
            }
            catch (Exception e)
            {
                Debug.LogError($"Exception in MessageHandler: {e.GetType().Name} {e.Message}\n{e.StackTrace}");
                conn.Disconnect();
            }
        };
示例#7
0
 /// <summary>
 /// This sends a network message with a message ID on the connection. This message is sent on channel zero, which by default is the reliable channel.
 /// </summary>
 /// <typeparam name="T">The message type to unregister.</typeparam>
 /// <param name="msg">The message to send.</param>
 /// <param name="channelId">The transport layer channel to send on.</param>
 /// <returns></returns>
 public bool Send <T>(T msg, int channelId = Channels.DefaultReliable) where T : IMessageBase
 {
     using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
     {
         // pack message and send allocation free
         MessagePacker.Pack(msg, writer);
         NetworkDiagnostics.OnSend(msg, channelId, writer.Position, 1);
         return(Send(writer.ToArraySegment(), channelId));
     }
 }
 /// <summary>
 /// This sends a network message to the connection. You can await it to check for errors
 /// </summary>
 /// <typeparam name="T">The message type</typeparam>
 /// <param name="msg">The message to send.</param>
 /// <param name="channelId">The transport layer channel to send on.</param>
 /// <returns></returns>
 public virtual UniTask SendAsync <T>(T msg, byte channelId = (byte)Channels.Reliable)
 {
     using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
     {
         // pack message and send allocation free
         MessagePacker.Pack(msg, writer);
         NetworkDiagnostics.OnSend(msg, channelId, writer.Length, 1);
         return(SendAsync(writer.ToArraySegment(), channelId));
     }
 }
示例#9
0
 /// <summary>Send a NetworkMessage to this connection over the given channel.</summary>
 public void Send <T>(T msg, int channelId = Channels.Reliable)
     where T : struct, NetworkMessage
 {
     using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
     {
         // pack message and send allocation free
         MessagePacking.Pack(msg, writer);
         NetworkDiagnostics.OnSend(msg, channelId, writer.Position, 1);
         Send(writer.ToArraySegment(), channelId);
     }
 }
示例#10
0
        /// <summary>
        /// This sends a network message with a message ID on the connection. This message is sent on channel zero, which by default is the reliable channel.
        /// </summary>
        /// <typeparam name="T">The message type to unregister.</typeparam>
        /// <param name="msg">The message to send.</param>
        /// <param name="channelId">The transport layer channel to send on.</param>
        /// <returns></returns>
        public virtual bool Send <T>(T msg, int channelId = Channels.DefaultReliable) where T : IMessageBase
        {
            NetworkWriter writer = NetworkWriterPool.GetWriter();

            // pack message and send allocation free
            MessagePacker.Pack(msg, writer);
            NetworkDiagnostics.OnSend(msg, channelId, writer.Position, 1);
            bool result = Send(writer.ToArraySegment(), channelId);

            NetworkWriterPool.Recycle(writer);
            return(result);
        }
        internal static NetworkMessageDelegate MessageHandler <T, C>(Action <C, T> handler, bool requireAuthenication)
            where T : IMessageBase, new()
            where C : NetworkConnection
        => (conn, reader, channelId) =>
        {
            // protect against DOS attacks if attackers try to send invalid
            // data packets to crash the server/client. there are a thousand
            // ways to cause an exception in data handling:
            // - invalid headers
            // - invalid message ids
            // - invalid data causing exceptions
            // - negative ReadBytesAndSize prefixes
            // - invalid utf8 strings
            // - etc.
            //
            // let's catch them all and then disconnect that connection to avoid
            // further attacks.
            T message = default;
            try
            {
                if (requireAuthenication && !conn.isAuthenticated)
                {
                    // message requires authentication, but the connection was not authenticated
                    Debug.LogWarning($"Closing connection: {conn}. Received message {typeof(T)} that required authentication, but the user has not authenticated yet");
                    conn.Disconnect();
                    return;
                }

                // if it is a value type, just use defult(T)
                // otherwise allocate a new instance
                message = default(T) != null ? default(T) : new T();
                message.Deserialize(reader);
            }
            catch (Exception exception)
            {
                Debug.LogError("Closed connection: " + conn + ". This can happen if the other side accidentally (or an attacker intentionally) sent invalid data. Reason: " + exception);
                conn.Disconnect();
                return;
            }
            finally
            {
                // TODO: Figure out the correct channel
                NetworkDiagnostics.OnReceive(message, channelId, reader.Length);
            }

            handler((C)conn, message);
        };
示例#12
0
        private static NetworkMessageDelegate MessageHandler <T, C>(Action <C, T> handler, bool requireAuthenication)
            where T : IMessageBase, new()
            where C : NetworkConnection
        {
            void AdapterFunction(NetworkConnection conn, NetworkReader reader, int channelId)
            {
                // protect against DOS attacks if attackers try to send invalid
                // data packets to crash the server/client. there are a thousand
                // ways to cause an exception in data handling:
                // - invalid headers
                // - invalid message ids
                // - invalid data causing exceptions
                // - negative ReadBytesAndSize prefixes
                // - invalid utf8 strings
                // - etc.
                //
                // let's catch them all and then disconnect that connection to avoid
                // further attacks.
                T message = default;

                try
                {
                    if (requireAuthenication && !conn.isAuthenticated)
                    {
                        // message requires authentication, but the connection was not authenticated
                        Debug.LogWarning($"Closing connection: {conn}. Received message {typeof(T)} that required authentication, but the user has not authenticated yet");
                        conn.Disconnect();
                        return;
                    }

                    message = default(T) != null ? default(T) : new T();
                    message.Deserialize(reader);
                }
                finally
                {
                    NetworkDiagnostics.OnReceive(message, channelId, reader.Length);
                }

                handler((C)conn, message);
            }

            return(AdapterFunction);
        }
        public static void Send <T>(IEnumerable <INetworkConnection> connections, T msg, byte channelId = (byte)Channels.Reliable)
        {
            using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
            {
                // pack message into byte[] once
                MessagePacker.Pack(msg, writer);
                var segment = writer.ToArraySegment();
                int count   = 0;

                foreach (INetworkConnection conn in connections)
                {
                    // send to all connections, but don't wait for them
                    conn.SendAsync(segment, channelId).Forget();
                    count++;
                }

                NetworkDiagnostics.OnSend(msg, channelId, segment.Count, count);
            }
        }