/// <summary> /// Finish the connect /// </summary> protected abstract void DoFinishConnect(SocketChannelAsyncOperation 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(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; } }
public abstract void FinishRead(SocketChannelAsyncOperation operation);
public void FinishWrite(SocketChannelAsyncOperation operation) { bool resetWritePending = this.Channel.ResetState(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) { input.FailFlushed(ex, true); throw; } // directly call base.Flush0() to force a flush now base.Flush0(); // todo: does it make sense now that we've actually written out everything that was flushed previously? concurrent flush handling? }
public override void FinishRead(SocketChannelAsyncOperation operation) { Contract.Requires(this.channel.EventLoop.InEventLoop); AbstractSocketMessageChannel ch = this.Channel; ch.ResetState(StateFlags.ReadScheduled); IChannelConfiguration config = ch.Configuration; if (!ch.ReadPending && !config.AutoRead) { // ChannelConfig.setAutoRead(false) was called in the meantime //removeReadOp(); -- noop with IOCP, just don't schedule receive again return; } int maxMessagesPerRead = config.MaxMessagesPerRead; IChannelPipeline pipeline = ch.Pipeline; bool closed = false; Exception exception = null; try { try { while (true) { int localRead = ch.DoReadMessages(this.readBuf); if (localRead == 0) { break; } if (localRead < 0) { closed = true; break; } // stop reading and remove op if (!config.AutoRead) { break; } if (this.readBuf.Count >= maxMessagesPerRead) { break; } } } catch (Exception t) { exception = t; } ch.ReadPending = false; int size = this.readBuf.Count; for (int i = 0; i < size; i++) { pipeline.FireChannelRead(this.readBuf[i]); } this.readBuf.Clear(); pipeline.FireChannelReadComplete(); if (exception != null) { var asSocketException = exception as SocketException; if (asSocketException != null && 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.CloseAsync(); } } } 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(); } } }
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 SocketChannelAsyncOperation PrepareWriteOperation(IByteBuffer buffer) { SocketChannelAsyncOperation operation = this.writeOperation ?? (this.writeOperation = new SocketChannelAsyncOperation(this, false)); if (!buffer.HasArray) { throw new NotImplementedException("IByteBuffer implementations not backed by array are currently not supported."); } operation.SetBuffer(buffer.Array, buffer.ArrayOffset + buffer.WriterIndex, buffer.WritableBytes); return operation; }
protected override void DoFinishConnect(SocketChannelAsyncOperation operation) { throw new NotSupportedException(); }
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 DoFinishConnect(SocketChannelAsyncOperation operation) { try { operation.Validate(); } finally { operation.Dispose(); } this.OnConnected(); }
protected override void DoFinishConnect(SocketChannelAsyncOperation operation) { try { operation.Validate(); } finally { operation.RemoteEndPoint = null; // cleanup after connect operation.Dispose(); } }
public void FinishConnect(SocketChannelAsyncOperation operation) { // Note this method is invoked by the event loop only if the connection attempt was // neither cancelled nor timed out. Contract.Assert(this.channel.EventLoop.InEventLoop); AbstractSocketChannel ch = this.Channel; try { bool wasActive = !ch.ResetState(StateFlags.ActivationPending); ch.DoFinishConnect(operation); this.FulfillConnectPromise(wasActive); } catch (Exception ex) { TaskCompletionSource promise = ch.connectPromise; EndPoint remoteAddress = promise == null ? null : (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 if (ch.connectCancellation != null) { ch.connectCancellation.Cancel(); } ch.connectPromise = null; } }
public override void FinishRead(SocketChannelAsyncOperation operation) { Contract.Requires(this.channel.EventLoop.InEventLoop); TcpServerSocketChannel ch = this.Channel; ch.ResetState(StateFlags.ReadScheduled); IChannelConfiguration config = ch.Configuration; int maxMessagesPerRead = config.MaxMessagesPerRead; IChannelPipeline pipeline = ch.Pipeline; bool closed = false; Exception exception = null; int messageCount = 0; try { Socket connectedSocket = null; try { connectedSocket = operation.AcceptSocket; operation.Validate(); operation.AcceptSocket = null; var message = new TcpSocketChannel(ch, connectedSocket, true); ch.ReadPending = false; pipeline.FireChannelRead(message); messageCount++; if (!config.AutoRead && !ch.ReadPending) { // ChannelConfig.setAutoRead(false) was called in the meantime. // Completed Accept has to be processed though. return; } while (messageCount < maxMessagesPerRead) { connectedSocket = null; connectedSocket = ch.Socket.Accept(); message = new TcpSocketChannel(ch, connectedSocket, true); pipeline.FireChannelRead(message); // stop reading and remove op if (!config.AutoRead) { break; } messageCount++; } } catch (ObjectDisposedException) { closed = true; } catch (Exception ex) { var asSocketException = ex as SocketException; if (asSocketException == null || asSocketException.SocketErrorCode != SocketError.WouldBlock) { Logger.Warn("Failed to create a new channel from an accepted socket.", ex); if (connectedSocket != null) { try { connectedSocket.Close(); } catch (Exception ex2) { Logger.Warn("Failed to close a socket.", ex2); } } exception = ex; } } 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) { if (ch.Open) { this.CloseAsync(); } } } finally { // Check if there is a readPending which was not processed yet. if (!closed && (config.AutoRead || ch.ReadPending)) { ch.DoBeginRead(); } } }
protected void IncompleteWrite(bool scheduleAsync, SocketChannelAsyncOperation operation) { // Did not write completely. if (scheduleAsync) { this.SetState(StateFlags.WriteScheduled); bool pending; if (ExecutionContext.IsFlowSuppressed()) { pending = this.Socket.SendAsync(operation); } else { using (ExecutionContext.SuppressFlow()) { pending = this.Socket.SendAsync(operation); } } if (!pending) { ((ISocketChannelUnsafe)this.Unsafe).FinishWrite(operation); } } else { // Schedule flush again later so other tasks can be picked up input the meantime this.EventLoop.Execute(FlushAction, this); } }
public void FinishWrite(SocketChannelAsyncOperation operation) { ChannelOutboundBuffer input = this.OutboundBuffer; try { operation.Validate(); int sent = operation.BytesTransferred; this.Channel.ResetWriteOperation(); if (sent > 0) { object msg = input.Current; var buffer = msg as IByteBuffer; if (buffer != null) { buffer.SetWriterIndex(buffer.WriterIndex + sent); } // todo: FileRegion support } } catch (Exception ex) { input.FailFlushed(ex, true); throw; } // directly call super.flush0() to force a flush now base.Flush0(); }
public override void FinishRead(SocketChannelAsyncOperation operation) { AbstractSocketByteChannel ch = this.Channel; ch.ResetState(StateFlags.ReadScheduled); IChannelConfiguration config = ch.Configuration; if (!config.AutoRead && !ch.ReadPending) { // ChannelConfig.setAutoRead(false) was called in the meantime //removeReadOp(); -- noop with IOCP, just don't schedule receive again return; } IChannelPipeline pipeline = ch.Pipeline; IByteBufferAllocator allocator = config.Allocator; int maxMessagesPerRead = config.MaxMessagesPerRead; IRecvByteBufAllocatorHandle allocHandle = this.RecvBufAllocHandle; IByteBuffer byteBuf = null; int messages = 0; bool close = false; try { operation.Validate(); int totalReadAmount = 0; bool readPendingReset = false; do { byteBuf = allocHandle.Allocate(allocator); int writable = byteBuf.WritableBytes; int localReadAmount = ch.DoReadBytes(byteBuf); if (localReadAmount <= 0) { // not was read release the buffer byteBuf.Release(); byteBuf = null; close = localReadAmount < 0; break; } if (!readPendingReset) { readPendingReset = true; ch.ReadPending = false; } pipeline.FireChannelRead(byteBuf); byteBuf = null; if (totalReadAmount >= int.MaxValue - localReadAmount) { // Avoid overflow. totalReadAmount = int.MaxValue; break; } totalReadAmount += localReadAmount; // stop reading if (!config.AutoRead) { break; } if (localReadAmount < writable) { // Read less than what the buffer can hold, // which might mean we drained the recv buffer completely. break; } } while (++messages < maxMessagesPerRead); pipeline.FireChannelReadComplete(); allocHandle.Record(totalReadAmount); if (close) { this.CloseOnRead(); close = false; } } catch (Exception t) { this.HandleReadException(pipeline, byteBuf, t, close); } 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 && (config.AutoRead || ch.ReadPending)) { ch.DoBeginRead(); } } }
public override void FinishRead(SocketChannelAsyncOperation operation) { AbstractSocketByteChannel ch = this.Channel; ch.ResetState(StateFlags.ReadScheduled); 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(); } } }