@Test
  public void testEcho() throws Exception {
    Socket client = newClient();

    client.setSoTimeout(60000);

    SocketChannel server = _connector.accept();
    server.configureBlocking(false);

    _manager.accept(server);

    // Write client to server
    client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8));

    // Verify echo server to client
    for (char c : "HelloWorld".toCharArray()) {
      int b = client.getInputStream().read();
      assertTrue(b > 0);
      assertEquals(c, (char) b);
    }

    // wait for read timeout
    client.setSoTimeout(500);
    long start = System.currentTimeMillis();
    try {
      client.getInputStream().read();
      Assert.fail();
    } catch (SocketTimeoutException e) {
      long duration = System.currentTimeMillis() - start;
      Assert.assertThat("timeout duration", duration, greaterThanOrEqualTo(400L));
    }

    // write then shutdown
    client.getOutputStream().write("Goodbye Cruel TLS".getBytes(StandardCharsets.UTF_8));

    // Verify echo server to client
    for (char c : "Goodbye Cruel TLS".toCharArray()) {
      int b = client.getInputStream().read();
      Assert.assertThat("expect valid char integer", b, greaterThan(0));
      assertEquals("expect characters to be same", c, (char) b);
    }
    client.close();

    for (int i = 0; i < 10; ++i) {
      if (server.isOpen()) Thread.sleep(10);
      else break;
    }
    assertFalse(server.isOpen());
  }
  @Test
  public void testWriteBlocked() throws Exception {
    Socket client = newClient();

    client.setSoTimeout(10000);

    SocketChannel server = _connector.accept();
    server.configureBlocking(false);

    _manager.accept(server);

    // Write client to server
    _writeCount = 10000;
    String data = "Now is the time for all good men to come to the aid of the party";
    client.getOutputStream().write(data.getBytes(StandardCharsets.UTF_8));
    BufferedInputStream in = new BufferedInputStream(client.getInputStream());

    int byteNum = 0;
    try {
      for (int i = 0; i < _writeCount; i++) {
        if (i % 1000 == 0) TimeUnit.MILLISECONDS.sleep(200);

        // Verify echo server to client
        for (int j = 0; j < data.length(); j++) {
          char c = data.charAt(j);
          int b = in.read();
          byteNum++;
          assertTrue(b > 0);
          assertEquals("test-" + i + "/" + j, c, (char) b);
        }

        if (i == 0) _lastEndPoint.setIdleTimeout(60000);
      }
    } catch (SocketTimeoutException e) {
      System.err.println("SelectorManager.dump() = " + _manager.dump());
      LOG.warn("Server: " + server);
      LOG.warn("Error reading byte #" + byteNum, e);
      throw e;
    }

    client.close();

    for (int i = 0; i < 10; ++i) {
      if (server.isOpen()) Thread.sleep(10);
      else break;
    }
    assertFalse(server.isOpen());
  }
Esempio n. 3
0
 /**
  * Sends a packet of data to the client through {@code buffer}.
  *
  * @param buffer the packet of data to send.
  */
 public void send(ByteBuffer buffer) {
   if (!channel.isOpen() || packetDisconnect || combatLogout) return;
   buffer.flip();
   try {
     channel.write(buffer);
   } catch (Exception ex) {
     ex.printStackTrace();
     disconnect(true);
   }
 }
Esempio n. 4
0
 private synchronized void close() throws IOException {
   data = null;
   dataLengthBuffer = null;
   if (!channel.isOpen()) return;
   try {
     socket.shutdownOutput();
   } catch (Exception e) {
   }
   if (channel.isOpen()) {
     try {
       channel.close();
     } catch (Exception e) {
     }
   }
   try {
     socket.close();
   } catch (Exception e) {
   }
 }
