KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sslexplorer > agent > client > tunneling > TunnelManager


1 package com.sslexplorer.agent.client.tunneling;
2
3 import java.io.IOException JavaDoc;
4 import java.text.MessageFormat JavaDoc;
5 import java.util.Enumeration JavaDoc;
6 import java.util.Hashtable JavaDoc;
7
8 import com.maverick.multiplex.MultiplexedConnection;
9 import com.maverick.multiplex.Request;
10 import com.maverick.multiplex.RequestHandler;
11 import com.maverick.util.ByteArrayReader;
12 import com.maverick.util.ByteArrayWriter;
13 import com.sslexplorer.agent.client.AbstractResourceManager;
14 import com.sslexplorer.agent.client.Agent;
15 import com.sslexplorer.agent.client.PortMonitor;
16 import com.sslexplorer.agent.client.util.TunnelConfiguration;
17
18 /**
19  * This class manages tunnels for the SSL-Explorer agent. Using the multiplexed
20  * protocol it will respond to requests from the server to start and stop tunnel
21  * listeners.
22  *
23  * @author Lee David Painter
24  *
25  */

26 public class TunnelManager extends AbstractResourceManager implements RequestHandler, LocalTunnelServerListener {
27
28     // #ifdef DEBUG
29
static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TunnelManager.class);
30     // #endif
31

32     /**
33      * Tunnel resource type ID
34      */

35     public final static int TUNNEL_RESOURCE_TYPE_ID = 4;
36
37     /**
38      * Sent by server to start a list of local tunnels. Payload consists of
39      * tunnel resource details including resource ID.
40      */

41     public static final String JavaDoc START_LOCAL_TUNNEL = "startLocalTunnel@3sp.com"; //$NON-NLS-1$
42

43     /**
44      * Sent by server to stop a single local tunnel. Payload consists of
45      * resourceID
46      */

47     public static final String JavaDoc STOP_LOCAL_TUNNEL = "stopLocalTunnel@3sp.com"; //$NON-NLS-1$
48

49     /**
50      * Notification request that a remote tunnel has started.
51      */

52     public static final String JavaDoc START_REMOTE_TUNNEL = "startRemoteTunnel@3sp.com";
53     
54     /**
55      * Notification request that a remote tunnel has stopped.
56      */

57     public static final String JavaDoc STOP_REMOTE_TUNNEL = "stopRemoteTunnel@3sp.com";
58     
59     /**
60      * Sent by server to request a list of all active local tunnels. Payload to
61      * be sent back to server consists of all active resource IDs
62      */

63     public static final String JavaDoc ACTIVE_LOCAL_TUNNELS = "activeLocalTunnels@3sp.com"; //$NON-NLS-1$
64

65     /**
66      * Sent by client to request the server to close a local tunnel. The server
67      * then sends a {@link STOP_LOCAL_FORWARDING} message back to the client
68      */

69     public static final String JavaDoc CLOSE_LOCAL_TUNNEL = "closeLocalTunnel@3sp.com"; //$NON-NLS-1$
70

71     /**
72      * Sent by client to request that a tunnel is launched. The server should
73      * then configure a launch session. If the tunnel is local, the server
74      * should reply in the same way of {@link #START_LOCAL_TUNNEL} (in which
75      * case the agent then configures and starts the local tunnel). If the
76      * tunnel is remote, no reply will be sent.
77      */

78     public static final String JavaDoc SETUP_AND_LAUNCH_TUNNEL = "setupAndLaunchTunnel@3sp.com"; //$NON-NLS-1$
79

80     // Private statics
81

82     private static int temporaryTunnelId = -1;
83
84     // Protected instance variables
85

86     /** The collection of active socket listeners * */
87     protected Hashtable JavaDoc activeLocalTunnels = new Hashtable JavaDoc();
88
89     /**
90      * Constructor.
91      *
92      * @param agent
93      */

