Пример #1
0
        private void StartSend(ClientToken clientToken)
        {
            #if DEBUG
            if (_disposed) return;
            #endif

            if (clientToken.Socket == null) return;

            if (clientToken.SendBytesRemaining <= _settings.BufferSize)
            {
                clientToken.SendEvent.SetBuffer(clientToken.BufferOffsetSend, clientToken.SendBytesRemaining);
                Buffer.BlockCopy(clientToken.DataToSend, clientToken.BytesSentAlready,
                    clientToken.SendEvent.Buffer, clientToken.BufferOffsetSend,
                    clientToken.SendBytesRemaining);
            }
            else
            {
                if (clientToken.SendEvent.Count != _settings.BufferSize)
                    clientToken.SendEvent.SetBuffer(clientToken.BufferOffsetSend, _settings.BufferSize);
                Buffer.BlockCopy(clientToken.DataToSend, clientToken.BytesSentAlready,
                    clientToken.SendEvent.Buffer, clientToken.BufferOffsetSend, _settings.BufferSize);
            }

            if (clientToken.Socket != null && clientToken.Socket.Connected &&
                !clientToken.Socket.SendAsync(clientToken.SendEvent))
            {
                ProcessSend(clientToken.SendEvent);
            }
        }
Пример #2
0
        public void Start()
        {
            for (int i = 0; i < _settings.MaxAcceptOps; i++)
            {
                SocketAsyncEventArgs e = new SocketAsyncEventArgs();
                e.Completed += ProcessAccept;
                _poolOfAcceptEventArgs.Push(e);
            }

            for (int i = 0; i < _settings.MaxConnections; i++)
            {
                SocketAsyncEventArgs receiveEvent = new SocketAsyncEventArgs();
                _bufferManager.SetBuffer(receiveEvent);
                receiveEvent.Completed += IOCompleted;

                SocketAsyncEventArgs sendEvent = new SocketAsyncEventArgs();
                _bufferManager.SetBuffer(sendEvent);
                sendEvent.Completed += IOCompleted;

                ClientToken clientToken = new ClientToken(receiveEvent, sendEvent);
                receiveEvent.UserToken = sendEvent.UserToken = clientToken;
                _clients[clientToken.Id] = clientToken;

                _poolOfDataEventArgs.Push(clientToken);
            }

            StartListen();
        }
Пример #3
0
 private void StartReceive(ClientToken clientToken)
 {
     #if DEBUG
     if (_disposed) return;
     #endif
     if (clientToken.Socket != null && clientToken.Socket.Connected &&
         !clientToken.Socket.ReceiveAsync(clientToken.ReceiveEvent))
     {
         ProcessReceive(clientToken.ReceiveEvent);
     }
 }
