Exemple #1
0
        private void HandlePayload(
            NetPeer peer,
            byte[] buffer,
            int length)
        {
            if (peer.IsConnected == false)
            {
                return;
            }

            // Read the payload
            bool success =
                NetEncoding.ReadPayload(
                    CreateEvent,
                    peer,
                    buffer,
                    length,
                    out ushort payloadSeq,
                    out NetEvent evnt);

            // Validate
            if (success == false)
            {
                NetDebug.LogError("Error reading payload");
                return;
            }

            // Enqueue the event for processing if the peer can receive it
            if (peer.OnReceivePayload(Time, payloadSeq))
            {
                eventOut.Enqueue(evnt);
            }
        }
Exemple #2
0
        private void HandlePing(
            NetPeer peer,
            byte[] buffer,
            int length)
        {
            if (peer.IsConnected == false)
            {
                return;
            }

            bool success =
                NetEncoding.ReadProtocol(
                    buffer,
                    length,
                    out byte pingSeq,
                    out byte loss);

            // Validate
            if (success == false)
            {
                NetDebug.LogError("Error reading ping");
                return;
            }

            peer.OnReceivePing(Time, loss);
            sender.SendPong(peer, pingSeq, peer.GenerateDrop());
        }
Exemple #3
0
        private void HandlePong(
            NetPeer peer,
            byte[] buffer,
            int length)
        {
            if (peer.IsConnected == false)
            {
                return;
            }

            bool success =
                NetEncoding.ReadProtocol(
                    buffer,
                    length,
                    out byte pongSeq,
                    out byte drop);

            // Validate
            if (success == false)
            {
                NetDebug.LogError("Error reading pong");
                return;
            }

            peer.OnReceivePong(Time, pongSeq, drop);
        }
Exemple #4
0
        /// <summary>
        /// Handles an incoming connection request from a remote peer.
        /// </summary>
        private void HandleConnectRequest(
            IPEndPoint source,
            byte[] buffer,
            int length)
        {
            bool success =
                NetEncoding.ReadConnectRequest(
                    buffer,
                    out string version,
                    out string token);

            // Validate
            if (success == false)
            {
                NetDebug.LogError("Error reading connect request");
                return;
            }

            if (ShouldCreatePeer(source, version))
            {
                long curTime = Time;
                // Create and add the new peer as a client
                NetPeer peer = new NetPeer(source, token, true, curTime);
                peers.Add(source, peer);
                peer.OnReceiveOther(curTime);

                // Accept the connection over the network
                sender.SendAccept(peer);

                // Queue the event out to the main thread to receive the connection
                eventOut.Enqueue(
                    CreateEvent(NetEventType.PeerConnected, peer));
            }
        }
Exemple #5
0
 /// <summary>
 /// Immediately sends out a payload to a peer.
 /// </summary>
 internal SocketError SendPayload(NetPeer peer, ushort sequence, byte[] data, ushort dataLength)
 {
     lock (sendLock)
     {
         var size = NetEncoding.PackPayload(sendBuffer, sequence, data, dataLength);
         return(TrySend(peer.EndPoint, sendBuffer, size));
     }
 }
Exemple #6
0
 /// <summary>
 /// Accepts a remote request and sends an affirmative reply.
 /// </summary>
 internal SocketError SendAccept(NetPeer peer)
 {
     lock (sendLock)
     {
         var length = NetEncoding.PackProtocol(sendBuffer, NetPacketType.Accept, 0, 0);
         return(TrySend(peer.EndPoint, sendBuffer, length));
     }
 }
Exemple #7
0
 /// <summary>
 /// Sends a generic ping packet.
 /// </summary>
 internal SocketError SendPing(NetPeer peer, long curTime)
 {
     lock (sendLock)
     {
         var length = NetEncoding.PackProtocol(sendBuffer, NetPacketType.Ping, peer.GeneratePing(curTime), peer.GenerateLoss());
         return(TrySend(peer.EndPoint, sendBuffer, length));
     }
 }
Exemple #8
0
 /// <summary>
 /// Sends a request to connect to a remote peer.
 /// </summary>
 internal SocketError SendConnect(NetPeer peer, string version)
 {
     lock (sendLock)
     {
         var length = NetEncoding.PackConnectRequest(sendBuffer, version, peer.Token);
         return(TrySend(peer.EndPoint, sendBuffer, length));
     }
 }
Exemple #9
0
 /// <summary>
 /// Sends a generic pong packet.
 /// </summary>
 internal SocketError SendPong(NetPeer peer, byte pingSeq, byte drop)
 {
     lock (sendLock)
     {
         var length = NetEncoding.PackProtocol(sendBuffer, NetPacketType.Pong, pingSeq, drop);
         return(TrySend(peer.EndPoint, sendBuffer, length));
     }
 }
Exemple #10
0
 /// <summary>
 /// Sends a scheduled notification message.
 /// </summary>
 internal SocketError SendNotifications(NetPeer peer)
 {
     lock (sendLock)
     {
         var packedLength = NetEncoding.PackCarrier(sendBuffer, peer.NotificationAck, peer.GetFirstSequence(), peer.Outgoing);
         var length       = packedLength;
         return(TrySend(peer.EndPoint, sendBuffer, length));
     }
 }
