/**
   * Encodes the proxy authorization request packet.
   *
   * @param request the socks proxy request data
   * @return the encoded buffer
   * @throws UnsupportedEncodingException if request's hostname charset can't be converted to ASCII.
   */
  private IoBuffer encodeProxyRequestPacket(final SocksProxyRequest request)
      throws UnsupportedEncodingException {
    int len = 6;
    InetSocketAddress adr = request.getEndpointAddress();
    byte addressType = 0;
    byte[] host = null;

    if (adr != null && !adr.isUnresolved()) {
      if (adr.getAddress() instanceof Inet6Address) {
        len += 16;
        addressType = SocksProxyConstants.IPV6_ADDRESS_TYPE;
      } else if (adr.getAddress() instanceof Inet4Address) {
        len += 4;
        addressType = SocksProxyConstants.IPV4_ADDRESS_TYPE;
      }
    } else {
      host = request.getHost() != null ? request.getHost().getBytes("ASCII") : null;

      if (host != null) {
        len += 1 + host.length;
        addressType = SocksProxyConstants.DOMAIN_NAME_ADDRESS_TYPE;
      } else {
        throw new IllegalArgumentException(
            "SocksProxyRequest object " + "has no suitable endpoint information");
      }
    }

    IoBuffer buf = IoBuffer.allocate(len);

    buf.put(request.getProtocolVersion());
    buf.put(request.getCommandCode());
    buf.put((byte) 0x00); // Reserved
    buf.put(addressType);

    if (host == null) {
      buf.put(request.getIpAddress());
    } else {
      buf.put((byte) host.length);
      buf.put(host);
    }

    buf.put(request.getPort());

    return buf;
  }
  /**
   * Encode a SOCKS4/SOCKS4a request and writes it to the next filter so it can be sent to the proxy
   * server.
   *
   * @param nextFilter the next filter
   * @param request the request to send.
   */
  protected void writeRequest(final NextFilter nextFilter, final SocksProxyRequest request) {
    try {
      boolean isV4ARequest = Arrays.equals(request.getIpAddress(), SocksProxyConstants.FAKE_IP);
      byte[] userID = request.getUserName().getBytes("ASCII");
      byte[] host = isV4ARequest ? request.getHost().getBytes("ASCII") : null;

      int len = 9 + userID.length;

      if (isV4ARequest) {
        len += host.length + 1;
      }

      IoBuffer buf = IoBuffer.allocate(len);

      buf.put(request.getProtocolVersion());
      buf.put(request.getCommandCode());
      buf.put(request.getPort());
      buf.put(request.getIpAddress());
      buf.put(userID);
      buf.put(SocksProxyConstants.TERMINATOR);

      if (isV4ARequest) {
        buf.put(host);
        buf.put(SocksProxyConstants.TERMINATOR);
      }

      if (isV4ARequest) {
        logger.debug("  sending SOCKS4a request");
      } else {
        logger.debug("  sending SOCKS4 request");
      }

      buf.flip();
      writeData(nextFilter, buf);
    } catch (Exception ex) {
      closeSession("Unable to send Socks request: ", ex);
    }
  }