Пример #4
0
 /// <summary>
 /// Authenticates with <paramref name="grantType"/>
 /// </summary>
 /// <param name="grantType"><see cref="GrantType"/></param>
 /// <param name="token">Client token, if null it will use the one provided in the client builder.</param>
 /// <param name="fields">The fields for the request</param>
 /// <returns>The Fortnite response</returns>
 public async Task <FortniteResponse <AuthResponse> > GetAccessTokenAsync(
     GrantType grantType,
     ClientToken token = null,
     params (string Key, string value)[] fields)
        // ideally call this once per frame in main loop.
        // -> pass queue so we don't need to create a new one each time!
        public void GetNextMessages(Queue <Message> messages)
        {
            // only if server is active
            if (!Active)
            {
                return;
            }

            // can we accept someone?
            if (AcceptNext(out long accepted))
            {
                // configure the client socket
                ConfigureSocket(accepted);

                // add client with next connection id ('++' because it should
                // start at '1' for Mirror. '0' is reserved for local player)
                clients[++nextConnectionId] = new ClientToken(accepted, MaxMessageSize, MaxReceivesPerTickPerConnection);
            }

            // check all clients for incoming data
            removeIds.Clear();
            foreach (KeyValuePair <int, ClientToken> kvp in clients)
            {
                // first of all: did the client just connect?
                if (!kvp.Value.connectProcessed)
                {
                    messages.Enqueue(new Message(kvp.Key, EventType.Connected, new ArraySegment <byte>()));
                    kvp.Value.connectProcessed = true;
                }
                // closed the handle at some point (e.g. in Send)?
                // or detected a disconnect?
                else if (kvp.Value.socket == -1 || WasDisconnected(kvp.Value.socket))
                {
                    // remove it when done
                    removeIds.Add(kvp.Key);
                }
                // still connected? then read a few messages
                else
                {
                    // IMPORTANT: read a few (not just one) messages per tick(!)
                    // -> client usually has higher tick rate than server
                    // -> if client sends 2 messages per tick but server only
                    //    reads 1 message per tick, then it will be an ever
                    //    growing receive buffer and cause extremely high
                    //    latency for that client (seconds/minutes) and never
                    //    recover from it.
                    // -> this happened in uMMORPG V2 with the new character
                    //    controller movement. Cmds were called each FixedUpdate
                    //    and the server didn't read them quickly enough,
                    //    causing ever growing latency on client for no obvious
                    //    reason whatsoever.
                    // => that's why we always need to read A FEW at once
                    //    * reading ALL available messages via while(available)
                    //      would make deadlocks possible if an attacker sends
                    //      lots of small messages very often, causing the
                    //      server to never exit the while loop (= deadlock)
                    //    * allowing N messages PER SECOND makes sense. but it's
                    //      a bit odd to implement.
                    //    * reading N messages PER FRAME is the most simple
                    //      solution. if the client still lags then so be it,
                    //      the server doesn't care. it does its best to process
                    //      N per tick and that's that.
                    //
                    // NOTE: we don't care if we reached 'max' in this frame and
                    //       there are still some pending. we could kick the
                    //       client, but let's just let it have some growing
                    //       latency and hope for it to recover later. after all
                    //       the server doesn't really care too much about ONE
                    //       client's latency!
                    //
                    // NOTE: we use 'contentBuffers.Length' instead of
                    //       'MaxReceivesPerTickPerConnection' so that runtime
                    //       changes of 'MaxReceivesPerTickPerConnection' won't
                    //       cause NullReferenceExceptions. we only create the
                    //       buffer once.
                    int i;
                    for (i = 0; i < kvp.Value.contentBuffers.Length; ++i)
                    {
                        // header not read yet, but can read it now?
                        if (kvp.Value.contentSize == 0)
                        {
                            if (ReadIfAvailable(kvp.Value.socket, 4, headerBuffer))
                            {
                                kvp.Value.contentSize = Utils.BytesToIntBigEndian(headerBuffer);
                            }
                            // can't read content size yet. try again next frame.
                            else
                            {
                                break;
                            }
                        }
                        // otherwise header was read last time. just read content.
                        // (don't break)

                        // try to read content
                        if (kvp.Value.contentSize > 0)
                        {
                            // protect against allocation attacks. an attacker might
                            // send multiple fake '2GB header' packets in a row,
                            // causing the server to allocate multiple 2GB byte
                            // arrays and run out of memory.
                            if (kvp.Value.contentSize <= MaxMessageSize)
                            {
                                // get a pointer to a content buffer. we read up
                                // to 'n' messages per tick, so use the n-th one
                                byte[] contentBuffer = kvp.Value.contentBuffers[i];

                                if (ReadIfAvailable(kvp.Value.socket, kvp.Value.contentSize, contentBuffer))
                                {
                                    // create ArraySegment from read content
                                    ArraySegment <byte> segment = new ArraySegment <byte>(contentBuffer, 0, kvp.Value.contentSize);
                                    messages.Enqueue(new Message(kvp.Key, EventType.Data, segment));

                                    // reset contentSize for next time
                                    kvp.Value.contentSize = 0;
                                }
                                // can't fully read it yet. try again next frame.
                                else
                                {
                                    break;
                                }
                            }
                            else
                            {
                                // remove it when done
                                Debug.LogWarning("[Server]: possible allocation attack with a header of: " + kvp.Value.contentSize + " bytes " + " from connectionId: " + kvp.Key + " IP: " + GetClientAddress(kvp.Key));
                                removeIds.Add(kvp.Key);

                                // no need to receive any more messages
                                break;
                            }
                        }
                        // no content yet. try again next frame.
                        else
                        {
                            break;
                        }
                    }

                    // for debugging
                    //if (i > 1) Debug.Log("[Server]: read multiple (" + i + ") messages for connection: " + kvp.Key + " this tick.");
                }
            }

            // close all connections in removeIds
            foreach (int connectionId in removeIds)
            {
                // clean up no matter what
                int error = 0;
                if (NativeBindings.network_close(clients[connectionId].socket, ref error) != 0)
                {
                    Debug.LogError("network_close client failed for connId=" + connectionId + " error=" + (NativeError)error);
                }

                // add 'Disconnected' message after disconnecting properly.
                // -> always AFTER closing the connection, because that's when
                //    it's truly disconnected.
                // -> enqueue Disconnected message in this GetNextMessages call
                //    don't just close and add the message later, otherwise the
                //    server might assume a player is still online for one more
                //    tick.
                messages.Enqueue(new Message(connectionId, EventType.Disconnected, new ArraySegment <byte>()));

                // remove from clients
                clients.Remove(connectionId);
            }
        }
        public Exception AuthToken(Guid accessToken, Guid uuid, string displayName)
        {
            lock (_locker)
            {
                Clear();
                if (string.IsNullOrWhiteSpace(displayName))
                {
                    return(new Exception("displayName为空"));
                }
                try
                {
                    WebRequest Http = WebRequest.Create(Auth_Validate);
                    Http.Method      = "POST";
                    Http.ContentType = "application/json";
                    Http.Timeout     = 100000;
                    var requestBody = JsonMapper.ToJson(new ValidateRequest
                    {
                        AccessToken = accessToken.ToString("N"),
                        ClientToken = ClientToken.ToString("N"),
                    });
                    byte[] postdata = Encoding.UTF8.GetBytes(requestBody);
                    Http.GetRequestStream().Write(postdata, 0, postdata.Length);

                    using (HttpWebResponse hwr = (HttpWebResponse)Http.GetResponse())
                    {
                        if (Convert.ToInt32(hwr.StatusCode) == 204)
                        {
                            var LoginInfo = new AuthenticationResponse()
                            {
                                AccessToken     = accessToken.ToString("N"),
                                ClientToken     = ClientToken.ToString("N"),
                                SelectedProfile = new GameProfile()
                                {
                                    Id   = uuid.ToString("N"),
                                    Name = displayName
                                }
                            };
                            UpdateFomrResponse(LoginInfo);
                            return(null);
                        }
                        else
                        {
                            using (StreamReader sr = new StreamReader(hwr.GetResponseStream()))
                            {
                                var response = JsonMapper.ToObject <Error>(sr.ReadToEnd());
                                return(new Exception(response.ErrorMessage));
                            }
                        }
                    }
                }

                catch (WebException ex)
                {
                    try
                    {
                        using (StreamReader sr = new StreamReader(((HttpWebResponse)ex.Response).GetResponseStream(), true))
                        {
                            var ErrorJson = JsonMapper.ToObject <Error>(sr.ReadToEnd());
                            return(new Exception(ErrorJson.ErrorMessage));
                        }
                    }
                    catch
                    {
                        return(ex);
                    }
                }
            }
        }
