View | Details | Raw Unified | Return to bug 4922 | Differences between
and this patch

Collapse All | Expand All

(-)META-INF/MANIFEST.MF (-1 / +2 lines)
Lines 13-19 Link Here
13
 org.eclipse.ui.navigator.resources;bundle-version="[3.2.100,4.0.0)",
13
 org.eclipse.ui.navigator.resources;bundle-version="[3.2.100,4.0.0)",
14
 org.eclipse.core.net;bundle-version="[1.0.0,2.0.0)",
14
 org.eclipse.core.net;bundle-version="[1.0.0,2.0.0)",
15
 org.eclipse.update.core;bundle-version="[3.1.100,4.0.0)",
15
 org.eclipse.update.core;bundle-version="[3.1.100,4.0.0)",
16
 com.ibm.icu;bundle-version="3.8.1"
16
 com.ibm.icu;bundle-version="3.8.1",
17
 org.eclipse.core.filesystem;bundle-version="1.2.0"
17
Export-Package: org.eclipse.ui.internal.ide.application;x-internal:=true,
18
Export-Package: org.eclipse.ui.internal.ide.application;x-internal:=true,
18
 org.eclipse.ui.internal.ide.application.dialogs;x-internal:=true
19
 org.eclipse.ui.internal.ide.application.dialogs;x-internal:=true
19
Bundle-RequiredExecutionEnvironment: J2SE-1.4
20
Bundle-RequiredExecutionEnvironment: J2SE-1.4
(-)src/org/eclipse/ui/internal/ide/application/IDEWorkbenchAdvisor.java (-6 / +53 lines)
Lines 16-22 Link Here
16
import java.util.Iterator;
16
import java.util.Iterator;
17
import java.util.Map;
17
import java.util.Map;
18
import java.util.TreeMap;
18
import java.util.TreeMap;
19
19
import org.eclipse.core.filesystem.EFS;
20
import org.eclipse.core.net.proxy.IProxyService;
20
import org.eclipse.core.net.proxy.IProxyService;
21
import org.eclipse.core.resources.IContainer;
21
import org.eclipse.core.resources.IContainer;
22
import org.eclipse.core.resources.IResource;
22
import org.eclipse.core.resources.IResource;
Lines 27-32 Link Here
27
import org.eclipse.core.runtime.IAdaptable;
27
import org.eclipse.core.runtime.IAdaptable;
28
import org.eclipse.core.runtime.IBundleGroup;
28
import org.eclipse.core.runtime.IBundleGroup;
29
import org.eclipse.core.runtime.IBundleGroupProvider;
29
import org.eclipse.core.runtime.IBundleGroupProvider;
30
import org.eclipse.core.runtime.IPath;
30
import org.eclipse.core.runtime.IProgressMonitor;
31
import org.eclipse.core.runtime.IProgressMonitor;
31
import org.eclipse.core.runtime.IStatus;
32
import org.eclipse.core.runtime.IStatus;
32
import org.eclipse.core.runtime.MultiStatus;
33
import org.eclipse.core.runtime.MultiStatus;
Lines 46-51 Link Here
46
import org.eclipse.swt.SWT;
47
import org.eclipse.swt.SWT;
47
import org.eclipse.swt.widgets.Display;
48
import org.eclipse.swt.widgets.Display;
48
import org.eclipse.swt.widgets.Listener;
49
import org.eclipse.swt.widgets.Listener;
50
import org.eclipse.ui.IWorkbenchPage;
51
import org.eclipse.ui.IWorkbenchWindow;
52
import org.eclipse.ui.PartInitException;
49
import org.eclipse.ui.PlatformUI;
53
import org.eclipse.ui.PlatformUI;
50
import org.eclipse.ui.application.IWorkbenchConfigurer;
54
import org.eclipse.ui.application.IWorkbenchConfigurer;
51
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
55
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
Lines 128-134 Link Here
128
	private IDEIdleHelper idleHelper;
132
	private IDEIdleHelper idleHelper;
