예제 #1
0
        private void ProcessReceive(SocketAsyncEventArgs args)
        {
            _idleTimeoutTimer?.Stop();
            _readTimeoutTimer?.Stop();

            if (args.BytesTransferred > 0 && args.SocketError == SocketError.Success)
            {
                ReceiveToken token = (ReceiveToken)args.UserToken;
                token.BufferLength += args.BytesTransferred;

                if (Socket.Available == 0)
                {
                    byte[] receiveBuffer = new byte[token.BufferLength];
                    Array.Copy(args.Buffer, receiveBuffer, token.BufferLength);
                    token.BufferLength = 0;
                    token.ReceiveHandler(receiveBuffer);

                    StartReceive(args);
                }
                else if (Socket.ReceiveAsync(args) == false)
                {
                    // Read the next block of data sent by client.
                    ProcessReceive(args);
                }
            }
            else
            {
                if (Socket.Connected)
                {
                    Close();
                }
            }
        }
예제 #2
0
        private static readonly byte[] HEADER_DELIM = { 13, 10, 13, 10 }; // UTF-8 for \r\n\r\n i.e. CRLF CRLF, which appears after the last HTTP header field

        protected byte[] HandleHttpHeader(SocketAsyncEventArgs e, ref int bytesAlreadyProcessed)
        {
            if (bytesAlreadyProcessed < 0)
            {
                throw new ArgumentException("bytesAlreadyProcessed must be non-negative.");
            }
            else if (bytesAlreadyProcessed >= e.BytesTransferred)
            {
                throw new ArgumentException("bytesAlreadyProcessed must be less than e.BytesTransferred.");
            }

            ReceiveToken token      = (ReceiveToken)e.UserToken;
            int          totalBytes = token.bytesReceived + e.BytesTransferred - bytesAlreadyProcessed;

            if (totalBytes >= 4)
            {
                int    searchSpace = totalBytes - 3; // totalBytes - HEADER_DELIM.Length + 1
                byte[] data        = token.internalBuffer.Array;
                for (int i = 0; i < searchSpace; i++)
                {
                    if (HEADER_DELIM[0] == data[token.internalBuffer.Offset + i])
                    {
                        if (HEADER_DELIM[1] == data[token.internalBuffer.Offset + i + 1] &&
                            HEADER_DELIM[2] == data[token.internalBuffer.Offset + i + 2] &&
                            HEADER_DELIM[3] == data[token.internalBuffer.Offset + i + 3])
                        {
                            byte[] header = new byte[i + 4];
                            Buffer.BlockCopy(data, token.internalBuffer.Offset, header, 0, header.Length);
                            if (token.bytesReceived > 0)
                            {
                                bytesAlreadyProcessed += header.Length - token.bytesReceived;
                                token.bytesReceived    = 0;
                                e.SetBuffer(token.internalBuffer.Offset, token.internalBuffer.Count);
                            }
                            else
                            {
                                bytesAlreadyProcessed += header.Length;
                            }
                            if (header.Length < totalBytes)
                            {
                                Buffer.BlockCopy(data, token.internalBuffer.Offset + header.Length, data, token.internalBuffer.Offset, totalBytes - header.Length);
                            }
                            e.UserToken = token;
                            return(header);
                        }
                    }
                }
                if (totalBytes == token.internalBuffer.Count)
                {
                    throw new Exception(String.Format("Could not find end of header within {0} bytes.", token.internalBuffer.Count));
                }
            }

            token.bytesReceived = totalBytes;
            e.SetBuffer(token.internalBuffer.Offset + totalBytes, token.internalBuffer.Count - totalBytes);
            bytesAlreadyProcessed = e.BytesTransferred;
            e.UserToken           = token;
            return(null);
        }
예제 #3
0
 private void ReturnBuffer(SocketAsyncEventArgs e)
 {
     if (e.UserToken != null)
     {
         ReceiveToken token = (ReceiveToken)e.UserToken;
         bufferManager.ReturnBuffer(token.internalBuffer);
         token.internalBuffer = default(ArraySegment <byte>);
         e.SetBuffer(new byte[0], 0, 0);
     }
 }