Esempio n. 5
0
 public void disconnect() {
   if (isConnected()) {
     try {
       inputStream.close();
       outputStream.close();
       if (channel.isOpen()) {
         channel.close();
       }
     } catch (IOException ex) {
       throw new JedisConnectionException(ex);
     }
   }
 }
 private Command readAsciiCommand() throws IOException {
   SocketChannel channel = this.socket.getChannel();
   if (channel == null || !channel.isOpen()) {
     throw new IllegalStateException("cannot read from channel");
   }
   buffer.clear();
   int bytesRead = channel.read(buffer);
   if (bytesRead == -1) {
     throw new IOException("EOF");
   }
   buffer.flip();
   return Command.valueOf(readCommand(buffer));
 }
  @Override
  public void run() {
    try {
      while (!mStopSignal) {
        final SocketChannel lSocketChannel = mServerSocketChannel.accept();
        // System.out.println("connection accepted");
        lSocketChannel.setOption(
            StandardSocketOptions.SO_SNDBUF, ClearVolumeTCPClient.cSocketBufferLength);

        try {
          if (lSocketChannel.isOpen()
              && lSocketChannel.isConnected()
              && mClearVolumeTCPServerSink.getLastVolumeSeen() != null) {
            // System.out.println("sending last seen volume: " +
            // mClearVolumeTCPServerSink.getLastVolumeSeen());
            sendVolumeToClient(
                lSocketChannel, mClearVolumeTCPServerSink.getLastVolumeSeen(), false);
          }

          while (lSocketChannel.isOpen() && lSocketChannel.isConnected() && !mStopSignal) {
            final Volume lVolumeToSend =
                mVolumeSource.requestVolumeAndWait(10, TimeUnit.MILLISECONDS);
            if (lVolumeToSend != null) sendVolumeToClient(lSocketChannel, lVolumeToSend, true);
          }
        } catch (final java.io.IOException e1) {
          continue;
        } catch (final Throwable e) {
          e.printStackTrace();
        }
      }

    } catch (final java.nio.channels.AsynchronousCloseException e) {
    } catch (final Throwable e) {
      handleError(e);
    } finally {
      mStoppedSignal = true;
    }
  }
 public void sendException(Exception e) {
   SocketChannel channel = this.socket.getChannel();
   if (channel == null || !channel.isOpen()) {
     throw new IllegalStateException("cannot write to channel");
   }
   try {
     if (e instanceof ClientError) {
       channel.write(charsetASCII.encode(Reply.CLIENT_ERROR.toString()));
     } else {
       channel.write(charsetASCII.encode(Reply.ERROR.toString()));
     }
   } catch (IOException ex) {
   }
 }
Esempio n. 9
0
  private void readText(Connection c) throws IOException {
    sc = c.channel();
    buffer.clear();

    if (sc == null || c.isWriteDisabled() || !sc.isOpen()) {
      c.close(false);
    }

    try {
      synchronized (sc) {
        read = sc.read(buffer);
      }
    } catch (IOException e) {
      if (debugEnabled) log.debug("IOException reading from connection " + c, e);
      c.close(false);
    }

    if (read > 0) {
      buffer.flip();

      if (debugEnabled)
        log.debug("Connection " + c + " about to process data from buffer " + buffer);

      if (workersEnabled) {
        try {
          choose().add(c, buffer);
        } catch (RuntimeException e) {
          if (debugEnabled) log.debug("Cannot queue packet " + buffer + " for connection " + c, e);
          c.close(false);
        }
      } else {
        try {
          if (!c.processData(buffer)) {
            c.close(false);
            return;
          }
        } catch (Exception e) {
          log.error(
              e.getClass().getSimpleName()
                  + " while processing buffer "
                  + buffer
                  + " for connection "
                  + c,
              e);
        }
      }
    } else if (read < 0) {
      c.close(false);
    }
  }
  private void sendVolumeToClient(
      SocketChannel lSocketChannel, Volume lVolumeToSend, boolean pReleaseOrForward)
      throws IOException {
    mByteBuffer = ClearVolumeSerialization.serialize(lVolumeToSend, mByteBuffer);
    mByteBuffer.rewind();
    if (lSocketChannel.isConnected() && lSocketChannel.isOpen()) {
      while (mByteBuffer.hasRemaining()) lSocketChannel.write(mByteBuffer);

      if (pReleaseOrForward) {
        if (mClearVolumeTCPServerSink.getRelaySink() == null)
          lVolumeToSend.makeAvailableToManager();
        else mClearVolumeTCPServerSink.getRelaySink().sendVolume(lVolumeToSend);
      }
    }
  }
  /**
   * Creates a NonBlockingConnection wrapping channel. If the channel is not yet connected,
   * writeAvailable() must be called when it is connected.
   *
   * @param channel SocketChannel used for I/O. Must be open.
   */
  public NonBlockingConnection(SocketChannel channel) {
    this(channel, channel);
    try {
      // NOTE: On Mac OS X, when an async connect to a localhost socket fails, this
      // can fail with an illegal argument exception, before finishConnect() is called.
      channel.socket().setTcpNoDelay(true);
      channel.configureBlocking(false);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }

    if (!channel.isConnected()) {
      if (!channel.isOpen()) {
        // not possible? configureBlocking will throw ClosedChannelException
        throw new IllegalArgumentException("channel is closed");
      }

      // The channel ether has a pending connect, or the connect hasn't started.
      writeBlocked = true;
    } else {
      // We haven't started connecting yet, to avoid the setTcpNoDelay issue
      assert channel.isConnectionPending() || channel.isOpen();
    }
  }
  public void start() throws IOException {
    System.err.println("Start");
    SocketChannel control = SocketChannel.open(new InetSocketAddress("localhost", 8080));
    control.write(BufferUtil.toBuffer(start));
    while (control.isOpen()) {
      BufferUtil.clear(responseBuf);
      int pos = BufferUtil.flipToFill(responseBuf);
      if (control.read(responseBuf) == -1) control.close();
      BufferUtil.flipToFlush(responseBuf, pos);
    }

    client = new SocketChannel[8];
    for (int i = 0; i < client.length; i++)
      client[i] = SocketChannel.open(new InetSocketAddress("localhost", 8080));
  }
  public void sendMessage(final M msg) throws CatException {
    if (isClosed()) {
      throw new ConnectionException("Connection is not ready to send message:\n" + msg);
    }

    try {
      socketChannel.write(ByteBuffer.wrap(msg.toString().getBytes()));
    } catch (final IOException e) {
      if (socketChannel.isOpen()) {
        e.printStackTrace();
      } else {
        // assume that the connection is proactively closed.
      }
      throw new ConnectionException("IOException occurred while sending message:\n" + msg);
    }
  }
 public void sendReply(ByteBuffer reply) throws IOException {
   // for binary set the response opCode
   if (this.protocol == Protocol.BINARY) {
     reply.rewind();
     reply.put(POSITION_OPCODE, buffer.get(POSITION_OPCODE));
     reply.putInt(POSITION_OPAQUE, buffer.getInt(POSITION_OPAQUE));
     if (ConnectionHandler.getLogger().finerEnabled()) {
       ConnectionHandler.getLogger()
           .finer("sending reply:" + reply + " " + Command.buffertoString(reply));
     }
   }
   SocketChannel channel = this.socket.getChannel();
   if (channel == null || !channel.isOpen()) {
     throw new IllegalStateException("cannot write to channel");
   }
   channel.write(reply);
 }
  @Override
  public void run() {
    log.debug("network thread started");
    try {
      // run once
      InetSocketAddress address = new InetSocketAddress(host, port);
      channel = SocketChannel.open(address);
      channel.configureBlocking(true);
      reportChannel();

      // main loop
      while (!Thread.currentThread().isInterrupted()) {
        int bytesRead = channel.read(readBuffer);
        if (bytesRead == -1) break;

        // TODO these StringBuilder shenanigans are fake
        // actually put chars in a CharBuffer and write to parser
        // parser returns list of events to be dispatched

        readBuffer.flip();
        while (readBuffer.hasRemaining()) {
          sb.append((char) (readBuffer.get() & 0xFF));
        }
        dispatchEvent(EventType.TEXT_RECEIVED, null, sb.toString());
        sb.setLength(0);
        readBuffer.clear();
      }

    } catch (ClosedByInterruptException e) {
      // normal result of being interrupted
    } catch (Throwable t) {
      log.error("network error", t);
      dispatchEvent(EventType.NETWORK_ERROR, null, t);
    } finally {
      if (channel != null && channel.isOpen()) {
        try {
          channel.close();
        } catch (IOException e) {
          // ignore
        }
      }
      reportStatus(NetworkState.DISCONNECTED);
      log.debug("network thread exiting");
    }
  }