129
133
130
	private Listener settingsChangeListener;
134
	private Listener settingsChangeListener;
131
	
135
132
	/**
136
	/**
133
	 * Support class for monitoring workspace changes and periodically
137
	 * Support class for monitoring workspace changes and periodically
134
	 * validating the undo history
138
	 * validating the undo history
Lines 140-145 Link Here
140
	 */
144
	 */
141
	private AbstractStatusHandler ideWorkbenchErrorHandler;
145
	private AbstractStatusHandler ideWorkbenchErrorHandler;
142
146
147
	static IDEWorkbenchAdvisor getInstance() {
148
		return workbenchAdvisor;
149
	}
150
143
	/**
151
	/**
144
	 * Creates a new workbench advisor instance.
152
	 * Creates a new workbench advisor instance.
145
	 */
153
	 */
Lines 159-165 Link Here
159
	public void initialize(IWorkbenchConfigurer configurer) {
167
	public void initialize(IWorkbenchConfigurer configurer) {
160
168
161
		PluginActionBuilder.setAllowIdeLogging(true);
169
		PluginActionBuilder.setAllowIdeLogging(true);
162
		
170
163
		// make sure we always save and restore workspace state
171
		// make sure we always save and restore workspace state
164
		configurer.setSaveAndRestore(true);
172
		configurer.setSaveAndRestore(true);
165
173
Lines 194-200 Link Here
194
202
195
		// initialize idle handler
203
		// initialize idle handler
196
		idleHelper = new IDEIdleHelper(configurer);
204
		idleHelper = new IDEIdleHelper(configurer);
197
		
205
198
		// initialize the workspace undo monitor
206
		// initialize the workspace undo monitor
199
		workspaceUndoMonitor = WorkspaceUndoMonitor.getInstance();
207
		workspaceUndoMonitor = WorkspaceUndoMonitor.getInstance();
200
208
Lines 242-253 Link Here
242
			initializeSettingsChangeListener();
250
			initializeSettingsChangeListener();
243
			Display.getCurrent().addListener(SWT.Settings,
251
			Display.getCurrent().addListener(SWT.Settings,
244
					settingsChangeListener);
252
					settingsChangeListener);
253
			runStartupCommand(Platform.getCommandLineArgs());
245
		} finally {// Resume background jobs after we startup
254
		} finally {// Resume background jobs after we startup
246
			Job.getJobManager().resume();
255
			Job.getJobManager().resume();
247
		}
256
		}
248
	}
257
	}
249
258
250
	/**
259
	/**
260
	 * Runs a command specified on the command line, if any
261
	 */
262
	boolean runStartupCommand(String[] arguments) {
263
		if (arguments.length == 0)
264
			return false;
265
		// if the last command line argument is a file, open that file in an
266
		// editor
267
		final IPath path = new Path(arguments[arguments.length - 1]);
268
		if (!path.toFile().exists())
269
			return false;
270
		IWorkbenchWindow window = PlatformUI.getWorkbench()
271
				.getActiveWorkbenchWindow();
272
		if (window == null) {
273
			IWorkbenchWindow[] windows = PlatformUI.getWorkbench()
274
					.getWorkbenchWindows();
275
			if (windows.length > 0)
276
				window = windows[0];
277
		}
278
		if (window == null)
279
			return false;
280
		final IWorkbenchPage page = window.getActivePage();
281
		if (page == null)
282
			return false;
283
		window.getShell().getDisplay().syncExec(new Runnable() {
284
			public void run() {
285
				try {
286
					IDE.openEditorOnFileStore(page, EFS.getLocalFileSystem()
287
							.getStore(path));
288
				} catch (PartInitException e) {
289
					IDEWorkbenchPlugin.log(
290
							"Error opening editor on path: " + path, e); //$NON-NLS-1$
291
				}
292
			}
293
		});
294
		return true;
295
	}
296
297
	/**
251
	 * Activate the proxy service by obtaining it.
298
	 * Activate the proxy service by obtaining it.
252
	 */
299
	 */