예제 #4
0
        public void Receive(Action <byte[]> buffer)
        {
            ReceiveToken token = new ReceiveToken
            {
                ReceiveHandler = buffer
            };

            ReceiveSocketAsyncEventArgs.UserToken = token;

            StartReceive(ReceiveSocketAsyncEventArgs);
        }
예제 #5
0
        // Should validate the handshake response from the server
        private void ReceiveAsync_Completed(object sender, SocketAsyncEventArgs e)
        {
            if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
            {
                int          bytesAlreadyProcessed = 0; // Count of the total freshly transferred bytes processed so far
                ReceiveToken token = (ReceiveToken)e.UserToken;
                if (!headerExchanged)
                {
                    byte[] header = HandleHttpHeader(e, ref bytesAlreadyProcessed);
                    token = (ReceiveToken)e.UserToken;
                    if (header == null)
                    {
                        DoRead(e);
                        return;
                    }
                    else if (Websockets.ValidateResponseHeader(headerHash, header))
                    {
                        headerExchanged       = true;
                        token.maxAllowedBytes = int.MaxValue;
                        e.UserToken           = token;

                        // Ping the server to finalize the player's connection
                        Send(Text.CreateFromString(Time.Timestep, InstanceGuid.ToString(), true, Receivers.Server,
                                                   MessageGroupIds.NETWORK_ID_REQUEST, true));
                    }
                    else
                    {
                        // Improper header, so a disconnect is required
                        Disconnect(true);
                        return;
                    }
                }

                while (bytesAlreadyProcessed < e.BytesTransferred)
                {
                    byte[] data = HandleData(e, true, ref bytesAlreadyProcessed);
                    if (data == null)
                    {
                        break;
                    }

                    FrameStream frame = Factory.DecodeMessage(data, false, MessageGroupIds.TCP_FIND_GROUP_ID, Server);

                    FireRead(frame, Server);
                }

                DoRead(e);
            }
            else
            {
                Disconnect(true);
            }
        }
예제 #6
0
        protected virtual void Initialize(string host, ushort port, bool pendCreates = true)
        {
            // By default pending creates should be true and flushed when ready
            if (pendCreates)
            {
                PendCreates = true;
            }

            // Get a random hash key that needs to be used for validating that the server was connected to
            headerHash = Websockets.HeaderHashKey();

            // This is a typical Websockets accept header to be validated
            byte[] connectionHeader = Websockets.ConnectionHeader(headerHash, port);

            // Register the server as a NetworkingPlayer
            server = new NetworkingPlayer(0, host, true, client, this);
            // Send the upgrade request to the server
            RawWrite(connectionHeader);

            //Let myself know I connected successfully
            OnPlayerConnected(server);
            // Set myself as a connected client
            server.Connected = true;

            ReceiveToken token = new ReceiveToken
            {
                internalBuffer  = new ArraySegment <byte>(buffer, 0, buffer.Length),
                player          = server,
                bytesReceived   = 0,
                dataHolder      = null,
                maxAllowedBytes = 8192
            };

            // Read from the server async
            SocketAsyncEventArgs e = new SocketAsyncEventArgs();

            e.Completed += new EventHandler <SocketAsyncEventArgs>(ReceiveAsync_Completed);
            e.UserToken  = token;
            e.SetBuffer(token.internalBuffer.Array, token.internalBuffer.Offset, token.internalBuffer.Count);

            if (!client.Client.ReceiveAsync(e))
            {
                Task.Queue(() => ReceiveAsync_Completed(this, e));
            }
        }