94     public TunnelManager(Agent agent) {
95         super(agent);
96         agent.getConnection().registerRequestHandler(START_LOCAL_TUNNEL, this);
97         agent.getConnection().registerRequestHandler(STOP_LOCAL_TUNNEL, this);
98         agent.getConnection().registerRequestHandler(START_REMOTE_TUNNEL, this);
99         agent.getConnection().registerRequestHandler(STOP_REMOTE_TUNNEL, this);
100         agent.getConnection().registerRequestHandler(ACTIVE_LOCAL_TUNNELS, this);
101     }
102
103     /**
104      * Retrieve all tunnel resources and add them to the GUI.
105      */

106     public void getTunnelResources() {
107         super.getResources(TUNNEL_RESOURCE_TYPE_ID, "Tunnels");
108     }
109
110     /*
111      * (non-Javadoc)
112      *
113      * @see com.sslexplorer.agent.client.AbstractResourceManager#launchResource(int)
114      */

115     public void launchResource(int resourceId) {
116         try {
117             ByteArrayWriter baw = new ByteArrayWriter();
118             baw.writeInt(resourceId);
119             Request request = new Request(SETUP_AND_LAUNCH_TUNNEL, baw.toByteArray());
120             if (agent.getConnection().sendRequest(request, true)) {
121                 // #ifdef DEBUG
122
log.debug("Tunnel launch setup");
123                 // #endif
124
processLaunchRequest(request);
125             } else {
126                 // #ifdef DEBUG
127
log.error("Failed to setup and launch tunnel launch");
128                 // #endif
129
}
130         } catch (IOException JavaDoc e) {
131             // #ifdef DEBUG
132
log.error("Failed to setup and launch tunnel launch", e);
133             // #endif
134
}
135     }
136
137     /**
138      * Request that the server closes a local tunnel
139      *
140      * @param id
141      */

142     public void closeLocalTunnel(int id) {
143         try {
144             ByteArrayWriter baw = new ByteArrayWriter();
145             baw.writeInt(id);
146             Request request = new Request(CLOSE_LOCAL_TUNNEL, baw.toByteArray());
147             agent.getConnection().sendRequest(request, false);
148         } catch (IOException JavaDoc e) {
149             // #ifdef DEBUG
150
log.error("Failed to setup and launch tunnel launch", e);
151             // #endif
152
}
153
154     }
155
156     /**
157      * Get a map of all active {@link LocalTunnelServerListener} keyed by
158      * resource ID.
159      *
160      * @return active local tunnels
161      */

162     public Hashtable JavaDoc getActiveLocalTunnels() {
163         return activeLocalTunnels;
164     }
165
166     /*
167      * (non-Javadoc)
168      *
169      * @see com.maverick.multiplex.RequestHandler#processRequest(com.maverick.multiplex.Request,
170      * com.maverick.multiplex.MultiplexedConnection)
171      */