253
	private void activateProxyService() {
300
	private void activateProxyService() {
Lines 260-266 Link Here
260
		}
307
		}
261
		if (proxyService == null) {
308
		if (proxyService == null) {
262
			IDEWorkbenchPlugin.log("Proxy service could not be found."); //$NON-NLS-1$
309
			IDEWorkbenchPlugin.log("Proxy service could not be found."); //$NON-NLS-1$
263
		}	
310
		}
264
	}
311
	}
265
312
266
	/**
313
	/**
Lines 697-703 Link Here
697
		declareWorkbenchImage(ideBundle,
744
		declareWorkbenchImage(ideBundle,
698
				IDEInternalWorkbenchImages.IMG_ETOOL_PROBLEM_CATEGORY,
745
				IDEInternalWorkbenchImages.IMG_ETOOL_PROBLEM_CATEGORY,
699
				PATH_ETOOL + "problem_category.gif", true); //$NON-NLS-1$
746
				PATH_ETOOL + "problem_category.gif", true); //$NON-NLS-1$
700
	
747
701
		// synchronization indicator objects
748
		// synchronization indicator objects
702
		// declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_WBET_STAT,
749
		// declareRegistryImage(IDEInternalWorkbenchImages.IMG_OBJS_WBET_STAT,
703
		// PATH_OVERLAY+"wbet_stat.gif");
750
		// PATH_OVERLAY+"wbet_stat.gif");
(-)src/org/eclipse/ui/internal/ide/application/IDEApplication.java (-1 / +15 lines)
Lines 105-111 Link Here
105
                Platform.endSplash();
105
                Platform.endSplash();
106
                return EXIT_OK;
106
                return EXIT_OK;
107
            }
107
            }
108
108
            
109
            // create the workbench with this advisor and run it until it exits
109
            // create the workbench with this advisor and run it until it exits
110
            // N.B. createWorkbench remembers the advisor, and also registers
110
            // N.B. createWorkbench remembers the advisor, and also registers
111
            // the workbench globally so that all UI plug-ins can find it using
111
            // the workbench globally so that all UI plug-ins can find it using
Lines 217-222 Link Here
217
        // -data @noDefault or -data not specified, prompt and set
217
        // -data @noDefault or -data not specified, prompt and set
218
        ChooseWorkspaceData launchData = new ChooseWorkspaceData(instanceLoc
218
        ChooseWorkspaceData launchData = new ChooseWorkspaceData(instanceLoc
219
                .getDefault());
219
                .getDefault());
220
        
221
        //check if someone is listening that we can pass our command line to
222
        if (launchData.getPort() != 0) {
223
        	if (new IDECommunication().writeToPort(launchData.getPort(), launchData.getIPCAuthorization())) {
224
        		//we successfully punted this application's command line to another instance,
225
        		//so we can just shutdown this instance.
226
        		return false;
227
        	}
228
        }
220
229
221
        boolean force = false;
230
        boolean force = false;
222
        while (true) {
231
        while (true) {
Lines 233-238 Link Here
233
                // the operation will fail if the url is not a valid
242
                // the operation will fail if the url is not a valid
234
                // instance data area, so other checking is unneeded
243
                // instance data area, so other checking is unneeded
235
                if (instanceLoc.setURL(workspaceUrl, true)) {
244
                if (instanceLoc.setURL(workspaceUrl, true)) {
245
                    int[] ipcData = new IDECommunication().listen();
246
                    if (ipcData != null) {
247
                    	launchData.setPort(ipcData[0]);
248
                    	launchData.setIPCAuthorization(ipcData[1]);
249
                    }
236
                    launchData.writePersistedData();
250
                    launchData.writePersistedData();
237
                    writeWorkspaceVersion();
251
                    writeWorkspaceVersion();
238
                    return true;
252
                    return true;
(-)src/org/eclipse/ui/internal/ide/application/IDECommunication.java (+208 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
12
package org.eclipse.ui.internal.ide.application;
13
14
import java.security.SecureRandom;
15
16
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
17
18
import java.io.*;
19
import java.net.*;
20
import org.eclipse.core.runtime.*;
21
import org.eclipse.core.runtime.jobs.Job;
22
23
/**
24
 * A helper class that deals with interprocess communication between applications.
25
 * <p>
26
 * This class uses a socket connection on a random available port to establish
27
 * communication between applications. The client must provide an authorization
28
 * code to protect against communication from arbitrary port sniffing applications.
29
 * 
30
 * @since 3.5
31
 */
