예제 #1
0
  void close(SctpChannelImpl channel, ChannelFuture future) {
    boolean connected = channel.isConnected();
    boolean bound = channel.isBound();
    try {
      channel.channel.close();
      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);
    }
  }
예제 #2
0
  private void cleanUpWriteBuffer(SctpChannelImpl channel) {
    Exception cause = null;
    boolean fireExceptionCaught = false;

    // Clean up the stale messages in the write buffer.
    synchronized (channel.writeLock) {
      MessageEvent evt = channel.currentWriteEvent;
      if (evt != null) {
        // Create the exception only once to avoid the excessive overhead
        // caused by fillStackTrace.
        if (channel.isOpen()) {
          cause = new NotYetConnectedException();
        } else {
          cause = new ClosedChannelException();
        }

        ChannelFuture future = evt.getFuture();
        channel.currentWriteBuffer.release();
        channel.currentWriteBuffer = null;
        channel.currentWriteEvent = null;
        evt = null;
        future.setFailure(cause);
        fireExceptionCaught = true;
      }

      Queue<MessageEvent> writeBuffer = channel.writeBuffer;
      if (!writeBuffer.isEmpty()) {
        // Create the exception only once to avoid the excessive overhead
        // caused by fillStackTrace.
        if (cause == null) {
          if (channel.isOpen()) {
            cause = new NotYetConnectedException();
          } else {
            cause = new ClosedChannelException();
          }
        }

        for (; ; ) {
          evt = writeBuffer.poll();
          if (evt == null) {
            break;
          }
          evt.getFuture().setFailure(cause);
          fireExceptionCaught = true;
        }
      }
    }

    if (fireExceptionCaught) {
      fireExceptionCaught(channel, cause);
    }
  }
예제 #3
0
    @Override
    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);
        }
        channel.setConnected();
        if (future != null) {
          future.setSuccess();
        }
      } 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);
        }
      }

      if (!server) {
        if (!((SctpClientChannel) channel).boundManually) {
          fireChannelBound(channel, localAddress);
        }
        fireChannelConnected(channel, remoteAddress);
      }
    }
예제 #4
0
  private void clearOpWrite(SctpChannelImpl channel) {
    Selector selector = this.selector;
    SelectionKey key = channel.channel.keyFor(selector);
    if (key == null) {
      return;
    }
    if (!key.isValid()) {
      close(key);
      return;
    }

    // interestOps can change at any time and at any thread.
    // Acquire a lock to avoid possible race condition.
    synchronized (channel.interestOpsLock) {
      int interestOps = channel.getRawInterestOps();
      if ((interestOps & SelectionKey.OP_WRITE) != 0) {
        interestOps &= ~SelectionKey.OP_WRITE;
        key.interestOps(interestOps);
        channel.setRawInterestOpsNow(interestOps);
      }
    }
  }
예제 #5
0
  void writeFromUserCode(final SctpChannelImpl channel) {
    if (!channel.isConnected()) {
      cleanUpWriteBuffer(channel);
      return;
    }

    if (scheduleWriteIfNecessary(channel)) {
      return;
    }

    // From here, we are sure Thread.currentThread() == workerThread.

    if (channel.writeSuspended) {
      return;
    }

    if (channel.inWriteNowLoop) {
      return;
    }

    write0(channel);
  }
예제 #6
0
  void setInterestOps(SctpChannelImpl 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) {
        Selector selector = this.selector;
        SelectionKey key = channel.channel.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() != thread && wakenUp.compareAndSet(false, true)) {
                selector.wakeup();
              }
              changed = true;
            }
            break;
          case 1:
          case 2:
            if (channel.getRawInterestOps() != interestOps) {
              if (Thread.currentThread() == thread) {
                key.interestOps(interestOps);
                changed = true;
              } else {
                selectorGuard.readLock().lock();
                try {
                  if (wakenUp.compareAndSet(false, true)) {
                    selector.wakeup();
                  }
                  key.interestOps(interestOps);
                  changed = true;
                } finally {
                  selectorGuard.readLock().unlock();
                }
              }
            }
            break;
          default:
            throw new Error();
        }

        if (changed) {
          channel.setRawInterestOpsNow(interestOps);
        }
      }

      future.setSuccess();
      if (changed) {
        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);
    }
  }
