private void sendSocks5Response(Session session, Socks5HandleResult result) throws IOException {
    if (result.getResponseToLocal() != null) {
      addDataToSend(session, ChannelType.LOCAL, result.getResponseToLocal(), false);
    }

    if (result.getResponseToRemote() != null) {
      if (!session.isRemoteConnected()) {
        session.connectToRemote();
      }
      addDataToSend(session, ChannelType.REMOTE, result.getResponseToRemote(), true);
    }
  }
  private void handleSocks5Read(Session session, ByteBuffer readableBuffer) throws IOException {
    // socks5 protocol
    Socks5StageHandler handler = Socks5HandlerFactory.getHandler(session.getStage());
    Socks5HandleResult result = handler.handle(readableBuffer);
    sendSocks5Response(session, result);

    if (result.getType() == Socks5HandleResult.Type.COMPLETED) {
      handleSocks5ReadCompleted(session, readableBuffer);
    } else if (result.getType() == Socks5HandleResult.Type.UNCOMPLETED) {
      handleSocks5ReadUncompleted(session, readableBuffer);
    } else if (result.getType() == Socks5HandleResult.Type.ERROR) {
      handleSocks5ReadError(session);
    } else {
      throw new IllegalStateException("wrong code: " + result.getType());
    }
  }