32
class IDECommunication {
33
	/**
34
	 * A job that listens on a socket for a command, and then invokes the
35
	 * workbench advisor to handle the command.
36
	 */
37
	class ListenJob extends Job {
38
		private ServerSocket server;
39
		private int auth;
40
41
		public ListenJob(ServerSocket server, int auth) {
42
			super("Listen"); //$NON-NLS-1$
43
			this.server = server;
44
			this.auth = auth;
45
			setSystem(true);
46
		}
47
48
		/* (non-Javadoc)
49
		 * @see org.eclipse.core.runtime.jobs.Job#canceling()
50
		 */
51
		protected void canceling() {
52
			try {
53
				server.close();
54
			} catch (IOException e) {
55
				//ignore
56
			}
57
		}
58
59
		/* (non-Javadoc)
60
		 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
61
		 */
62
		protected IStatus run(IProgressMonitor monitor) {
63
			if (server.isClosed())
64
				return Status.OK_STATUS;
65
			Socket client = null;
66
			DataInputStream in = null;
67
			DataOutputStream out = null;
68
			try {
69
				client = server.accept();
70
				in = new DataInputStream(client.getInputStream());
71
				out = new DataOutputStream(client.getOutputStream());
72
				//read the protocol version
73
				int version = in.readInt();
74
				String[] args = null;
75
				if (version == PROTOCOL_VERSION_ONE) {
76
					//read the authorization checksum
77
					int receivedAuth = in.readInt();
78
					//abort immediately if we failed to read the authorization integer
79
					if (receivedAuth != auth) {
80
						schedule(SCHEDULE_DELAY);
81
						return new Status(IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, "Connection from unauthorized client on port " + server.getLocalPort()); //$NON-NLS-1$
82
					}
83
					args = new String[in.readInt()];
84
					for (int i = 0; i < args.length; i++) {
85
						args[i] = in.readUTF();
86
					}
87
				}
88
				//pass the read arguments to the workbench advisor
89
				IDEWorkbenchAdvisor advisor = IDEWorkbenchAdvisor.getInstance();
90
				if (advisor != null && args != null) {
91
					if (advisor.runStartupCommand(args))
92
						out.writeUTF(OK);
93
					else
94
						out.writeUTF(FAIL);
95
				}
96
			} catch (IOException e) {
97
				IDEWorkbenchPlugin.log("Error communicating with client", e); //$NON-NLS-1$
98
			} finally {
99
				safeClose(in);
100
				safeClose(out);
101
				safeClose(client);
102
			}
103
			//reschedule
104
			schedule(SCHEDULE_DELAY);
105
			return Status.OK_STATUS;
106
		}
107
	}
108
109
	/**
110
	 * The first communication protocol version. This version contains an authorization
111
	 * integer followed by a list of command line arguments. The format is: int authorizationId, int N, String[N].
112
	 */
113
	private static final int PROTOCOL_VERSION_ONE = 1;
114
115
	private static final long SCHEDULE_DELAY = 1000;
116
117
	static final String OK = "OK"; //$NON-NLS-1$
118
	static final String FAIL = "FAIL"; //$NON-NLS-1$
119
120
	/**
121
	 * Start listening for commands.
122
	 * @return An integer array of size two. The first integer is the port
123
	 * number we are listening on, and the second integer is an authorization
124
	 * integer used to validate connections.  Returns <code>null</code> if
125
	 * there was a failure to establish communication
126
	 */
127
	public int[] listen() {
128
		try {
129
			ServerSocket server = new ServerSocket(0);
130
			int auth = new SecureRandom().nextInt();
131
			new ListenJob(server, auth).schedule(SCHEDULE_DELAY);
132
			return new int[] {server.getLocalPort(), auth};
133
		} catch (IOException e) {
134
			return null;
135
		}
136
	}
137
138
	/**
139
	 * Close the given stream and ignore secondary failures.
140
	 */
141
	void safeClose(DataInputStream in) {
142
		try {
143
			if (in != null)
144
				in.close();
145
		} catch (IOException e) {
146
			//ignore secondary failure while closing
147
		}
148
	}
149
150
	/**
151
	 * Close the given stream and ignore secondary failures.
152
	 */
153
	void safeClose(DataOutputStream out) {
154
		try {
155
			if (out != null)
156
				out.close();
157
		} catch (IOException e) {
158
			//ignore secondary failure while closing
159
		}
160
	}
161
162
	/**
163
	 * Close the given socket and ignore secondary failures.
164
	 */
165
	void safeClose(Socket socket) {
166
		try {
167
			if (socket != null)
168
				socket.close();
169
		} catch (IOException e) {
170
			//ignore secondary failure while closing
171
		}
172
	}
173
174
	/**
175
	 * Writes this application's command line arguments to the given port.
176
	 * 
177
	 * @param port The port to write data to
178
	 * @param auth The authorization integer
179
	 * @return <code>true</code> if written successfully, and <code>false</code> otherwise.
180
	 */
181
	public boolean writeToPort(int port, int auth) {
182
		Socket socket = null;
183
		DataOutputStream out = null;
184
		DataInputStream in = null;
185
		try {
186
			socket = new Socket("localhost", port);//$NON-NLS-1$
187
			out = new DataOutputStream(socket.getOutputStream());
188
			in = new DataInputStream(socket.getInputStream());
189
			out.writeInt(PROTOCOL_VERSION_ONE);
190
			out.writeInt(auth);
191
			String[] args = Platform.getCommandLineArgs();
192
			out.writeInt(args.length);
193
			for (int i = 0; i < args.length; i++)
194
				out.writeUTF(args[i]);
195
			//server will return OK or FAIL
196
			return in.readUTF().equals(OK);
197
		} catch (UnknownHostException e) {
198
			return false;
199
		} catch (IOException e) {
200
			return false;
201
		} finally {
202
			safeClose(socket);
203
			safeClose(out);
204
			safeClose(in);
205
		}
206
	}
207
208
}
(-)src/org/eclipse/ui/internal/ide/ChooseWorkspaceData.java (-3 / +63 lines)
Lines 69-75 Link Here
69
    /**
69
    /**
70
	 * This is the second version of the encode/decode protocol that uses the
70
	 * This is the second version of the encode/decode protocol that uses the
71
	 * confi area preferences store for persistence. This version is the same as
71
	 * confi area preferences store for persistence. This version is the same as
72
	 * the previous version except it uses a \n character to seperate the path
72
	 * the previous version except it uses a \n character to separate the path
73
	 * entries instead of commas. (see bug 98467)
73
	 * entries instead of commas. (see bug 98467)
74
	 * 
74
	 * 
75
	 * @since 3.3.1
75
	 * @since 3.3.1
Lines 83-88 Link Here
83
    private String selection;
83
    private String selection;
84
84
85
    private String[] recentWorkspaces;
85
    private String[] recentWorkspaces;
86
    
87
    /**
88
     * The port on which an instance of this configuration is already listening for remote communication.
89
     * This value is 0 if nobody is already listening.
90
     */