Пример #7
0
        // the listener thread's listen function
        // note: no maxConnections parameter. high level API should handle that.
        //       (Transport can't send a 'too full' message anyway)
        void Listen(int port)
        {
            // absolutely must wrap with try/catch, otherwise thread
            // exceptions are silent
            try
            {
                // start listener
                listener = new TcpListener(new IPEndPoint(IPAddress.Any, port));
                listener.Server.NoDelay     = NoDelay;
                listener.Server.SendTimeout = SendTimeout;
                listener.Start();
                Logger.Log("Server: listening port=" + port);

                // keep accepting new clients
                while (true)
                {
                    // wait and accept new client
                    // note: 'using' sucks here because it will try to
                    // dispose after thread was started but we still need it
                    // in the thread
                    TcpClient client = listener.AcceptTcpClient();

                    // generate the next connection id (thread safely)
                    int connectionId = NextConnectionId();

                    // add to dict immediately
                    ClientToken token = new ClientToken(client);
                    clients[connectionId] = token;

                    // spawn a send thread for each client
                    Thread sendThread = new Thread(() =>
                    {
                        // wrap in try-catch, otherwise Thread exceptions
                        // are silent
                        try
                        {
                            // run the send loop
                            SendLoop(connectionId, client, token.sendQueue, token.sendPending);
                        }
                        catch (ThreadAbortException)
                        {
                            // happens on stop. don't log anything.
                            // (we catch it in SendLoop too, but it still gets
                            //  through to here when aborting. don't show an
                            //  error.)
                        }
                        catch (Exception exception)
                        {
                            Logger.LogError("Server send thread exception: " + exception);
                        }
                    });
                    sendThread.IsBackground = true;
                    sendThread.Start();

                    // spawn a receive thread for each client
                    Thread receiveThread = new Thread(() =>
                    {
                        // wrap in try-catch, otherwise Thread exceptions
                        // are silent
                        try
                        {
                            // run the receive loop
                            ReceiveLoop(connectionId, client, receiveQueue);

                            // remove client from clients dict afterwards
                            clients.TryRemove(connectionId, out ClientToken _);

                            // sendthread might be waiting on ManualResetEvent,
                            // so let's make sure to end it if the connection
                            // closed.
                            // otherwise the send thread would only end if it's
                            // actually sending data while the connection is
                            // closed.
                            sendThread.Interrupt();
                        }
                        catch (Exception exception)
                        {
                            Logger.LogError("Server client thread exception: " + exception);
                        }
                    });
                    receiveThread.IsBackground = true;
                    receiveThread.Start();
                }
            }
            catch (ThreadAbortException exception)
            {
                // UnityEditor causes AbortException if thread is still
                // running when we press Play again next time. that's okay.
                Logger.Log("Server thread aborted. That's okay. " + exception);
            }
            catch (SocketException exception)
            {
                // calling StopServer will interrupt this thread with a
                // 'SocketException: interrupted'. that's okay.
                Logger.Log("Server Thread stopped. That's okay. " + exception);
            }
            catch (Exception exception)
            {
                // something went wrong. probably important.
                Logger.LogError("Server Exception: " + exception);
            }
        }