예제 #7
0
        private void DoRead(SocketAsyncEventArgs e)
        {
            if (!IsBound)
            {
                ReturnBuffer(e);
                return;
            }

            ReceiveToken token        = (ReceiveToken)e.UserToken;
            Socket       playerSocket = null;

            try
            {
                // Try to get the client stream if it is still available
                playerSocket = token.player.TcpClientHandle.Client;
            }
            catch
            {
                // Failed to get the stream for the client so forcefully disconnect it
                //Console.WriteLine("Exception: Failed to get stream for client (Forcefully disconnecting)");
                Disconnect(token.player, true);
                ReturnBuffer(e);
                return;
            }

            // If the player is no longer connected, then make sure to disconnect it properly
            if (!token.player.TcpClientHandle.Connected)
            {
                Disconnect(token.player, false);
                ReturnBuffer(e);
                return;
            }

            // False means operation was synchronous (usually error)
            if (!playerSocket.ReceiveAsync(e))
            {
                ReceiveAsync_Completed(this, e);
            }
        }
예제 #8
0
        protected byte[] HandleData(SocketAsyncEventArgs e, bool isStream, ref int bytesAlreadyProcessed)
        {
            if (bytesAlreadyProcessed < 0)
            {
                throw new ArgumentException("bytesAlreadyProcessed must be non-negative.");
            }
            else if (bytesAlreadyProcessed >= e.BytesTransferred)
            {
                throw new ArgumentException("bytesAlreadyProcessed must be less than e.BytesTransferred.");
            }

            ReceiveToken token        = (ReceiveToken)e.UserToken;
            int          socketOffset = token.internalBuffer.Offset;

            byte[] bytes = token.internalBuffer.Array;
            int    totalBytes;

            #region ParseFrameHeader
            if (token.dataHolder == null) // Null dataHolder means header not parsed yet
            {
                totalBytes = token.bytesReceived + e.BytesTransferred - bytesAlreadyProcessed;
                if (totalBytes < 2) // Not enough bytes to determine length, so move offset
                {
                    token.bytesReceived = totalBytes;
                    e.SetBuffer(socketOffset + totalBytes, token.internalBuffer.Count - totalBytes);
                    bytesAlreadyProcessed = e.BytesTransferred;
                    e.UserToken           = token;
                    return(null);
                }
                int  dataLength = bytes[socketOffset + 1] & 127;
                bool usingMask  = bytes[socketOffset + 1] > 127; // same as bytes[socketOffset + 1] & 128 != 0
                int  payloadOffset;
                if (dataLength == 126)                           // 126 means 125 < length < 65536
                {
                    payloadOffset = 4;
                }
                else if (dataLength == 127)  // 127 means length >= 65536
                {
                    payloadOffset = 10;
                }
                else
                {
                    payloadOffset = 2;
                }
                int length;
                if (payloadOffset != 2)
                {
                    if (totalBytes < payloadOffset)  // Not enough bytes to determine length, so move offset
                    {
                        token.bytesReceived = totalBytes;
                        e.SetBuffer(socketOffset + totalBytes, token.internalBuffer.Count - totalBytes);
                        bytesAlreadyProcessed = e.BytesTransferred;
                        e.UserToken           = token;
                        return(null);
                    }

                    // Need to worry about endian order since length is in big endian
                    if (payloadOffset == 4)
                    {
                        if (BitConverter.IsLittleEndian)
                        {
                            length = BitConverter.ToUInt16(new byte[] { bytes[socketOffset + 3], bytes[socketOffset + 2] }, 0);
                        }
                        else
                        {
                            length = BitConverter.ToUInt16(bytes, socketOffset + 2);
                        }
                    }
                    else
                    {
                        // First 4 bytes will be 0 for sizes less than max int32
                        if (BitConverter.IsLittleEndian)
                        {
                            length = (int)BitConverter.ToUInt32(new byte[] { bytes[socketOffset + 9], bytes[socketOffset + 8], bytes[socketOffset + 7], bytes[socketOffset + 6] }, 0);
                        }
                        else
                        {
                            length = (int)BitConverter.ToUInt32(bytes, socketOffset + 6);
                        }
                    }

                    // Group id, receivers, time step, unique id, and router id lengths will be present in the payload length

                    //if (isStream)
                    //    length += 21;  // Group id (4), receivers (1), time step (8), unique id (8)
                    //if ((bytes[socketOffset + 0] & 0xF) == (Binary.CONTROL_BYTE & 0xF))
                    //    length += 1; // routerId (1) if this is a binary frame
                }
                else
                {
                    length = dataLength;
                }
                length += usingMask ? 4 + payloadOffset : payloadOffset; // Add full length of header to length
                if (length < 0 || length > token.maxAllowedBytes)
                {
                    throw new UnauthorizedAccessException(String.Format("Tried to receive a frame larger than expected. Got {0}, and expected less than {1}", length, token.maxAllowedBytes));
                }
                e.SetBuffer(token.internalBuffer.Offset, token.internalBuffer.Count);
                token.bytesReceived = 0;
                token.dataHolder    = new byte[length];
            }
            #endregion

            totalBytes = token.bytesReceived + e.BytesTransferred - bytesAlreadyProcessed;
            if (totalBytes < token.dataHolder.Length) // Full frame not yet received
            {
                Buffer.BlockCopy(bytes, socketOffset, token.dataHolder, token.bytesReceived, e.BytesTransferred - bytesAlreadyProcessed);
                token.bytesReceived  += e.BytesTransferred - bytesAlreadyProcessed;
                bytesAlreadyProcessed = e.BytesTransferred;
                e.UserToken           = token;
                return(null);
            }
            else
            {
                byte[] data          = token.dataHolder;
                int    dataProcessed = (data.Length - token.bytesReceived);
                Buffer.BlockCopy(bytes, socketOffset, data, token.bytesReceived, dataProcessed);


                token.bytesReceived    = 0;
                token.dataHolder       = null;
                bytesAlreadyProcessed += dataProcessed;
                if (bytesAlreadyProcessed < e.BytesTransferred) // More frames left to handle, so shuffle the remaining data to beginning of buffer.
                {
                    Buffer.BlockCopy(bytes, socketOffset + dataProcessed, bytes, socketOffset, e.BytesTransferred - bytesAlreadyProcessed);
                }
                e.UserToken = token;
                return(data);
            }
        }