91
    private int port = 0;
92
    /**
93
     * An authorization integer that a client must provide when communication with
94
     * this application. This is a simple security measure to prevent a port scanner 
95
     * from executing commands in this application.
96
     */
97
    private int ipcAuth = 0;
86
98
87
    // xml tags
99
    // xml tags
88
    private static interface XML {
100
    private static interface XML {
Lines 101-107 Link Here
101
        public static final String MAX_LENGTH = "maxLength"; //$NON-NLS-1$
113
        public static final String MAX_LENGTH = "maxLength"; //$NON-NLS-1$
102
114
103
        public static final String PATH = "path"; //$NON-NLS-1$
115
        public static final String PATH = "path"; //$NON-NLS-1$
104
    }
116
117
        public static final String PORT= "port"; //$NON-NLS-1$
118
119
        public static final String IPC_AUTH= "ipcAuth"; //$NON-NLS-1$
120
}
105
121
106
    /**
122
    /**
107
     * Creates a new instance, loading persistent data if its found.
123
     * Creates a new instance, loading persistent data if its found.
Lines 151-156 Link Here
151
		}
167
		}
152
        initialDefault = dir;
168
        initialDefault = dir;
153
    }
169
    }
170
    
171
    /**
172
     * Sets the port on which an instance is listening for remote communication.
173
     * @param port The port, or 0 to indicate not listening.
174
     */
