Bug 84473 - Unable to timeout when attaching to a bogus debug port
diff --git a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.properties b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.properties
index f9a8f39..bceafd6 100644
--- a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.properties
+++ b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.properties
@@ -16,6 +16,8 @@
 SocketAttachingConnectorImpl.Host_2=Host
 SocketAttachingConnectorImpl.Port_number_to_which_to_attach_for_VM_connections_3=Port number to which to attach for VM connections
 SocketAttachingConnectorImpl.Port_4=Port
+SocketAttachingConnectorImpl.1=Connection Timeout
+SocketAttachingConnectorImpl.2=Connection Timeout
 SocketAttachingConnectorImpl.Attaches_by_socket_to_other_VMs_5=Attaches by socket to other VMs
 SocketAttachingConnectorImpl.Connection_argument_is_not_of_the_right_type_6=Connection argument is not of the right type
 SocketAttachingConnectorImpl.Necessary_connection_argument_is_null_7=Necessary connection argument is null
@@ -63,3 +65,5 @@
 PacketReceiveManager.Got_{0}_from_Virtual_Machine_1=Got {0} from Virtual Machine
 PacketReceiveManager.Got_{0}_from_Virtual_Machine__{1}_1=Got {0} from Virtual Machine: {1}
 PacketReceiveManager.0=Timeout occurred while waiting for packet {0}
+SocketTransportService.0=Attach Thread
+SocketTransportService.1=Handshake Thread
diff --git a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketAttachingConnectorImpl.java b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketAttachingConnectorImpl.java
index 343f28d..73aba21 100644
--- a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketAttachingConnectorImpl.java
+++ b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketAttachingConnectorImpl.java
@@ -30,6 +30,7 @@
 	private String fHostname;
 	/** Port to which is attached. */
 	private int fPort;
