Пример #1
0
 /**
  * Works around some Android {@link SSLEngine} implementations that skip {@link
  * HandshakeStatus#FINISHED} and go straight into {@link HandshakeStatus#NOT_HANDSHAKING} when
  * handshake is finished.
  *
  * @return {@code true} if and only if the workaround has been applied and thus {@link
  *     #handshakeFuture} has been marked as success by this method
  */
 private boolean setHandshakeSuccessIfStillHandshaking() {
   if (!handshakePromise.isDone()) {
     setHandshakeSuccess();
     return true;
   }
   return false;
 }
Пример #2
0
  @Override
  public void read(ChannelHandlerContext ctx) throws Exception {
    if (!handshakePromise.isDone()) {
      readDuringHandshake = true;
    }

    ctx.read();
  }
Пример #3
0
  @Override
  public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
    // Discard bytes of the cumulation buffer if needed.
    discardSomeReadBytes();

    if (needsFlush) {
      needsFlush = false;
      ctx.flush();
    }

    // If handshake is not finished yet, we need more data.
    if (!ctx.channel().config().isAutoRead() && (!firedChannelRead || !handshakePromise.isDone())) {
      // No auto-read used and no message passed through the ChannelPipeline or the handhshake was
      // not complete
      // yet, which means we need to trigger the read to ensure we not encounter any stalls.
      ctx.read();
    }

    firedChannelRead = false;
    ctx.fireChannelReadComplete();
  }
Пример #4
0
 @Override
 public void flush(ChannelHandlerContext ctx) throws Exception {
   // Do not encrypt the first write request if this handler is
   // created with startTLS flag turned on.
   if (startTls && !sentFirstMessage) {
     sentFirstMessage = true;
     pendingUnencryptedWrites.removeAndWriteAll();
     ctx.flush();
     return;
   }
   if (pendingUnencryptedWrites.isEmpty()) {
     // It's important to NOT use a voidPromise here as the user
     // may want to add a ChannelFutureListener to the ChannelPromise later.
     //
     // See https://github.com/netty/netty/issues/3364
     pendingUnencryptedWrites.add(Unpooled.EMPTY_BUFFER, ctx.newPromise());
   }
   if (!handshakePromise.isDone()) {
     flushedBeforeHandshake = true;
   }
   wrap(ctx, false);
   ctx.flush();
 }
Пример #5
0
  /**
   * Performs TLS (re)negotiation.
   *
   * @param newHandshakePromise if {@code null}, use the existing {@link #handshakePromise},
   *     assuming that the current negotiation has not been finished. Currently, {@code null} is
   *     expected only for the initial handshake.
   */
  private void handshake(final Promise<Channel> newHandshakePromise) {
    final Promise<Channel> p;
    if (newHandshakePromise != null) {
      final Promise<Channel> oldHandshakePromise = handshakePromise;
      if (!oldHandshakePromise.isDone()) {
        // There's no need to handshake because handshake is in progress already.
        // Merge the new promise into the old one.
        oldHandshakePromise.addListener(
            new FutureListener<Channel>() {
              @Override
              public void operationComplete(Future<Channel> future) throws Exception {
                if (future.isSuccess()) {
                  newHandshakePromise.setSuccess(future.getNow());
                } else {
                  newHandshakePromise.setFailure(future.cause());
                }
              }
            });
        return;
      }

      handshakePromise = p = newHandshakePromise;
    } else {
      // Forced to reuse the old handshake.
      p = handshakePromise;
      assert !p.isDone();
    }

    // Begin handshake.
    final ChannelHandlerContext ctx = this.ctx;
    try {
      engine.beginHandshake();
      wrapNonAppData(ctx, false);
      ctx.flush();
    } catch (Exception e) {
      notifyHandshakeFailure(e);
    }

    // Set timeout if necessary.
    final long handshakeTimeoutMillis = this.handshakeTimeoutMillis;
    if (handshakeTimeoutMillis <= 0 || p.isDone()) {
      return;
    }

    final ScheduledFuture<?> timeoutFuture =
        ctx.executor()
            .schedule(
                new Runnable() {
                  @Override
                  public void run() {
                    if (p.isDone()) {
                      return;
                    }
                    notifyHandshakeFailure(HANDSHAKE_TIMED_OUT);
                  }
                },
                handshakeTimeoutMillis,
                TimeUnit.MILLISECONDS);

    // Cancel the handshake timeout when handshake is finished.
    p.addListener(
        new FutureListener<Channel>() {
          @Override
          public void operationComplete(Future<Channel> f) throws Exception {
            timeoutFuture.cancel(false);
          }
        });
  }