172     public boolean processRequest(Request request, MultiplexedConnection con) {
173         // #ifdef DEBUG
174
log.info("Processing request " + request.getRequestName());
175         // #endif
176
if (request.getRequestName().equals(START_LOCAL_TUNNEL)) {
177             return startLocalTunnel(request.getRequestData());
178         } else if (request.getRequestName().equals(STOP_LOCAL_TUNNEL)) {
179             stopLocalTunnel(request);
180             return true;
181         } else if (request.getRequestName().equals(ACTIVE_LOCAL_TUNNELS)) {
182
183             try {
184                 Hashtable JavaDoc l = getActiveLocalTunnels();
185
186                 ByteArrayWriter msg = new ByteArrayWriter();
187                 msg.writeInt(l.size());
188                 for (Enumeration JavaDoc e = l.keys(); e.hasMoreElements();) {
189                     msg.writeInt(((Integer JavaDoc) e.nextElement()).intValue());
190                 }
191
192                 request.setRequestData(msg.toByteArray());
193                 return true;
194             } catch (IOException JavaDoc e) {
195                 return false;
196             }
197
198         } else if((request.getRequestName().equals(START_REMOTE_TUNNEL)
199                 || request.getRequestName().equals(STOP_REMOTE_TUNNEL))
200                 && request.getRequestData()!=null) {
201             
202
203 // if (portItem.getActiveTunnelCount() == 0) {
204
// portMonitor.removeItemAt(idx);
205
// } else {
206

207             try {
208                 ByteArrayReader bar = new ByteArrayReader(request.getRequestData());
209                 int resourceId = (int)bar.readInt();
210                 String JavaDoc resourceName = bar.readString();
211                 String JavaDoc launchId = bar.readString();
212                 String JavaDoc listeningInterface = bar.readString();
213                 int listeningPort = (int) bar.readInt();
214                 String JavaDoc destinationHost = bar.readString();
215                 int destinationPort = (int) bar.readInt();
216                 
217                 /**
218                  * This code should be called after this method but from the agent
219                  * class.
220                  */

221                 
222                 if (agent.getConfiguration().isDisplayInformationPopups()) {
223                     agent.getGUI()
224                         .popup(null,
225                             MessageFormat.format(Messages.getString(
226                                     request.getRequestName().equals(START_REMOTE_TUNNEL) ? "TunnelManager.openedRemoteTunnel" : "TunnelManager.closingRemoteTunnel"), new Object JavaDoc[] {
227                                     listeningInterface, String.valueOf(listeningPort), //$NON-NLS-1$$
228
destinationHost + ":" + destinationPort }),
229                             Messages.getString("Agent.title"), //$NON-NLS-1$
230
"popup-tunnel", -1); //$NON-NLS-1$
231
}
232                 agent.updateInformation();
233                 
234                 /*
235                  * Update the port monitor to show a remote tunnel with
236                  * no active connections when starting or remove it when
237                  * stopping
238                  */

239                 PortMonitor portMonitor = agent.getGUI().getPortMonitor();
240                 if(request.getRequestName().equals(START_REMOTE_TUNNEL)) {
241                     TunnelConfiguration conf = new DefaultTunnel(
242                             resourceId, TunnelConfiguration.REMOTE_TUNNEL, TunnelConfiguration.TCP_TUNNEL, listeningInterface, listeningPort, destinationPort, destinationHost, true, false, resourceName, launchId);
243                     RemotePortItem portItem = new RemotePortItem(conf);
244                     portMonitor.addPortItem(portItem);
245                 }
246                 else {
247                     int idx = portMonitor.getIndexForId(resourceId);
248                     if(idx != -1) {
249                         portMonitor.removeItemAt(idx);
250                     }
251                 }
252                 
253                 return true;
254             } catch (IOException JavaDoc e) {
255                 // #ifdef DEBUG
256
log.error("Failed to process remote tunnel request", e);
257                 // #endif
258
}
259             
260         }
261
262         return false;
263     }
264
265     /* (non-Javadoc)
266      * @see com.maverick.multiplex.RequestHandler#postReply(com.maverick.multiplex.MultiplexedConnection)
267      */

268     public void postReply(MultiplexedConnection connection) {
269     }
270
271     /**
272      * Configure and start a temporary local tunnel.
273      *
274      * @param name name
275      * @param hostToConnect host to connect to
276      * @param sourceInterface source interface
277      * @param portToConnect port to connect to
278      * @param usePreferredPort use the preferred port
279      * @param singleConnection single connection (tunnel closes when done)
280      * @param launchId launch ID
281      * @return local tunnel
282      * @throws IOException
283      */

