/// <summary> /// This method is invoked by the IoCompleted method to process the send completion. /// </summary> private void ProcessSend(long requestId, RequestContext context, int status, uint byteTransferred) { sendStatusQueue.Add(status); if (status != (int)SocketError.Success) { logger.LogError("Socket send operation failed with error {0}", status); context.Data.Release(); return; } var data = context.Data; data.ReaderIndex += (int)byteTransferred; if (data.IsReadable()) { // If some of the bytes in the message have NOT been sent, // then we need to post another send operation. context.Data = data; DoSend(requestId, context); } else { // All the bytes in the data have been sent, // release the buffer back to pool. data.Release(); } }
/// <summary> /// This method is invoked by the IoCompleted method to process the receive completion. /// </summary> private void ProcessReceive(RequestContext context, int status, uint byteTransferred) { context.Data.Status = status; var data = context.Data; data.WriterIndex += (int)byteTransferred; receivedDataQueue.Add(data); if (status != (int) SocketError.Success) { logger.LogError("Socket receive operation failed with error {0}", status); context.Data.Release(); return; } if (status == 0 && byteTransferred == 0) { // The remote has gracefully closed the connection logger.LogDebug("ProcessReceive() with status(0) and byteTransferred(0). The connection has been gracefully closed."); return; } // Posts another receive operation DoReceive(); }
/// <summary> /// Posts a receive operation to this socket /// </summary> private unsafe void DoReceive() { // Make a room from Request Queue of this socket for operation. var errorStatus = AllocateRequest(); if (errorStatus != 0) { logger.LogError("Cannot post receive operation due to no room in Request Queue."); receivedDataQueue.Add(ByteBuf.NewErrorStatusByteBuf(errorStatus)); return; } // Allocate buffer to receive incoming network data. var dataBuffer = ByteBufPool.UnsafeDefault.Allocate(); if (dataBuffer == null) { logger.LogError("Failed to allocate ByteBuf at DoReceive()."); receivedDataQueue.Add(ByteBuf.NewErrorStatusByteBuf((int)SocketError.NoBufferSpaceAvailable)); return; } var context = new RequestContext(SocketOperation.Receive, dataBuffer); var recvId = GenerateUniqueKey(); // Add the operation context to request table for completion callback. while (!requestContexts.TryAdd(recvId, context)) { // Generate another key, if the key is duplicated. recvId = GenerateUniqueKey(); } // Post a receive operation via native method. var rioBuf = dataBuffer.GetInputRioBuf(); if (RioNative.PostRIOReceive(rioRqHandle, &rioBuf, 1, 0, recvId)) return; requestContexts.TryRemove(recvId, out context); context.Data.Release(); if (isCleanedUp) { logger.LogDebug("Socket is already disposed. DoReceive() do nothing."); receivedDataQueue.Add(ByteBuf.NewErrorStatusByteBuf((int)SocketError.NetworkDown)); return; } // Log exception, if post receive operation failed. var socketException = new SocketException(); logger.LogError("Failed to call DoReceive() with error code [{0}], error message: {1}", socketException.ErrorCode, socketException.Message); context.Data.Status = socketException.ErrorCode; receivedDataQueue.Add(context.Data); }
/// <summary> /// Posts a send operation to this socket. /// </summary> private unsafe void DoSend(long sendId, RequestContext context) { // Make a room from Request Queue of this socket for operation. var errorStatus = AllocateRequest(); if ( errorStatus != 0) { logger.LogError("Cannot post send operation due to no room in Request Queue."); sendStatusQueue.Add(errorStatus); return; } // Add the operation context to request table for completion callback. while (!requestContexts.TryAdd(sendId, context)) { // Generate another key, if the key is duplicated. sendId = GenerateUniqueKey(); } // Post a send operation via native method. var rioBuf = context.Data.GetOutputRioBuf(); if (RioNative.PostRIOSend(rioRqHandle, &rioBuf, 1, 0, sendId)) return; requestContexts.TryRemove(sendId, out context); context.Data.Release(); if (isCleanedUp) { logger.LogDebug("Socket is already disposed. PostSend() do nothing."); receivedDataQueue.Add(ByteBuf.NewErrorStatusByteBuf((int)SocketError.NetworkDown)); return; } // Log exception, if post send operation failed. var socketException = new SocketException(); logger.LogError("Failed to call PostRIOSend() with error code [{0}]. Error message: {1}", socketException.ErrorCode, socketException.Message); sendStatusQueue.Add(socketException.ErrorCode); }
/// <summary> /// Sends data to this socket with a ByteBuf object that contains data to be sent. /// </summary> /// <param name="data">A ByteBuf object that contains data to be sent</param> public void Send(ByteBuf data) { EnsureAccessible(); if (!isConnected) { throw new InvalidOperationException("The operation is not allowed on non-connected sockets."); } if (!data.IsReadable()) { throw new ArgumentException("The parameter {0} must contain one or more elements.", "data"); } var context = new RequestContext(SocketOperation.Send, data); DoSend(GenerateUniqueKey(), context); var status = sendStatusQueue.Take(); if (status == (int)SocketError.Success) return; // throw a SocketException if theres is an error. Dispose(true); var socketException = new SocketException(status); throw socketException; }