175
    public void setPort(int port) {
176
    	this.port = port;
177
    }
178
    
179
    /**
180
     * Sets an authorization integer that a client must provide to establish
181
     * remote communication.  This is used to prevent a port sniffer from
182
     * executing commands.
183
     */
184
    public void setIPCAuthorization(int auth) {
185
    	this.ipcAuth = auth;
186
    }
154
187
155
    /**
188
    /**
156
     * Return the currently selected workspace or null if nothing is selected.
189
     * Return the currently selected workspace or null if nothing is selected.
Lines 173-178 Link Here
173
    public String[] getRecentWorkspaces() {
206
    public String[] getRecentWorkspaces() {
174
        return recentWorkspaces;
207
        return recentWorkspaces;
175
    }
208
    }
209
    
210
    /**
211
     * Returns the port on which an instance of this same configuration is
212
     * already listening for remote communication, or 0 if nobody is listening.
213
     * @return The port number, or 0.
214
     */
215
    public int getPort() {
216
    	return port;
217
    }
218
    
219
    /**
220
     * Returns the authorization integer for establishing interprocess communication.
221
     * @return The authorization integer
222
     */
223
    public int getIPCAuthorization() {
224
    	return ipcAuth;
225
    }
176
226
177
    /**
227
    /**
178
     * The argument workspace has been selected, update the receiver.  Does not
228
     * The argument workspace has been selected, update the receiver.  Does not
Lines 230-237 Link Here
230
		// 5. store the protocol version used to encode the list
280
		// 5. store the protocol version used to encode the list
231
		node.putInt(IDE.Preferences.RECENT_WORKSPACES_PROTOCOL,
281
		node.putInt(IDE.Preferences.RECENT_WORKSPACES_PROTOCOL,
232
				PERS_ENCODING_VERSION_CONFIG_PREFS_NO_COMMAS);
282
				PERS_ENCODING_VERSION_CONFIG_PREFS_NO_COMMAS);
283
		
284
		// 6. store the interprocess communication data, if any
285
		if (port != 0) {
286
			node.putInt(XML.PORT, port);
287
			node.putInt(XML.IPC_AUTH, ipcAuth);
288
		}
233
289
234
		// 6. store the node
290
		// 7. store the node
235
		try {
291
		try {
236
			node.flush();
292
			node.flush();
237
		} catch (BackingStoreException e) {
293
		} catch (BackingStoreException e) {
Lines 405-410 Link Here
405
				.getString(IDE.Preferences.RECENT_WORKSPACES);
461
				.getString(IDE.Preferences.RECENT_WORKSPACES);
406
		recentWorkspaces = decodeStoredWorkspacePaths(protocol, max, workspacePathPref);
462
		recentWorkspaces = decodeStoredWorkspacePaths(protocol, max, workspacePathPref);
407
463
464
		// 5. load the interprocess communication data
465
		port = store.getInt(XML.PORT);
466
		ipcAuth = store.getInt(XML.IPC_AUTH);
467
		
408
		return true;
468
		return true;
409
	}
469
	}
410
470

Return to bug 4922