Пример #8
0
        // the listener thread's listen function
        // note: no maxConnections parameter. high level API should handle that.
        //       (Transport can't send a 'too full' message anyway)
        void Listen(int port)
        {
            // absolutely must wrap with try/catch, otherwise thread
            // exceptions are silent
            try
            {
                // start listener on all IPv4 and IPv6 address via .Create
                listener = TcpListener.Create(port);
                listener.Server.NoDelay     = NoDelay;
                listener.Server.SendTimeout = SendTimeout;

                // Wappen: Linger 0, force reset
                listener.Server.LingerState = new LingerOption(true, 0);

                Logger.Log($"Server: listening port={port} nodelay={NoDelay} SendTimeout={SendTimeout}");
                listener.Start();

                // keep accepting new clients
                while (true)
                {
                    // wait and accept new client
                    // note: 'using' sucks here because it will try to
                    // dispose after thread was started but we still need it
                    // in the thread
                    TcpClient client = listener.AcceptTcpClient();

                    // Wappen: resolve address now!
                    int    tempId  = -1;
                    string address = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString();
                    addressDictionary[tempId]       = address;
                    clientPreConnectWaiting[tempId] = 0;

                    // Notify above now!
                    receiveQueue.Enqueue(new Message(tempId, EventType.PreConnect, null));

                    // Then wait for preconnect result, only 1 may wait at a time
                    int verdict;
                    while (true)
                    {
                        verdict = clientPreConnectWaiting[tempId];
                        if (verdict == 0)
                        {
                            // No verdict yet
                            Thread.Sleep(10);
                            continue;
                        }

                        break;
                    }

                    // Check verdict.
                    clientPreConnectWaiting.Clear( );
                    if (verdict < 0)  // Prekill, aka FTL kill
                    {
                        client.Close();
                        continue; // Back to accept new client again
                    }

                    // VERDICT ACCEPTED! continue to usual Mirror code vvvvvvv

                    // set socket options
                    client.NoDelay     = NoDelay;
                    client.SendTimeout = SendTimeout;
                    client.LingerState = new LingerOption(true, 0);   // Wappen, will not linger

                    // generate the next connection id (thread safely)
                    int connectionId = NextConnectionId();

                    // add to dict immediately
                    ClientToken token = new ClientToken(client);
                    clients[connectionId]           = token;
                    addressDictionary[connectionId] = address;

                    // spawn a send thread for each client
                    Thread sendThread = new Thread(() =>
                    {
                        // wrap in try-catch, otherwise Thread exceptions
                        // are silent
                        try
                        {
                            // run the send loop
                            SendLoop(connectionId, client, token.sendQueue, token.sendPending);
                        }
                        catch (ThreadAbortException)
                        {
                            // happens on stop. don't log anything.
                            // (we catch it in SendLoop too, but it still gets
                            //  through to here when aborting. don't show an
                            //  error.)
                        }
                        catch (Exception exception)
                        {
                            Logger.LogError("Server send thread exception: " + exception);
                        }
                    });
                    sendThread.IsBackground = true;
                    sendThread.Start();

                    // spawn a receive thread for each client
                    Thread receiveThread = new Thread(() =>
                    {
                        // wrap in try-catch, otherwise Thread exceptions
                        // are silent
                        try
                        {
                            // run the receive loop
                            ReceiveLoop(connectionId, client, receiveQueue, MaxMessageSize);

                            // remove client from clients dict afterwards
                            clients.TryRemove(connectionId, out ClientToken _);

                            // sendthread might be waiting on ManualResetEvent,
                            // so let's make sure to end it if the connection
                            // closed.
                            // otherwise the send thread would only end if it's
                            // actually sending data while the connection is
                            // closed.
                            sendThread.Interrupt();
                        }
                        catch (Exception exception)
                        {
                            Logger.LogError("Server client thread exception: " + exception);
                        }
                    });
                    receiveThread.IsBackground = true;
                    receiveThread.Start();
                }
            }
            catch (ThreadAbortException exception)
            {
                // UnityEditor causes AbortException if thread is still
                // running when we press Play again next time. that's okay.
                Logger.Log("Server thread aborted. That's okay. " + exception);
            }
            catch (SocketException exception)
            {
                // calling StopServer will interrupt this thread with a
                // 'SocketException: interrupted'. that's okay.
                Logger.Log("Server Thread stopped. That's okay. " + exception);
            }
            catch (ThreadInterruptedException)
            {
                // Wappen: This is ok, came from sleep and interruped.
            }
            catch (Exception exception)
            {
                // something went wrong. probably important.
                Logger.LogError("Server Exception: " + exception);
            }
        }
