Exemplo n.º 1
0
  private ChannelFuture wrap(ChannelHandlerContext context, Channel channel) throws SSLException {

    ChannelFuture future = null;
    ChannelBuffer msg;
    ByteBuffer outNetBuf = bufferPool.acquire();
    boolean success = true;
    boolean offered = false;
    boolean needsUnwrap = false;
    try {
      loop:
      for (; ; ) {
        // Acquire a lock to make sure unencrypted data is polled
        // in order and their encrypted counterpart is offered in
        // order.
        synchronized (pendingUnencryptedWrites) {
          PendingWrite pendingWrite = pendingUnencryptedWrites.peek();
          if (pendingWrite == null) {
            break;
          }

          ByteBuffer outAppBuf = pendingWrite.outAppBuf;
          if (outAppBuf == null) {
            // A write request with an empty buffer
            pendingUnencryptedWrites.remove();
            offerEncryptedWriteRequest(
                new DownstreamMessageEvent(
                    channel,
                    pendingWrite.future,
                    ChannelBuffers.EMPTY_BUFFER,
                    channel.getRemoteAddress()));
            offered = true;
          } else {
            SSLEngineResult result = null;
            try {
              synchronized (handshakeLock) {
                result = engine.wrap(outAppBuf, outNetBuf);
              }
            } finally {
              if (!outAppBuf.hasRemaining()) {
                pendingUnencryptedWrites.remove();
              }
            }

            if (result.bytesProduced() > 0) {
              outNetBuf.flip();
              msg = ChannelBuffers.buffer(outNetBuf.remaining());
              msg.writeBytes(outNetBuf.array(), 0, msg.capacity());
              outNetBuf.clear();

              if (pendingWrite.outAppBuf.hasRemaining()) {
                // pendingWrite's future shouldn't be notified if
                // only partial data is written.
                future = succeededFuture(channel);
              } else {
                future = pendingWrite.future;
              }

              MessageEvent encryptedWrite =
                  new DownstreamMessageEvent(channel, future, msg, channel.getRemoteAddress());
              offerEncryptedWriteRequest(encryptedWrite);
              offered = true;
            } else {
              final HandshakeStatus handshakeStatus = result.getHandshakeStatus();
              handleRenegotiation(handshakeStatus);
              switch (handshakeStatus) {
                case NEED_WRAP:
                  if (outAppBuf.hasRemaining()) {
                    break;
                  } else {
                    break loop;
                  }
                case NEED_UNWRAP:
                  needsUnwrap = true;
                  break loop;
                case NEED_TASK:
                  runDelegatedTasks();
                  break;
                case FINISHED:
                case NOT_HANDSHAKING:
                  if (handshakeStatus == HandshakeStatus.FINISHED) {
                    setHandshakeSuccess(channel);
                  }
                  if (result.getStatus() == Status.CLOSED) {
                    success = false;
                  }
                  break loop;
                default:
                  throw new IllegalStateException("Unknown handshake status: " + handshakeStatus);
              }
            }
          }
        }
      }
    } catch (SSLException e) {
      success = false;
      setHandshakeFailure(channel, e);
      throw e;
    } finally {
      bufferPool.release(outNetBuf);

      if (offered) {
        flushPendingEncryptedWrites(context);
      }

      if (!success) {
        IllegalStateException cause = new IllegalStateException("SSLEngine already closed");
        // Mark all remaining pending writes as failure if anything
        // wrong happened before the write requests are wrapped.
        // Please note that we do not call setFailure while a lock is
        // acquired, to avoid a potential dead lock.
        for (; ; ) {
          PendingWrite pendingWrite;
          synchronized (pendingUnencryptedWrites) {
            pendingWrite = pendingUnencryptedWrites.poll();
            if (pendingWrite == null) {
              break;
            }
          }

          pendingWrite.future.setFailure(cause);
        }
      }
    }

    if (needsUnwrap) {
      unwrap(context, channel, ChannelBuffers.EMPTY_BUFFER, 0, 0);
    }

    if (future == null) {
      future = succeededFuture(channel);
    }
    return future;
  }