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); } }
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(); }
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); } }
/// <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); } } } }
// 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); } }
// 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); } }
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); } }
public ConcertsController(IGatewayService gateway, ILogger <ConcertsController> logger) { _gateway = gateway; _logger = logger; _token = new ClientToken(); }
public async Task <HttpResponseMessage> PostConcert(Concert concert, ClientToken token) { return(await concertService.PostOne(concert, token)); }
// 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); } }
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); } }
// 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); } }