예제 #9
0
 public TokenInput(ReceiveToken callback)
 {
     this.callback = callback;
 }
예제 #10
0
        private void ReceiveAsync_Completed(object sender, SocketAsyncEventArgs e)
        {
            if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
            {
                int          bytesAlreadyProcessed = 0;
                ReceiveToken token = (ReceiveToken)e.UserToken;
                if (!token.player.Accepted && !token.player.Connected)
                {
                    byte[] header = HandleHttpHeader(e, ref bytesAlreadyProcessed);
                    if (header == null)
                    {
                        DoRead(e);
                        return;
                    }
                    byte[] response = Websockets.ValidateConnectionHeader(header);

                    // The response will be null if the header sent is invalid, if so then disconnect client as they are sending invalid headers
                    if (response == null)
                    {
                        OnPlayerRejected(token.player);
                        Disconnect(token.player, true);
                        ReturnBuffer(e);
                        return;
                    }

                    // If all is in order then send the validated response to the client
                    token.player.TcpClientHandle.GetStream().Write(response, 0, response.Length);

                    // The player has successfully connected
                    token.player.Connected = true;
                }
                while (bytesAlreadyProcessed < e.BytesTransferred)
                {
                    byte[] data = HandleData(e, true, ref bytesAlreadyProcessed);
                    if (data == null)
                    {
                        break;
                    }
                    FrameStream frame = Factory.DecodeMessage(data, true, MessageGroupIds.TCP_FIND_GROUP_ID, token.player);
                    if (!token.player.Accepted)
                    {
                        if (frame.GroupId == MessageGroupIds.NETWORK_ID_REQUEST)
                        {
                            token.player.InstanceGuid = ((Text)frame).ToString();

                            // If the player was rejected during the handling of the playerGuidAssigned event, don't accept them.
                            if (!TryPlayerGuidAssignment(token.player))
                            {
                                break;
                            }

                            token.maxAllowedBytes = int.MaxValue;

                            if (authenticator != null)
                            {
                                authenticator.IssueChallenge(this, token.player, IssueChallenge, AuthUser);
                            }
                            else
                            {
                                AuthUser(token.player);
                            }
                        }
                        else if (frame.GroupId == MessageGroupIds.AUTHENTICATION_RESPONSE)
                        {
                            // Authenticate user response
                            if (authenticator == null)
                            {
                                return;
                            }

                            authenticator.VerifyResponse(this, token.player, frame.StreamData, AuthUser, RejectUser);
                        }
                        else
                        {
                            Disconnect(token.player, true);
                            ReturnBuffer(e);
                        }
                    }
                    else
                    {
                        token.player.Ping();
                        FireRead(frame, token.player);
                    }
                }
                DoRead(e);
            }
            else
            {
                Disconnect(((ReceiveToken)e.UserToken).player, true);
                ReturnBuffer(e);
            }
        }
