Beispiel #1
0
  /**
   * Starts an SSL / TLS handshake for the specified channel.
   *
   * @return a {@link ChannelFuture} which is notified when the handshake succeeds or fails.
   */
  public ChannelFuture handshake() {
    if (handshaken && !isEnableRenegotiation()) {
      throw new IllegalStateException("renegotiation disabled");
    }

    ChannelHandlerContext ctx = this.ctx;
    Channel channel = ctx.getChannel();
    ChannelFuture handshakeFuture;
    synchronized (handshakeLock) {
      if (handshaking) {
        return this.handshakeFuture;
      } else {
        handshaking = true;
        try {
          engine.beginHandshake();
          runDelegatedTasks();
          handshakeFuture = this.handshakeFuture = future(channel);
        } catch (SSLException e) {
          handshakeFuture = this.handshakeFuture = failedFuture(channel, e);
        }
      }
    }

    try {
      wrapNonAppData(ctx, channel);
    } catch (SSLException e) {
      handshakeFuture.setFailure(e);
    }
    return handshakeFuture;
  }
Beispiel #2
0
  @Override
  public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {

    // Make sure the handshake future is notified when a connection has
    // been closed during handshake.
    synchronized (handshakeLock) {
      if (handshaking) {
        handshakeFuture.setFailure(new ClosedChannelException());
      }
    }

    try {
      super.channelDisconnected(ctx, e);
    } finally {
      unwrap(ctx, e.getChannel(), ChannelBuffers.EMPTY_BUFFER, 0, 0);
      engine.closeOutbound();
      if (!sentCloseNotify.get() && handshaken) {
        try {
          engine.closeInbound();
        } catch (SSLException ex) {
          logger.debug("Failed to clean up SSLEngine.", ex);
        }
      }
    }
  }
Beispiel #3
0
 static void close(OioDatagramChannel channel, ChannelFuture future) {
   boolean connected = channel.isConnected();
   boolean bound = channel.isBound();
   try {
     channel.socket.close();
     if (channel.setClosed()) {
       future.setSuccess();
       if (connected) {
         // Notify the worker so it stops reading.
         Thread currentThread = Thread.currentThread();
         Thread workerThread = channel.workerThread;
         if (workerThread != null && currentThread != workerThread) {
           workerThread.interrupt();
         }
         fireChannelDisconnected(channel);
       }
       if (bound) {
         fireChannelUnbound(channel);
       }
       fireChannelClosed(channel);
     } else {
       future.setSuccess();
     }
   } catch (Throwable t) {
     future.setFailure(t);
     fireExceptionCaught(channel, t);
   }
 }
  private void bind(OioDatagramChannel channel, ChannelFuture future, SocketAddress localAddress) {
    boolean bound = false;
    boolean workerStarted = false;
    try {
      channel.socket.bind(localAddress);
      bound = true;

      // Fire events
      future.setSuccess();
      fireChannelBound(channel, channel.getLocalAddress());

      // Start the business.
      workerExecutor.execute(
          new IoWorkerRunnable(
              new ThreadRenamingRunnable(
                  new OioDatagramWorker(channel),
                  "Old I/O datagram worker (channelId: "
                      + channel.getId()
                      + ", "
                      + channel.getLocalAddress()
                      + ')')));
      workerStarted = true;
    } catch (Throwable t) {
      future.setFailure(t);
      fireExceptionCaught(channel, t);
    } finally {
      if (bound && !workerStarted) {
        OioDatagramWorker.close(channel, future);
      }
    }
  }
  /**
   * Will bind the DatagramSocket to the passed-in address. Every call bind will spawn a new thread
   * using the that basically in turn
   */
  private void bind(
      final NioDatagramChannel channel,
      final ChannelFuture future,
      final InetSocketAddress address) {
    boolean bound = false;
    boolean started = false;
    try {
      // First bind the DatagramSocket the specified port.
      channel.getDatagramChannel().socket().bind(address);
      bound = true;

      future.setSuccess();
      fireChannelBound(channel, address);

      channel.worker.register(channel, null);
      started = true;
    } catch (final Throwable t) {
      future.setFailure(t);
      fireExceptionCaught(channel, t);
    } finally {
      if (!started && bound) {
        close(channel, future);
      }
    }
  }
Beispiel #6
0
  static void write(
      OioDatagramChannel channel,
      ChannelFuture future,
      Object message,
      SocketAddress remoteAddress) {
    try {
      ChannelBuffer buf = (ChannelBuffer) message;
      int length = buf.readableBytes();
      ByteBuffer nioBuf = buf.toByteBuffer();
      DatagramPacket packet;
      if (nioBuf.hasArray()) {
        // Avoid copy if the buffer is backed by an array.
        packet = new DatagramPacket(nioBuf.array(), nioBuf.arrayOffset(), length);
      } else {
        // Otherwise it will be expensive.
        byte[] arrayBuf = new byte[length];
        buf.getBytes(0, arrayBuf);
        packet = new DatagramPacket(arrayBuf, length);
      }

      if (remoteAddress != null) {
        packet.setSocketAddress(remoteAddress);
      }
      channel.socket.send(packet);
      fireWriteComplete(channel, length);
      future.setSuccess();
    } catch (Throwable t) {
      future.setFailure(t);
      fireExceptionCaught(channel, t);
    }
  }
