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); } }
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()); }
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); }
/// <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)); } }
/// <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)); } }
/// <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)); } }
/// <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)); } }
/// <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)); } }
/// <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)); } }
/// <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)); } }
/// <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; } } } } }
/// <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); }
/// <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); }
/// <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)); } }
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); } } }
/// <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); }
/// <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)); } }
/// <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); }
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)); }
/// <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));; }
/// <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); }