@Override protected void doFlushMessageBuffer(Queue<Object> buf) throws Exception { if (state < 2) { throw new NotYetConnectedException(); } if (state > 2) { throw new ClosedChannelException(); } final LocalChannel peer = this.peer; assert peer != null; Queue<Object> out = peer.pipeline().inboundMessageBuffer(); for (; ; ) { Object msg = buf.poll(); if (msg == null) { break; } out.add(msg); } peer.eventLoop() .execute( new Runnable() { @Override public void run() { peer.pipeline().fireInboundBufferUpdated(); } }); }
@Override protected void doClose() throws Exception { if (state > 2) { // Closed already return; } if (parent() == null) { LocalChannelRegistry.unregister(localAddress); } localAddress = null; state = 3; if (peer.isActive()) { peer.unsafe().close(peer.unsafe().voidFuture()); peer = null; } }
@Override protected void doWrite(ChannelOutboundBuffer in) throws Exception { switch (state) { case OPEN: case BOUND: throw new NotYetConnectedException(); case CLOSED: throw new ClosedChannelException(); } final LocalChannel peer = this.peer; final ChannelPipeline peerPipeline = peer.pipeline(); final EventLoop peerLoop = peer.eventLoop(); if (peerLoop == eventLoop()) { for (; ; ) { Object msg = in.current(); if (msg == null) { break; } peer.inboundBuffer.add(msg); ReferenceCountUtil.retain(msg); in.remove(); } finishPeerRead(peer, peerPipeline); } else { // Use a copy because the original msgs will be recycled by AbstractChannel. final Object[] msgsCopy = new Object[in.size()]; for (int i = 0; i < msgsCopy.length; i++) { msgsCopy[i] = ReferenceCountUtil.retain(in.current()); in.remove(); } peerLoop.execute( new Runnable() { @Override public void run() { Collections.addAll(peer.inboundBuffer, msgsCopy); finishPeerRead(peer, peerPipeline); } }); } }
@Override protected void doRegister() throws Exception { // Check if both peer and parent are non-null because this channel was created by a // LocalServerChannel. // This is needed as a peer may not be null also if a LocalChannel was connected before and // deregistered / registered later again. // // See https://github.com/netty/netty/issues/2400 if (peer != null && parent() != null) { // Store the peer in a local variable as it may be set to null if doClose() is called. // Because of this we also set registerInProgress to true as we check for this in doClose() // and make sure // we delay the fireChannelInactive() to be fired after the fireChannelActive() and so keep // the correct // order of events. // // See https://github.com/netty/netty/issues/2144 final LocalChannel peer = this.peer; registerInProgress = true; state = State.CONNECTED; peer.remoteAddress = parent() == null ? null : parent().localAddress(); peer.state = State.CONNECTED; // Always call peer.eventLoop().execute() even if peer.eventLoop().inEventLoop() is true. // This ensures that if both channels are on the same event loop, the peer's channelActive // event is triggered *after* this channel's channelRegistered event, so that this channel's // pipeline is fully initialized by ChannelInitializer before any channelRead events. peer.eventLoop() .execute( new Runnable() { @Override public void run() { registerInProgress = false; peer.pipeline().fireChannelActive(); peer.connectPromise.setSuccess(); } }); } ((SingleThreadEventExecutor) eventLoop()).addShutdownHook(shutdownHook); }
private static void finishPeerRead(LocalChannel peer, ChannelPipeline peerPipeline) { if (peer.readInProgress) { peer.readInProgress = false; for (; ; ) { Object received = peer.inboundBuffer.poll(); if (received == null) { break; } peerPipeline.fireChannelRead(received); } peerPipeline.fireChannelReadComplete(); } }
@Override protected void doClose() throws Exception { if (state != State.CLOSED) { // Update all internal state before the closeFuture is notified. if (localAddress != null) { if (parent() == null) { LocalChannelRegistry.unregister(localAddress); } localAddress = null; } state = State.CLOSED; } final LocalChannel peer = this.peer; if (peer != null && peer.isActive()) { // Need to execute the close in the correct EventLoop // See https://github.com/netty/netty/issues/1777 EventLoop eventLoop = peer.eventLoop(); // Also check if the registration was not done yet. In this case we submit the close to the // EventLoop // to make sure it is run after the registration completes. // // See https://github.com/netty/netty/issues/2144 if (eventLoop.inEventLoop() && !registerInProgress) { peer.unsafe().close(unsafe().voidPromise()); } else { peer.eventLoop() .execute( new Runnable() { @Override public void run() { peer.unsafe().close(unsafe().voidPromise()); } }); } this.peer = null; } }
@Override protected Runnable doRegister() throws Exception { final LocalChannel peer = this.peer; Runnable postRegisterTask; if (peer != null) { state = 2; peer.remoteAddress = parent().localAddress(); peer.state = 2; // Ensure the peer's channelActive event is triggered *after* this channel's // channelRegistered event is triggered, so that this channel's pipeline is fully // initialized by ChannelInitializer. final EventLoop peerEventLoop = peer.eventLoop(); postRegisterTask = new Runnable() { @Override public void run() { peerEventLoop.execute( new Runnable() { @Override public void run() { peer.connectFuture.setSuccess(); peer.pipeline().fireChannelActive(); } }); } }; } else { postRegisterTask = null; } ((SingleThreadEventLoop) eventLoop()).addShutdownHook(shutdownHook); return postRegisterTask; }
LocalChannel(LocalServerChannel parent, EventLoop eventLoop, LocalChannel peer) { super(parent, eventLoop); this.peer = peer; localAddress = parent.localAddress(); remoteAddress = peer.localAddress(); }
LocalChannel(LocalServerChannel parent, LocalChannel peer) { super(parent, null); this.peer = peer; localAddress = parent.localAddress(); remoteAddress = peer.localAddress(); }