@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); }
private boolean handleClientSideCustomPacket( S3FPacketCustomPayload msg, ChannelHandlerContext context) { String channelName = msg.getChannelName(); if ("FML|MP".equals(channelName)) { try { if (multipart == null) { multipart = new MultiPartCustomPayload(msg.getBufferData()); } else { multipart.processPart(msg.getBufferData()); } } catch (IOException e) { this.kickWithMessage(e.getMessage()); multipart = null; return true; } if (multipart.isComplete()) { msg = multipart; channelName = msg.getChannelName(); multipart = null; } else { return true; // Haven't received all so return till we have. } } if ("FML|HS".equals(channelName) || "REGISTER".equals(channelName) || "UNREGISTER".equals(channelName)) { FMLProxyPacket proxy = new FMLProxyPacket(msg); proxy.setDispatcher(this); handshakeChannel.writeInbound(proxy); // forward any messages into the regular channel for (Object push : handshakeChannel.inboundMessages()) { List<FMLProxyPacket> messageResult = FMLNetworkHandler.forwardHandshake( (FMLMessage.CompleteHandshake) push, this, Side.CLIENT); for (FMLProxyPacket result : messageResult) { result.setTarget(Side.CLIENT); result.payload().resetReaderIndex(); context.fireChannelRead(result); } } handshakeChannel.inboundMessages().clear(); return true; } else if (NetworkRegistry.INSTANCE.hasChannel(channelName, Side.CLIENT)) { FMLProxyPacket proxy = new FMLProxyPacket(msg); proxy.setDispatcher(this); context.fireChannelRead(proxy); return true; } return false; }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) { NettyMessage message = (NettyMessage) msg; log.info("接收响应:" + message); if (message != null && message.getHeader().getType() == MessageType.HAND_RES.value) { byte loginResult = (byte) message.getBody(); if (loginResult != 0) { ctx.close(); } else { log.info("Login is OK:" + message); ctx.fireChannelRead(msg); } } else { ctx.fireChannelRead(msg); } }
@Override public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception { if (msg instanceof DefaultLastHttpContent) { DefaultLastHttpContent response = (DefaultLastHttpContent) msg; ctx.fireChannelRead(response.content()); } }
/** * Calls {@link ChannelHandlerContext#fireChannelRead(Object)} to forward to the next {@link * ChannelHandler} in the {@link ChannelPipeline}. * * <p>Sub-classes may override this method to change behavior. */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { NettyMessage message = (NettyMessage) msg; // 如果是握手请求消息,处理,其它消息透传 if (message.getHeader() != null && message.getHeader().getType() == MessageType.LOGIN_REQ.value()) { String nodeIndex = ctx.channel().remoteAddress().toString(); NettyMessage loginResp = null; // 重复登陆,拒绝 if (nodeCheck.containsKey(nodeIndex)) { loginResp = buildResponse((byte) -1); } else { InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress(); String ip = address.getAddress().getHostAddress(); boolean isOK = false; for (String WIP : whitekList) { if (WIP.equals(ip)) { isOK = true; break; } } loginResp = isOK ? buildResponse((byte) 0) : buildResponse((byte) -1); if (isOK) nodeCheck.put(nodeIndex, true); } System.out.println( "The login response is : " + loginResp + " body [" + loginResp.getBody() + "]"); ctx.writeAndFlush(loginResp); } else { ctx.fireChannelRead(msg); } }
@Override protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { FullHttpRequest req = (FullHttpRequest) msg; String upgrade = req.headers().get(HttpHeaders.Names.UPGRADE); if (HttpHeaders.Values.WEBSOCKET.equalsIgnoreCase(upgrade)) { WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(req.getUri(), null, false); WebSocketServerHandshaker handshaker = wsFactory.newHandshaker(req); if (handshaker == null) { WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel()); } else { ChannelFuture future = handshaker.handshake(ctx.channel(), req); future.addListener( f -> { this.configurator.switchToWebSockets(ctx.pipeline()); }); } } else { ReferenceCountUtil.retain(msg); this.configurator.switchToPlainHttp(ctx.pipeline()); ChannelHandlerContext agg = ctx.pipeline().context(HttpObjectAggregator.class); agg.fireChannelRead(msg); } }
@Override public void onSettingsRead(ChannelHandlerContext ctx, Http2Settings settings) throws Http2Exception { if (propagateSettings) { // Provide an interface for non-listeners to capture settings ctx.fireChannelRead(settings); } }
@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); } }
/** * Calls {@link SSLEngine#unwrap(ByteBuffer, ByteBuffer)} with an empty buffer to handle * handshakes, etc. */ private void unwrapNonApp(ChannelHandlerContext ctx) throws SSLException { try { unwrapSingle(ctx, Unpooled.EMPTY_BUFFER.nioBuffer(), 0); } finally { ByteBuf decodeOut = this.decodeOut; if (decodeOut != null && decodeOut.isReadable()) { this.decodeOut = null; ctx.fireChannelRead(decodeOut); } } }
/* * SPDY Stream Error Handling: * * Upon a stream error, the endpoint must send a RST_STREAM frame which contains * the Stream-ID for the stream where the error occurred and the error getStatus which * caused the error. * * After sending the RST_STREAM, the stream is closed to the sending endpoint. * * Note: this is only called by the worker thread */ private void issueStreamError(ChannelHandlerContext ctx, int streamId, SpdyStreamStatus status) { boolean fireChannelRead = !spdySession.isRemoteSideClosed(streamId); ChannelPromise promise = ctx.newPromise(); removeStream(streamId, promise); SpdyRstStreamFrame spdyRstStreamFrame = new DefaultSpdyRstStreamFrame(streamId, status); ctx.writeAndFlush(spdyRstStreamFrame, promise); if (fireChannelRead) { ctx.fireChannelRead(spdyRstStreamFrame); } }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (isRemote(ctx)) { ByteBuf payload = (ByteBuf) msg; byte[] data = getPayloadFromByteBuf(payload); writeBuffer(data); return; } ReferenceCountUtil.retain(msg); // propagate the data to rest of handlers in pipeline ctx.fireChannelRead(msg); }
protected void decode(ChannelHandlerContext context, ByteBuf buffer) throws Exception { ChannelPipeline pipeline = context.pipeline(); if (detectSsl && SslHandler.isEncrypted(buffer)) { SSLEngine engine = SSL_SERVER_CONTEXT.getValue().createSSLEngine(); engine.setUseClientMode(false); pipeline.addLast( new SslHandler(engine), new ChunkedWriteHandler(), new PortUnificationServerHandler(delegatingHttpRequestHandler, false, detectGzip)); } else { int magic1 = buffer.getUnsignedByte(buffer.readerIndex()); int magic2 = buffer.getUnsignedByte(buffer.readerIndex() + 1); if (detectGzip && magic1 == 31 && magic2 == 139) { pipeline.addLast( new JZlibEncoder(ZlibWrapper.GZIP), new JdkZlibDecoder(ZlibWrapper.GZIP), new PortUnificationServerHandler(delegatingHttpRequestHandler, detectSsl, false)); } else if (isHttp(magic1, magic2)) { NettyUtil.initHttpHandlers(pipeline); pipeline.addLast(delegatingHttpRequestHandler); if (BuiltInServer.LOG.isDebugEnabled()) { pipeline.addLast( new ChannelOutboundHandlerAdapter() { @Override public void write( ChannelHandlerContext context, Object message, ChannelPromise promise) throws Exception { if (message instanceof HttpResponse) { // BuiltInServer.LOG.debug("OUT HTTP:\n" + message); HttpResponse response = (HttpResponse) message; BuiltInServer.LOG.debug( "OUT HTTP: " + response.getStatus().code() + " " + response.headers().get("Content-type")); } super.write(context, message, promise); } }); } } else if (magic1 == 'C' && magic2 == 'H') { buffer.skipBytes(2); pipeline.addLast(new CustomHandlerDelegator()); } else { BuiltInServer.LOG.warn("unknown request, first two bytes " + magic1 + " " + magic2); context.close(); } } // must be after new channels handlers addition (netty bug?) ensureThatExceptionHandlerIsLast(pipeline); pipeline.remove(this); context.fireChannelRead(buffer); }
@Override protected void channelRead0(ChannelHandlerContext ctx, PEASMessage obj) throws Exception { if (obj.getHeader().getCommand().equals("KEY")) { // byte[] keyBytes = Files.readAllBytes(Paths.get("./resources/").resolve("pubKey2.der")); String jarPath = new File( KeyHandler.class .getProtectionDomain() .getCodeSource() .getLocation() .toURI() .getPath()) .getParentFile() .getPath(); InputStream inputStream = new FileInputStream(new File(jarPath + "/resources/pubKey2.der")); // InputStream inputStream = // KeyHandler.class.getClassLoader().getResourceAsStream("pubKey2.der"); byte[] keyBytes = IOUtils.toByteArray(inputStream); // construct key response PEASHeader header = new PEASHeader(); header.setCommand("RESPONSE"); header.setIssuer(obj.getHeader().getIssuer()); header.setStatus("100"); header.setContentLength(keyBytes.length); PEASBody body = new PEASBody(keyBytes.length); body.getContent().writeBytes(keyBytes); PEASMessage res = new PEASMessage(header, body); // send reponse back ChannelFuture f = ctx.writeAndFlush(res); f.addListener( new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) { if (future.isSuccess()) { System.out.println("return key successful"); } else { System.out.println("return key failed"); future.channel().close(); } } }); } else { ctx.fireChannelRead(obj); } }
@Override protected void channelRead0(ChannelHandlerContext ctx, Packet msg) throws Exception { boolean handled = false; if (msg instanceof C17PacketCustomPayload) { handled = handleServerSideCustomPacket((C17PacketCustomPayload) msg, ctx); } else if (msg instanceof S3FPacketCustomPayload) { handled = handleClientSideCustomPacket((S3FPacketCustomPayload) msg, ctx); } else if (state != ConnectionState.CONNECTED && state != ConnectionState.HANDSHAKECOMPLETE) { handled = handleVanilla(msg); } if (!handled) { ctx.fireChannelRead(msg); } }
@Override protected void channelRead0(ChannelHandlerContext ctx, FMLProxyPacket msg) throws Exception { Side side = ctx.channel().attr(NetworkRegistry.CHANNEL_SOURCE).get(); if (msg.channel().equals("REGISTER") || msg.channel().equals("UNREGISTER")) { byte[] data = new byte[msg.payload().readableBytes()]; msg.payload().readBytes(data); String channels = new String(data, Charsets.UTF_8); String[] split = channels.split("\0"); for (String channel : split) { System.out.printf("Register %s from %s\n", channel, side); } } else { ctx.fireChannelRead(msg); } }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Thread t = this.t; if (t == null) { this.t = Thread.currentThread(); } else { Assert.assertSame(t, Thread.currentThread()); } int actual = (Integer) msg; int expected = inCnt++; Assert.assertEquals(expected, actual); ctx.fireChannelRead(msg); }
private boolean handleServerSideCustomPacket( C17PacketCustomPayload msg, ChannelHandlerContext context) { if (state == ConnectionState.AWAITING_HANDSHAKE) { synchronized (this) { // guard from other threads changing the state on us if (state == ConnectionState.AWAITING_HANDSHAKE) { state = ConnectionState.HANDSHAKING; } } } String channelName = msg.getChannelName(); if ("FML|HS".equals(channelName) || "REGISTER".equals(channelName) || "UNREGISTER".equals(channelName)) { FMLProxyPacket proxy = new FMLProxyPacket(msg); proxy.setDispatcher(this); handshakeChannel.writeInbound(proxy); for (Object push : handshakeChannel.inboundMessages()) { List<FMLProxyPacket> messageResult = FMLNetworkHandler.forwardHandshake( (FMLMessage.CompleteHandshake) push, this, Side.SERVER); for (FMLProxyPacket result : messageResult) { result.setTarget(Side.SERVER); result.payload().resetReaderIndex(); context.fireChannelRead(result); } } handshakeChannel.inboundMessages().clear(); return true; } else if (NetworkRegistry.INSTANCE.hasChannel(channelName, Side.SERVER)) { FMLProxyPacket proxy = new FMLProxyPacket(msg); proxy.setDispatcher(this); context.fireChannelRead(proxy); return true; } return false; }
@Override public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception { Channel session = ctx.channel(); if ((firewall.getClientType(session) != ClientType.MIS) && (firewall.blockedByPacks(ctx.channel(), 1))) { String remoteIp = sessionManager.getRemoteIp(session); long playerId = sessionManager.getPlayerId(session).longValue(); LOGGER.error( String.format( "In blacklist: [ip: %s, playerId: %d]", new Object[] {remoteIp, Long.valueOf(playerId)})); sessionManager.closeSession(session); return; } ctx.fireChannelRead(msg); }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Thread t = this.t; if (t == null) { this.t = Thread.currentThread(); } else { Assert.assertSame(t, Thread.currentThread()); } ByteBuf out = ctx.alloc().buffer(4); int m = ((Integer) msg).intValue(); int expected = inCnt++; Assert.assertEquals(expected, m); out.writeInt(m); ctx.fireChannelRead(out); }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof Http2Settings) { // Expected } else if (msg instanceof FullHttpResponse) { FullHttpResponse response = (FullHttpResponse) msg; final Invocation invocation = waitsHolder.poll(response); if (invocation != null) { final ServiceInvocationContext iCtx = invocation.invocationContext(); final SerializationFormat serializationFormat = iCtx.scheme().serializationFormat(); try { final Promise<FullHttpResponse> resultPromise = invocation.resultPromise(); if (HttpStatusClass.SUCCESS == response.status().codeClass() // No serialization indicates a raw HTTP protocol which should // have error responses returned. || serializationFormat == SerializationFormat.NONE) { iCtx.resolvePromise(resultPromise, response.retain()); } else { iCtx.rejectPromise( resultPromise, new InvalidResponseException("HTTP Response code: " + response.status())); } } finally { ReferenceCountUtil.release(msg); } } else { // if invocation not found, we just bypass message to next ctx.fireChannelRead(msg); } if (!isMultiplex && HttpHeaderValues.CLOSE.contentEqualsIgnoreCase( response.headers().get(HttpHeaderNames.CONNECTION))) { ctx.close(); } } else { try { throw new IllegalStateException("unexpected message type: " + msg); } finally { ReferenceCountUtil.release(msg); } } }
@Override protected void channelRead0(ChannelHandlerContext context, ByteBuf message) throws Exception { ByteBuf buffer = getBufferIfSufficient(message, UUID_LENGTH, context); if (buffer == null) { message.release(); } else { UUID uuid = new UUID(buffer.readLong(), buffer.readLong()); for (BinaryRequestHandler customHandler : BinaryRequestHandler.EP_NAME.getExtensions()) { if (uuid.equals(customHandler.getId())) { ChannelPipeline pipeline = context.pipeline(); pipeline.addLast(customHandler.getInboundHandler()); ensureThatExceptionHandlerIsLast(pipeline); pipeline.remove(this); context.fireChannelRead(buffer); break; } } } }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Thread t = this.t; if (t == null) { this.t = Thread.currentThread(); } else { Assert.assertSame(t, Thread.currentThread()); } ByteBuf m = (ByteBuf) msg; int count = m.readableBytes() / 4; for (int j = 0; j < count; j++) { int actual = m.readInt(); int expected = inCnt++; Assert.assertEquals(expected, actual); ctx.fireChannelRead(actual); } m.release(); }
@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); } }
@Override public void channelRead0(final ChannelHandlerContext ctx, final FullHttpRequest request) throws Exception { final String content = getContent(request); if (noContent(content)) { ctx.writeAndFlush( internalServerErrorResponse(request.getProtocolVersion(), "Payload expected.")) .addListener(ChannelFutureListener.CLOSE); } else { try { final String[] messages = JsonUtil.decode(content); for (String message : messages) { ctx.fireChannelRead(message); } respond(ctx, request); } catch (final JsonParseException e) { ctx.writeAndFlush( internalServerErrorResponse(request.getProtocolVersion(), "Broken JSON encoding.")); } } }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Class<?> messageClass = msg.getClass(); if (HttpResponse.class.isAssignableFrom(messageClass)) { HttpResponse response = (HttpResponse) msg; if (request != null) { request.setNettyResponse(response); } checkResponseCode(ctx, response); if (FullHttpResponse.class.isAssignableFrom(messageClass)) { postRead(ctx, msg); } channelSubscription.updatePendingRequests(1); ctx.fireChannelRead(msg); } else if (HttpContent.class.isAssignableFrom(messageClass)) { super.channelRead(ctx, ((ByteBufHolder) msg).content()); postRead(ctx, msg); } else if (!discardBody) { super.channelRead(ctx, msg); } }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { inboundThreadNames.add(Thread.currentThread().getName()); ctx.fireChannelRead(msg); }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof SpdyDataFrame) { /* * SPDY Data frame processing requirements: * * If an endpoint receives a data frame for a Stream-ID which is not open * and the endpoint has not sent a GOAWAY frame, it must issue a stream error * with the error code INVALID_STREAM for the Stream-ID. * * If an endpoint which created the stream receives a data frame before receiving * a SYN_REPLY on that stream, it is a protocol error, and the recipient must * issue a stream error with the getStatus code PROTOCOL_ERROR for the Stream-ID. * * If an endpoint receives multiple data frames for invalid Stream-IDs, * it may close the session. * * If an endpoint refuses a stream it must ignore any data frames for that stream. * * If an endpoint receives a data frame after the stream is half-closed from the * sender, it must send a RST_STREAM frame with the getStatus STREAM_ALREADY_CLOSED. * * If an endpoint receives a data frame after the stream is closed, it must send * a RST_STREAM frame with the getStatus PROTOCOL_ERROR. */ SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg; int streamId = spdyDataFrame.streamId(); int deltaWindowSize = -1 * spdyDataFrame.content().readableBytes(); int newSessionWindowSize = spdySession.updateReceiveWindowSize(SPDY_SESSION_STREAM_ID, deltaWindowSize); // Check if session window size is reduced beyond allowable lower bound if (newSessionWindowSize < 0) { issueSessionError(ctx, SpdySessionStatus.PROTOCOL_ERROR); return; } // Send a WINDOW_UPDATE frame if less than half the session window size remains if (newSessionWindowSize <= initialSessionReceiveWindowSize / 2) { int sessionDeltaWindowSize = initialSessionReceiveWindowSize - newSessionWindowSize; spdySession.updateReceiveWindowSize(SPDY_SESSION_STREAM_ID, sessionDeltaWindowSize); SpdyWindowUpdateFrame spdyWindowUpdateFrame = new DefaultSpdyWindowUpdateFrame(SPDY_SESSION_STREAM_ID, sessionDeltaWindowSize); ctx.writeAndFlush(spdyWindowUpdateFrame); } // Check if we received a data frame for a Stream-ID which is not open if (!spdySession.isActiveStream(streamId)) { spdyDataFrame.release(); if (streamId <= lastGoodStreamId) { issueStreamError(ctx, streamId, SpdyStreamStatus.PROTOCOL_ERROR); } else if (!sentGoAwayFrame) { issueStreamError(ctx, streamId, SpdyStreamStatus.INVALID_STREAM); } return; } // Check if we received a data frame for a stream which is half-closed if (spdySession.isRemoteSideClosed(streamId)) { spdyDataFrame.release(); issueStreamError(ctx, streamId, SpdyStreamStatus.STREAM_ALREADY_CLOSED); return; } // Check if we received a data frame before receiving a SYN_REPLY if (!isRemoteInitiatedId(streamId) && !spdySession.hasReceivedReply(streamId)) { spdyDataFrame.release(); issueStreamError(ctx, streamId, SpdyStreamStatus.PROTOCOL_ERROR); return; } /* * SPDY Data frame flow control processing requirements: * * Recipient should not send a WINDOW_UPDATE frame as it consumes the last data frame. */ // Update receive window size int newWindowSize = spdySession.updateReceiveWindowSize(streamId, deltaWindowSize); // Window size can become negative if we sent a SETTINGS frame that reduces the // size of the transfer window after the peer has written data frames. // The value is bounded by the length that SETTINGS frame decrease the window. // This difference is stored for the session when writing the SETTINGS frame // and is cleared once we send a WINDOW_UPDATE frame. if (newWindowSize < spdySession.getReceiveWindowSizeLowerBound(streamId)) { spdyDataFrame.release(); issueStreamError(ctx, streamId, SpdyStreamStatus.FLOW_CONTROL_ERROR); return; } // Window size became negative due to sender writing frame before receiving SETTINGS // Send data frames upstream in initialReceiveWindowSize chunks if (newWindowSize < 0) { while (spdyDataFrame.content().readableBytes() > initialReceiveWindowSize) { SpdyDataFrame partialDataFrame = new DefaultSpdyDataFrame( streamId, spdyDataFrame.content().readSlice(initialReceiveWindowSize).retain()); ctx.writeAndFlush(partialDataFrame); } } // Send a WINDOW_UPDATE frame if less than half the stream window size remains if (newWindowSize <= initialReceiveWindowSize / 2 && !spdyDataFrame.isLast()) { int streamDeltaWindowSize = initialReceiveWindowSize - newWindowSize; spdySession.updateReceiveWindowSize(streamId, streamDeltaWindowSize); SpdyWindowUpdateFrame spdyWindowUpdateFrame = new DefaultSpdyWindowUpdateFrame(streamId, streamDeltaWindowSize); ctx.writeAndFlush(spdyWindowUpdateFrame); } // Close the remote side of the stream if this is the last frame if (spdyDataFrame.isLast()) { halfCloseStream(streamId, true, ctx.newSucceededFuture()); } } else if (msg instanceof SpdySynStreamFrame) { /* * SPDY SYN_STREAM frame processing requirements: * * If an endpoint receives a SYN_STREAM with a Stream-ID that is less than * any previously received SYN_STREAM, it must issue a session error with * the getStatus PROTOCOL_ERROR. * * If an endpoint receives multiple SYN_STREAM frames with the same active * Stream-ID, it must issue a stream error with the getStatus code PROTOCOL_ERROR. * * The recipient can reject a stream by sending a stream error with the * getStatus code REFUSED_STREAM. */ SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg; int streamId = spdySynStreamFrame.streamId(); // Check if we received a valid SYN_STREAM frame if (spdySynStreamFrame.isInvalid() || !isRemoteInitiatedId(streamId) || spdySession.isActiveStream(streamId)) { issueStreamError(ctx, streamId, SpdyStreamStatus.PROTOCOL_ERROR); return; } // Stream-IDs must be monotonically increasing if (streamId <= lastGoodStreamId) { issueSessionError(ctx, SpdySessionStatus.PROTOCOL_ERROR); return; } // Try to accept the stream byte priority = spdySynStreamFrame.priority(); boolean remoteSideClosed = spdySynStreamFrame.isLast(); boolean localSideClosed = spdySynStreamFrame.isUnidirectional(); if (!acceptStream(streamId, priority, remoteSideClosed, localSideClosed)) { issueStreamError(ctx, streamId, SpdyStreamStatus.REFUSED_STREAM); return; } } else if (msg instanceof SpdySynReplyFrame) { /* * SPDY SYN_REPLY frame processing requirements: * * If an endpoint receives multiple SYN_REPLY frames for the same active Stream-ID * it must issue a stream error with the getStatus code STREAM_IN_USE. */ SpdySynReplyFrame spdySynReplyFrame = (SpdySynReplyFrame) msg; int streamId = spdySynReplyFrame.streamId(); // Check if we received a valid SYN_REPLY frame if (spdySynReplyFrame.isInvalid() || isRemoteInitiatedId(streamId) || spdySession.isRemoteSideClosed(streamId)) { issueStreamError(ctx, streamId, SpdyStreamStatus.INVALID_STREAM); return; } // Check if we have received multiple frames for the same Stream-ID if (spdySession.hasReceivedReply(streamId)) { issueStreamError(ctx, streamId, SpdyStreamStatus.STREAM_IN_USE); return; } spdySession.receivedReply(streamId); // Close the remote side of the stream if this is the last frame if (spdySynReplyFrame.isLast()) { halfCloseStream(streamId, true, ctx.newSucceededFuture()); } } else if (msg instanceof SpdyRstStreamFrame) { /* * SPDY RST_STREAM frame processing requirements: * * After receiving a RST_STREAM on a stream, the receiver must not send * additional frames on that stream. * * An endpoint must not send a RST_STREAM in response to a RST_STREAM. */ SpdyRstStreamFrame spdyRstStreamFrame = (SpdyRstStreamFrame) msg; removeStream(spdyRstStreamFrame.streamId(), ctx.newSucceededFuture()); } else if (msg instanceof SpdySettingsFrame) { SpdySettingsFrame spdySettingsFrame = (SpdySettingsFrame) msg; int settingsMinorVersion = spdySettingsFrame.getValue(SpdySettingsFrame.SETTINGS_MINOR_VERSION); if (settingsMinorVersion >= 0 && settingsMinorVersion != minorVersion) { // Settings frame had the wrong minor version issueSessionError(ctx, SpdySessionStatus.PROTOCOL_ERROR); return; } int newConcurrentStreams = spdySettingsFrame.getValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS); if (newConcurrentStreams >= 0) { remoteConcurrentStreams = newConcurrentStreams; } // Persistence flag are inconsistent with the use of SETTINGS to communicate // the initial window size. Remove flags from the sender requesting that the // value be persisted. Remove values that the sender indicates are persisted. if (spdySettingsFrame.isPersisted(SpdySettingsFrame.SETTINGS_INITIAL_WINDOW_SIZE)) { spdySettingsFrame.removeValue(SpdySettingsFrame.SETTINGS_INITIAL_WINDOW_SIZE); } spdySettingsFrame.setPersistValue(SpdySettingsFrame.SETTINGS_INITIAL_WINDOW_SIZE, false); int newInitialWindowSize = spdySettingsFrame.getValue(SpdySettingsFrame.SETTINGS_INITIAL_WINDOW_SIZE); if (newInitialWindowSize >= 0) { updateInitialSendWindowSize(newInitialWindowSize); } } else if (msg instanceof SpdyPingFrame) { /* * SPDY PING frame processing requirements: * * Receivers of a PING frame should send an identical frame to the sender * as soon as possible. * * Receivers of a PING frame must ignore frames that it did not initiate */ SpdyPingFrame spdyPingFrame = (SpdyPingFrame) msg; if (isRemoteInitiatedId(spdyPingFrame.id())) { ctx.writeAndFlush(spdyPingFrame); return; } // Note: only checks that there are outstanding pings since uniqueness is not enforced if (pings.get() == 0) { return; } pings.getAndDecrement(); } else if (msg instanceof SpdyGoAwayFrame) { receivedGoAwayFrame = true; } else if (msg instanceof SpdyHeadersFrame) { SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg; int streamId = spdyHeadersFrame.streamId(); // Check if we received a valid HEADERS frame if (spdyHeadersFrame.isInvalid()) { issueStreamError(ctx, streamId, SpdyStreamStatus.PROTOCOL_ERROR); return; } if (spdySession.isRemoteSideClosed(streamId)) { issueStreamError(ctx, streamId, SpdyStreamStatus.INVALID_STREAM); return; } // Close the remote side of the stream if this is the last frame if (spdyHeadersFrame.isLast()) { halfCloseStream(streamId, true, ctx.newSucceededFuture()); } } else if (msg instanceof SpdyWindowUpdateFrame) { /* * SPDY WINDOW_UPDATE frame processing requirements: * * Receivers of a WINDOW_UPDATE that cause the window size to exceed 2^31 * must send a RST_STREAM with the getStatus code FLOW_CONTROL_ERROR. * * Sender should ignore all WINDOW_UPDATE frames associated with a stream * after sending the last frame for the stream. */ SpdyWindowUpdateFrame spdyWindowUpdateFrame = (SpdyWindowUpdateFrame) msg; int streamId = spdyWindowUpdateFrame.streamId(); int deltaWindowSize = spdyWindowUpdateFrame.deltaWindowSize(); // Ignore frames for half-closed streams if (streamId != SPDY_SESSION_STREAM_ID && spdySession.isLocalSideClosed(streamId)) { return; } // Check for numerical overflow if (spdySession.getSendWindowSize(streamId) > Integer.MAX_VALUE - deltaWindowSize) { if (streamId == SPDY_SESSION_STREAM_ID) { issueSessionError(ctx, SpdySessionStatus.PROTOCOL_ERROR); } else { issueStreamError(ctx, streamId, SpdyStreamStatus.FLOW_CONTROL_ERROR); } return; } updateSendWindowSize(ctx, streamId, deltaWindowSize); } ctx.fireChannelRead(msg); }
@Override public void channelRead0(ChannelHandlerContext ctx, ByteBuf input) throws Exception { int readable = input.readableBytes(); if (readable <= 0) { return; } com.alibaba.dubbo.remoting.buffer.ChannelBuffer message; if (buffer.readable()) { if (buffer instanceof DynamicChannelBuffer) { buffer.writeBytes(input.nioBuffer()); message = buffer; } else { int size = buffer.readableBytes() + input.readableBytes(); message = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.dynamicBuffer( size > bufferSize ? size : bufferSize); message.writeBytes(buffer, buffer.readableBytes()); message.writeBytes(input.nioBuffer()); } } else { message = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.wrappedBuffer(input.nioBuffer()); } NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler); Object msg; int saveReaderIndex; try { // decode object. do { saveReaderIndex = message.readerIndex(); try { msg = codec.decode(channel, message); } catch (IOException e) { buffer = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER; throw e; } if (msg == Codec2.DecodeResult.NEED_MORE_INPUT) { message.readerIndex(saveReaderIndex); break; } else { if (saveReaderIndex == message.readerIndex()) { buffer = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER; throw new IOException("Decode without read data."); } if (msg != null) { ctx.fireChannelRead(msg); } } } while (message.readable()); } finally { if (message.readable()) { message.discardReadBytes(); buffer = message; } else { buffer = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER; } NettyChannel.removeChannelIfDisconnected(ctx.channel()); } }
/* (non-Javadoc) * @see org.jboss.netty.channel.SimpleChannelHandler#messageReceived(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.MessageEvent) */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { boolean sentUpstream = false; if (msg instanceof UpdatePacket) { PeerConnectionInformation peerConnInfo = ctx.channel().attr(Attributes.peerInfoKey).get(); UpdatePacket update = (UpdatePacket) msg; List<PathAttribute> attributeFlagsErrorList = new LinkedList<PathAttribute>(); List<Class<? extends PathAttribute>> missingWellKnownList = new LinkedList<Class<? extends PathAttribute>>(); Set<Class<? extends PathAttribute>> givenAttributes = new HashSet<Class<? extends PathAttribute>>(); // check if passed optional / transitive bits match the presettings of the attribute type for (PathAttribute attribute : update.getPathAttributes()) { boolean badAttr = false; givenAttributes.add(attribute.getClass()); switch (attribute.getCategory()) { case WELL_KNOWN_MANDATORY: case WELL_KNOWN_DISCRETIONARY: badAttr = attribute.isOptional() || !attribute.isTransitive(); break; case OPTIONAL_NON_TRANSITIVE: badAttr = !attribute.isOptional() || attribute.isTransitive(); break; case OPTIONAL_TRANSITIVE: badAttr = !attribute.isOptional() || !attribute.isTransitive(); break; } if (badAttr) { log.info("detected attribute " + attribute + " with invalid flags"); attributeFlagsErrorList.add(attribute); } } // if we have any bad attribute, generate notification message and leave if (!attributeFlagsErrorList.isEmpty()) { attributeFlagsErrorList.forEach( (n) -> NotificationHelper.sendNotification( ctx, new AttributeFlagsNotificationPacket(n), new BgpEventFireChannelFutureListener(ctx))); } else { // check presence of mandatory attributes Set<Class<? extends PathAttribute>> mandatoryAttributes; if (peerConnInfo.isIBGPConnection()) mandatoryAttributes = mandatoryIBGPAttributes; else mandatoryAttributes = mandatoryEBGPAttributes; for (Class<? extends PathAttribute> attrClass : mandatoryAttributes) { if (!givenAttributes.contains(attrClass)) { missingWellKnownList.add(attrClass); } } if (missingWellKnownList.size() > 0) { Map<Class<? extends PathAttribute>, Integer> codeMap; List<NotificationPacket> notifications = new LinkedList<NotificationPacket>(); if (peerConnInfo.isAS4OctetsInUse()) codeMap = as4ClazzCodeMap; else codeMap = as2ClazzCodeMap; if (peerConnInfo.isAS4OctetsInUse()) codeMap = as4ClazzCodeMap; else codeMap = as2ClazzCodeMap; for (Class<? extends PathAttribute> attrClass : missingWellKnownList) { int code = codeMap.get(attrClass); log.info("detected missing well-known atribute, type " + code); notifications.add(new MissingWellKnownAttributeNotificationPacket(code)); } notifications.forEach( (n) -> NotificationHelper.sendNotification( ctx, n, new BgpEventFireChannelFutureListener(ctx))); } else { boolean haveBougsWidth = false; // check path attributes for AS number width (2 or 4) settings which mismatch the // connection configuration for (PathAttribute attribute : update.getPathAttributes()) { if (attribute instanceof ASTypeAware) { if (((ASTypeAware) attribute).getAsType() != peerConnInfo.getAsTypeInUse()) { haveBougsWidth = true; } } } if (haveBougsWidth) { NotificationHelper.sendNotification( ctx, new MalformedAttributeListNotificationPacket(), new BgpEventFireChannelFutureListener(ctx)); } else sentUpstream = true; } } } else sentUpstream = true; if (sentUpstream) ctx.fireChannelRead(msg); }
/** Unwraps inbound SSL records. */ private boolean unwrap(ChannelHandlerContext ctx, ByteBuf packet, int offset, int length) throws SSLException { boolean decoded = false; boolean wrapLater = false; boolean notifyClosure = false; ByteBuf decodeOut = allocate(ctx, length); try { for (; ; ) { final SSLEngineResult result = unwrap(engine, packet, offset, length, decodeOut); final Status status = result.getStatus(); final HandshakeStatus handshakeStatus = result.getHandshakeStatus(); final int produced = result.bytesProduced(); final int consumed = result.bytesConsumed(); // Update indexes for the next iteration offset += consumed; length -= consumed; switch (status) { case BUFFER_OVERFLOW: int readableBytes = decodeOut.readableBytes(); if (readableBytes > 0) { decoded = true; ctx.fireChannelRead(decodeOut); } else { decodeOut.release(); } // Allocate a new buffer which can hold all the rest data and loop again. // TODO: We may want to reconsider how we calculate the length here as we may // have more then one ssl message to decode. decodeOut = allocate(ctx, engine.getSession().getApplicationBufferSize() - readableBytes); continue; case CLOSED: // notify about the CLOSED state of the SSLEngine. See #137 notifyClosure = true; break; default: break; } switch (handshakeStatus) { case NEED_UNWRAP: break; case NEED_WRAP: wrapNonAppData(ctx, true); break; case NEED_TASK: runDelegatedTasks(); break; case FINISHED: setHandshakeSuccess(); wrapLater = true; continue; case NOT_HANDSHAKING: if (setHandshakeSuccessIfStillHandshaking()) { wrapLater = true; continue; } if (flushedBeforeHandshake) { // We need to call wrap(...) in case there was a flush done before the handshake // completed. // // See https://github.com/netty/netty/pull/2437 flushedBeforeHandshake = false; wrapLater = true; } break; default: throw new IllegalStateException("unknown handshake status: " + handshakeStatus); } if (status == Status.BUFFER_UNDERFLOW || consumed == 0 && produced == 0) { break; } } if (wrapLater) { wrap(ctx, true); } if (notifyClosure) { sslCloseFuture.trySuccess(ctx.channel()); } } catch (SSLException e) { setHandshakeFailure(ctx, e); throw e; } finally { if (decodeOut.isReadable()) { decoded = true; ctx.fireChannelRead(decodeOut); } else { decodeOut.release(); } } return decoded; }