Esempio n. 16
0
  @Override
  public void process(SocietyPacket inPacket, SocketChannel conn) {
    int sendBufferSize;
    byte[] sendData;
    ByteBuffer sendBuffer;
    ArrayList<SocketChannel> subscribers;

    subscribers = shared.subscribers.getSubscribers(inPacket.source);
    if (subscribers != null) {
      try {
        sendData = inPacket.serialize();
        sendBuffer = ByteBuffer.wrap(sendData);
        for (SocketChannel sub : subscribers) {
          if (sub.isOpen()) {
            sendBuffer.clear();
            sendBufferSize = sub.socket().getSendBufferSize();

            if (sendBuffer.capacity() > sendBufferSize) {
              sendBuffer.limit(sendBufferSize);
            }
            while (sendBuffer.position() != sendBuffer.capacity()) {
              //							could send less bytes than buffer size
              sub.write(sendBuffer);

              if ((sendBuffer.limit() + sendBufferSize) <= sendBuffer.capacity()) {
                sendBuffer.limit(sendBuffer.limit() + sendBufferSize);
              } else {
                sendBuffer.limit(sendBuffer.capacity());
              }
            }

          } else {
            shared.subscribers.removeSubscriber(sub);
          }
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    } else {
      System.out.println("no subscribers");
    }
    inPacket = null;
  }
Esempio n. 17
0
  /**
   * This will only close the connection without taking care of the rest. May be called only by
   * Dispatcher Thread. Returns true if connection was not closed before.
   *
   * @return true if connection was not closed before.
   */
  final boolean onlyClose() {
    /**
     * Test if this build should use assertion. If NetworkAssertion == false javac will remove this
     * code block
     */
    if (Assertion.NetworkAssertion) assert Thread.currentThread() == dispatcher;

    synchronized (guard) {
      if (closed) return false;
      try {
        if (socketChannel.isOpen()) {
          socketChannel.close();
          key.attach(null);
          key.cancel();
        }
        closed = true;
      } catch (IOException ignored) {
      }
    }
    return true;
  }
Esempio n. 18
0
  @Override
  public void close() throws IOException {
    synchronized (_monitor) {
      if (isClose()) {
        return;
      }

      if (isNew()) {
        _status = Status.Close;
        return;
      }

      logger.debug("{} start session close", _key.toString());
      logout();
      _status = Status.Close;
      _heartbeatKeep.shutdown();
      if (_channel != null && _channel.isOpen()) {
        _channel.close();
      }
      logger.debug("{} finish session close", _key.toString());
    }
  }
  public void stop(String test, int count, int of) throws IOException {
    System.err.println("Stop " + test + " " + count + " of " + of);
    String stop =
        "GET "
            + URIUtil.encodePath("/benchmark/stop/ " + test + " " + count + " of " + of)
            + " HTTP/1.1\r\n"
            + "Host: benchmarkControl:8080\r\n"
            + "Connection: close\r\n"
            + "\r\n";

    SocketChannel control = SocketChannel.open(new InetSocketAddress("localhost", 8080));
    control.write(BufferUtil.toBuffer(stop));
    while (control.isOpen()) {
      BufferUtil.clear(responseBuf);
      int pos = BufferUtil.flipToFill(responseBuf);
      if (control.read(responseBuf) == -1) control.close();
      BufferUtil.flipToFlush(responseBuf, pos);
    }

    for (int i = 0; i < client.length; i++)
      if (client[i] != null && client[i].isOpen()) client[i].close();
    client = null;
  }
Esempio n. 20
0
    protected void disconnect(final long timeout, final long bannedFor, final String reason) {
      try {
        if (hasConnectionSlot.tryAcquire()) {
          if (unsolicited) {
            unsolicitedConnectSlot.release();
          } else {
            connectSlot.release();
          }
        }
        if (connected.tryAcquire()) {
          openConnections.decrementAndGet();
          log.trace("Number of connections is now " + openConnections.get());
        }
        if (channel.isRegistered()) {
          selectorChanges.add(
              new ChangeRequest(channel, ChangeRequest.CANCEL, SelectionKey.OP_ACCEPT, null));
          selector.wakeup();
        }
        if (channel.isOpen()) {
          channel.close();
          log.trace("Disconnect " + channel);

          writes.clear();
          reads.clear();
          reads.add(closedMark);
          peerThreads.execute(
              new Runnable() {
                @Override
                public void run() {
                  onDisconnect(timeout, bannedFor, reason);
                }
              });
        }
      } catch (IOException e) {
        log.trace("Exception in disconnect ", e);
      }
    }
Esempio n. 21
0
  @Override
  protected boolean isOpenImpl() {
    if (socketChannel.isConnected() == false || socketChannel.isOpen() == false) {
      return false;
    }

    boolean ret = false;
    try {
      if (lock.isHeldByCurrentThread()) {
        ret = _isOpenImpl();
      } else {
        lock.lock();
        try {
          ret = _isOpenImpl();
        } finally {
          lock.unlock();
        }
      }
    } catch (IOException e) {
      Interpreter.getInstance().logWarning(e);
      return false;
    }
    return ret;
  }
Esempio n. 22
0
 /*
  * (non-Javadoc)
  * @see java.io.OutputStream#close()
  */
 public void close() throws IOException {
   if (channel.isOpen()) {
     flush();
     channel.close();
   }
 }
Esempio n. 23
0
  /**
   * @param data 要发送的数据
   * @param socketChannel 发往的通道
   * @return 数据发送成功:true;失败:false
   * @throws IOException
   */
  private boolean sendData(byte[] data, SocketChannel socketChannel) throws IOException {
    try {
      ByteBuffer dataBuffer = ByteBuffer.wrap(data);

      long sendSize = send(socketChannel, dataBuffer);
      long allSendSize = sendSize;
      long starttime = SystemTimer.currentTimeMillis();

      while (dataBuffer.hasRemaining()
          && socketChannel.isOpen()) // 还有数据没写干净,一般是网络不好导致,也可能是发送和接收量太大。
      {
        sendSize = send(socketChannel, dataBuffer);

        if (sendSize == 0) {
          Thread.sleep(5);
        } else {
          allSendSize += sendSize;
        }

        if (DebugUtils.isNeedDebug(channelContext)) {
          try {
            long endtime = SystemTimer.currentTimeMillis();
            long costtime = (endtime - starttime);
            double speed = -1;
            if (costtime > 0) {
              speed = allSendSize / costtime;
            }

            log.error(
                "{} bytes was sent, {}/{}({}%), cost time: {} ms, {}bytes/ms,{}",
                sendSize,
                allSendSize,
                data.length,
                (allSendSize * 100) / data.length,
                costtime,
                speed,
                channelContext);
          } catch (Exception e) {
            log.error(e.getLocalizedMessage(), e);
          }
        }
      }
      StatVo.getAllSentMsgCount().incrementAndGet();
      this.getProcessedMsgCount().incrementAndGet();
      long endtime = SystemTimer.currentTimeMillis();

      if (DebugUtils.isNeedDebug(channelContext)) {
        try {
          long costtime = (endtime - starttime);
          double speed = -1;
          if (costtime > 0) {
            speed = allSendSize / costtime;
          }
          log.error("cost time: {} ms, {}bytes/ms, {}", costtime, speed, channelContext);

          log.error(
              "ok sent to "
                  + channelContext
                  + ",total num["
                  + StatVo.getAllSentMsgCount().get()
                  + "],num to this ["
                  + getProcessedMsgCount().get()
                  + "],waiting for send to this ["
                  + getMsgQueue().size()
                  + "]");
        } catch (Exception e) {
          log.error(e.getLocalizedMessage(), e);
        }
      }

      return true;
    } catch (InterruptedException e) {
      return false;
    }
  }
 public boolean isClosed() {
   return (socketChannel == null) || !socketChannel.isOpen();
 }
 /** {@inheritDoc} */
 public boolean isOpen() {
   return channel.isOpen();
 }
  /**
   * The use of threaded tasks in the send/receive service makes it difficult to observer the socket
   * state changes.
   *
   * <p>So let's begin by writing some tests over the raw sockets.
   *
   * <p>Note that connecting and then immediately closing the socket is perfectly okay. ...with an
   * accept followed by a read() of -1 on the returned Socket stream.
   *
   * @throws IOException
   * @throws InterruptedException
   */
  public void testDirectSockets() throws IOException, InterruptedException {

    // The payload size that we will use.
    final int DATA_LEN = 200;

    final Random r = new Random();
    final byte[] data = new byte[DATA_LEN];
    r.nextBytes(data);
    final byte[] dst = new byte[DATA_LEN];

    // The server side receive buffer size (once we open the server socket).
    int receiveBufferSize = -1;

    final InetSocketAddress serverAddr = new InetSocketAddress(getPort(0));

    // First our ServerSocket
    final ServerSocket ss = new ServerSocket();
    try {

      assertTrue(ss.getChannel() == null);

      // bind the server socket to the port.
      ss.bind(serverAddr);

      assertTrue(ss.getChannel() == null);

      // figure out the receive buffer size on the server socket.
      receiveBufferSize = ss.getReceiveBufferSize();

      if (log.isInfoEnabled())
        log.info("receiveBufferSize=" + receiveBufferSize + ", payloadSize=" + DATA_LEN);

      if (receiveBufferSize < DATA_LEN) {

        fail(
            "Service socket receive buffer is smaller than test payload size: receiveBufferSize="
                + receiveBufferSize
                + ", payloadSize="
                + DATA_LEN);
      }

      {
        /*
         * InputStream for server side of socket connection - set below and
         * then reused outside of the try/finally block.
         */
        InputStream instr = null;

        // Now the first Client SocketChannel
        final SocketChannel cs1 = SocketChannel.open();
        try {

          /*
           * Note: true if connection made. false if connection in
           * progress.
           */
          final boolean immediate1 = cs1.connect(serverAddr);
          if (!immediate1) {
            if (!cs1.finishConnect()) {
              fail("Did not connect?");
            }
          }

          assertTrue(ss.getChannel() == null);

          /*
           * We are connected.
           */

          final ByteBuffer src = ByteBuffer.wrap(data);

          // Write some data on the client socket.
          cs1.write(src);

          /*
           * Accept client's connection on server (after connect and
           * write).
           */
          final Socket readSckt1 = accept(ss);

          // Stream to read the data from the socket on the server
          // side.
          instr = readSckt1.getInputStream();

          // and read the data
          instr.read(dst);

          // confirming the read is correct
          assertTrue(BytesUtil.bytesEqual(data, dst));

          assertTrue(ss.getChannel() == null);

          /*
           * Attempting to read more returns ZERO because there is
           * nothing in the buffer and the connection is still open on
           * the client side.
           *
           * Note: instr.read(buf) will BLOCK until the data is
           * available, the EOF is detected, or an exception is
           * thrown.
           */
          assertEquals(0, instr.available());
          // assertEquals(0, instr.read(dst));

          /*
           * Now write some more data into the channel and *then*
           * close it.
           */
          cs1.write(ByteBuffer.wrap(data));

          // close the client side of the socket
          cs1.close();

          // The server side of client connection is still open.
          assertTrue(readSckt1.isConnected());
          assertFalse(readSckt1.isClosed());

          /*
           * Now try writing some more data. This should be disallowed
           * since we closed the client side of the socket.
           */
          try {
            cs1.write(ByteBuffer.wrap(data));
            fail("Expected closed channel exception");
          } catch (ClosedChannelException e) {
            // expected
          }

          /*
           * Since we closed the client side of the socket, when we
           * try to read more data on the server side of the
           * connection. The data that we already buffered is still
           * available on the server side of the socket.
           */
          {
            // the already buffered data should be available.
            final int rdlen = instr.read(dst);
            assertEquals(DATA_LEN, rdlen);
            assertTrue(BytesUtil.bytesEqual(data, dst));
          }

          /*
           * We have drained the buffered data. There is no more
           * buffered data and client side is closed, so an attempt to
           * read more data on the server side of the socket will
           * return EOF (-1).
           */
          assertEquals(-1, instr.read(dst)); // read EOF

          // if so then should we explicitly close its socket?
          readSckt1.close();
          assertTrue(readSckt1.isClosed());

          /*
           * Still reports EOF after the accepted server socket is
           * closed.
           */
          assertEquals(-1, instr.read(dst));

          assertFalse(ss.isClosed());
          assertTrue(ss.getChannel() == null);

        } finally {
          cs1.close();
        }

        // failing to read from original stream
        final int nrlen = instr.read(dst);
        assertEquals(-1, nrlen);
      }

      /*
       * Now open a new client Socket and connect to the server.
       */
      final SocketChannel cs2 = SocketChannel.open();
      try {

        // connect to the server socket again.
        final boolean immediate2 = cs2.connect(serverAddr);
        if (!immediate2) {
          if (!cs2.finishConnect()) {
            fail("Did not connect?");
          }
        }

        // Now server should accept the new client connection
        final Socket s2 = accept(ss);

        // Client writes to the SocketChannel
        final int wlen = cs2.write(ByteBuffer.wrap(data));
        assertEquals(DATA_LEN, wlen); // verify data written.

        // but succeeding to read from the new Socket
        final InputStream instr2 = s2.getInputStream();
        instr2.read(dst);
        assertTrue(BytesUtil.bytesEqual(data, dst));

        /*
         * Question: Can a downstream close be detected upstream?
         *
         * Answer: No. Closing the server socket does not tell the
         * client that the socket was closed.
         */
        {
          // close server side input stream.
          instr2.close();

          // but the client still thinks its connected.
          assertTrue(cs2.isOpen());

          // Does the client believe it is still open after a brief
          // sleep?
          Thread.sleep(1000);
          assertTrue(cs2.isOpen()); // yes.

          // close server stocket.
          s2.close();

          // client still thinks it is connected after closing server
          // socket.
          assertTrue(cs2.isOpen());

          // Does the client believe it is still open after a brief
          // sleep?
          Thread.sleep(1000);
          assertTrue(cs2.isOpen()); // yes.
        }

        /*
         * Now write some more to the socket. We have closed the
         * accepted connection on the server socket. Our observations
         * show that the 1st write succeeds. The second write then fails
         * with 'IOException: "Broken pipe"'
         *
         * The server socket is large (256k). We are not filling it up,
         * but the 2nd write always fails. Further, the client never
         * believes that the connection is closed until the 2nd write,
         */
        {
          final int writeSize = 1;
          int nwritesOk = 0;
          long nbytesReceived = 0L;
          while (true) {
            try {
              // write a payload.
              final int wlen2 = cs2.write(ByteBuffer.wrap(data, 0, writeSize));
              // if write succeeds, should have written all bytes.
              assertEquals(writeSize, wlen2);
              nwritesOk++;
              nbytesReceived += wlen2;
              // does the client think the connection is still open?
              assertTrue(cs2.isOpen()); // yes.
              Thread.sleep(1000);
              assertTrue(cs2.isOpen()); // yes.
            } catch (IOException ex) {
              if (log.isInfoEnabled())
                log.info(
                    "Expected exception: nwritesOk="
                        + nwritesOk
                        + ", nbytesReceived="
                        + nbytesReceived
                        + ", ex="
                        + ex);
              break;
            }
          }
        }

        /*
         * Having closed the input, without a new connect request we
         * should not be able to accept the new write since the data
         * were written on a different client connection.
         */
        try {
          final Socket s3 = accept(ss);
          fail("Expected timeout failure");
        } catch (AssertionFailedError afe) {
          // expected
        }

      } finally {
        cs2.close();
      }

    } finally {
      ss.close();
    }
  }
  @Slow
  @Test
  public void testConnectTimeoutBeforeSuccessfulConnect() throws Exception {
    ServerSocketChannel server = ServerSocketChannel.open();
    server.bind(new InetSocketAddress("localhost", 0));
    SocketAddress address = server.getLocalAddress();

    final AtomicLong timeoutConnection = new AtomicLong();
    final long connectTimeout = 1000;
    SelectorManager selectorManager =
        new SelectorManager(executor, scheduler) {
          @Override
          protected EndPoint newEndPoint(
              SocketChannel channel, ManagedSelector selector, SelectionKey selectionKey)
              throws IOException {
            return new SelectChannelEndPoint(
                channel, selector, selectionKey, getScheduler(), connectTimeout / 2);
          }

          @Override
          protected boolean finishConnect(SocketChannel channel) throws IOException {
            try {
              long timeout = timeoutConnection.get();
              if (timeout > 0) TimeUnit.MILLISECONDS.sleep(timeout);
              return super.finishConnect(channel);
            } catch (InterruptedException e) {
              return false;
            }
          }

          @Override
          public Connection newConnection(
              SocketChannel channel, EndPoint endpoint, Object attachment) throws IOException {
            ((Callback) attachment).succeeded();
            return new AbstractConnection(endpoint, executor) {
              @Override
              public void onFillable() {}
            };
          }

          @Override
          protected void connectionFailed(SocketChannel channel, Throwable ex, Object attachment) {
            ((Callback) attachment).failed(ex);
          }
        };
    selectorManager.setConnectTimeout(connectTimeout);
    selectorManager.start();

    try {
      SocketChannel client1 = SocketChannel.open();
      client1.configureBlocking(false);
      client1.connect(address);
      long timeout = connectTimeout * 2;
      timeoutConnection.set(timeout);
      final CountDownLatch latch1 = new CountDownLatch(1);
      selectorManager.connect(
          client1,
          new Callback.Adapter() {
            @Override
            public void failed(Throwable x) {
              latch1.countDown();
            }
          });
      Assert.assertTrue(latch1.await(connectTimeout * 3, TimeUnit.MILLISECONDS));
      Assert.assertFalse(client1.isOpen());

      // Wait for the first connect to finish, as the selector thread is waiting in finishConnect().
      Thread.sleep(timeout);

      // Verify that after the failure we can connect successfully.
      try (SocketChannel client2 = SocketChannel.open()) {
        client2.configureBlocking(false);
        client2.connect(address);
        timeoutConnection.set(0);
        final CountDownLatch latch2 = new CountDownLatch(1);
        selectorManager.connect(
            client2,
            new Callback.Adapter() {
              @Override
              public void succeeded() {
                latch2.countDown();
              }
            });
        Assert.assertTrue(latch2.await(connectTimeout * 5, TimeUnit.MILLISECONDS));
        Assert.assertTrue(client2.isOpen());
      }
    } finally {
      selectorManager.stop();
    }
  }
Esempio n. 28
0
 public InetSocketAddress getLocalSocketAddress() throws IOException {
   if (_channel != null && _channel.isOpen()) {
     return (InetSocketAddress) _channel.socket().getLocalSocketAddress();
   }
   return _localAddress;
 }
 /**
  * Times out any expired connections then, if {@code selectionCount > 0}, processes the selected
  * keys. Removes closed connections from the connections field, and from the connections
  * parameter.
  *
  * @param selectionCount Number of IO Events, if 0 we were probably woken up by a close.
  * @param selector The selector.
  * @param server The server socket channel.
  * @param connections Map of connections.
  * @throws IOException Any IOException.
  */
 protected void processNioSelections(
     int selectionCount,
     final Selector selector,
     ServerSocketChannel server,
     Map<SocketChannel, TcpNioConnection> connections)
     throws IOException {
   final long now = System.currentTimeMillis();
   rescheduleDelayedReads(selector, now);
   if (this.soTimeout > 0 || now >= this.nextCheckForClosedNioConnections || selectionCount == 0) {
     this.nextCheckForClosedNioConnections = now + this.nioHarvestInterval;
     Iterator<Entry<SocketChannel, TcpNioConnection>> it = connections.entrySet().iterator();
     while (it.hasNext()) {
       SocketChannel channel = it.next().getKey();
       if (!channel.isOpen()) {
         logger.debug("Removing closed channel");
         it.remove();
       } else if (soTimeout > 0) {
         TcpNioConnection connection = connections.get(channel);
         if (now - connection.getLastRead() >= this.soTimeout) {
           /*
            * For client connections, we have to wait for 2 timeouts if the last
            * send was within the current timeout.
            */
           if (!connection.isServer()
               && now - connection.getLastSend() < this.soTimeout
               && now - connection.getLastRead() < this.soTimeout * 2) {
             if (logger.isDebugEnabled()) {
               logger.debug(
                   "Skipping a connection timeout because we have a recent send "
                       + connection.getConnectionId());
             }
           } else {
             if (logger.isWarnEnabled()) {
               logger.warn("Timing out TcpNioConnection " + connection.getConnectionId());
             }
             SocketTimeoutException exception =
                 new SocketTimeoutException("Timing out connection");
             connection.publishConnectionExceptionEvent(exception);
             connection.timeout();
             connection.sendExceptionToListener(exception);
           }
         }
       }
     }
   }
   this.harvestClosedConnections();
   if (logger.isTraceEnabled()) {
     if (host == null) {
       logger.trace("Port " + this.port + " SelectionCount: " + selectionCount);
     } else {
       logger.trace(
           "Host " + this.host + " port " + this.port + " SelectionCount: " + selectionCount);
     }
   }
   if (selectionCount > 0) {
     Set<SelectionKey> keys = selector.selectedKeys();
     Iterator<SelectionKey> iterator = keys.iterator();
     while (iterator.hasNext()) {
       final SelectionKey key = iterator.next();
       iterator.remove();
       try {
         if (!key.isValid()) {
           logger.debug("Selection key no longer valid");
         } else if (key.isReadable()) {
           key.interestOps(key.interestOps() - SelectionKey.OP_READ);
           final TcpNioConnection connection;
           connection = (TcpNioConnection) key.attachment();
           connection.setLastRead(System.currentTimeMillis());
           try {
             this.taskExecutor.execute(
                 new Runnable() {
                   @Override
                   public void run() {
                     boolean delayed = false;
                     try {
                       connection.readPacket();
                     } catch (RejectedExecutionException e) {
                       delayRead(selector, now, key);
                       delayed = true;
                     } catch (Exception e) {
                       if (connection.isOpen()) {
                         logger.error(
                             "Exception on read "
                                 + connection.getConnectionId()
                                 + " "
                                 + e.getMessage());
                         connection.close();
                       } else {
                         logger.debug("Connection closed");
                       }
                     }
                     if (!delayed) {
                       if (key.channel().isOpen()) {
                         key.interestOps(SelectionKey.OP_READ);
                         selector.wakeup();
                       } else {
                         connection.sendExceptionToListener(
                             new EOFException("Connection is closed"));
                       }
                     }
                   }
                 });
           } catch (RejectedExecutionException e) {
             delayRead(selector, now, key);
           }
         } else if (key.isAcceptable()) {
           try {
             doAccept(selector, server, now);
           } catch (Exception e) {
             logger.error("Exception accepting new connection", e);
           }
         } else {
           logger.error("Unexpected key: " + key);
         }
       } catch (CancelledKeyException e) {
         if (logger.isDebugEnabled()) {
           logger.debug("Selection key " + key + " cancelled");
         }
       } catch (Exception e) {
         logger.error("Exception on selection key " + key, e);
       }
     }
   }
 }
 private Command readBinaryCommand() throws IOException {
   SocketChannel channel = this.socket.getChannel();
   if (channel == null || !channel.isOpen()) {
     throw new IllegalStateException("cannot read from channel");
   }
   Command cmd = null;
   boolean done = false;
   boolean read = false;
   while (!done) {
     if (!buffer.hasRemaining()) {
       buffer.clear();
       read = true;
     } else if (!read) {
       // compact is meant for partial writes, but we want to use
       // it partial reads, so the new limit should be the position
       // after the compact operation and we want to start reading
       // from the beginning
       buffer.compact();
       buffer.limit(buffer.position());
       buffer.position(0);
     }
     if (read) {
       int bytesRead = channel.read(buffer);
       if (bytesRead == -1) {
         throw new IOException("EOF");
       }
       buffer.flip();
     }
     // read again if we did not read enough bytes
     if (buffer.limit() < HEADER_LENGTH) {
       buffer.compact();
       read = true;
       continue;
     }
     int requestLength = buffer.remaining();
     byte magic = buffer.get();
     if (magic != REQUEST_MAGIC) {
       throw new IllegalStateException("Not a valid request, magic byte incorrect");
     }
     byte opCode = buffer.get();
     if (ConnectionHandler.getLogger().finerEnabled()) {
       String str = Command.buffertoString(buffer);
       ConnectionHandler.getLogger().finer("Request:" + buffer + str.toString());
     }
     int bodyLength = buffer.getInt(AbstractCommand.TOTAL_BODY_LENGTH_INDEX);
     if ((HEADER_LENGTH + bodyLength) > requestLength) {
       // set the position back to the start of the request
       buffer.position(buffer.position() - 2 /*since we read two bytes*/);
       buffer.compact();
       // ensure that the buffer is big enough
       if (buffer.capacity() < (HEADER_LENGTH + bodyLength)) {
         // allocate bigger buffer and copy the bytes to the bigger buffer
         ByteBuffer oldBuffer = buffer;
         oldBuffer.position(0);
         buffer = ByteBuffer.allocate(HEADER_LENGTH + bodyLength);
         buffer.put(oldBuffer);
       }
       read = true;
       continue;
     }
     cmd = Command.getCommandFromOpCode(opCode);
     done = true;
   }
   if (ConnectionHandler.getLogger().fineEnabled()) {
     ConnectionHandler.getLogger().fine("read command " + cmd);
   }
   return cmd;
 }