예제 #11
0
        /// <summary>
        /// Infinite loop listening for client connections on a separate thread.
        /// This loop breaks if there is an exception thrown on the blocking accept call
        /// </summary>
        private void ListenForConnections(IAsyncResult obj)
        {
            TcpListener asyncListener = (TcpListener)obj.AsyncState;
            TcpClient   client        = null;

            try
            {
                client = asyncListener.EndAcceptTcpClient(obj);
            }
            catch
            {
                return;
            }

            asyncListener.BeginAcceptTcpClient(ListenForConnections, asyncListener);

            if (rawClients.Count == MaxConnections)
            {
                // Tell the client why they are being disconnected
                Send(client, Error.CreateErrorMessage(Time.Timestep, "Max Players Reached On Server", false, MessageGroupIds.MAX_CONNECTIONS, true));

                // Send the close connection frame to the client
                Send(client, new ConnectionClose(Time.Timestep, false, Receivers.Target, MessageGroupIds.DISCONNECT, true));

                // Do disconnect logic for client
                ClientRejected(client, false);
                return;
            }
            else if (!AcceptingConnections)
            {
                // Tell the client why they are being disconnected
                Send(client, Error.CreateErrorMessage(Time.Timestep, "The server is busy and not accepting connections", false, MessageGroupIds.MAX_CONNECTIONS, true));

                // Send the close connection frame to the client
                Send(client, new ConnectionClose(Time.Timestep, false, Receivers.Target, MessageGroupIds.DISCONNECT, true));

                // Do disconnect logic for client
                ClientRejected(client, false);
                return;
            }

            ArraySegment <byte> segment;

            if (!bufferManager.TryTakeBuffer(out segment))
            {
                // Tell the client why they are being disconnected
                Send(client, Error.CreateErrorMessage(Time.Timestep, "The server is busy and not accepting connections", false, MessageGroupIds.MAX_CONNECTIONS, true));

                // Send the close connection frame to the client
                Send(client, new ConnectionClose(Time.Timestep, false, Receivers.Target, MessageGroupIds.DISCONNECT, true));

                // Do disconnect logic for client
                ClientRejected(client, false);
                throw new OutOfMemoryException("Buffer manager has run out of allocated memory (possible memory leak).");
            }

            // Clients will be looped through on other threads so be sure to lock it before adding
            ReceiveToken token;

            lock (Players)
            {
                rawClients.Add(client);

                // Create the identity wrapper for this player
                NetworkingPlayer player = new NetworkingPlayer(ServerPlayerCounter++, ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString(), false, client, this);

                // Generically add the player and fire off the events attached to player joining
                OnPlayerConnected(player);

                token = new ReceiveToken
                {
                    internalBuffer  = segment,
                    player          = player,
                    bytesReceived   = 0,
                    dataHolder      = null,
                    maxAllowedBytes = 8192
                };
            }

            // Let all of the event listeners know that the client has successfully connected
            if (rawClientConnected != null)
            {
                rawClientConnected(client);
            }

            SocketAsyncEventArgs e = new SocketAsyncEventArgs();

            e.Completed += new EventHandler <SocketAsyncEventArgs>(ReceiveAsync_Completed);
            e.UserToken  = token;
            e.SetBuffer(token.internalBuffer.Array, token.internalBuffer.Offset, token.internalBuffer.Count);

            if (!client.Client.ReceiveAsync(e))
            {
                Task.Queue(() => ReceiveAsync_Completed(this, e));
            }
        }