protected SocketChannelAsyncOperation PrepareWriteOperation(ArraySegment <byte> buffer) { SocketChannelAsyncOperation operation = this.WriteOperation; operation.SetBuffer(buffer.Array, buffer.Offset, buffer.Count); return(operation); }
protected SocketChannelAsyncOperation PrepareWriteOperation(IList <ArraySegment <byte> > buffers) { SocketChannelAsyncOperation operation = this.WriteOperation; operation.BufferList = buffers; return(operation); }
protected override void ScheduleSocketRead() { SocketChannelAsyncOperation operation = this.ReadOperation; bool pending; #if NETSTANDARD1_3 pending = this.Socket.ReceiveAsync(operation); #else if (ExecutionContext.IsFlowSuppressed()) { pending = this.Socket.ReceiveAsync(operation); } else { using (ExecutionContext.SuppressFlow()) { pending = this.Socket.ReceiveAsync(operation); } } #endif if (!pending) { // todo: potential allocation / non-static field? this.EventLoop.Execute(ReadCompletedSyncCallback, this.Unsafe, operation); } }
protected override void DoClose() { TaskCompletionSource promise = this.connectPromise; if (promise != null) { // Use TrySetException() instead of SetException() to avoid the race against cancellation due to timeout. promise.TrySetException(new ClosedChannelException()); this.connectPromise = null; } IScheduledTask cancellationTask = this.connectCancellationTask; if (cancellationTask != null) { cancellationTask.Cancel(); this.connectCancellationTask = null; } SocketChannelAsyncOperation readOp = this.readOperation; if (readOp != null) { readOp.Dispose(); this.readOperation = null; } SocketChannelAsyncOperation writeOp = this.writeOperation; if (writeOp != null) { writeOp.Dispose(); this.writeOperation = null; } }
protected override bool DoConnect(EndPoint remoteAddress, EndPoint localAddress) { if (localAddress != null) { this.Socket.Bind(localAddress); } bool success = false; try { var eventPayload = new SocketChannelAsyncOperation(this, false); eventPayload.RemoteEndPoint = remoteAddress; bool connected = !this.Socket.ConnectAsync(eventPayload); success = true; return(connected); } finally { if (!success) { this.DoClose(); } } }
protected override void ScheduleMessageWrite(object message) { if (!(message is IAddressedEnvelope <IByteBuffer> envelope)) { throw new InvalidOperationException( $"Unexpected type: {message.GetType().FullName}, expecting DatagramPacket or IAddressedEnvelope."); } IByteBuffer data = envelope.Content; int length = data.ReadableBytes; if (length == 0) { return; } SocketChannelAsyncOperation operation = this.PrepareWriteOperation(data.GetIoBuffer(data.ReaderIndex, length)); operation.RemoteEndPoint = envelope.Recipient; this.SetState(StateFlags.WriteScheduled); bool pending = this.Socket.SendToAsync(operation); if (!pending) { ((ISocketChannelUnsafe)this.Unsafe).FinishWrite(operation); } }
public void FinishWrite(SocketChannelAsyncOperation operation) { bool resetWritePending = this.Channel.TryResetState(StateFlags.WriteScheduled); Contract.Assert(resetWritePending); ChannelOutboundBuffer input = this.OutboundBuffer; try { operation.Validate(); int sent = operation.BytesTransferred; this.Channel.ResetWriteOperation(); if (sent > 0) { input.RemoveBytes(sent); } } catch (Exception ex) { Util.CompleteChannelCloseTaskSafely(this.channel, this.CloseAsync(new ClosedChannelException("Failed to write", ex), false)); } // Double check if there's no pending flush // See https://github.com/Azure/DotNetty/issues/218 this.Flush0(); // todo: does it make sense now that we've actually written out everything that was flushed previously? concurrent flush handling? }
public void FinishConnect(SocketChannelAsyncOperation operation) { Contract.Assert(this.channel.EventLoop.InEventLoop); AbstractSocketChannel ch = this.Channel; try { bool wasActive = ch.Active; ch.DoFinishConnect(operation); this.FulfillConnectPromise(wasActive); } catch (Exception ex) { TaskCompletionSource promise = ch.connectPromise; var remoteAddress = (EndPoint)promise?.Task.AsyncState; this.FulfillConnectPromise(this.AnnotateConnectException(ex, remoteAddress)); } finally { // Check for null as the connectTimeoutFuture is only created if a connectTimeoutMillis > 0 is used // See https://github.com/netty/netty/issues/1770 ch.connectCancellationTask?.Cancel(); ch.connectPromise = null; } }
protected override void DoFinishConnect(SocketChannelAsyncOperation operation) { try { operation.Validate(); } finally { operation.Dispose(); } this.OnConnected(); }
protected void ResetWriteOperation() { SocketChannelAsyncOperation operation = this.writeOperation; Contract.Assert(operation != null); if (operation.BufferList == null) { operation.SetBuffer(null, 0, 0); } else { operation.BufferList = null; } }
protected override void ScheduleSocketRead() { bool closed = false; SocketChannelAsyncOperation operation = this.AcceptOperation; while (!closed) { try { bool pending = this.Socket.AcceptAsync(operation); if (!pending) { this.EventLoop.Execute(ReadCompletedSyncCallback, this.Unsafe, operation); } return; } catch (SocketException ex) when(ex.SocketErrorCode == SocketError.OperationAborted || ex.SocketErrorCode == SocketError.InvalidArgument) { closed = true; } catch (SocketException ex) { // socket exceptions here are internal to channel's operation and should not go through the pipeline // especially as they have no effect on overall channel's operation Logger.Info("Exception on accept.", ex); } catch (ObjectDisposedException) { closed = true; } catch (Exception ex) { this.Pipeline.FireExceptionCaught(ex); closed = true; } } if (closed && this.Open) { this.Unsafe.CloseSafe(); } }
protected bool IncompleteWrite(bool scheduleAsync, SocketChannelAsyncOperation operation) { // Did not write completely. if (scheduleAsync) { this.SetState(StateFlags.WriteScheduled); bool pending; #if NETSTANDARD1_3 pending = this.Socket.SendAsync(operation); #else if (ExecutionContext.IsFlowSuppressed()) { pending = this.Socket.SendAsync(operation); } else { using (ExecutionContext.SuppressFlow()) { pending = this.Socket.SendAsync(operation); } } #endif if (!pending) { ((ISocketChannelUnsafe)this.Unsafe).FinishWrite(operation); } return(pending); } else { // Schedule flush again later so other tasks can be picked up input the meantime this.EventLoop.Execute(FlushAction, this); return(true); } }
protected override void ScheduleSocketRead() { SocketChannelAsyncOperation operation = this.ReadOperation; operation.RemoteEndPoint = this.anyRemoteEndPoint; IRecvByteBufAllocatorHandle handle = this.Unsafe.RecvBufAllocHandle; IByteBuffer buffer = handle.Allocate(this.config.Allocator); handle.AttemptedBytesRead = buffer.WritableBytes; operation.UserToken = buffer; ArraySegment <byte> bytes = buffer.GetIoBuffer(0, buffer.WritableBytes); operation.SetBuffer(bytes.Array, bytes.Offset, bytes.Count); bool pending; #if NETSTANDARD1_3 pending = this.Socket.ReceiveFromAsync(operation); #else if (ExecutionContext.IsFlowSuppressed()) { pending = this.Socket.ReceiveFromAsync(operation); } else { using (ExecutionContext.SuppressFlow()) { pending = this.Socket.ReceiveFromAsync(operation); } } #endif if (!pending) { this.EventLoop.Execute(ReceiveFromCompletedSyncCallback, this.Unsafe, operation); } }
protected override int DoReadMessages(List <object> buf) { Contract.Requires(buf != null); SocketChannelAsyncOperation operation = this.ReadOperation; var data = (IByteBuffer)operation.UserToken; bool free = true; try { IRecvByteBufAllocatorHandle handle = this.Unsafe.RecvBufAllocHandle; int received = operation.BytesTransferred; if (received <= 0) { return(0); } handle.LastBytesRead = received; data.SetWriterIndex(data.WriterIndex + received); EndPoint remoteAddress = operation.RemoteEndPoint; buf.Add(new DatagramPacket(data, remoteAddress, this.LocalAddress)); free = false; return(1); } finally { if (free) { data.Release(); } operation.UserToken = null; } }
public override void FinishRead(SocketChannelAsyncOperation operation) { Contract.Assert(this.channel.EventLoop.InEventLoop); TcpServerSocketChannel ch = this.Channel; if ((ch.ResetState(StateFlags.ReadScheduled) & StateFlags.Active) == 0) { return; // read was signaled as a result of channel closure } IChannelConfiguration config = ch.Configuration; IChannelPipeline pipeline = ch.Pipeline; IRecvByteBufAllocatorHandle allocHandle = this.Channel.Unsafe.RecvBufAllocHandle; allocHandle.Reset(config); bool closed = false; Exception exception = null; try { Socket connectedSocket = null; try { connectedSocket = operation.AcceptSocket; operation.AcceptSocket = null; operation.Validate(); var message = this.PrepareChannel(connectedSocket); connectedSocket = null; ch.ReadPending = false; pipeline.FireChannelRead(message); allocHandle.IncMessagesRead(1); if (!config.AutoRead && !ch.ReadPending) { // ChannelConfig.setAutoRead(false) was called in the meantime. // Completed Accept has to be processed though. return; } while (allocHandle.ContinueReading()) { connectedSocket = ch.Socket.Accept(); message = this.PrepareChannel(connectedSocket); connectedSocket = null; ch.ReadPending = false; pipeline.FireChannelRead(message); allocHandle.IncMessagesRead(1); } } catch (SocketException ex) when(ex.SocketErrorCode == SocketError.OperationAborted || ex.SocketErrorCode == SocketError.InvalidArgument) { closed = true; } catch (SocketException ex) when(ex.SocketErrorCode == SocketError.WouldBlock) { } catch (SocketException ex) { // socket exceptions here are internal to channel's operation and should not go through the pipeline // especially as they have no effect on overall channel's operation Logger.Info("Exception on accept.", ex); } catch (ObjectDisposedException) { closed = true; } catch (Exception ex) { exception = ex; } allocHandle.ReadComplete(); pipeline.FireChannelReadComplete(); if (exception != null) { // ServerChannel should not be closed even on SocketException because it can often continue // accepting incoming connections. (e.g. too many open files) pipeline.FireExceptionCaught(exception); } if (closed && ch.Open) { this.CloseSafe(); } } finally { // Check if there is a readPending which was not processed yet. if (!closed && (ch.ReadPending || config.AutoRead)) { ch.DoBeginRead(); } } }
protected override void DoFinishConnect(SocketChannelAsyncOperation operation) { throw new NotSupportedException(); }
public override void FinishRead(SocketChannelAsyncOperation operation) { AbstractSocketByteChannel ch = this.Channel; if ((ch.ResetState(StateFlags.ReadScheduled) & StateFlags.Active) == 0) { return; // read was signaled as a result of channel closure } IChannelConfiguration config = ch.Configuration; IChannelPipeline pipeline = ch.Pipeline; IByteBufferAllocator allocator = config.Allocator; IRecvByteBufAllocatorHandle allocHandle = this.RecvBufAllocHandle; allocHandle.Reset(config); IByteBuffer byteBuf = null; bool close = false; try { operation.Validate(); do { byteBuf = allocHandle.Allocate(allocator); //int writable = byteBuf.WritableBytes; allocHandle.LastBytesRead = ch.DoReadBytes(byteBuf); if (allocHandle.LastBytesRead <= 0) { // nothing was read -> release the buffer. byteBuf.Release(); byteBuf = null; close = allocHandle.LastBytesRead < 0; break; } allocHandle.IncMessagesRead(1); this.Channel.ReadPending = false; pipeline.FireChannelRead(byteBuf); byteBuf = null; }while (allocHandle.ContinueReading()); allocHandle.ReadComplete(); pipeline.FireChannelReadComplete(); if (close) { this.CloseOnRead(); } } catch (Exception t) { this.HandleReadException(pipeline, byteBuf, t, close, allocHandle); } finally { // Check if there is a readPending which was not processed yet. // This could be for two reasons: // /// The user called Channel.read() or ChannelHandlerContext.read() input channelRead(...) method // /// The user called Channel.read() or ChannelHandlerContext.read() input channelReadComplete(...) method // // See https://github.com/netty/netty/issues/2254 if (!close && (ch.ReadPending || config.AutoRead)) { ch.DoBeginRead(); } } }
//protected long doWriteFileRegion(FileRegion region) //{ // long position = region.transfered(); // return region.transferTo(javaChannel(), position); //} protected override void DoWrite(ChannelOutboundBuffer input) { List <ArraySegment <byte> > sharedBufferList = null; try { while (true) { int size = input.Size; if (size == 0) { // All written break; } long writtenBytes = 0; bool done = false; // Ensure the pending writes are made of ByteBufs only. int maxBytesPerGatheringWrite = ((TcpSocketChannelConfig)this.config).GetMaxBytesPerGatheringWrite(); sharedBufferList = input.GetSharedBufferList(1024, maxBytesPerGatheringWrite); int nioBufferCnt = sharedBufferList.Count; long expectedWrittenBytes = input.NioBufferSize; Socket socket = this.Socket; List <ArraySegment <byte> > bufferList = sharedBufferList; // Always us nioBuffers() to workaround data-corruption. // See https://github.com/netty/netty/issues/2761 switch (nioBufferCnt) { case 0: // We have something else beside ByteBuffers to write so fallback to normal writes. base.DoWrite(input); return; default: for (int i = this.Configuration.WriteSpinCount - 1; i >= 0; i--) { long localWrittenBytes = socket.Send(bufferList, SocketFlags.None, out SocketError errorCode); if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock) { throw new SocketException((int)errorCode); } if (localWrittenBytes == 0) { break; } expectedWrittenBytes -= localWrittenBytes; writtenBytes += localWrittenBytes; if (expectedWrittenBytes == 0) { done = true; break; } else { bufferList = this.AdjustBufferList(localWrittenBytes, bufferList); } } break; } if (writtenBytes > 0) { // Release the fully written buffers, and update the indexes of the partially written buffer. input.RemoveBytes(writtenBytes); } if (!done) { SocketChannelAsyncOperation asyncOperation = this.PrepareWriteOperation(bufferList); // Did not write all buffers completely. if (this.IncompleteWrite(true, asyncOperation)) { break; } } } } finally { sharedBufferList?.Clear(); } }
public override void FinishRead(SocketChannelAsyncOperation operation) { Contract.Assert(this.channel.EventLoop.InEventLoop); AbstractSocketMessageChannel ch = this.Channel; if ((ch.ResetState(StateFlags.ReadScheduled) & StateFlags.Active) == 0) { return; // read was signaled as a result of channel closure } IChannelConfiguration config = ch.Configuration; IChannelPipeline pipeline = ch.Pipeline; IRecvByteBufAllocatorHandle allocHandle = this.Channel.Unsafe.RecvBufAllocHandle; allocHandle.Reset(config); bool closed = false; Exception exception = null; try { try { do { int localRead = ch.DoReadMessages(this.readBuf); if (localRead == 0) { break; } if (localRead < 0) { closed = true; break; } allocHandle.IncMessagesRead(localRead); }while (allocHandle.ContinueReading()); } catch (Exception t) { exception = t; } int size = this.readBuf.Count; for (int i = 0; i < size; i++) { ch.ReadPending = false; pipeline.FireChannelRead(this.readBuf[i]); } this.readBuf.Clear(); allocHandle.ReadComplete(); pipeline.FireChannelReadComplete(); if (exception != null) { if (exception is SocketException asSocketException && asSocketException.SocketErrorCode != SocketError.TryAgain) // todo: other conditions for not closing message-based socket? { // ServerChannel should not be closed even on SocketException because it can often continue // accepting incoming connections. (e.g. too many open files) closed = !(ch is IServerChannel); } pipeline.FireExceptionCaught(exception); } if (closed) { if (ch.Open) { this.CloseSafe(); } } } finally { // Check if there is a readPending which was not processed yet. // This could be for two reasons: // /// The user called Channel.read() or ChannelHandlerContext.read() in channelRead(...) method // /// The user called Channel.read() or ChannelHandlerContext.read() in channelReadComplete(...) method // // See https://github.com/netty/netty/issues/2254 if (!closed && (ch.ReadPending || config.AutoRead)) { ch.DoBeginRead(); } } }
/// <summary> /// Finish the connect /// </summary> protected abstract void DoFinishConnect(SocketChannelAsyncOperation operation);
public abstract void FinishRead(SocketChannelAsyncOperation operation);