+    private int fTimeout;
 	
 	/**
 	 * Creates new SocketAttachingConnectorImpl.
@@ -57,6 +58,10 @@
 		IntegerArgumentImpl intArg = new IntegerArgumentImpl("port", ConnectMessages.getString("SocketAttachingConnectorImpl.Port_number_to_which_to_attach_for_VM_connections_3"), ConnectMessages.getString("SocketAttachingConnectorImpl.Port_4"), true, SocketTransportImpl.MIN_PORTNR, SocketTransportImpl.MAX_PORTNR); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 		arguments.put(intArg.name(), intArg);
 		
+        // Timeout
+        IntegerArgumentImpl timeoutArg = new IntegerArgumentImpl("timeout", ConnectMessages.getString("SocketAttachingConnectorImpl.1"), ConnectMessages.getString("SocketAttachingConnectorImpl.2"), false, 0, Integer.MAX_VALUE); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        arguments.put(timeoutArg.name(), timeoutArg);
+        
 		return arguments;
 	}
 	
@@ -84,7 +89,14 @@
 		 	fHostname = ((Connector.StringArgument)connectionArgs.get(attribute)).value();
 		 	attribute = "port"; //$NON-NLS-1$
 		 	fPort = ((Connector.IntegerArgument)connectionArgs.get(attribute)).intValue();
-		 	// TODO: new timeout attribute ?
+		 	attribute = "timeout"; //$NON-NLS-1$
+		 	Object object = connectionArgs.get(attribute);
+		 	if (object != null) {
+               Connector.IntegerArgument timeoutArg = (IntegerArgument) object;
+               if (timeoutArg.value() != null) {
+		 	    fTimeout = timeoutArg.intValue();
+               }
+		 	} 
 		} catch (ClassCastException e) {
 			throw new IllegalConnectorArgumentsException(ConnectMessages.getString("SocketAttachingConnectorImpl.Connection_argument_is_not_of_the_right_type_6"), attribute); //$NON-NLS-1$
 		} catch (NullPointerException e) {
@@ -102,7 +114,7 @@
 		getConnectionArguments(connectionArgs);
 		Connection connection = null;
 		try {
-			connection = ((SocketTransportImpl)fTransport).attach(fHostname, fPort);
+			connection = ((SocketTransportImpl)fTransport).attach(fHostname, fPort, fTimeout, 0);
 		} catch (IllegalArgumentException e) {
 			List args = new ArrayList();
 			args.add("hostname"); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportImpl.java b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportImpl.java
index 1e2b2b2..fa461ac 100644
--- a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportImpl.java
+++ b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportImpl.java
@@ -39,8 +39,8 @@
         return TRANSPORT_NAME;
     }
 
-    public Connection attach(String hostname, int port) throws IOException {
-        return service.attach(hostname, port, 0, 0);
+    public Connection attach(String hostname, int port, long attachTimeout, long handshakeTimeout) throws IOException {
+        return service.attach(hostname, port, attachTimeout, handshakeTimeout);
     }
 
     public String startListening(int port) throws IOException {
diff --git a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportService.java b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportService.java
index 7ae1435..d620692 100644
--- a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportService.java
+++ b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportService.java
@@ -20,6 +20,8 @@
 import java.net.SocketTimeoutException;
 import java.util.Arrays;
 
+import org.eclipse.jdi.TimeoutException;
+
 import com.sun.jdi.connect.TransportTimeoutException;
 import com.sun.jdi.connect.spi.ClosedConnectionException;
 import com.sun.jdi.connect.spi.Connection;
@@ -118,26 +120,46 @@
         return attach(host, port, attachTimeout, handshakeTimeout);
     }
 
-    public Connection attach(String host, int port, long attachTimeout, long handshakeTimeout) throws IOException {
+    public Connection attach(final String host, final int port, long attachTimeout, final long handshakeTimeout) throws IOException {
         if (attachTimeout > 0){
             if (attachTimeout > Integer.MAX_VALUE) {
                 attachTimeout = Integer.MAX_VALUE;  //approx 25 days!
             }
-            fSocket.setSoTimeout((int) attachTimeout);
         }
+        
+        final IOException[] ex = new IOException[1];
+        Thread attachThread = new Thread(new Runnable() {
+            public void run() {
+                try {
+                    fSocket = new Socket(host, port);
+                    fInput = fSocket.getInputStream();
+                    fOutput = fSocket.getOutputStream();
+                    performHandshake(fInput, fOutput, handshakeTimeout);
+                } catch (IOException e) {
+                    ex[0] = e;
+                }                
+            }
+        }, ConnectMessages.getString("SocketTransportService.0")); //$NON-NLS-1$
+        
+        attachThread.start();
         try {
-            fSocket = new Socket(host, port);
-        } catch (SocketTimeoutException e) {
-            throw new TransportTimeoutException();
+            attachThread.join(attachTimeout);
+            if (attachThread.isAlive()) {
+                attachThread.interrupt();
+                throw new TimeoutException();
+            }
+        } catch (InterruptedException e) {
         }
-        fInput = fSocket.getInputStream();
-        fOutput = fSocket.getOutputStream();
-        performHandshake(fInput, fOutput, handshakeTimeout);
+        
+        if (ex[0] != null) {
+            throw ex[0];
+        }
+
+        
         return new SocketConnection(this);
     }
 
     void performHandshake(final InputStream in, final OutputStream out, final long timeout) throws IOException {
-        final Object lock = new Object();
         final IOException[] ex = new IOException[1];
         final boolean[] handshakeCompleted = new boolean[1];
         
@@ -146,37 +168,31 @@
                 try {
                     writeHandshake(out);
                     readHandshake(in);
-                    synchronized(lock) {
-                        handshakeCompleted[0] = true;
-                        lock.notify();
-                    }
+                    handshakeCompleted[0] = true;
                 } catch (IOException e) {
                     ex[0] = e;
                 }
             }
-        });
+        }, ConnectMessages.getString("SocketTransportService.1")); //$NON-NLS-1$
         
         t.start();
-        synchronized(lock) {
-            try {
-	            if (!handshakeCompleted[0]) 
-	                lock.wait(timeout);
-            } catch (InterruptedException e) {
-            }
+        try {
+            t.join(timeout);
+        } catch (InterruptedException e1) {
         }
-        
+                
         if (handshakeCompleted[0])
             return;
-        
-        if (ex[0] != null)
-            throw ex[0];
-        
+
         try {
-	        in.close();
-	        out.close();
+            in.close();
+            out.close();
         } catch (IOException e) {
         }
         
+        if (ex[0] != null)
+            throw ex[0];
+
         throw new TransportTimeoutException();
     }
     
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/JavaRemoteApplicationLaunchConfigurationDelegate.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/JavaRemoteApplicationLaunchConfigurationDelegate.java
index 5f8862d..7f116c4 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/JavaRemoteApplicationLaunchConfigurationDelegate.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/JavaRemoteApplicationLaunchConfigurationDelegate.java
@@ -59,6 +59,9 @@
 		}
 		
 		Map argMap = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_CONNECT_MAP, (Map)null);
+        
+        int connectTimeout = JavaRuntime.getPreferences().getInt(JavaRuntime.PREF_CONNECT_TIMEOUT);
+        argMap.put("timeout", ""+connectTimeout);  //$NON-NLS-1$//$NON-NLS-2$
 
 		// check for cancellation
 		if (monitor.isCanceled()) {
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/SocketAttachConnector.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/SocketAttachConnector.java
index 28ae0e3..07ac2e0 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/SocketAttachConnector.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/SocketAttachConnector.java
@@ -116,10 +116,18 @@
 			abort(LaunchingMessages.getString("SocketAttachConnector.Hostname_unspecified_for_remote_connection._4"), null, IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_HOSTNAME); //$NON-NLS-1$
 		}
 		Map map= connector.defaultArguments();
-		Connector.Argument param= (Connector.Argument) map.get("hostname"); //$NON-NLS-1$
+		
+        Connector.Argument param= (Connector.Argument) map.get("hostname"); //$NON-NLS-1$
 		param.setValue(host);
 		param= (Connector.Argument) map.get("port"); //$NON-NLS-1$
 		param.setValue(portNumberString);
+        
+        String timeoutString = (String)arguments.get("timeout"); //$NON-NLS-1$
+        if (timeoutString != null) {
+            param= (Connector.Argument) map.get("timeout"); //$NON-NLS-1$
+            param.setValue(timeoutString);
+        }
+        
 		ILaunchConfiguration configuration = launch.getLaunchConfiguration();
 		boolean allowTerminate = false;
 		if (configuration != null) {