Пример #9
0
        private void Listen(int port)
        {
            try
            {
                listener = new TcpListener(new IPEndPoint(IPAddress.Any, port));
                listener.Server.NoDelay     = NoDelay;
                listener.Server.SendTimeout = SendTimeout;
                listener.Start();
                Logger.Log("Server: listening port=" + port);

                while (true)
                {
                    TcpClient client = listener.AcceptTcpClient();

                    int connectionId = NextConnectionId();

                    ClientToken token = new ClientToken(client);
                    clients[connectionId] = token;

                    Thread sendThread = new Thread(() =>
                    {
                        try
                        {
                            SendLoop(connectionId, client, token.sendQueue, token.sendPending);
                        }
                        catch (ThreadAbortException) { }
                        catch (Exception exception)
                        {
                            Logger.LogError("Server send thread exception: " + exception);
                        }
                    });
                    sendThread.IsBackground = true;
                    sendThread.Start();

                    Thread receiveThread = new Thread(() =>
                    {
                        try
                        {
                            ReceiveLoop(connectionId, client, receiveQueue, MaxMessageSize);

                            clients.TryRemove(connectionId, out ClientToken _);

                            sendThread.Interrupt();
                        }
                        catch (Exception exception)
                        {
                            Logger.LogError("Server client thread exception: " + exception);
                        }
                    });
                    receiveThread.IsBackground = true;
                    receiveThread.Start();
                }
            }
            catch (ThreadAbortException exception)
            {
                Logger.Log("Server thread aborted. That's okay. " + exception);
            }
            catch (SocketException exception)
            {
                Logger.Log("Server Thread stopped. That's okay. " + exception);
            }
            catch (Exception exception)
            {
                Logger.LogError("Server Exception: " + exception);
            }
        }
