@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);
  }
Example #2
0
  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);
   }
 }
Example #4
0
 @Override
 public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
   if (msg instanceof DefaultLastHttpContent) {
     DefaultLastHttpContent response = (DefaultLastHttpContent) msg;
     ctx.fireChannelRead(response.content());
   }
 }
Example #5
0
  /**
   * 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);
   }
 }
Example #8
0
 @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);
   }
 }
Example #9
0
 /**
  * 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);
     }
   }
 }
Example #10
0
  /*
   * 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);
    }
  }
Example #11
0
 @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);
    }
  }
Example #14
0
 @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);
    }
Example #17
0
 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);
 }
Example #27
0
  @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);
  }
Example #30
0
  /** 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;
  }