/** Attach to the specified address with optional attach and handshake timeout. */
  public Connection attach(String address, long attachTimeout, long handshakeTimeout)
      throws IOException {

    if (address == null) {
      throw new NullPointerException("address is null");
    }
    if (attachTimeout < 0 || handshakeTimeout < 0) {
      throw new IllegalArgumentException("timeout is negative");
    }

    int splitIndex = address.indexOf(':');
    String host;
    String portStr;
    if (splitIndex < 0) {
      host = InetAddress.getLocalHost().getHostName();
      portStr = address;
    } else {
      host = address.substring(0, splitIndex);
      portStr = address.substring(splitIndex + 1);
    }

    int port;
    try {
      port = Integer.decode(portStr).intValue();
    } catch (NumberFormatException e) {
      throw new IllegalArgumentException("unable to parse port number in address");
    }

    // open TCP connection to VM

    InetSocketAddress sa = new InetSocketAddress(host, port);
    Socket s = new Socket();
    try {
      s.connect(sa, (int) attachTimeout);
    } catch (SocketTimeoutException exc) {
      try {
        s.close();
      } catch (IOException x) {
      }
      throw new TransportTimeoutException("timed out trying to establish connection");
    }

    // handshake with the target VM
    try {
      handshake(s, handshakeTimeout);
    } catch (IOException exc) {
      try {
        s.close();
      } catch (IOException x) {
      }
      throw exc;
    }

    return new SocketConnection(s);
  }
  /** Handshake with the debuggee */
  void handshake(Socket s, long timeout) throws IOException {
    s.setSoTimeout((int) timeout);

    byte[] hello = "JDWP-Handshake".getBytes("UTF-8");
    s.getOutputStream().write(hello);

    byte[] b = new byte[hello.length];
    int received = 0;
    while (received < hello.length) {
      int n;
      try {
        n = s.getInputStream().read(b, received, hello.length - received);
      } catch (SocketTimeoutException x) {
        throw new IOException("handshake timeout");
      }
      if (n < 0) {
        s.close();
        throw new IOException("handshake failed - connection prematurally closed");
      }
      received += n;
    }
    for (int i = 0; i < hello.length; i++) {
      if (b[i] != hello[i]) {
        throw new IOException("handshake failed - unrecognized message from target VM");
      }
    }

    // disable read timeout
    s.setSoTimeout(0);
  }
 public void close() throws IOException {
   synchronized (closeLock) {
     if (closed) {
       return;
     }
     socketOutput.close();
     socketInput.close();
     socket.close();
     closed = true;
   }
 }