Пример #10
0
 public ConcertsController(IGatewayService gateway, ILogger <ConcertsController> logger)
 {
     _gateway = gateway;
     _logger  = logger;
     _token   = new ClientToken();
 }
Пример #11
0
 public async Task <HttpResponseMessage> PostConcert(Concert concert, ClientToken token)
 {
     return(await concertService.PostOne(concert, token));
 }
Пример #12
0
        // the listener thread's listen function
        // note: no maxConnections parameter. high level API should handle that.
        //       (Transport can't send a 'too full' message anyway)
        void Listen(int port)
        {
            // absolutely must wrap with try/catch, otherwise thread
            // exceptions are silent
            try
            {
                // start listener on all IPv4 and IPv6 address via .Create
                listener = TcpListener.Create(port);
                listener.Server.NoDelay     = NoDelay;
                listener.Server.SendTimeout = SendTimeout;
                listener.Start();
                Logger.Log("Server: listening port=" + port);

                X509Certificate cert           = null;
                bool            selfSignedCert = false;

                if (Encrypted)
                {
                    if (CertFile == null)
                    {
                        // Create a new self-signed certificate
                        selfSignedCert = true;
                        cert           =
                            new X509Certificate2Builder
                        {
                            SubjectName = string.Format("CN={0}", ((IPEndPoint)listener.LocalEndpoint).Address.ToString())
                        }.Build();
                    }
                    else
                    {
                        cert           = X509Certificate.CreateFromCertFile(CertFile);
                        selfSignedCert = false;
                    }
                }

                // keep accepting new clients
                while (true)
                {
                    // wait and accept new client
                    // note: 'using' sucks here because it will try to
                    // dispose after thread was started but we still need it
                    // in the thread
                    TcpClient client = listener.AcceptTcpClient();

                    // set socket options
                    client.NoDelay     = NoDelay;
                    client.SendTimeout = SendTimeout;

                    // generate the next connection id (thread safely)
                    int connectionId = NextConnectionId();

                    // add to dict immediately
                    ClientToken token = new ClientToken(client);
                    clients[connectionId] = token;

                    Stream stream = client.GetStream();

                    Thread sslAuthenticator = null;
                    if (Encrypted)
                    {
                        RemoteCertificateValidationCallback trustCert = (object sender, X509Certificate x509Certificate,
                                                                         X509Chain x509Chain, SslPolicyErrors policyErrors) =>
                        {
                            if (selfSignedCert)
                            {
                                // All certificates are accepted
                                return(true);
                            }
                            else
                            {
                                if (policyErrors == SslPolicyErrors.None)
                                {
                                    return(true);
                                }
                                else
                                {
                                    return(false);
                                }
                            }
                        };

                        SslStream sslStream = new SslStream(client.GetStream(), false, trustCert);
                        stream = sslStream;

                        sslAuthenticator = new Thread(() => {
                            try
                            {
                                // Using System.Security.Authentication.SslProtocols.None (the Microsoft recommended parameter which
                                // chooses the highest version of TLS) does not seem to work with Unity. Unity 2018.2 added support
                                // for TLS 1.2 when used with the .NET 4.x runtime, so use preprocessor directives to choose the right protocol
#if UNITY_2018_2_OR_NEWER && NET_4_6
                                System.Security.Authentication.SslProtocols protocol = System.Security.Authentication.SslProtocols.Tls12;
#else
                                System.Security.Authentication.SslProtocols protocol = System.Security.Authentication.SslProtocols.Default;
#endif

                                bool checkCertificateRevocation = !selfSignedCert;
                                sslStream.AuthenticateAsServer(cert, false, protocol, checkCertificateRevocation);
                            }
                            catch (Exception exception)
                            {
                                Logger.LogError("SSL Authenticator exception: " + exception);
                            }
                        });

                        sslAuthenticator.IsBackground = true;
                        sslAuthenticator.Start();
                    }

                    // spawn a send thread for each client
                    Thread sendThread = new Thread(() =>
                    {
                        // wrap in try-catch, otherwise Thread exceptions
                        // are silent
                        try
                        {
                            if (sslAuthenticator != null)
                            {
                                sslAuthenticator.Join();
                            }

                            // run the send loop
                            SendLoop(connectionId, client, stream, token.sendQueue, token.sendPending);
                        }
                        catch (ThreadAbortException)
                        {
                            // happens on stop. don't log anything.
                            // (we catch it in SendLoop too, but it still gets
                            //  through to here when aborting. don't show an
                            //  error.)
                        }
                        catch (Exception exception)
                        {
                            Logger.LogError("Server send thread exception: " + exception);
                        }
                    });
                    sendThread.IsBackground = true;
                    sendThread.Start();

                    // spawn a receive thread for each client
                    Thread receiveThread = new Thread(() =>
                    {
                        // wrap in try-catch, otherwise Thread exceptions
                        // are silent
                        try
                        {
                            if (sslAuthenticator != null)
                            {
                                sslAuthenticator.Join();
                            }

                            // run the receive loop
                            ReceiveLoop(connectionId, client, stream, receiveQueue, MaxMessageSize);

                            // remove client from clients dict afterwards
                            clients.TryRemove(connectionId, out ClientToken _);

                            // sendthread might be waiting on ManualResetEvent,
                            // so let's make sure to end it if the connection
                            // closed.
                            // otherwise the send thread would only end if it's
                            // actually sending data while the connection is
                            // closed.
                            sendThread.Interrupt();
                        }
                        catch (Exception exception)
                        {
                            Logger.LogError("Server client thread exception: " + exception);
                        }
                    });
                    receiveThread.IsBackground = true;
                    receiveThread.Start();
                }
            }
            catch (ThreadAbortException exception)
            {
                // UnityEditor causes AbortException if thread is still
                // running when we press Play again next time. that's okay.
                Logger.Log("Server thread aborted. That's okay. " + exception);
            }
            catch (SocketException exception)
            {
                // calling StopServer will interrupt this thread with a
                // 'SocketException: interrupted'. that's okay.
                Logger.Log("Server Thread stopped. That's okay. " + exception);
            }
            catch (Exception exception)
            {
                // something went wrong. probably important.
                Logger.LogError("Server Exception: " + exception);
            }
        }
