static void close(OioDatagramChannel channel, ChannelFuture future) { boolean connected = channel.isConnected(); boolean bound = channel.isBound(); try { channel.socket.close(); if (channel.setClosed()) { future.setSuccess(); if (connected) { // Notify the worker so it stops reading. Thread currentThread = Thread.currentThread(); Thread workerThread = channel.workerThread; if (workerThread != null && currentThread != workerThread) { workerThread.interrupt(); } fireChannelDisconnected(channel); } if (bound) { fireChannelUnbound(channel); } fireChannelClosed(channel); } else { future.setSuccess(); } } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } }
/** * Will bind the DatagramSocket to the passed-in address. Every call bind will spawn a new thread * using the that basically in turn */ private void bind( final NioDatagramChannel channel, final ChannelFuture future, final InetSocketAddress address) { boolean bound = false; boolean started = false; try { // First bind the DatagramSocket the specified port. channel.getDatagramChannel().socket().bind(address); bound = true; future.setSuccess(); fireChannelBound(channel, address); channel.worker.register(channel, null); started = true; } catch (final Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } finally { if (!started && bound) { close(channel, future); } } }
private void bind(OioDatagramChannel channel, ChannelFuture future, SocketAddress localAddress) { boolean bound = false; boolean workerStarted = false; try { channel.socket.bind(localAddress); bound = true; // Fire events future.setSuccess(); fireChannelBound(channel, channel.getLocalAddress()); // Start the business. workerExecutor.execute( new IoWorkerRunnable( new ThreadRenamingRunnable( new OioDatagramWorker(channel), "Old I/O datagram worker (channelId: " + channel.getId() + ", " + channel.getLocalAddress() + ')'))); workerStarted = true; } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } finally { if (bound && !workerStarted) { OioDatagramWorker.close(channel, future); } } }
static void close(NioSocketChannel channel, ChannelFuture future) { NioWorker worker = channel.worker; boolean connected = channel.isConnected(); boolean bound = channel.isBound(); try { channel.socket.close(); worker.cancelledKeys++; if (channel.setClosed()) { future.setSuccess(); if (connected) { fireChannelDisconnected(channel); } if (bound) { fireChannelUnbound(channel); } cleanUpWriteBuffer(channel); fireChannelClosed(channel); } else { future.setSuccess(); } } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } }
@Override public void run(Timeout timeout) throws Exception { if (timeout.isCancelled()) { return; } if (!ctx.getChannel().isOpen()) { return; } State state = (State) ctx.getAttachment(); long currentTime = System.currentTimeMillis(); long nextDelay = timeoutMillis - (currentTime - state.lastReadTime); if (nextDelay <= 0) { // Read timed out - set a new timeout and notify the callback. state.timeout = timer.newTimeout(this, timeoutMillis, TimeUnit.MILLISECONDS); try { // FIXME This should be called from an I/O thread. // To be fixed in Netty 4. readTimedOut(ctx); } catch (Throwable t) { fireExceptionCaught(ctx, t); } } else { // Read occurred before the timeout - set a new timeout with shorter delay. state.timeout = timer.newTimeout(this, nextDelay, TimeUnit.MILLISECONDS); } }
static void write( OioDatagramChannel channel, ChannelFuture future, Object message, SocketAddress remoteAddress) { try { ChannelBuffer buf = (ChannelBuffer) message; int length = buf.readableBytes(); ByteBuffer nioBuf = buf.toByteBuffer(); DatagramPacket packet; if (nioBuf.hasArray()) { // Avoid copy if the buffer is backed by an array. packet = new DatagramPacket(nioBuf.array(), nioBuf.arrayOffset(), length); } else { // Otherwise it will be expensive. byte[] arrayBuf = new byte[length]; buf.getBytes(0, arrayBuf); packet = new DatagramPacket(arrayBuf, length); } if (remoteAddress != null) { packet.setSocketAddress(remoteAddress); } channel.socket.send(packet); fireWriteComplete(channel, length); future.setSuccess(); } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } }
private void connect( OioDatagramChannel channel, ChannelFuture future, SocketAddress remoteAddress) { boolean bound = channel.isBound(); boolean connected = false; boolean workerStarted = false; future.addListener(ChannelFutureListener.CLOSE_ON_FAILURE); // Clear the cached address so that the next getRemoteAddress() call // updates the cache. channel.remoteAddress = null; try { channel.socket.connect(remoteAddress); connected = true; // Fire events. future.setSuccess(); if (!bound) { fireChannelBound(channel, channel.getLocalAddress()); } fireChannelConnected(channel, channel.getRemoteAddress()); String threadName = "Old I/O datagram worker (channelId: " + channel.getId() + ", " + channel.getLocalAddress() + " => " + channel.getRemoteAddress() + ')'; if (!bound) { // Start the business. workerExecutor.execute( new IoWorkerRunnable( new ThreadRenamingRunnable(new OioDatagramWorker(channel), threadName))); } else { // Worker started by bind() - just rename. Thread workerThread = channel.workerThread; if (workerThread != null) { try { workerThread.setName(threadName); } catch (SecurityException e) { // Ignore. } } } workerStarted = true; } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } finally { if (connected && !workerStarted) { OioDatagramWorker.close(channel, future); } } }
@Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { HttpChildChannel httpChildChannel = this.httpChildChannel; if (httpChildChannel != null) { this.httpChildChannel = null; switch (httpChildChannel.readState()) { case UPGRADED: if (httpChildChannel.setReadClosed()) { fireChannelDisconnected(httpChildChannel); fireChannelUnbound(httpChildChannel); fireChannelClosed(httpChildChannel); } break; case CONTENT_COMPLETE: break; default: ChannelException exception = new ChannelException("Channel closed unexpectedly"); exception.fillInStackTrace(); fireExceptionCaught(httpChildChannel, exception); break; } switch (httpChildChannel.writeState()) { case UPGRADED: case CONTENT_CLOSE: if (httpChildChannel.setWriteClosed()) { fireChannelDisconnected(httpChildChannel); fireChannelUnbound(httpChildChannel); fireChannelClosed(httpChildChannel); } break; case CONTENT_COMPLETE: break; default: ChannelException exception = new ChannelException("Channel closed unexpectedly"); exception.fillInStackTrace(); fireExceptionCaught(httpChildChannel, exception); break; } } }
@Override protected boolean read(SelectionKey k) { final SocketChannel ch = (SocketChannel) k.channel(); final NioSocketChannel channel = (NioSocketChannel) k.attachment(); final ReceiveBufferSizePredictor predictor = channel.getConfig().getReceiveBufferSizePredictor(); final int predictedRecvBufSize = predictor.nextReceiveBufferSize(); int ret = 0; int readBytes = 0; boolean failure = true; ByteBuffer bb = recvBufferPool.acquire(predictedRecvBufSize); try { while ((ret = ch.read(bb)) > 0) { readBytes += ret; if (!bb.hasRemaining()) { break; } } failure = false; } catch (ClosedChannelException e) { // Can happen, and does not need a user attention. } catch (Throwable t) { fireExceptionCaught(channel, t); } if (readBytes > 0) { bb.flip(); final ChannelBufferFactory bufferFactory = channel.getConfig().getBufferFactory(); final ChannelBuffer buffer = bufferFactory.getBuffer(readBytes); buffer.setBytes(0, bb); buffer.writerIndex(readBytes); recvBufferPool.release(bb); // Update the predictor. predictor.previousReceiveBufferSize(readBytes); // Fire the event. fireMessageReceived(channel, buffer); } else { recvBufferPool.release(bb); } if (ret < 0 || failure) { k.cancel(); // Some JDK implementations run into an infinite loop without this. close(channel, succeededFuture(channel)); return false; } return true; }
@Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (e.getMessage() instanceof List) { @SuppressWarnings("unchecked") List<OFMessage> msglist = (List<OFMessage>) e.getMessage(); for (OFMessage ofm : msglist) { try { // Do the actual packet processing state.processOFMessage(ofm); } catch (Exception ex) { // We are the last handler in the stream, so run the // exception through the channel again by passing in // ctx.getChannel(). Channels.fireExceptionCaught(ctx.getChannel(), ex); } } } else { Channels.fireExceptionCaught( ctx.getChannel(), new AssertionError("Message received from channel is not a list")); } }
public void run() { channel.workerThread = Thread.currentThread(); final MulticastSocket socket = channel.socket; while (channel.isOpen()) { synchronized (channel.interestOpsLock) { while (!channel.isReadable()) { try { // notify() is not called at all. // close() and setInterestOps() calls Thread.interrupt() channel.interestOpsLock.wait(); } catch (InterruptedException e) { if (!channel.isOpen()) { break; } } } } ReceiveBufferSizePredictor predictor = channel.getConfig().getReceiveBufferSizePredictor(); byte[] buf = new byte[predictor.nextReceiveBufferSize()]; DatagramPacket packet = new DatagramPacket(buf, buf.length); try { socket.receive(packet); } catch (InterruptedIOException e) { // Can happen on interruption. // Keep receiving unless the channel is closed. continue; } catch (Throwable t) { if (!channel.socket.isClosed()) { fireExceptionCaught(channel, t); } break; } fireMessageReceived( channel, channel.getConfig().getBufferFactory().getBuffer(buf, 0, packet.getLength()), packet.getSocketAddress()); } // Setting the workerThread to null will prevent any channel // operations from interrupting this thread from now on. channel.workerThread = null; // Clean up. close(channel, succeededFuture(channel)); }
private static void cleanUpWriteBuffer(NioSocketChannel channel) { Exception cause = null; boolean fireExceptionCaught = false; // Clean up the stale messages in the write buffer. synchronized (channel.writeLock) { MessageEvent evt = channel.currentWriteEvent; if (evt != null) { channel.currentWriteEvent = null; channel.currentWriteIndex = 0; // Create the exception only once to avoid the excessive overhead // caused by fillStackTrace. if (channel.isOpen()) { cause = new NotYetConnectedException(); } else { cause = new ClosedChannelException(); } evt.getFuture().setFailure(cause); fireExceptionCaught = true; } Queue<MessageEvent> writeBuffer = channel.writeBuffer; if (!writeBuffer.isEmpty()) { // Create the exception only once to avoid the excessive overhead // caused by fillStackTrace. if (cause == null) { if (channel.isOpen()) { cause = new NotYetConnectedException(); } else { cause = new ClosedChannelException(); } } for (; ; ) { evt = writeBuffer.poll(); if (evt == null) { break; } evt.getFuture().setFailure(cause); fireExceptionCaught = true; } } } if (fireExceptionCaught) { fireExceptionCaught(channel, cause); } }
@Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { if (httpChildChannel != null) { HttpChildChannel httpChildChannel = this.httpChildChannel; this.httpChildChannel = null; if (httpChildChannel.setReadClosed() || httpChildChannel.setWriteClosed()) { fireExceptionCaught(httpChildChannel, e.getCause()); fireChannelClosed(httpChildChannel); } } Channel channel = ctx.getChannel(); channel.close(); }
private void handleRenegotiation(HandshakeStatus handshakeStatus) { if (handshakeStatus == HandshakeStatus.NOT_HANDSHAKING || handshakeStatus == HandshakeStatus.FINISHED) { // Not handshaking return; } if (!handshaken) { // Not renegotiation return; } final boolean renegotiate; synchronized (handshakeLock) { if (handshaking) { // Renegotiation in progress or failed already. // i.e. Renegotiation check has been done already below. return; } if (engine.isInboundDone() || engine.isOutboundDone()) { // Not handshaking but closing. return; } if (isEnableRenegotiation()) { // Continue renegotiation. renegotiate = true; } else { // Do not renegotiate. renegotiate = false; // Prevent reentrance of this method. handshaking = true; } } if (renegotiate) { // Renegotiate. handshake(); } else { // Raise an exception. fireExceptionCaught( ctx, new SSLException("renegotiation attempted by peer; " + "closing the connection")); // Close the connection to stop renegotiation. Channels.close(ctx, succeededFuture(ctx.getChannel())); } }
private void close(NioDatagramChannel channel, ChannelFuture future) { try { channel.getDatagramChannel().socket().close(); if (channel.setClosed()) { future.setSuccess(); if (channel.isBound()) { fireChannelUnbound(channel); } fireChannelClosed(channel); } else { future.setSuccess(); } } catch (final Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } }
private static boolean read(SelectionKey k) { ScatteringByteChannel ch = (ScatteringByteChannel) k.channel(); NioSocketChannel channel = (NioSocketChannel) k.attachment(); ReceiveBufferSizePredictor predictor = channel.getConfig().getReceiveBufferSizePredictor(); ChannelBufferFactory bufferFactory = channel.getConfig().getBufferFactory(); ChannelBuffer buffer = bufferFactory.getBuffer(predictor.nextReceiveBufferSize()); int ret = 0; int readBytes = 0; boolean failure = true; try { while ((ret = buffer.writeBytes(ch, buffer.writableBytes())) > 0) { readBytes += ret; if (!buffer.writable()) { break; } } failure = false; } catch (AsynchronousCloseException e) { // Can happen, and does not need a user attention. } catch (Throwable t) { fireExceptionCaught(channel, t); } if (readBytes > 0) { // Update the predictor. predictor.previousReceiveBufferSize(readBytes); // Fire the event. fireMessageReceived(channel, buffer); } if (ret < 0 || failure) { close(k); return false; } return true; }
private void connect( NioDatagramChannel channel, ChannelFuture future, SocketAddress remoteAddress) { boolean bound = channel.isBound(); boolean connected = false; boolean workerStarted = false; future.addListener(ChannelFutureListener.CLOSE_ON_FAILURE); // Clear the cached address so that the next getRemoteAddress() call // updates the cache. channel.remoteAddress = null; try { channel.getDatagramChannel().connect(remoteAddress); connected = true; // Fire events. future.setSuccess(); if (!bound) { fireChannelBound(channel, channel.getLocalAddress()); } fireChannelConnected(channel, channel.getRemoteAddress()); if (!bound) { channel.worker.register(channel, future); } workerStarted = true; } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } finally { if (connected && !workerStarted) { channel.worker.close(channel, future); } } }
static void setInterestOps(OioDatagramChannel channel, ChannelFuture future, int interestOps) { // Override OP_WRITE flag - a user cannot change this flag. interestOps &= ~Channel.OP_WRITE; interestOps |= channel.getInterestOps() & Channel.OP_WRITE; boolean changed = false; try { if (channel.getInterestOps() != interestOps) { if ((interestOps & Channel.OP_READ) != 0) { channel.setInterestOpsNow(Channel.OP_READ); } else { channel.setInterestOpsNow(Channel.OP_NONE); } changed = true; } future.setSuccess(); if (changed) { synchronized (channel.interestOpsLock) { channel.setInterestOpsNow(interestOps); // Notify the worker so it stops or continues reading. Thread currentThread = Thread.currentThread(); Thread workerThread = channel.workerThread; if (workerThread != null && currentThread != workerThread) { workerThread.interrupt(); } } fireChannelInterestChanged(channel); } } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } }
static void disconnect(OioDatagramChannel channel, ChannelFuture future) { boolean connected = channel.isConnected(); try { channel.socket.disconnect(); future.setSuccess(); if (connected) { // Update the worker's thread name to reflect the state change. Thread workerThread = channel.workerThread; if (workerThread != null) { try { workerThread.setName("Old I/O datagram worker (" + channel + ')'); } catch (SecurityException e) { // Ignore. } } // Notify. fireChannelDisconnected(channel); } } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } }
static void setInterestOps(NioSocketChannel channel, ChannelFuture future, int interestOps) { boolean changed = false; try { // interestOps can change at any time and at any thread. // Acquire a lock to avoid possible race condition. synchronized (channel.interestOpsLock) { NioWorker worker = channel.worker; Selector selector = worker.selector; SelectionKey key = channel.socket.keyFor(selector); if (key == null || selector == null) { // Not registered to the worker yet. // Set the rawInterestOps immediately; RegisterTask will pick it up. channel.setRawInterestOpsNow(interestOps); return; } // Override OP_WRITE flag - a user cannot change this flag. interestOps &= ~Channel.OP_WRITE; interestOps |= channel.getRawInterestOps() & Channel.OP_WRITE; switch (CONSTRAINT_LEVEL) { case 0: if (channel.getRawInterestOps() != interestOps) { key.interestOps(interestOps); if (Thread.currentThread() != worker.thread && worker.wakenUp.compareAndSet(false, true)) { selector.wakeup(); } changed = true; } break; case 1: case 2: if (channel.getRawInterestOps() != interestOps) { if (Thread.currentThread() == worker.thread) { key.interestOps(interestOps); changed = true; } else { worker.selectorGuard.readLock().lock(); try { if (worker.wakenUp.compareAndSet(false, true)) { selector.wakeup(); } key.interestOps(interestOps); changed = true; } finally { worker.selectorGuard.readLock().unlock(); } } } break; default: throw new Error(); } } future.setSuccess(); if (changed) { channel.setRawInterestOpsNow(interestOps); fireChannelInterestChanged(channel); } } catch (CancelledKeyException e) { // setInterestOps() was called on a closed channel. ClosedChannelException cce = new ClosedChannelException(); future.setFailure(cce); fireExceptionCaught(channel, cce); } catch (Throwable t) { future.setFailure(t); fireExceptionCaught(channel, t); } }
private static void writeNow(NioSocketChannel channel, int writeSpinCount) { boolean open = true; boolean addOpWrite = false; boolean removeOpWrite = false; MessageEvent evt; ChannelBuffer buf; int bufIdx; int writtenBytes = 0; Queue<MessageEvent> writeBuffer = channel.writeBuffer; synchronized (channel.writeLock) { channel.inWriteNowLoop = true; evt = channel.currentWriteEvent; for (; ; ) { if (evt == null) { evt = writeBuffer.poll(); if (evt == null) { channel.currentWriteEvent = null; removeOpWrite = true; break; } evt = consolidateComposite(evt); buf = (ChannelBuffer) evt.getMessage(); bufIdx = buf.readerIndex(); } else { buf = (ChannelBuffer) evt.getMessage(); bufIdx = channel.currentWriteIndex; } try { for (int i = writeSpinCount; i > 0; i--) { int localWrittenBytes = buf.getBytes(bufIdx, channel.socket, buf.writerIndex() - bufIdx); if (localWrittenBytes != 0) { bufIdx += localWrittenBytes; writtenBytes += localWrittenBytes; break; } } if (bufIdx == buf.writerIndex()) { // Successful write - proceed to the next message. channel.currentWriteEvent = null; evt.getFuture().setSuccess(); evt = null; } else { // Not written fully - perhaps the kernel buffer is full. channel.currentWriteEvent = evt; channel.currentWriteIndex = bufIdx; addOpWrite = true; break; } } catch (AsynchronousCloseException e) { // Doesn't need a user attention - ignore. channel.currentWriteEvent = evt; channel.currentWriteIndex = bufIdx; } catch (Throwable t) { channel.currentWriteEvent = null; evt.getFuture().setFailure(t); evt = null; fireExceptionCaught(channel, t); if (t instanceof IOException) { open = false; close(channel, succeededFuture(channel)); } } } channel.inWriteNowLoop = false; } fireWriteComplete(channel, writtenBytes); if (open) { if (addOpWrite) { setOpWrite(channel); } else if (removeOpWrite) { clearOpWrite(channel); } } }
protected void readTimedOut(ChannelHandlerContext ctx) throws Exception { Channels.fireExceptionCaught(ctx, EXCEPTION); }