284     public LocalTunnelServer startTemporaryLocalTunnel(String JavaDoc name, String JavaDoc hostToConnect, String JavaDoc sourceInterface,
285                                                             int portToConnect, boolean usePreferredPort, boolean singleConnection,
286                                                             String JavaDoc launchId) throws IOException JavaDoc {
287             DefaultTunnel t = new DefaultTunnel(getTemporaryTunnelId(),
288                             TunnelConfiguration.LOCAL_TUNNEL,
289                             TunnelConfiguration.TCP_TUNNEL,
290                             sourceInterface,
291                             (usePreferredPort ? portToConnect : 0),
292                             portToConnect,
293                             hostToConnect,
294                             false,
295                             singleConnection,
296                             name,
297                             launchId);
298
299             return startLocalTunnel(t);
300     }
301
302     /**
303      * Start a local tunnel given its configuration.
304      *
305      * @param conf configuration
306      * @return tunnel
307      * @throws IOException if tunnel cannot be started
308      */

309     public LocalTunnelServer startLocalTunnel(TunnelConfiguration conf) throws IOException JavaDoc {
310
311         if (conf.getType() != TunnelConfiguration.LOCAL_TUNNEL)
312             throw new IOException JavaDoc("Invalid tunnel type " + conf.getType()); //$NON-NLS-1$
313

314         LocalTunnelServer listener = new LocalTunnelServer(agent, agent.getTXIOListener(), agent.getRXIOListener(), conf);
315         listener.addListener(this);
316         listener.start();
317         return listener;
318     }
319
320     /**
321      * Send a request to the server to stop the tunnel. This will in turn send a
322      * request back to this agent to stop the listening socket.
323      *
324      * @param id
325      */

326     public void stopLocalTunnel(int id) {
327         stopLocalTunnel(new Integer JavaDoc(id), true);
328     }
329
330     /*
331      * (non-Javadoc)
332      *
333      * @see com.sslexplorer.agent.client.tunneling.LocalForwardingServerListener#activeTunnelDataTransferred(com.sslexplorer.agent.client.tunneling.LocalForwardingServer,
334      * com.sslexplorer.agent.client.tunneling.ActiveTunnel, byte[], int,
335      * boolean)
336      */

337     public void localTunnelConnectionDataTransferred(LocalTunnelServer localForwardingServer, LocalTunnelConnection activeTunnel, byte[] buffer,
338                                             int count, boolean sent) {
339     }
340
341     /*
342      * (non-Javadoc)
343      *
344      * @see com.sslexplorer.agent.client.tunneling.LocalForwardingServerListener#activeTunnelStarted(com.sslexplorer.agent.client.tunneling.LocalForwardingServer,
345      * com.sslexplorer.agent.client.tunneling.ActiveTunnel)
346      */

347     public void localTunnelConnectionStarted(LocalTunnelServer localForwardingServer, LocalTunnelConnection activeTunnel) {
348         // Update port monitor
349
PortMonitor portMonitor = agent.getGUI().getPortMonitor();
350         synchronized (portMonitor) {
351             int idx = portMonitor.getIndexForId(localForwardingServer.getId());
352             AbstractPortItem item = portMonitor.getItemAt(idx);
353             item.increaseActive();
354             portMonitor.updateItemAt(idx);
355         }
356         agent.updateInformation();
357         // #ifdef DEBUG
358
TunnelManager.log.info("Tunnel has been opened on " + activeTunnel.getClientHost() //$NON-NLS-1$
359
+ " to " + localForwardingServer.getTunnel().getDestinationHost() //$NON-NLS-1$
360
+ ":" + localForwardingServer.getTunnel().getDestinationPort()); //$NON-NLS-1$
361
// #endif
362
}
363
364     /*
365      * (non-Javadoc)
366      *
367      * @see com.sslexplorer.agent.client.tunneling.LocalForwardingServerListener#activeTunnelStopped(com.sslexplorer.agent.client.tunneling.LocalForwardingServer,
368      * com.sslexplorer.agent.client.tunneling.ActiveTunnel)
369      */

