예제 #1
0
  private ChannelFuture wrapNonAppData(ChannelHandlerContext ctx, Channel channel)
      throws SSLException {
    ChannelFuture future = null;
    ByteBuffer outNetBuf = bufferPool.acquire();

    SSLEngineResult result;
    try {
      for (; ; ) {
        synchronized (handshakeLock) {
          result = engine.wrap(EMPTY_BUFFER, outNetBuf);
        }

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

          future = future(channel);
          future.addListener(
              new ChannelFutureListener() {
                public void operationComplete(ChannelFuture future) throws Exception {
                  if (future.getCause() instanceof ClosedChannelException) {
                    synchronized (ignoreClosedChannelExceptionLock) {
                      ignoreClosedChannelException++;
                    }
                  }
                }
              });

          write(ctx, future, msg);
        }

        final HandshakeStatus handshakeStatus = result.getHandshakeStatus();
        handleRenegotiation(handshakeStatus);
        switch (handshakeStatus) {
          case FINISHED:
            setHandshakeSuccess(channel);
            runDelegatedTasks();
            break;
          case NEED_TASK:
            runDelegatedTasks();
            break;
          case NEED_UNWRAP:
            if (!Thread.holdsLock(handshakeLock)) {
              // unwrap shouldn't be called when this method was
              // called by unwrap - unwrap will keep running after
              // this method returns.
              unwrap(ctx, channel, ChannelBuffers.EMPTY_BUFFER, 0, 0);
            }
            break;
          case NOT_HANDSHAKING:
          case NEED_WRAP:
            break;
          default:
            throw new IllegalStateException("Unexpected handshake status: " + handshakeStatus);
        }

        if (result.bytesProduced() == 0) {
          break;
        }
      }
    } catch (SSLException e) {
      setHandshakeFailure(channel, e);
      throw e;
    } finally {
      bufferPool.release(outNetBuf);
    }

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

    return future;
  }
예제 #2
0
  private ChannelBuffer unwrap(
      ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, int offset, int length)
      throws SSLException {
    ByteBuffer inNetBuf = buffer.toByteBuffer(offset, length);
    ByteBuffer outAppBuf = bufferPool.acquire();

    try {
      boolean needsWrap = false;
      loop:
      for (; ; ) {
        SSLEngineResult result;
        synchronized (handshakeLock) {
          if (!handshaken
              && !handshaking
              && !engine.getUseClientMode()
              && !engine.isInboundDone()
              && !engine.isOutboundDone()) {
            handshake();
          }

          try {
            result = engine.unwrap(inNetBuf, outAppBuf);
          } catch (SSLException e) {
            throw e;
          }

          final HandshakeStatus handshakeStatus = result.getHandshakeStatus();
          handleRenegotiation(handshakeStatus);
          switch (handshakeStatus) {
            case NEED_UNWRAP:
              if (inNetBuf.hasRemaining() && !engine.isInboundDone()) {
                break;
              } else {
                break loop;
              }
            case NEED_WRAP:
              wrapNonAppData(ctx, channel);
              break;
            case NEED_TASK:
              runDelegatedTasks();
              break;
            case FINISHED:
              setHandshakeSuccess(channel);
              needsWrap = true;
              break loop;
            case NOT_HANDSHAKING:
              needsWrap = true;
              break loop;
            default:
              throw new IllegalStateException("Unknown handshake status: " + handshakeStatus);
          }
        }
      }

      if (needsWrap) {
        // wrap() acquires pendingUnencryptedWrites first and then
        // handshakeLock.  If handshakeLock is already hold by the
        // current thread, calling wrap() will lead to a dead lock
        // i.e. pendingUnencryptedWrites -> handshakeLock vs.
        //      handshakeLock -> pendingUnencryptedLock -> handshakeLock
        //
        // There is also a same issue between pendingEncryptedWrites
        // and pendingUnencryptedWrites.
        if (!Thread.holdsLock(handshakeLock)
            && !pendingEncryptedWritesLock.isHeldByCurrentThread()) {
          wrap(ctx, channel);
        }
      }

      outAppBuf.flip();

      if (outAppBuf.hasRemaining()) {
        ChannelBuffer frame = ChannelBuffers.buffer(outAppBuf.remaining());
        frame.writeBytes(outAppBuf.array(), 0, frame.capacity());
        return frame;
      } else {
        return null;
      }
    } catch (SSLException e) {
      setHandshakeFailure(channel, e);
      throw e;
    } finally {
      bufferPool.release(outAppBuf);
    }
  }
예제 #3
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;
  }