Пример #13
0
        private void ProcessReceive(SocketAsyncEventArgs e)
        {
            if (e.SocketError != SocketError.Success)
            {
                if (e.SocketError == SocketError.OperationAborted)
                {
                    return;
                }

                //Fire ClientDataReceiveError event
                if (DataReceiveError != null)
                {
                    if (CallDataReceiveErrorAsync)
                    {
                        DataReceiveError.BeginInvoke(this, r => DataReceiveError.EndInvoke(r), null);
                    }
                    else
                    {
                        DataReceiveError(this);
                    }
                }

                ProcessDisconnect(e);
                return;
            }

            ClientToken clientToken      = (ClientToken)e.UserToken;
            int         bytesTransferred = e.BytesTransferred;

            if (bytesTransferred != 0)
            {
                clientToken.AcceptData(e, bytesTransferred);

                //Parse received data for packets
                List <BaseResponse> packets = clientToken.ProcessReceivedDataRsp();

                //Fire ClientDataReceived event
                if (packets.Count > 0 && DataReceived != null)
                {
                    if (CallDataReceivedAsync)
                    {
                        DataReceived.BeginInvoke(this, packets, r => DataReceived.EndInvoke(r), null);
                    }
                    else
                    {
                        DataReceived(this, packets);
                    }
                }

                StartReceive(e);

                //clientToken.AcceptDataAsync(e, bytesTransferred).ContinueWith
                //    (
                //        a =>
                //        {
                //            //Parse received data for packets
                //            List<BaseResponse> packets = clientToken.ProcessReceivedDataRsp();

                //            //Fire ClientDataReceived event
                //            if (packets.Count > 0 && DataReceived != null)
                //            {
                //                DataReceived.BeginInvoke(this, packets, r => DataReceived.EndInvoke(r), null);
                //            }

                //            StartReceive(e);
                //        }
                //    );

                return;
            }

            //Return of zero bytes transferred means that the server is no longer connected
            if (!clientToken.Closed && clientToken.Socket != null)
            {
                ProcessDisconnect(e);
            }
        }