Beispiel #7
0
  static void close(NioSocketChannel channel, ChannelFuture future) {
    NioWorker worker = channel.worker;

    boolean connected = channel.isConnected();
    boolean bound = channel.isBound();
    try {
      channel.socket.close();
      worker.cancelledKeys++;

      if (channel.setClosed()) {
        future.setSuccess();
        if (connected) {
          fireChannelDisconnected(channel);
        }
        if (bound) {
          fireChannelUnbound(channel);
        }

        cleanUpWriteBuffer(channel);
        fireChannelClosed(channel);
      } else {
        future.setSuccess();
      }
    } catch (Throwable t) {
      future.setFailure(t);
      fireExceptionCaught(channel, t);
    }
  }
  private void connect(
      OioDatagramChannel channel, ChannelFuture future, SocketAddress remoteAddress) {

    boolean bound = channel.isBound();
    boolean connected = false;
    boolean workerStarted = false;

    future.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);

    // Clear the cached address so that the next getRemoteAddress() call
    // updates the cache.
    channel.remoteAddress = null;

    try {
      channel.socket.connect(remoteAddress);
      connected = true;

      // Fire events.
      future.setSuccess();
      if (!bound) {
        fireChannelBound(channel, channel.getLocalAddress());
      }
      fireChannelConnected(channel, channel.getRemoteAddress());

      String threadName =
          "Old I/O datagram worker (channelId: "
              + channel.getId()
              + ", "
              + channel.getLocalAddress()
              + " => "
              + channel.getRemoteAddress()
              + ')';
      if (!bound) {
        // Start the business.
        workerExecutor.execute(
            new IoWorkerRunnable(
                new ThreadRenamingRunnable(new OioDatagramWorker(channel), threadName)));
      } else {
        // Worker started by bind() - just rename.
        Thread workerThread = channel.workerThread;
        if (workerThread != null) {
          try {
            workerThread.setName(threadName);
          } catch (SecurityException e) {
            // Ignore.
          }
        }
      }

      workerStarted = true;
    } catch (Throwable t) {
      future.setFailure(t);
      fireExceptionCaught(channel, t);
    } finally {
      if (connected && !workerStarted) {
        OioDatagramWorker.close(channel, future);
      }
    }
  }
    public void run() {
      SocketAddress localAddress = channel.getLocalAddress();
      SocketAddress remoteAddress = channel.getRemoteAddress();

      if (localAddress == null || remoteAddress == null) {
        if (future != null) {
          future.setFailure(new ClosedChannelException());
        }
        close(channel, succeededFuture(channel));
        return;
      }

      try {
        if (server) {
          channel.channel.configureBlocking(false);
        }

        synchronized (channel.interestOpsLock) {
          channel.channel.register(selector, channel.getRawInterestOps(), channel);
        }
        if (future != null) {
          channel.setConnected();
          future.setSuccess();
        }

        if (server || !((NioClientSocketChannel) channel).boundManually) {
          fireChannelBound(channel, localAddress);
        }
        fireChannelConnected(channel, remoteAddress);
      } catch (IOException e) {
        if (future != null) {
          future.setFailure(e);
        }
        close(channel, succeededFuture(channel));
        if (!(e instanceof ClosedChannelException)) {
          throw new ChannelException("Failed to register a socket to the selector.", e);
        }
      }
    }
Beispiel #10
0
  private void setHandshakeFailure(Channel channel, SSLException cause) {
    synchronized (handshakeLock) {
      if (!handshaking) {
        return;
      }
      handshaking = false;
      handshaken = false;

      if (handshakeFuture == null) {
        handshakeFuture = future(channel);
      }
    }
    handshakeFuture.setFailure(cause);
  }
 private void close(NioDatagramChannel channel, ChannelFuture future) {
   try {
     channel.getDatagramChannel().socket().close();
     if (channel.setClosed()) {
       future.setSuccess();
       if (channel.isBound()) {
         fireChannelUnbound(channel);
       }
       fireChannelClosed(channel);
     } else {
       future.setSuccess();
     }
   } catch (final Throwable t) {
     future.setFailure(t);
     fireExceptionCaught(channel, t);
   }
 }
  private void connect(
      NioDatagramChannel channel, ChannelFuture future, SocketAddress remoteAddress) {

    boolean bound = channel.isBound();
    boolean connected = false;
    boolean workerStarted = false;

    future.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);

    // Clear the cached address so that the next getRemoteAddress() call
    // updates the cache.
    channel.remoteAddress = null;

    try {
      channel.getDatagramChannel().connect(remoteAddress);
      connected = true;

      // Fire events.
      future.setSuccess();
      if (!bound) {
        fireChannelBound(channel, channel.getLocalAddress());
      }
      fireChannelConnected(channel, channel.getRemoteAddress());

      if (!bound) {
        channel.worker.register(channel, future);
      }

      workerStarted = true;
    } catch (Throwable t) {
      future.setFailure(t);
      fireExceptionCaught(channel, t);
    } finally {
      if (connected && !workerStarted) {
        channel.worker.close(channel, future);
      }
    }
  }
