/// <summary> /// Sends a <see cref="Packet"/> through this channel. /// </summary> /// <param name="packet">The packet to send through the channel.</param> /// <returns>Whether the send was successful or not.</returns> public void Send(Packet packet) { // Check if we are processing if (!this.IsRunning || packet == null) { return; } // Get a context for this send using (var context = ProcessingContext.Acquire(this, this.Encoding)) { try { // Encode the packet, then queue the buffer var buffer = context.OnSend(packet); if (buffer != null) { if (buffer.Length <= 0) { // We have to release the buffer since we are not going to send it and // the packet was already compiled. buffer.TryRelease(); return; } // We don't need to await here, since WriteAsync() will actually copy the buffer // segment into a tail, we can dispose the thing straight away. this.WriteAsync(buffer.AsSegment(), default(CancellationToken)).Forget(); // Release the buffer once we sent the thing buffer.TryRelease(); } } /*catch (CapacityExceededException) * { * Service.Logger.Log(LogLevel.Info, String.Format("{0} disconnected. Too much data pending.", this)); * OnDispose(false); * return; * }*/ #if DEBUG catch (Exception ex) { ex.Log(); return; } #else catch (Exception) { return; } #endif } }
/// <summary> /// Primary loop which consumes socket input, parses it for protocol framing, and invokes the /// application delegate for as long as the socket is intended to remain open. The resulting /// Task from this loop is preserved in a field which is used when the server needs to drain /// and close all currently active connections. /// </summary> public async Task OnReceive() { try { while (!this.ProcessingStopping) { // Update the expires timer this.Expires = Timer.Now + Timeout; this._abortedCts = null; // If _requestAbort is set, the connection has already been closed. if (Volatile.Read(ref _requestAborted) != 0) { return; } // If we're disconnecting, do not process if (this.State == ConnectionState.Disconnecting || this.State == ConnectionState.SocketClosed || this.Decoding == null) { return; } // Book a buffer var incoming = this.DecodingSettings.BufferProvider.Reserve(Constants.ReceiveBufferSize); // Read from the socket incoming.Length = await this.SocketInput.ReadAsync(incoming.Array, incoming.Offset, incoming.Length); // Process whatever we just read using (var context = ProcessingContext.Acquire(this, this.Decoding)) { // Forward to the receive await context.OnReceive(incoming); } } } catch (Exception ex) { // Dig out the inner exception if (ex.InnerException != null) { ex = ex.InnerException; } // If the task was canceled, do not log if (ex is TaskCanceledException) { return; } // Log everything else Service.Logger.Log(ex); //Service.Logger.Log(LogLevel.Warning, "Connection processing ended abnormally. Reason: " + ex.Message); } finally { try { // Reset the task source this._abortedCts = null; // If _requestAborted is set, the connection has already been closed. if (Volatile.Read(ref _requestAborted) == 0) { this.Close(CloseType.SocketShutdown); } // Also dispose this.OnDispose(); } catch (Exception ex) { Service.Logger.Log(ex); //Service.Logger.Log(LogLevel.Warning, "Connection shutdown abnormally. Reason: " + ex.Message)); } } }