Exemple #11
0
        /// <summary>
        /// Polls the socket and receives all pending packet data.
        /// </summary>
        private void ReadPackets()
        {
            for (int i = 0; i < NetConfig.MaxPacketReads; i++)
            {
                IPEndPoint  source;
                byte[]      buffer;
                int         length;
                SocketError result =
                    this.receiver.TryReceive(out source, out buffer, out length);
                if (NetSocket.Succeeded(result) == false)
                {
                    return;
                }

                NetPacketType type = NetEncoding.GetType(buffer);
                if (type == NetPacketType.Connect)
                {
                    // We don't have a peer yet -- special case
                    this.HandleConnectRequest(source, buffer, length);
                }
                else
                {
                    NetPeer peer;
                    if (this.peers.TryGetValue(source, out peer))
                    {
                        switch (type)
                        {
                        case NetPacketType.Accept:
                            this.HandleConnectAccept(peer, buffer, length);
                            break;

                        case NetPacketType.Kick:
                            this.HandleKick(peer, buffer, length);
                            break;

                        case NetPacketType.Ping:
                            this.HandlePing(peer, buffer, length);
                            break;

                        case NetPacketType.Pong:
                            this.HandlePong(peer, buffer, length);
                            break;

                        case NetPacketType.Carrier:
                            this.HandleCarrier(peer, buffer, length);
                            break;

                        case NetPacketType.Payload:
                            this.HandlePayload(peer, buffer, length);
                            break;
                        }
                    }
                }
            }
        }
Exemple #12
0
        /// <summary>
        /// Packs a payload to the given buffer.
        /// </summary>
        internal static int PackPayload(
            byte[] buffer,
            ushort sequence,
            byte[] data,
            ushort dataLength)
        {
            buffer[0] = (byte)NetPacketType.Payload;
            NetEncoding.PackU16(buffer, 1, sequence);
            int position = NetEncoding.PAYLOAD_HEADER_SIZE;

            Array.Copy(data, 0, buffer, position, dataLength);
            return(position + dataLength);
        }
Exemple #13
0
        /// <summary>
        /// Packs a notification prepended with that notification's length.
        /// </summary>
        private static int PackNotification(
            byte[] buffer,
            int position,
            byte[] data,
            ushort dataLength)
        {
            // For notifications we add the length since there may be multiple
            NetEncoding.PackU16(buffer, position, dataLength);
            position += NetEncoding.NOTIFICATION_HEADER_SIZE;

            Array.Copy(data, 0, buffer, position, dataLength);
            return(NetEncoding.NOTIFICATION_HEADER_SIZE + dataLength);
        }
Exemple #14
0
        /// <summary>
        /// Notifies a peer that we are disconnecting. May not arrive.
        /// </summary>
        internal SocketError SendKick(NetPeer peer, NetCloseReason reason, byte userReason = 0)
        {
            // Skip the packet if it's a bad reason (this will cause error output)
            if (NetUtil.ValidateKickReason(reason) == NetCloseReason.INVALID)
            {
                return(SocketError.Success);
            }

            lock (sendLock)
            {
                var length = NetEncoding.PackProtocol(sendBuffer, NetPacketType.Kick, (byte)reason, userReason);
                return(TrySend(peer.EndPoint, sendBuffer, length));
            }
        }
Exemple #15
0
        private void HandleCarrier(
            NetPeer peer,
            byte[] buffer,
            int length)
        {
            if (peer.IsConnected == false)
            {
                return;
            }

            // Read the carrier and notifications
            ushort notificationAck;
            ushort notificationSeq;

            this.reusableQueue.Clear();
            bool success =
                NetEncoding.ReadCarrier(
                    this.CreateEvent,
                    peer,
                    buffer,
                    length,
                    out notificationAck,
                    out notificationSeq,
                    this.reusableQueue);

            // Validate
            if (success == false)
            {
                NetDebug.LogError("Error reading carrier");
                return;
            }

            long curTime = this.Time;

            peer.OnReceiveCarrier(curTime, notificationAck, this.RecycleEvent);

            // The packet contains the first sequence number. All subsequent
            // notifications have sequence numbers in order, so we just increment.
            foreach (NetEvent notification in this.reusableQueue)
            {
                if (peer.OnReceiveNotification(curTime, notificationSeq++))
                {
                    this.eventOut.Enqueue(notification);
                }
            }
        }
