@Override public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception { long size = calculateSize(msg); long curtime = System.currentTimeMillis(); if (trafficCounter != null) { trafficCounter.bytesRecvFlowControl(size); if (readLimit == 0) { // no action ctx.fireChannelRead(msg); return; } // compute the number of ms to wait before reopening the channel long wait = getTimeToWait( readLimit, trafficCounter.currentReadBytes(), trafficCounter.lastTime(), curtime); if (wait >= MINIMAL_WAIT) { // At least 10ms seems a minimal // time in order to // try to limit the traffic if (!isSuspended(ctx)) { ctx.attr(READ_SUSPENDED).set(true); // Create a Runnable to reactive the read if needed. If one was create before it will just // be // reused to limit object creation Attribute<Runnable> attr = ctx.attr(REOPEN_TASK); Runnable reopenTask = attr.get(); if (reopenTask == null) { reopenTask = new ReopenReadTimerTask(ctx); attr.set(reopenTask); } ctx.executor().schedule(reopenTask, wait, TimeUnit.MILLISECONDS); } else { // Create a Runnable to update the next handler in the chain. If one was create before it // will // just be reused to limit object creation Runnable bufferUpdateTask = new Runnable() { @Override public void run() { ctx.fireChannelRead(msg); } }; ctx.executor().schedule(bufferUpdateTask, wait, TimeUnit.MILLISECONDS); return; } } } ctx.fireChannelRead(msg); }
/** * Starts an SSL / TLS handshake for the specified channel. * * @return a {@link ChannelFuture} which is notified when the handshake succeeds or fails. */ public ChannelFuture handshake(final ChannelFuture future) { final ChannelHandlerContext ctx = this.ctx; final ScheduledFuture<?> timeoutFuture; if (handshakeTimeoutMillis > 0) { timeoutFuture = ctx.executor() .schedule( new Runnable() { @Override public void run() { if (future.isDone()) { return; } SSLException e = new SSLException("handshake timed out"); if (future.setFailure(e)) { ctx.fireExceptionCaught(e); ctx.close(); } } }, handshakeTimeoutMillis, TimeUnit.MILLISECONDS); } else { timeoutFuture = null; } ctx.executor() .execute( new Runnable() { @Override public void run() { try { if (timeoutFuture != null) { timeoutFuture.cancel(false); } engine.beginHandshake(); handshakeFutures.add(future); flush(ctx, ctx.newFuture()); } catch (Exception e) { if (future.setFailure(e)) { ctx.fireExceptionCaught(e); ctx.close(); } } } }); return future; }
@Override public void write(final ChannelHandlerContext ctx, final Object msg, final ChannelPromise promise) throws Exception { long curtime = System.currentTimeMillis(); long size = calculateSize(msg); if (size > -1 && trafficCounter != null) { trafficCounter.bytesWriteFlowControl(size); if (writeLimit == 0) { ctx.write(msg, promise); return; } // compute the number of ms to wait before continue with the // channel long wait = getTimeToWait( writeLimit, trafficCounter.currentWrittenBytes(), trafficCounter.lastTime(), curtime); if (wait >= MINIMAL_WAIT) { ctx.executor() .schedule( new Runnable() { @Override public void run() { ctx.write(msg, promise); } }, wait, TimeUnit.MILLISECONDS); return; } } ctx.write(msg, promise); }
/** Performs TLS renegotiation. */ public Future<Channel> renegotiate(final Promise<Channel> promise) { if (promise == null) { throw new NullPointerException("promise"); } ChannelHandlerContext ctx = this.ctx; if (ctx == null) { throw new IllegalStateException(); } EventExecutor executor = ctx.executor(); if (!executor.inEventLoop()) { executor.execute( new OneTimeTask() { @Override public void run() { handshake(promise); } }); return promise; } handshake(promise); return promise; }
/** Performs TLS renegotiation. */ public Future<Channel> renegotiate() { ChannelHandlerContext ctx = this.ctx; if (ctx == null) { throw new IllegalStateException(); } return renegotiate(ctx.executor().<Channel>newPromise()); }
@Override public void channelRead0(final ChannelHandlerContext ctx, HttpRequest req) throws Exception { if (req.getUri().equals("/hello")) { ctx.executor().schedule(new HelloWorldRunnable(ctx), 10, TimeUnit.SECONDS); } else { ctx.fireChannelRead(req); } }
private void safeClose( final ChannelHandlerContext ctx, ChannelFuture flushFuture, final ChannelPromise promise) { if (!ctx.channel().isActive()) { ctx.close(promise); return; } final ScheduledFuture<?> timeoutFuture; if (closeNotifyTimeoutMillis > 0) { // Force-close the connection if close_notify is not fully sent in time. timeoutFuture = ctx.executor() .schedule( new Runnable() { @Override public void run() { logger.warn( "{} Last write attempt timed out; force-closing the connection.", ctx.channel()); // We notify the promise in the TryNotifyListener as there is a "race" where // the close(...) call // by the timeoutFuture and the close call in the flushFuture listener will be // called. Because of // this we need to use trySuccess() and tryFailure(...) as otherwise we can // cause an // IllegalStateException. ctx.close(ctx.newPromise()).addListener(new ChannelPromiseNotifier(promise)); } }, closeNotifyTimeoutMillis, TimeUnit.MILLISECONDS); } else { timeoutFuture = null; } // Close the connection if close_notify is sent in time. flushFuture.addListener( new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture f) throws Exception { if (timeoutFuture != null) { timeoutFuture.cancel(false); } // Trigger the close in all cases to make sure the promise is notified // See https://github.com/netty/netty/issues/2358 // // We notify the promise in the ChannelPromiseNotifier as there is a "race" where the // close(...) call // by the timeoutFuture and the close call in the flushFuture listener will be called. // Because of // this we need to use trySuccess() and tryFailure(...) as otherwise we can cause an // IllegalStateException. ctx.close(ctx.newPromise()).addListener(new ChannelPromiseNotifier(promise)); } }); }
private void scheduleTimeout(final ChannelHandlerContext ctx, final ChannelPromise promise) { // Schedule a timeout. final WriteTimeoutTask task = new WriteTimeoutTask(ctx, promise); task.scheduledFuture = ctx.executor().schedule(task, timeoutNanos, TimeUnit.NANOSECONDS); if (!task.scheduledFuture.isDone()) { addWriteTimeoutTask(task); // Cancel the scheduled timeout if the flush promise is complete. promise.addListener(task); } }
/** See {@link #close()} */ public ChannelFuture close(final ChannelFuture future) { final ChannelHandlerContext ctx = this.ctx; ctx.executor() .execute( new Runnable() { @Override public void run() { engine.closeOutbound(); ctx.flush(future); } }); return future; }
private void safeClose( final ChannelHandlerContext ctx, ChannelFuture flushFuture, final ChannelFuture closeFuture) { if (!ctx.channel().isActive()) { ctx.close(closeFuture); return; } final ScheduledFuture<?> timeoutFuture; if (closeNotifyTimeoutMillis > 0) { // Force-close the connection if close_notify is not fully sent in time. timeoutFuture = ctx.executor() .schedule( new Runnable() { @Override public void run() { logger.warn( ctx.channel() + " last write attempt timed out." + " Force-closing the connection."); ctx.close(closeFuture); } }, closeNotifyTimeoutMillis, TimeUnit.MILLISECONDS); } else { timeoutFuture = null; } // Close the connection if close_notify is sent in time. flushFuture.addListener( new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture f) throws Exception { if (timeoutFuture != null) { timeoutFuture.cancel(false); } if (ctx.channel().isActive()) { ctx.close(closeFuture); } } }); }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Message message = (Message) msg; // 握手成功主动发送心跳 if (message.getHeader() != null && message.getHeader().getType() == MessageType.LOGIN_RESP.value()) { heartBeat = ctx.executor() .scheduleAtFixedRate(new HeartBeatTask(ctx), 0, 5000, TimeUnit.MILLISECONDS); } else if (message.getHeader() != null && message.getHeader().getType() == MessageType.HEARTBEAT_RESP.value()) { System.out.println("Client receive server heart beat message:---->" + message); } else { ctx.fireChannelRead(message); } }
/** See {@link #close()} */ public ChannelFuture close(final ChannelPromise future) { final ChannelHandlerContext ctx = this.ctx; ctx.executor() .execute( new Runnable() { @Override public void run() { engine.closeOutbound(); try { write(ctx, Unpooled.EMPTY_BUFFER, future); flush(ctx); } catch (Exception e) { if (!future.tryFailure(e)) { logger.warn("{} flush() raised a masked exception.", ctx.channel(), e); } } } }); return future; }
private Future<Channel> handshake() { final ScheduledFuture<?> timeoutFuture; if (handshakeTimeoutMillis > 0) { timeoutFuture = ctx.executor() .schedule( new Runnable() { @Override public void run() { if (handshakePromise.isDone()) { return; } notifyHandshakeFailure(HANDSHAKE_TIMED_OUT); } }, handshakeTimeoutMillis, TimeUnit.MILLISECONDS); } else { timeoutFuture = null; } handshakePromise.addListener( new GenericFutureListener<Future<Channel>>() { @Override public void operationComplete(Future<Channel> f) throws Exception { if (timeoutFuture != null) { timeoutFuture.cancel(false); } } }); try { engine.beginHandshake(); wrapNonAppData(ctx, false); ctx.flush(); } catch (Exception e) { notifyHandshakeFailure(e); } return handshakePromise; }
protected void scheduleTask(ChannelHandlerContext ctx, Runnable task, long delay, TimeUnit tu) { cancelTask(); responseTask = ctx.executor().schedule(task, delay, tu); }
/** * Performs TLS (re)negotiation. * * @param newHandshakePromise if {@code null}, use the existing {@link #handshakePromise}, * assuming that the current negotiation has not been finished. Currently, {@code null} is * expected only for the initial handshake. */ private void handshake(final Promise<Channel> newHandshakePromise) { final Promise<Channel> p; if (newHandshakePromise != null) { final Promise<Channel> oldHandshakePromise = handshakePromise; if (!oldHandshakePromise.isDone()) { // There's no need to handshake because handshake is in progress already. // Merge the new promise into the old one. oldHandshakePromise.addListener( new FutureListener<Channel>() { @Override public void operationComplete(Future<Channel> future) throws Exception { if (future.isSuccess()) { newHandshakePromise.setSuccess(future.getNow()); } else { newHandshakePromise.setFailure(future.cause()); } } }); return; } handshakePromise = p = newHandshakePromise; } else { // Forced to reuse the old handshake. p = handshakePromise; assert !p.isDone(); } // Begin handshake. final ChannelHandlerContext ctx = this.ctx; try { engine.beginHandshake(); wrapNonAppData(ctx, false); ctx.flush(); } catch (Exception e) { notifyHandshakeFailure(e); } // Set timeout if necessary. final long handshakeTimeoutMillis = this.handshakeTimeoutMillis; if (handshakeTimeoutMillis <= 0 || p.isDone()) { return; } final ScheduledFuture<?> timeoutFuture = ctx.executor() .schedule( new Runnable() { @Override public void run() { if (p.isDone()) { return; } notifyHandshakeFailure(HANDSHAKE_TIMED_OUT); } }, handshakeTimeoutMillis, TimeUnit.MILLISECONDS); // Cancel the handshake timeout when handshake is finished. p.addListener( new FutureListener<Channel>() { @Override public void operationComplete(Future<Channel> f) throws Exception { timeoutFuture.cancel(false); } }); }
@Override public void flush(final ChannelHandlerContext ctx, ChannelFuture future) throws Exception { final ByteBuf in = ctx.outboundByteBuffer(); final ByteBuf out = ctx.nextOutboundByteBuffer(); out.unsafe().discardSomeReadBytes(); // Do not encrypt the first write request if this handler is // created with startTLS flag turned on. if (startTls && !sentFirstMessage) { sentFirstMessage = true; out.writeBytes(in); ctx.flush(future); return; } if (ctx.executor() == ctx.channel().eventLoop()) { flushFutureNotifier.addFlushFuture(future, in.readableBytes()); } else { synchronized (flushFutureNotifier) { flushFutureNotifier.addFlushFuture(future, in.readableBytes()); } } boolean unwrapLater = false; int bytesConsumed = 0; try { for (; ; ) { SSLEngineResult result = wrap(engine, in, out); bytesConsumed += result.bytesConsumed(); if (result.getStatus() == Status.CLOSED) { // SSLEngine has been closed already. // Any further write attempts should be denied. if (in.readable()) { in.clear(); SSLException e = new SSLException("SSLEngine already closed"); future.setFailure(e); ctx.fireExceptionCaught(e); flush0(ctx, bytesConsumed, e); bytesConsumed = 0; } break; } else { switch (result.getHandshakeStatus()) { case NEED_WRAP: ctx.flush(); continue; case NEED_UNWRAP: if (ctx.inboundByteBuffer().readable()) { unwrapLater = true; } break; case NEED_TASK: runDelegatedTasks(); continue; case FINISHED: setHandshakeSuccess(); continue; case NOT_HANDSHAKING: break; default: throw new IllegalStateException( "Unknown handshake status: " + result.getHandshakeStatus()); } if (result.bytesConsumed() == 0 && result.bytesProduced() == 0) { break; } } } if (unwrapLater) { inboundBufferUpdated(ctx); } } catch (SSLException e) { setHandshakeFailure(e); throw e; } finally { in.unsafe().discardSomeReadBytes(); flush0(ctx, bytesConsumed); } }