예제 #7
0
  private void write0(SctpChannelImpl channel) {
    boolean open = true;
    boolean addOpWrite = false;
    boolean removeOpWrite = false;

    long writtenBytes = 0;

    final SctpSendBufferPool sendBufferPool = this.sendBufferPool;
    final com.sun.nio.sctp.SctpChannel ch = channel.channel;
    final Queue<MessageEvent> writeBuffer = channel.writeBuffer;
    final int writeSpinCount = channel.getConfig().getWriteSpinCount();
    synchronized (channel.writeLock) {
      channel.inWriteNowLoop = true;
      for (; ; ) {
        MessageEvent evt = channel.currentWriteEvent;
        SendBuffer buf;
        if (evt == null) {
          if ((channel.currentWriteEvent = evt = writeBuffer.poll()) == null) {
            removeOpWrite = true;
            channel.writeSuspended = false;
            break;
          }

          channel.currentWriteBuffer = buf = sendBufferPool.acquire(evt.getMessage());
        } else {
          buf = channel.currentWriteBuffer;
        }

        ChannelFuture future = evt.getFuture();
        try {
          long localWrittenBytes = 0;
          for (int i = writeSpinCount; i > 0; i--) {
            localWrittenBytes = buf.transferTo(ch);
            if (localWrittenBytes != 0) {
              writtenBytes += localWrittenBytes;
              break;
            }
            if (buf.finished()) {
              break;
            }
          }

          if (buf.finished()) {
            // Successful write - proceed to the next message.
            buf.release();
            channel.currentWriteEvent = null;
            channel.currentWriteBuffer = null;
            evt = null;
            buf = null;
            future.setSuccess();
          } else {
            // Not written fully - perhaps the kernel buffer is full.
            addOpWrite = true;
            channel.writeSuspended = true;

            if (localWrittenBytes > 0) {
              // Notify progress listeners if necessary.
              future.setProgress(localWrittenBytes, buf.writtenBytes(), buf.totalBytes());
            }
            break;
          }
        } catch (AsynchronousCloseException e) {
          // Doesn't need a user attention - ignore.
        } catch (Throwable t) {
          buf.release();
          channel.currentWriteEvent = null;
          channel.currentWriteBuffer = null;
          buf = null;
          evt = null;
          future.setFailure(t);
          fireExceptionCaught(channel, t);
          if (t instanceof IOException) {
            open = false;
            close(channel, succeededFuture(channel));
          }
        }
      }
      channel.inWriteNowLoop = false;
    }

    if (open) {
      if (addOpWrite) {
        setOpWrite(channel);
      } else if (removeOpWrite) {
        clearOpWrite(channel);
      }
    }

    fireWriteComplete(channel, writtenBytes);
  }
예제 #8
0
 void writeFromSelectorLoop(final SelectionKey k) {
   SctpChannelImpl ch = (SctpChannelImpl) k.attachment();
   ch.writeSuspended = false;
   write0(ch);
 }
예제 #9
0
  private boolean read(SelectionKey k) {
    final SctpChannelImpl channel = (SctpChannelImpl) k.attachment();

    final ReceiveBufferSizePredictor predictor =
        channel.getConfig().getReceiveBufferSizePredictor();
    final int predictedRecvBufSize = predictor.nextReceiveBufferSize();

    boolean messageReceived = false;
    boolean failure = true;
    MessageInfo messageInfo = null;

    ByteBuffer bb = recvBufferPool.acquire(predictedRecvBufSize);
    try {
      messageInfo = channel.channel.receive(bb, null, notificationHandler);
      if (messageInfo != null) {
        messageReceived = true;
        if (!messageInfo.isUnordered()) {
          failure = false;
        } else {
          if (logger.isErrorEnabled()) {
            logger.error("Received unordered SCTP Packet");
          }
          failure = true;
        }
      } else {
        messageReceived = false;
        failure = false;
      }
    } catch (ClosedChannelException e) {
      // Can happen, and does not need a user attention.
    } catch (Throwable t) {
      fireExceptionCaught(channel, t);
    }

    if (messageReceived) {
      bb.flip();

      final ChannelBufferFactory bufferFactory = channel.getConfig().getBufferFactory();
      final int receivedBytes = bb.remaining();
      final ChannelBuffer buffer = bufferFactory.getBuffer(receivedBytes);
      buffer.setBytes(0, bb);
      buffer.writerIndex(receivedBytes);

      recvBufferPool.release(bb);

      // Update the predictor.
      predictor.previousReceiveBufferSize(receivedBytes);

      // Fire the event.
      fireMessageReceived(channel, new SctpFrame(messageInfo, buffer), messageInfo.address());
    } else {
      recvBufferPool.release(bb);
    }

    if (channel.channel.isBlocking() && !messageReceived || failure) {
      k.cancel(); // Some JDK implementations run into an infinite loop without this.
      close(channel, succeededFuture(channel));
      return false;
    }

    return true;
  }