370     public void localTunnelConnectionStopped(LocalTunnelServer localForwardingServer, LocalTunnelConnection activeTunnel) {
371
372         // Update port monitor
373
PortMonitor portMonitor = agent.getGUI().getPortMonitor();
374         synchronized (portMonitor) {
375             int idx = portMonitor.getIndexForId(localForwardingServer.getId());
376             if (idx != -1) {
377                 AbstractPortItem item = portMonitor.getItemAt(idx);
378                 item.decreaseActive();
379                 portMonitor.updateItemAt(idx);
380             }
381         }
382
383         agent.updateInformation();
384
385         // #ifdef DEBUG
386
TunnelManager.log.info("Tunnel has been closed on " + activeTunnel.getClientHost() //$NON-NLS-1$
387
+ " to " + localForwardingServer.getTunnel().getDestinationHost() //$NON-NLS-1$
388
+ ":" + localForwardingServer.getTunnel().getDestinationPort() + " ( single connect = " + localForwardingServer.getTunnel().isTemporarySingleConnect() + ", permanent = " + localForwardingServer.getTunnel().isPermanent() + " )"); //$NON-NLS-1$
389
// #endif
390

391         if (!localForwardingServer.isStopping() && localForwardingServer.getTunnel().isTemporarySingleConnect()) {
392             // #ifdef DEBUG
393
TunnelManager.log.info("Closing listening temporary listening socket"); //$NON-NLS-1$
394
// #endif
395
localForwardingServer.stop();
396         }
397     }
398
399     /*
400      * (non-Javadoc)
401      *
402      * @see com.sslexplorer.agent.client.tunneling.LocalForwardingServerListener#localForwardingDataTransferred(com.sslexplorer.agent.client.tunneling.LocalForwardingServer,
403      * byte[], int, boolean)
404      */

405     public void localTunnelDataTransferred(LocalTunnelServer localForwardingServer, byte[] buffer, int count, boolean sent) {
406     }
407
408     /*
409      * (non-Javadoc)
410      *
411      * @see com.sslexplorer.agent.client.tunneling.LocalForwardingServerListener#localForwardingServerStarted(com.sslexplorer.agent.client.tunneling.LocalForwardingServer)
412      */

413     public void localTunnelServerStarted(LocalTunnelServer localForwardingServer) {
414
415         // Save the listener to our table
416
activeLocalTunnels.put(new Integer JavaDoc(localForwardingServer.getId()), localForwardingServer);
417
418         /**
419          * This code should be called after this method but from the agent
420          * class.
421          */

422         AbstractPortItem pi = new LocalPortItem(this, localForwardingServer.getTunnel(), localForwardingServer);
423         agent.getGUI().getPortMonitor().addPortItem(pi);
424         if (agent.getConfiguration().isDisplayInformationPopups()) {
425             agent.getGUI()
426                             .popup(null,
427                                 MessageFormat.format(Messages.getString("TunnelManager.openedLocalTunnel"), new Object JavaDoc[] { localForwardingServer.getTunnel().getName(), String.valueOf(localForwardingServer.getTunnel().getSourcePort()), //$NON-NLS-1$$
428
localForwardingServer.getTunnel().getDestinationHost() + ":" + localForwardingServer.getTunnel().getDestinationPort() }), //$NON-NLS-1$$
429
Messages.getString("Agent.title"), //$NON-NLS-1$
430
"popup-tunnel", -1); //$NON-NLS-1$
431
}
432         agent.updateInformation();
433     }
434
435     /*
436      * (non-Javadoc)
437      *
438      * @see com.sslexplorer.agent.client.tunneling.LocalForwardingServerListener#localForwardingStopped(com.sslexplorer.agent.client.tunneling.LocalForwardingServer)
439      */