Пример #14
0
        // the listener thread's listen function
        // note: no maxConnections parameter. high level API should handle that.
        //       (Transport can't send a 'too full' message anyway)
        void Listen(int port)
        {
            // absolutely must wrap with try/catch, otherwise thread
            // exceptions are silent
            try
            {
                // keep accepting new clients
                while (true)
                {
                    // wait and accept new client
                    // note: 'using' sucks here because it will try to
                    // dispose after thread was started but we still need it
                    // in the thread
                    TcpClient client = listener.AcceptTcpClient();

                    // generate the next connection id (thread safely)
                    int connectionId = NextConnectionId();

                    // add to dict immediately
                    ClientToken token = new ClientToken(client);
                    clients[connectionId] = token;

                    // spawn a send thread for each client
                    Thread sendThread = new Thread(() =>
                    {
                        // wrap in try-catch, otherwise Thread exceptions
                        // are silent
                        try
                        {
                            // run the send loop
                            SendLoop(connectionId, client, token.sendQueue, token.sendPending);
                        }
                        catch (ThreadAbortException)
                        {
                            // happens on stop. don't log anything.
                            // (we catch it in SendLoop too, but it still gets
                            //  through to here when aborting. don't show an
                            //  error.)
                        }
                        catch (Exception exception)
                        {
                            Logger.LogError("Server send thread exception: " + exception);
                        }
                    });
                    sendThread.IsBackground = true;
                    sendThread.Start();
                }
            }
            catch (ThreadAbortException exception)
            {
                // UnityEditor causes AbortException if thread is still
                // running when we press Play again next time. that's okay.
                Logger.Log("Server thread aborted. That's okay. " + exception);
            }
            catch (SocketException exception)
            {
                // calling StopServer will interrupt this thread with a
                // 'SocketException: interrupted'. that's okay.
                Logger.Log("Server Thread stopped. That's okay. " + exception);
            }
            catch (Exception exception)
            {
                // something went wrong. probably important.
                Logger.LogError("Server Exception: " + exception);
            }
        }