/*
  * Resize (if necessary) the inbound data buffer, and then read more
  * data into the read buffer.
  */
 int read() throws IOException {
   /*
    * Allocate more space if less than 5% remains
    */
   resizeRequestBB(requestBBSize / 20);
   return sc.read(requestBB);
 }
 private byte[] _recv(int length) throws IOException {
   SocketChannel channel = (SocketChannel) key.channel();
   int nrecvd = 0;
   byte[] data = new byte[length];
   ByteBuffer buffer = ByteBuffer.wrap(data);
   key.interestOps(SelectionKey.OP_READ);
   try {
     while (nrecvd < length) {
       if (key.isReadable()) {
         long n = channel.read(buffer);
         if (n < 0) throw new EOFException();
         nrecvd += (int) n;
         if (nrecvd < length && System.currentTimeMillis() > endTime)
           throw new SocketTimeoutException();
       } else blockUntil(key, endTime);
     }
   } finally {
     if (key.isValid()) key.interestOps(0);
   }
   return data;
 }
  private void go() throws IOException {
    // Create a new selector
    Selector selector = Selector.open();

    // Open a listener on each port, and register each one
    // with the selector
    for (int i = 0; i < ports.length; ++i) {
      ServerSocketChannel ssc = ServerSocketChannel.open();
      ssc.configureBlocking(false);
      ServerSocket ss = ssc.socket();
      InetSocketAddress address = new InetSocketAddress(ports[i]);
      ss.bind(address);

      SelectionKey key = ssc.register(selector, SelectionKey.OP_ACCEPT);

      System.out.println("Going to listen on " + ports[i]);
    }

    while (true) {
      int num = selector.select();

      Set selectedKeys = selector.selectedKeys();
      Iterator it = selectedKeys.iterator();

      while (it.hasNext()) {
        SelectionKey key = (SelectionKey) it.next();

        if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {
          // Accept the new connection
          ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
          SocketChannel sc = ssc.accept();
          sc.configureBlocking(false);

          // Add the new connection to the selector
          SelectionKey newKey = sc.register(selector, SelectionKey.OP_READ);
          it.remove();

          System.out.println("Got connection from " + sc);
        } else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
          // Read the data
          SocketChannel sc = (SocketChannel) key.channel();

          // Echo data
          int bytesEchoed = 0;
          while (true) {
            echoBuffer.clear();

            int r = sc.read(echoBuffer);

            if (r <= 0) {
              break;
            }

            echoBuffer.flip();

            sc.write(echoBuffer);
            bytesEchoed += r;
          }

          System.out.println("Echoed " + bytesEchoed + " from " + sc);

          it.remove();
        }
      }

      // System.out.println( "going to clear" );
      //      selectedKeys.clear();
      // System.out.println( "cleared" );
    }
  }
  public static void main(String[] args) {
    try {
      System.out.println("CliTest.java");
      // create TCP socket channel
      SocketChannel channel = SocketChannel.open();
      System.out.println("CliTest.java: channel created");
      channel.connect(new InetSocketAddress("localhost", PORT));
      System.out.println("CliTest.java: channel socket connected");
      System.out.println();

      // create  & send a login message
      byte[] bytes = LoginMessage.getLoginMessage("user1", "password1");
      System.out.println("CliTest.java: login message created");
      System.out.println(LoginMessage.getMessageString(bytes));
      System.out.printf("CliTest.java: login message length in bytes: %d\n", bytes.length);
      ByteBuffer buf = ByteBuffer.allocate(4096);
      buf.put(bytes);
      buf.flip();
      // System.out.printf("CliTest.java: buf.remaining before channel.write(): %d\n",
      // buf.remaining());
      int numwritten = channel.write(buf);
      System.out.printf(
          "CliTest.java: login mesage written: number of bytes written: %d\n", numwritten);

      // read reply message
      buf.clear();
      int numread = channel.read(buf);
      bytes = new byte[numread];
      buf.flip();
      buf.get(bytes);
      if (LoginMessage.isLoginSuccessMessage(bytes)) {
        System.out.printf(
            "CliTest.java: first message read: Success Message: number of bytes read: %d\n",
            numread);
        // get remote port number from success message
        int port = LoginMessage.getPort(bytes);
        System.out.printf("Port Number: %d\n", port);
        byte playerid = LoginMessage.getPlayerId(bytes);
        System.out.printf("Player id: %d\n", playerid);
        String mcastString = LoginMessage.getMulticastAddress(bytes);
        System.out.printf("Multicast Address: %s\n", mcastString);
        // create datagram channel & connect to rem port
        DatagramChannel dchannel = DatagramChannel.open();
        dchannel.socket().bind(new InetSocketAddress(0));
        dchannel.socket().connect(new InetSocketAddress(channel.socket().getInetAddress(), port));
        // get localport of datagram socket
        int localport = dchannel.socket().getLocalPort();
        System.out.printf("UDP local port: %d\n", localport);
        // send success message to send port number to server
        bytes = LoginMessage.getLoginSuccessMessage(playerid, null, localport);
        buf.clear();
        buf.put(bytes);
        buf.flip();
        channel.write(buf);

        DeathMessage dm = new DeathMessage((byte) 1, (byte) 1);
        bytes = dm.getByteMessage();
        buf.clear();
        buf.put(bytes);
        buf.flip();
        channel.write(buf);
      } else {
        System.out.printf(
            "CliTest.java: first message read: NOT Success Message: number of bytes read: %d\n",
            numread);
      }
      channel.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
 private void readMessage(SelectionKey sk, SocketChannel readChannel, TcpAddress incomingAddress)
     throws IOException {
   // note that socket has been used
   SocketEntry entry = (SocketEntry) sockets.get(incomingAddress);
   if (entry != null) {
     entry.used();
     ByteBuffer readBuffer = entry.getReadBuffer();
     if (readBuffer != null) {
       readChannel.read(readBuffer);
       if (readBuffer.hasRemaining()) {
         readChannel.register(selector, SelectionKey.OP_READ, entry);
       } else {
         dispatchMessage(incomingAddress, readBuffer, readBuffer.capacity());
       }
       return;
     }
   }
   ByteBuffer byteBuffer = ByteBuffer.wrap(buf);
   byteBuffer.limit(messageLengthDecoder.getMinHeaderLength());
   long bytesRead = readChannel.read(byteBuffer);
   if (logger.isDebugEnabled()) {
     logger.debug("Reading header " + bytesRead + " bytes from " + incomingAddress);
   }
   MessageLength messageLength = new MessageLength(0, Integer.MIN_VALUE);
   if (bytesRead == messageLengthDecoder.getMinHeaderLength()) {
     messageLength = messageLengthDecoder.getMessageLength(ByteBuffer.wrap(buf));
     if (logger.isDebugEnabled()) {
       logger.debug("Message length is " + messageLength);
     }
     if ((messageLength.getMessageLength() > getMaxInboundMessageSize())
         || (messageLength.getMessageLength() <= 0)) {
       logger.error(
           "Received message length "
               + messageLength
               + " is greater than inboundBufferSize "
               + getMaxInboundMessageSize());
       synchronized (entry) {
         entry.getSocket().close();
         logger.info("Socket to " + entry.getPeerAddress() + " closed due to an error");
       }
     } else {
       byteBuffer.limit(messageLength.getMessageLength());
       bytesRead += readChannel.read(byteBuffer);
       if (bytesRead == messageLength.getMessageLength()) {
         dispatchMessage(incomingAddress, byteBuffer, bytesRead);
       } else {
         byte[] message = new byte[byteBuffer.limit()];
         byteBuffer.flip();
         byteBuffer.get(message, 0, byteBuffer.limit() - byteBuffer.remaining());
         entry.setReadBuffer(ByteBuffer.wrap(message));
       }
       readChannel.register(selector, SelectionKey.OP_READ, entry);
     }
   } else if (bytesRead < 0) {
     logger.debug("Socket closed remotely");
     sk.cancel();
     readChannel.close();
     TransportStateEvent e =
         new TransportStateEvent(
             DefaultTcpTransportMapping.this,
             incomingAddress,
             TransportStateEvent.STATE_DISCONNECTED_REMOTELY,
             null);
     fireConnectionStateChanged(e);
   }
 }