Exemple #16
0
        /// <summary>
        /// Packs a series of notifications into the buffer.
        /// </summary>
        internal static int PackCarrier(
            byte[] buffer,
            ushort notificationAck,
            ushort notificationSeq,
            IEnumerable <NetEvent> notifications)
        {
            int notificationHeaderSize = NetEncoding.NOTIFICATION_HEADER_SIZE;

            // Pack header
            buffer[0] = (byte)NetPacketType.Carrier;
            NetEncoding.PackU16(buffer, 1, notificationAck);
            NetEncoding.PackU16(buffer, 3, notificationSeq);
            int position = NetEncoding.CARRIER_HEADER_SIZE;

            // Pack notifications
            int dataPacked  = 0;
            int maxDataPack = NetEncoding.MAX_NOTIFICATION_PACK;

            foreach (NetEvent notification in notifications)
            {
                // See if we can fit the notification
                int packedSize = notificationHeaderSize + notification.EncodedLength;
                if ((dataPacked + packedSize) > maxDataPack)
                {
                    break;
                }

                // Pack the notification data
                int packSize =
                    NetEncoding.PackNotification(
                        buffer,
                        position,
                        notification.EncodedData,
                        notification.EncodedLength);

                // Increment counters
                dataPacked += packSize;
                position   += packSize;
            }

            return(position);
        }
Exemple #17
0
        /// <summary>
        /// Sends a kick (reject) message to an unconnected peer.
        /// </summary>
        internal SocketError SendReject(
            IPEndPoint destination,
            NetCloseReason reason)
        {
            // Skip the packet if it's a bad reason (this will cause error output)
            if (NetUtil.ValidateKickReason(reason) == NetCloseReason.INVALID)
            {
                return(SocketError.Success);
            }

            lock (this.sendLock)
            {
                int length =
                    NetEncoding.PackProtocol(
                        this.sendBuffer,
                        NetPacketType.Kick,
                        (byte)reason,
                        0);
                return(this.TrySend(destination, this.sendBuffer, length));
            }
        }
Exemple #18
0
        /// <summary>
        /// Reads a collection of notifications packed in the buffer.
        /// </summary>
        internal static bool ReadCarrier(
            Func <NetEventType, NetPeer, NetEvent> eventFactory,
            NetPeer peer,
            byte[] buffer,
            int length,
            out ushort notificationAck,
            out ushort notificationSeq,
            Queue <NetEvent> destinationQueue)
        {
            // Read header (already know the type)
            notificationAck = NetEncoding.ReadU16(buffer, 1);
            notificationSeq = NetEncoding.ReadU16(buffer, 3);
            int position = NetEncoding.CARRIER_HEADER_SIZE;

            // Validate
            int maxDataPack = NetEncoding.MAX_NOTIFICATION_PACK;

            if ((position > length) || ((length - position) > maxDataPack))
            {
                return(false);
            }

            // Read notifications
            while (position < length)
            {
                NetEvent evnt      = eventFactory.Invoke(NetEventType.Notification, peer);
                int      bytesRead =
                    NetEncoding.ReadNotification(buffer, length, position, evnt);
                if (bytesRead < 0)
                {
                    return(false);
                }

                destinationQueue.Enqueue(evnt);
                position += bytesRead;
            }

            return(true);
        }
Exemple #19
0
        private void HandleKick(
            NetPeer peer,
            byte[] buffer,
            int length)
        {
            if (peer.IsClosed)
            {
                return;
            }

            byte rawReason;
            byte userReason;
            bool success =
                NetEncoding.ReadProtocol(
                    buffer,
                    length,
                    out rawReason,
                    out userReason);

            // Validate
            if (success == false)
            {
                NetDebug.LogError("Error reading kick");
                return;
            }

            NetCloseReason closeReason = (NetCloseReason)rawReason;

            // Skip the packet if it's a bad reason (this will cause error output)
            if (NetUtil.ValidateKickReason(closeReason) == NetCloseReason.INVALID)
            {
                return;
            }

            peer.OnReceiveOther(this.Time);
            this.ClosePeerSilent(peer);
            this.eventOut.Enqueue(
                this.CreateClosedEvent(peer, closeReason, userReason));
        }
Exemple #20
0
        /// <summary>
        /// Reads payload data from the given buffer.
        /// </summary>
        internal static bool ReadPayload(
            Func <NetEventType, NetPeer, NetEvent> eventFactory,
            NetPeer peer,
            byte[] buffer,
            int length,
            out ushort sequence,
            out NetEvent evnt)
        {
            evnt = null;

            // Read header (already know the type)
            sequence = NetEncoding.ReadU16(buffer, 1);
            int position = NetEncoding.PAYLOAD_HEADER_SIZE;

            ushort dataLength = (ushort)(length - position);

            if ((position + dataLength) > length)
            {
                return(false); // We're reading past the end of the packet data
            }
            evnt = eventFactory.Invoke(NetEventType.Payload, peer);
            return(evnt.ReadData(buffer, position, dataLength));;
        }
Exemple #21
0
        /// <summary>
        /// Reads a length-prefixed notification block.
        /// </summary>
        private static int ReadNotification(
            byte[] buffer,
            int length,
            int position,
            NetEvent destination)
        {
            // Read the length we added
            ushort dataLength = NetEncoding.ReadU16(buffer, position);

            position += NetEncoding.NOTIFICATION_HEADER_SIZE;

            // Avoid a crash if the packet is bad (or malicious)
            if ((position + dataLength) > length)
            {
                return(-1);
            }

            // Read the data into the event's buffer
            if (destination.ReadData(buffer, position, dataLength) == false)
            {
                return(-1);
            }
            return(NetEncoding.NOTIFICATION_HEADER_SIZE + dataLength);
        }