static void removeIfExists( ChannelPipeline pipeline, Class<? extends ChannelHandler> handlerClass) { ChannelHandler channelHandler = pipeline.get(handlerClass); if (channelHandler != null) { pipeline.remove(channelHandler); } }
private static String getWebSocketLocation(ChannelPipeline cp, HttpRequest req, String path) { String protocol = "ws"; if (cp.get(SslHandler.class) != null) { // SSL in use so use Secure WebSockets protocol = "wss"; } return protocol + "://" + req.getHttpHeaders().getHeaderString(HttpHeaders.Names.HOST) + path; }
/** * Reconnect to the remote address that the closed channel was connected to. This creates a new * {@link ChannelPipeline} with the same handler instances contained in the old channel's * pipeline. * * @param timeout Timer task handle. * @throws Exception when reconnection fails. */ @Override public void run(Timeout timeout) throws Exception { ChannelPipeline old = channel.pipeline(); final CommandHandler<?, ?> handler = old.get(CommandHandler.class); final RedisAsyncConnection<?, ?> connection = old.get(RedisAsyncConnection.class); ChannelFuture connect = null; // TODO use better concurrent workaround synchronized (bootstrap) { connect = bootstrap .handler( new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel ch) throws Exception { ch.pipeline().addLast(this, handler, connection); } }) .connect(); } connect.sync(); }
/** 连接建立成功后要加载的channelHandler */ protected void bindHandler(ChannelPipeline pipe, CMPPEndpointEntity entity) { // 修改连接空闲时间,使用server.xml里配置的连接空闲时间生效 if (entity instanceof CMPPServerChildEndpointEntity) { ChannelHandler handler = pipe.get(GlobalConstance.IdleCheckerHandlerName); if (handler != null) { pipe.replace( handler, GlobalConstance.IdleCheckerHandlerName, new IdleStateHandler(0, 0, entity.getIdleTimeSec(), TimeUnit.SECONDS)); } } pipe.addFirst( "socketLog", new LoggingHandler( String.format(GlobalConstance.loggerNamePrefix, entity.getId()), LogLevel.TRACE)); pipe.addLast("msgLog", new CMPPMessageLogHandler(entity)); pipe.addLast("CmppActiveTestRequestMessageHandler", GlobalConstance.activeTestHandler); pipe.addLast("CmppActiveTestResponseMessageHandler", GlobalConstance.activeTestRespHandler); pipe.addLast("CmppTerminateRequestMessageHandler", GlobalConstance.terminateHandler); pipe.addLast("CmppTerminateResponseMessageHandler", GlobalConstance.terminateRespHandler); List<BusinessHandlerInterface> handlers = entity.getBusinessHandlerSet(); if (handlers != null && handlers.size() > 0) { for (BusinessHandlerInterface handler : handlers) { if (handler instanceof AbstractBusinessHandler) { AbstractBusinessHandler buziHandler = (AbstractBusinessHandler) handler; buziHandler.setEndpointEntity(entity); if (buziHandler.isSharable()) { pipe.addLast(buziHandler.name(), buziHandler); } else { AbstractBusinessHandler cloned = null; try { cloned = buziHandler.clone(); } catch (CloneNotSupportedException e) { logger.error("handlers is not shareable and not implements Cloneable", e); } if (cloned != null) { cloned.setEndpointEntity(entity); pipe.addLast(buziHandler.name(), cloned); logger.info("handlers is not shareable . clone it success. {}", cloned); } } } } } // 黑洞处理,丢弃所有消息 pipe.addLast("BlackHole", GlobalConstance.blackhole); }
@Override public void send(final InputStream stream) throws Exception { byte[] chunk = new byte[bufferSize]; int count = ByteStreams.read(stream, chunk, 0, bufferSize); if (count <= 0) { return; } ByteBuf buffer = Unpooled.wrappedBuffer(chunk, 0, count); if (count < bufferSize) { send(buffer); } else { DefaultHttpResponse rsp = new DefaultHttpResponse(HttpVersion.HTTP_1_1, status); if (!headers.contains(HttpHeaderNames.CONTENT_LENGTH)) { headers.set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED); } else { if (keepAlive) { headers.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); } } // dump headers rsp.headers().set(headers); ChannelHandlerContext ctx = this.ctx; ctx.attr(NettyRequest.NEED_FLUSH).set(false); // add chunker ChannelPipeline pipeline = ctx.pipeline(); if (pipeline.get("chunker") == null) { pipeline.addAfter("encoder", "chunker", new ChunkedWriteHandler()); } // group all write ctx.channel() .eventLoop() .execute( () -> { // send headers ctx.write(rsp); // send head chunk ctx.write(buffer); // send tail ctx.write(new ChunkedStream(stream, bufferSize)); keepAlive(ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT)); }); } committed = true; }
/** * Handle the web socket handshake for the web socket specification <a href= * "http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17">HyBi versions 13-17</a>. * Versions 13-17 share the same wire protocol. * * <p>Browser request to the server: * * <pre> * GET /chat HTTP/1.1 * Host: server.example.com * Upgrade: websocket * Connection: Upgrade * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== * Sec-WebSocket-Origin: http://example.com * Sec-WebSocket-Protocol: chat, superchat * Sec-WebSocket-Version: 13 * </pre> * * <p>Server response: * * <pre> * HTTP/1.1 101 Switching Protocols * Upgrade: websocket * Connection: Upgrade * Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= * Sec-WebSocket-Protocol: chat * </pre> * * @param channel Channel * @param req HTTP request */ @Override public ChannelFuture handshake(Channel channel, HttpRequest req) { if (logger.isDebugEnabled()) { logger.debug(String.format("Channel %s WS Version 13 server handshake", channel.getId())); } HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS); String key = req.getHeader(Names.SEC_WEBSOCKET_KEY); if (key == null) { throw new WebSocketHandshakeException("not a WebSocket request: missing key"); } String acceptSeed = key + WEBSOCKET_13_ACCEPT_GUID; byte[] sha1 = WebSocketUtil.sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII)); String accept = WebSocketUtil.base64(sha1); if (logger.isDebugEnabled()) { logger.debug( String.format("WS Version 13 Server Handshake key: %s. Response: %s.", key, accept)); } res.setStatus(HttpResponseStatus.SWITCHING_PROTOCOLS); res.addHeader(Names.UPGRADE, WEBSOCKET.toLowerCase()); res.addHeader(Names.CONNECTION, Names.UPGRADE); res.addHeader(Names.SEC_WEBSOCKET_ACCEPT, accept); String protocol = req.getHeader(Names.SEC_WEBSOCKET_PROTOCOL); if (protocol != null) { res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, selectSubprotocol(protocol)); } ChannelFuture future = channel.write(res); // Upgrade the connection and send the handshake response. ChannelPipeline p = channel.getPipeline(); if (p.get(HttpChunkAggregator.class) != null) { p.remove(HttpChunkAggregator.class); } p.replace( HttpRequestDecoder.class, "wsdecoder", new WebSocket13FrameDecoder(true, allowExtensions, this.getMaxFramePayloadLength())); p.replace(HttpResponseEncoder.class, "wsencoder", new WebSocket13FrameEncoder(false)); return future; }
public void sendLoginSuccess(int status, Player player) { ByteBuf buf = channel.alloc().buffer(11); buf.writeByte(player.getRights()); buf.writeByte(0); buf.writeByte(0); buf.writeByte(0); buf.writeByte(0); buf.writeByte(0); buf.writeByte(0); buf.writeShort(player.getId()); buf.writeByte(1); buf.writeByte(1); ChannelPipeline pipeline = channel.pipeline(); GameSession session = new GameSession(server, channel, player); RsChannelHandler handler = pipeline.get(RsChannelHandler.class); handler.setSession(session); pipeline.remove(ReadTimeoutHandler.class); // TODO a different timeout mechanism is used in-game LoginResponse response = new LoginResponse(status, buf); channel.write(response); pipeline.addFirst( new GameFrameEncoder(outRandom), new GameMessageEncoder(server.getCodecRepository()), new GameFrameDecoder(inRandom), new GameMessageDecoder(server.getCodecRepository())); if (displayMode == 0 || displayMode == 1) player.getInterfaceSet().setDisplayMode(DisplayMode.FIXED); else player.getInterfaceSet().setDisplayMode(DisplayMode.RESIZABLE); session.init(); }
NetSocket createNetSocket() { DefaultNetSocket socket = new DefaultNetSocket(vertx, channel, context, server.tcpHelper, false); Map<Channel, DefaultNetSocket> connectionMap = new HashMap<Channel, DefaultNetSocket>(1); connectionMap.put(channel, socket); // Flush out all pending data endReadAndFlush(); // remove old http handlers and replace the old handler with one that handle plain sockets ChannelPipeline pipeline = channel.pipeline(); ChannelHandler compressor = pipeline.get(HttpChunkContentCompressor.class); if (compressor != null) { pipeline.remove(compressor); } pipeline.remove("httpDecoder"); if (pipeline.get("chunkedWriter") != null) { pipeline.remove("chunkedWriter"); } channel .pipeline() .replace( "handler", "handler", new VertxNetHandler(server.vertx, connectionMap) { @Override public void exceptionCaught(ChannelHandlerContext chctx, Throwable t) throws Exception { // remove from the real mapping server.connectionMap.remove(channel); super.exceptionCaught(chctx, t); } @Override public void channelInactive(ChannelHandlerContext chctx) throws Exception { // remove from the real mapping server.connectionMap.remove(channel); super.channelInactive(chctx); } @Override public void channelRead(ChannelHandlerContext chctx, Object msg) throws Exception { if (msg instanceof HttpContent) { ReferenceCountUtil.release(msg); return; } super.channelRead(chctx, msg); } }); // check if the encoder can be removed yet or not. if (lastWriteFuture == null) { channel.pipeline().remove("httpEncoder"); } else { lastWriteFuture.addListener( new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { channel.pipeline().remove("httpEncoder"); } }); } return socket; }
public static void removeTimeoutHandler(ChannelPipeline pipeline) { if (pipeline.get(READ_TIMEOUT_HANDLER_NAME) != null) { pipeline.remove(READ_TIMEOUT_HANDLER_NAME); } }