/// <summary> /// Called when a ConnectAsync operation completes /// </summary> private void ProcessConnect(SocketAsyncEventArgs e, string token) { if (e.SocketError == SocketError.Success) { byte[] buffer = Encoding.UTF8.GetBytes(token + "\r"); e.SetBuffer(buffer, 0, buffer.Length); Socket sock = ((GainCapitalUserToken)e.UserToken).Socket; SocketDelegate temp = Connected; if (temp != null) { temp((IPEndPoint)sock.RemoteEndPoint); } bool willRaiseEvent = sock.SendAsync(e); if (!willRaiseEvent) { ProcessSend(e); } } else { throw new SocketException((int)e.SocketError); } }
private async Task ExecuteApplication(SocketDelegate socketDelegate, ConnectionContext connection) { // Jump onto the thread pool thread so blocking user code doesn't block the setup of the // connection and transport await AwaitableThreadPool.Yield(); // Running this in an async method turns sync exceptions into async ones await socketDelegate(connection); }
private void DoConnectSucess(object src, SocketDelegate callBack) { Socket socket = (Socket)src; socket.Blocking = true; if (callBack != null) { callBack(identiy); } socket.BeginReceive(mReceiveData, 0, mReceiveData.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket); }
public SocketDelegate Build() { SocketDelegate app = features => { return(Task.CompletedTask); }; foreach (var component in _components.Reverse()) { app = component(app); } return(app); }
private async Task ExecuteApplication(SocketDelegate socketDelegate, ConnectionContext connection) { // Verify some initialization invariants // We want to be positive that the IConnectionInherentKeepAliveFeature is initialized before invoking the application, if the long polling transport is in use. Debug.Assert(connection.Metadata[ConnectionMetadataNames.Transport] != null, "Transport has not been initialized yet"); Debug.Assert((TransportType?)connection.Metadata[ConnectionMetadataNames.Transport] != TransportType.LongPolling || connection.Features.Get <IConnectionInherentKeepAliveFeature>() != null, "Long-polling transport is in use but IConnectionInherentKeepAliveFeature as not configured"); // Jump onto the thread pool thread so blocking user code doesn't block the setup of the // connection and transport await AwaitableThreadPool.Yield(); // Running this in an async method turns sync exceptions into async ones await socketDelegate(connection); }
private async Task DoPersistentConnection(SocketDelegate socketDelegate, IHttpTransport transport, HttpContext context, DefaultConnectionContext connection) { try { await connection.Lock.WaitAsync(); if (connection.Status == DefaultConnectionContext.ConnectionStatus.Disposed) { _logger.ConnectionDisposed(connection.ConnectionId); // Connection was disposed context.Response.StatusCode = StatusCodes.Status404NotFound; return; } // There's already an active request if (connection.Status == DefaultConnectionContext.ConnectionStatus.Active) { _logger.ConnectionAlreadyActive(connection.ConnectionId, connection.GetHttpContext().TraceIdentifier); // Reject the request with a 409 conflict context.Response.StatusCode = StatusCodes.Status409Conflict; return; } // Mark the connection as active connection.Status = DefaultConnectionContext.ConnectionStatus.Active; // Call into the end point passing the connection connection.ApplicationTask = ExecuteApplication(socketDelegate, connection); // Start the transport connection.TransportTask = transport.ProcessRequestAsync(context, context.RequestAborted); } finally { connection.Lock.Release(); } // Wait for any of them to end await Task.WhenAny(connection.ApplicationTask, connection.TransportTask); await _manager.DisposeAndRemoveAsync(connection); }
public static void Main(string[] args) { sd = new SocketDelegate(CallbackSocket); messageHandling(); Console.WriteLine("Press Esc to stop the CableCloud"); ConsoleKeyInfo cki; //Petla wykonuje sie poki nie nacisniemy klawisza "esc" while (true) { cki = Console.ReadKey(); if (cki.Key == ConsoleKey.Escape) { _cts.Cancel(); break; } } // closeAllSocket(); }
private void ReleaseSocket(SocketDelegate callBack) { if (this.socket != null) { try { //this.socket.Shutdown(SocketShutdown.Both); this.socket.Close(); this.socket = null; } catch (Exception e) { this.socket = null; DebugLogError(identiy, e.ToString()); } finally { if (callBack != null) { callBack(this.identiy); } } } }
private async Task ExecuteEndpointAsync(HttpContext context, SocketDelegate socketDelegate, HttpSocketOptions options, ConnectionLogScope logScope) { var supportedTransports = options.Transports; // Server sent events transport // GET /{path} // Accept: text/event-stream var headers = context.Request.GetTypedHeaders(); if (headers.Accept?.Contains(new Net.Http.Headers.MediaTypeHeaderValue("text/event-stream")) == true) { // Connection must already exist var connection = await GetConnectionAsync(context); if (connection == null) { // No such connection, GetConnection already set the response status code return; } if (!await EnsureConnectionStateAsync(connection, context, TransportType.ServerSentEvents, supportedTransports, logScope, options)) { // Bad connection state. It's already set the response status code. return; } _logger.EstablishedConnection(); // ServerSentEvents is a text protocol only connection.TransportCapabilities = TransferMode.Text; // We only need to provide the Input channel since writing to the application is handled through /send. var sse = new ServerSentEventsTransport(connection.Application.Reader, connection.ConnectionId, _loggerFactory); await DoPersistentConnection(socketDelegate, sse, context, connection); } else if (context.WebSockets.IsWebSocketRequest) { // Connection can be established lazily var connection = await GetOrCreateConnectionAsync(context); if (connection == null) { // No such connection, GetOrCreateConnection already set the response status code return; } if (!await EnsureConnectionStateAsync(connection, context, TransportType.WebSockets, supportedTransports, logScope, options)) { // Bad connection state. It's already set the response status code. return; } _logger.EstablishedConnection(); var ws = new WebSocketsTransport(options.WebSockets, connection.Application, connection, _loggerFactory); await DoPersistentConnection(socketDelegate, ws, context, connection); } else { // GET /{path} maps to long polling // Connection must already exist var connection = await GetConnectionAsync(context); if (connection == null) { // No such connection, GetConnection already set the response status code return; } if (!await EnsureConnectionStateAsync(connection, context, TransportType.LongPolling, supportedTransports, logScope, options)) { // Bad connection state. It's already set the response status code. return; } try { await connection.Lock.WaitAsync(); if (connection.Status == DefaultConnectionContext.ConnectionStatus.Disposed) { _logger.ConnectionDisposed(connection.ConnectionId); // The connection was disposed context.Response.StatusCode = StatusCodes.Status404NotFound; context.Response.ContentType = "plain/text"; return; } if (connection.Status == DefaultConnectionContext.ConnectionStatus.Active) { var existing = connection.GetHttpContext(); _logger.ConnectionAlreadyActive(connection.ConnectionId, existing.TraceIdentifier); using (connection.Cancellation) { // Cancel the previous request connection.Cancellation.Cancel(); // Wait for the previous request to drain await connection.TransportTask; _logger.PollCanceled(connection.ConnectionId, existing.TraceIdentifier); } } // Mark the connection as active connection.Status = DefaultConnectionContext.ConnectionStatus.Active; // Raise OnConnected for new connections only since polls happen all the time if (connection.ApplicationTask == null) { _logger.EstablishedConnection(); connection.Metadata[ConnectionMetadataNames.Transport] = TransportType.LongPolling; connection.ApplicationTask = ExecuteApplication(socketDelegate, connection); } else { _logger.ResumingConnection(); } // REVIEW: Performance of this isn't great as this does a bunch of per request allocations connection.Cancellation = new CancellationTokenSource(); var timeoutSource = new CancellationTokenSource(); var tokenSource = CancellationTokenSource.CreateLinkedTokenSource(connection.Cancellation.Token, context.RequestAborted, timeoutSource.Token); // Dispose these tokens when the request is over context.Response.RegisterForDispose(timeoutSource); context.Response.RegisterForDispose(tokenSource); var longPolling = new LongPollingTransport(timeoutSource.Token, connection.Application.Reader, connection.ConnectionId, _loggerFactory); // Start the transport connection.TransportTask = longPolling.ProcessRequestAsync(context, tokenSource.Token); // Start the timeout after we return from creating the transport task timeoutSource.CancelAfter(options.LongPolling.PollTimeout); } finally { connection.Lock.Release(); } var resultTask = await Task.WhenAny(connection.ApplicationTask, connection.TransportTask); var pollAgain = true; // If the application ended before the transport task then we potentially need to end the connection if (resultTask == connection.ApplicationTask) { // Complete the transport (notifying it of the application error if there is one) connection.Transport.Writer.TryComplete(connection.ApplicationTask.Exception); // Wait for the transport to run await connection.TransportTask; // If the status code is a 204 it means the connection is done if (context.Response.StatusCode == StatusCodes.Status204NoContent) { // We should be able to safely dispose because there's no more data being written await _manager.DisposeAndRemoveAsync(connection); // Don't poll again if we've removed the connection completely pollAgain = false; } } else if (context.Response.StatusCode == StatusCodes.Status204NoContent) { // Don't poll if the transport task was cancelled pollAgain = false; } if (pollAgain) { // Otherwise, we update the state to inactive again and wait for the next poll try { await connection.Lock.WaitAsync(); if (connection.Status == DefaultConnectionContext.ConnectionStatus.Active) { // Mark the connection as inactive connection.LastSeenUtc = DateTime.UtcNow; connection.Status = DefaultConnectionContext.ConnectionStatus.Inactive; connection.SetHttpContext(null); // Dispose the cancellation token connection.Cancellation.Dispose(); connection.Cancellation = null; } } finally { connection.Lock.Release(); } } } }
public async Task ExecuteAsync(HttpContext context, HttpSocketOptions options, SocketDelegate socketDelegate) { // Create the log scope and attempt to pass the Connection ID to it so as many logs as possible contain // the Connection ID metadata. If this is the negotiate request then the Connection ID for the scope will // be set a little later. var logScope = new ConnectionLogScope(GetConnectionId(context)); using (_logger.BeginScope(logScope)) { if (!await AuthorizeHelper.AuthorizeAsync(context, options.AuthorizationData)) { return; } if (HttpMethods.IsPost(context.Request.Method)) { // POST /{path} await ProcessSend(context); } else if (HttpMethods.IsGet(context.Request.Method)) { // GET /{path} await ExecuteEndpointAsync(context, socketDelegate, options, logScope); } else { context.Response.ContentType = "text/plain"; context.Response.StatusCode = StatusCodes.Status405MethodNotAllowed; } } }