440     public void localTunnelStopped(LocalTunnelServer localForwardingServer) {
441         activeLocalTunnels.remove(new Integer JavaDoc(localForwardingServer.getId()));
442         synchronized (agent.getGUI().getPortMonitor()) {
443             int idx = agent.getGUI().getPortMonitor().getIndexForId(localForwardingServer.getId());
444             if (idx != -1) {
445                 agent.getGUI().getPortMonitor().removeItemAt(idx);
446             }
447         }
448         TunnelConfiguration listeningSocketConfiguration = localForwardingServer.getTunnel();
449         if (agent.getConfiguration().isDisplayInformationPopups()) {
450             agent.getGUI()
451                             .popup(null,
452                                 MessageFormat.format(Messages.getString("TunnelManager.closingLocalTunnel"), new Object JavaDoc[] { listeningSocketConfiguration.getName(),//$NON-NLS-1$
453
String.valueOf(listeningSocketConfiguration.getSourcePort()),
454                                         listeningSocketConfiguration.getDestinationHost() + ":" + listeningSocketConfiguration.getDestinationPort() }), //$NON-NLS-1$
455
Messages.getString("Agent.title"), //$NON-NLS-1$
456
"popup-tunnel", -1); //$NON-NLS-1$
457
}
458         agent.updateInformation();
459     }
460
461     // Supporting methods
462

463     synchronized int getTemporaryTunnelId() {
464         return temporaryTunnelId--;
465     }
466
467     void processLaunchRequest(Request request) throws IOException JavaDoc {
468         /*
469          * If there is no returned request data, then the launched tunnnel was
470          * remote and we do not need to do any more
471          */

472         if (request.getRequestData() == null) {
473             // #ifdef DEBUG
474
log.info("No request data returned, assuming launch was a remote tunnel");
475             // #endif
476
return;
477         }
478         startLocalTunnel(request.getRequestData());
479     }
480
481     void stopLocalTunnel(Request request) {
482
483         if (request.getRequestData() == null)
484             return;
485         try {
486             ByteArrayReader msg = new ByteArrayReader(request.getRequestData());
487             stopLocalTunnel(new Integer JavaDoc((int) msg.readInt()), false);
488             request.setRequestData(null);
489
490         } catch (IOException JavaDoc ex) {
491             // #ifdef DEBUG
492
log.error("Failed to read tunnel id from request", ex);
493             // #endif
494
}
495     }
496
497     void stopLocalTunnel(Integer JavaDoc id, boolean informServer) {
498
499         // #ifdef DEBUG
500
log.info("Stopping local tunnel with id" + id); //$NON-NLS-1$
501
// #endif DEBUG
502

503         LocalTunnelServer listener = (LocalTunnelServer) activeLocalTunnels.get(id);
504
505         if (listener != null) {
506             listener.stop();
507         } else {
508             // #ifdef DEBUG
509
log.error("Request to close unknown local tunnel " + id);
510             // #endif
511
}
512
513     }
514
515     boolean startLocalTunnel(byte[] configurationData) {
516
517         try {
518
519             /**
520              * Start a local forwarding. This creates a listening socket on the
521              * client and will forward sockets opened through the multiplexed
522              * connection to the SSL-Explorer server.
523              */

524             ByteArrayReader reply = new ByteArrayReader(configurationData);
525             String JavaDoc launchId = reply.readString();
526
527             int id = (int) reply.readInt();
528             String JavaDoc name = reply.readString();
529             int type = (int) reply.readInt();
530             String JavaDoc transport = reply.readString();
531             String JavaDoc sourceInterface = reply.readString();
532             int sourcePort = (int) reply.readInt();
533             int destinationPort = (int) reply.readInt();
534             String JavaDoc destinationHost = reply.readString();
535
536             // #ifdef DEBUG
537
log.info("Received permanent tunnel named " + name + " for " + destinationHost + ":" + destinationPort);
538             // #endif
539

540             DefaultTunnel t = new DefaultTunnel(id,
541                             type,
542                             transport,
543                             sourceInterface,
544                             sourcePort,
545                             destinationPort,
546                             destinationHost,
547                             true,
548                             false,
549                             name,
550                             launchId);
551
552             startLocalTunnel(t);
553             return true;
554
555         } catch (IOException JavaDoc e) {
556             // #ifdef DEBUG
557
log.error("Request permanent tunnels operation failed", e);
558             // #endif
559
return false;
560         }
561     }
562 }
563
Popular Tags