Beispiel #13
0
  static void setInterestOps(OioDatagramChannel channel, ChannelFuture future, int interestOps) {

    // Override OP_WRITE flag - a user cannot change this flag.
    interestOps &= ~Channel.OP_WRITE;
    interestOps |= channel.getInterestOps() & Channel.OP_WRITE;

    boolean changed = false;
    try {
      if (channel.getInterestOps() != interestOps) {
        if ((interestOps & Channel.OP_READ) != 0) {
          channel.setInterestOpsNow(Channel.OP_READ);
        } else {
          channel.setInterestOpsNow(Channel.OP_NONE);
        }
        changed = true;
      }

      future.setSuccess();
      if (changed) {
        synchronized (channel.interestOpsLock) {
          channel.setInterestOpsNow(interestOps);

          // Notify the worker so it stops or continues reading.
          Thread currentThread = Thread.currentThread();
          Thread workerThread = channel.workerThread;
          if (workerThread != null && currentThread != workerThread) {
            workerThread.interrupt();
          }
        }

        fireChannelInterestChanged(channel);
      }
    } catch (Throwable t) {
      future.setFailure(t);
      fireExceptionCaught(channel, t);
    }
  }
  @Test
  public void shouldNotPropagateDownstreamFlushOnPipelineFutureFailure() throws Exception {

    context.checking(
        new Expectations() {
          {
            oneOf(upstream)
                .handleUpstream(
                    with(any(ChannelHandlerContext.class)), with(any(PreparationEvent.class)));
            oneOf(upstream)
                .handleUpstream(
                    with(any(ChannelHandlerContext.class)), with(channelState(OPEN, TRUE)));
          }
        });

    channelFactory.newChannel(pipeline);
    ChannelFuture executionFuture = execution.getHandlerFuture();
    executionFuture.setFailure(new ChannelException("pipeline already failed"));

    ChannelFuture handlerFuture = handler.getHandlerFuture();
    assertFalse(handlerFuture.isDone());

    context.assertIsSatisfied();
  }
Beispiel #15
0
  static void disconnect(OioDatagramChannel channel, ChannelFuture future) {
    boolean connected = channel.isConnected();
    try {
      channel.socket.disconnect();
      future.setSuccess();
      if (connected) {
        // Update the worker's thread name to reflect the state change.
        Thread workerThread = channel.workerThread;
        if (workerThread != null) {
          try {
            workerThread.setName("Old I/O datagram worker (" + channel + ')');
          } catch (SecurityException e) {
            // Ignore.
          }
        }

        // Notify.
        fireChannelDisconnected(channel);
      }
    } catch (Throwable t) {
      future.setFailure(t);
      fireExceptionCaught(channel, t);
    }
  }
Beispiel #16
0
  static void setInterestOps(NioSocketChannel channel, ChannelFuture future, int interestOps) {
    boolean changed = false;
    try {
      // interestOps can change at any time and at any thread.
      // Acquire a lock to avoid possible race condition.
      synchronized (channel.interestOpsLock) {
        NioWorker worker = channel.worker;
        Selector selector = worker.selector;
        SelectionKey key = channel.socket.keyFor(selector);

        if (key == null || selector == null) {
          // Not registered to the worker yet.
          // Set the rawInterestOps immediately; RegisterTask will pick it up.
          channel.setRawInterestOpsNow(interestOps);
          return;
        }

        // Override OP_WRITE flag - a user cannot change this flag.
        interestOps &= ~Channel.OP_WRITE;
        interestOps |= channel.getRawInterestOps() & Channel.OP_WRITE;

        switch (CONSTRAINT_LEVEL) {
          case 0:
            if (channel.getRawInterestOps() != interestOps) {
              key.interestOps(interestOps);
              if (Thread.currentThread() != worker.thread
                  && worker.wakenUp.compareAndSet(false, true)) {
                selector.wakeup();
              }
              changed = true;
            }
            break;
          case 1:
          case 2:
            if (channel.getRawInterestOps() != interestOps) {
              if (Thread.currentThread() == worker.thread) {
                key.interestOps(interestOps);
                changed = true;
              } else {
                worker.selectorGuard.readLock().lock();
                try {
                  if (worker.wakenUp.compareAndSet(false, true)) {
                    selector.wakeup();
                  }
                  key.interestOps(interestOps);
                  changed = true;
                } finally {
                  worker.selectorGuard.readLock().unlock();
                }
              }
            }
            break;
          default:
            throw new Error();
        }
      }

      future.setSuccess();
      if (changed) {
        channel.setRawInterestOpsNow(interestOps);
        fireChannelInterestChanged(channel);
      }
    } catch (CancelledKeyException e) {
      // setInterestOps() was called on a closed channel.
      ClosedChannelException cce = new ClosedChannelException();
      future.setFailure(cce);
      fireExceptionCaught(channel, cce);
    } catch (Throwable t) {
      future.setFailure(t);
      fireExceptionCaught(channel, t);
    }
  }