KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jacorb > orb > iiop > ClientIIOPConnection


1 /*
2  * JacORB - a free Java ORB
3  *
4  * Copyright (C) 1997-2004 Gerald Brose.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the Free
18  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */

20
21 package org.jacorb.orb.iiop;
22
23 import java.io.BufferedOutputStream JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.List JavaDoc;
28
29 import org.apache.avalon.framework.configuration.*;
30
31 import org.jacorb.orb.CDRInputStream;
32 import org.jacorb.orb.IIOPAddress;
33 import org.jacorb.orb.factory.SocketFactory;
34 import org.jacorb.orb.giop.TransportManager;
35
36 import org.omg.CSIIOP.*;
37 import org.omg.SSLIOP.*;
38 import org.omg.CORBA.*;
39
40
41 /**
42  * ClientIIOPConnection.java
43  *
44  *
45  * Created: Sun Aug 12 20:56:32 2002
46  *
47  * @author Nicolas Noffke / Andre Spiegel
48  * @version $Id: ClientIIOPConnection.java,v 1.14 2004/08/25 09:31:41 simon.mcqueen Exp $
49  */

50
51 public class ClientIIOPConnection
52     extends IIOPConnection
53     implements Configurable
54 {
55     //private IIOPProfile target_profile;
56
private int timeout = 0;
57
58     private int ssl_port = -1;
59     private int noOfRetries = 5;
60     private int retryInterval = 0;
61     private boolean doSupportSSL = false;
62     private TransportManager transportManager;
63
64     //for testing purposes only: # of open transports
65
//used by org.jacorb.test.orb.connection[Client|Server]ConnectionTimeoutTest
66
public static int openTransports = 0;
67
68     //for storing exceptions during connect
69
private Exception JavaDoc exception = null;
70
71     public ClientIIOPConnection()
72     {
73         use_ssl = false;
74     }
75
76     public void configure(Configuration configuration)
77         throws ConfigurationException
78     {
79         super.configure(configuration);
80         //get the client-side timeout property value
81

82         timeout =
83             configuration.getAttributeAsInteger("jacorb.connection.client.idle_timeout",0 );
84         noOfRetries =
85             configuration.getAttributeAsInteger("jacorb.retries", 5);
86         retryInterval =
87             configuration.getAttributeAsInteger("jacorb.retry_interval",500);
88         doSupportSSL =
89             configuration.getAttribute("jacorb.security.support_ssl","off").equals("on");
90         transportManager =
91             this.configuration.getORB().getTransportManager();
92
93     }
94
95     public ClientIIOPConnection (ClientIIOPConnection other)
96     {
97         super (other);
98         this.timeout = other.timeout;
99         this.ssl_port = other.ssl_port;
100     }
101
102     /**
103      * Attempts to establish a 1-to-1 connection with a server using the
104      * Listener endpoint from the given Profile description. It shall
105      * throw a COMM_FAILURE exception if it fails (e.g. if the endpoint
106      * is unreachable) or a TIMEOUT exception if the given time_out period
107      * has expired before a connection is established. If the connection
108      * is successfully established it shall store the used Profile data.
109      *
110      */

111     public synchronized void connect(org.omg.ETF.Profile server_profile, long time_out)
112     {
113         if( ! connected )
114         {
115             if (server_profile instanceof IIOPProfile)
116             {
117                 this.profile = (IIOPProfile) server_profile;
118             }
119             else
120             {
121                 throw new org.omg.CORBA.BAD_PARAM JavaDoc
122                     ( "attempt to connect an IIOP connection "
123                     + "to a non-IIOP profile: " + server_profile.getClass());
124             }
125
126             checkSSL();
127
128             int retries = noOfRetries;
129             while( retries >= 0 )
130             {
131                 try
132                 {
133                     createSocket(time_out);
134
135                     if( timeout != 0 )
136                     {
137                         /* re-set the socket timeout */
138                         socket.setSoTimeout( timeout /*note: this is another timeout!*/ );
139                     }
140
141                     in_stream =
142                         socket.getInputStream();
143
144                     out_stream =
145                         new BufferedOutputStream JavaDoc( socket.getOutputStream());
146
147                     if (logger.isInfoEnabled())
148                     {
149                         logger.info("Connected to " + connection_info +
150                                     " from local port " +
151                                     socket.getLocalPort() +
152                                     ( this.isSSL() ? " via SSL" : "" ));
153                     }
154
155                     connected = true;
156
157                     //for testing purposes
158
++openTransports;
159
160                     return;
161                 }
162                 catch ( IOException JavaDoc c )
163                 {
164                     if (logger.isDebugEnabled())
165                         logger.debug("Exception", c );
166
167                     //only sleep and print message if we're actually
168
//going to retry
169
retries--;
170                     if( retries >= 0 )
171                     {
172                         if (logger.isInfoEnabled())
173                             logger.info("Retrying to connect to " +
174                                         connection_info );
175                         try
176                         {
177                             Thread.sleep( retryInterval );
178                         }
179                         catch( InterruptedException JavaDoc i )
180                         {
181                         }
182                     }
183                 }
184                 catch (TIMEOUT e)
185                 {
186                    //thrown if timeout is expired
187
profile = null;
188                    use_ssl = false;
189                    ssl_port = -1;
190                    throw e;
191                 }
192
193             }
194
195             if( retries < 0 )
196             {
197                 profile = null;
198                 use_ssl = false;
199                 ssl_port = -1;
200                 throw new org.omg.CORBA.TRANSIENT JavaDoc
201                     ( "Retries exceeded, couldn't reconnect to " +
202                       connection_info );
203             }
204         }
205     }
206
207     /**
208      * Tries to create a socket connection to any of the addresses in
209      * the target profile, starting with the primary IIOP address,
210      * and then any alternate IIOP addresses that have been specified.
211      */

212     private void createSocket(long time_out)
213         throws IOException JavaDoc
214     {
215         List JavaDoc addressList = new ArrayList JavaDoc();
216         addressList.add(((IIOPProfile)profile).getAddress());
217         addressList.addAll(((IIOPProfile)profile).getAlternateAddresses());
218
219         Iterator JavaDoc addressIterator = addressList.iterator();
220
221         exception = null;
222         socket = null;
223         while (socket == null && addressIterator.hasNext())
224         {
225             try
226             {
227                 IIOPAddress address = (IIOPAddress)addressIterator.next();
228
229                 final SocketFactory factory =
230                     (use_ssl) ? transportManager.getSSLSocketFactory() :
231                     transportManager.getSocketFactory();
232
233                 final String JavaDoc ipAddress = address.getIP();
234                 final int port = (use_ssl) ? ssl_port : address.getPort();
235                 connection_info = ipAddress + ":" + port;
236
237                 if (logger.isDebugEnabled())
238                 {
239                     logger.debug("Trying to connect to " + connection_info + " with timeout=" + time_out);
240                 }
241                 exception = null;
242                 socket = null;
243
244                 if( time_out > 0 )
245                 {
246                    //set up connect with an extra thread
247
//if thread returns within time_out it notifies current thread
248
//if not this thread will cancel the connect-thread
249
//this is necessary since earlier JDKs didnt support connect()
250
//with time_out
251
final ClientIIOPConnection self = this;
252                    Thread JavaDoc thread = new Thread JavaDoc( new Runnable JavaDoc()
253                                                     {
254                                                        public void run()
255                                                        {
256                                                           try
257                                                           {
258                                                              socket = factory.createSocket(ipAddress, port);
259                                                           }
260                                                           catch (Exception JavaDoc e)
261                                                           {
262                                                              exception = e;
263                                                           }
264                                                           finally
265                                                           {
266                                                              synchronized (self)
267                                                              {
268                                                                 self.notify();
269                                                              }
270                                                           }
271                                                        }
272                                                     } );
273                    thread.setDaemon(true);
274                    try
275                    {
276                        synchronized (self)
277                        {
278                            thread.start();
279                            self.wait(time_out);
280                        }
281                    }
282                    catch (InterruptedException JavaDoc _ex)
283                    { }
284                    
285                    if (socket == null)
286                    {
287                        if (exception == null)
288                        {
289                            if (logger.isDebugEnabled())
290                            {
291                                logger.debug("connect to " + connection_info +
292                                             " with timeout=" + time_out + " timed out");
293                            }
294                            thread.interrupt();
295                            exception =
296                                new TIMEOUT("connection timeout of " + time_out + " milliseconds expired");
297                        }
298                        else
299                        {
300                            if (logger.isDebugEnabled())
301                            {
302                                logger.debug("connect to " + connection_info + " with timeout="
303                                             + time_out + " raised exception: " + exception.toString());
304                            }
305                        }
306                    }
307                 }
308                 else
309                 {
310                     //no timeout --> may hang forever!
311
socket = factory.createSocket(ipAddress, port);
312                 }
313             }
314             catch (Exception JavaDoc e)
315             {
316                 exception = e;
317             }
318         }
319
320         if (exception != null)
321         {
322             if( exception instanceof IOException JavaDoc )
323             {
324                 throw (IOException JavaDoc)exception;
325             }
326             else if( exception instanceof org.omg.CORBA.TIMEOUT JavaDoc )
327             {
328                 throw (org.omg.CORBA.TIMEOUT JavaDoc)exception;
329             }
330             else
331             {
332                 //not expected, because all used methods just throw IOExceptions or TIMEOUT
333
//but... never say never ;o)
334
throw new IOException JavaDoc ( "Unexpected exception occured: " + exception.toString() );
335             }
336         }
337     }
338
339
340     public synchronized void close()
341     {
342         try
343         {
344             if (connected && socket != null)
345             {
346                 socket.close ();
347
348                 //this will cause exceptions when trying to read from
349
//the streams. Better than "nulling" them.
350
if( in_stream != null )
351                 {
352                     in_stream.close();
353                 }
354                 if( out_stream != null )
355                 {
356                     out_stream.close();
357                 }
358
359                 //for testing purposes
360
--openTransports;
361             }
362
363             connected = false;
364         }
365         catch (IOException JavaDoc ex)
366         {
367             throw to_COMM_FAILURE (ex);
368         }
369
370         if (logger.isInfoEnabled())
371         {
372             logger.info("Client-side TCP transport to " +
373                         connection_info + " closed.");
374         }
375     }
376
377
378     
379
380     /**
381      * Check if this client should use SSL when connecting to
382      * the server described by the 'profile'. The result
383      * is stored in the private fields use_ssl and ssl_port.
384      */

385     private void checkSSL()
386     {
387         CompoundSecMechList sas
388             = (CompoundSecMechList)((IIOPProfile)profile).getComponent
389                                            (TAG_CSI_SEC_MECH_LIST.value,
390                                             CompoundSecMechListHelper.class);
391
392         TLS_SEC_TRANS tls = null;
393         if (sas != null && sas.mechanism_list[0].transport_mech.tag == TAG_TLS_SEC_TRANS.value) {
394             try
395             {
396                 byte[] tagData = sas.mechanism_list[0].transport_mech.component_data;
397                 CDRInputStream in = new CDRInputStream( (org.omg.CORBA.ORB JavaDoc)null, tagData );
398                 in.openEncapsulatedArray();
399                 tls = TLS_SEC_TRANSHelper.read( in );
400             }
401             catch ( Exception JavaDoc ex )
402             {
403                 logger.warn("Error parsing TLS_SEC_TRANS: "+ex);
404             }
405         }
406
407         SSL ssl = (SSL)((IIOPProfile)profile).getComponent
408                                            (TAG_SSL_SEC_TRANS.value,
409                                             SSLHelper.class);
410         //if( sas != null &&
411
// ssl != null )
412
//{
413
// ssl.target_requires |= sas.mechanism_list[0].target_requires;
414
//}
415

416         // SSL usage is decided the following way: At least one side
417
// must require it. Therefore, we first check if it is
418
// supported by both sides, and then if it is required by at
419
// least one side. The distinction between
420
// EstablishTrustInTarget and EstablishTrustInClient is
421
// handled at the socket factory layer.
422

423         //the following is used as a bit mask to check, if any of
424
//these options are set
425
int minimum_options =
426             Integrity.value |
427             Confidentiality.value |
428             DetectReplay.value |
429             DetectMisordering.value |
430             EstablishTrustInTarget.value |
431             EstablishTrustInClient.value;
432
433         int client_required = 0;
434         int client_supported = 0;
435
436         //only read in the properties if ssl is really supported.
437
if( doSupportSSL )
438         {
439             client_required =
440                 configuration.getAttributeAsInteger("jacorb.security.ssl.client.required_options", 16);
441             client_supported =
442                 configuration.getAttributeAsInteger("jacorb.security.ssl.client.supported_options",16);
443         }
444
445         if( tls != null && // server knows about ssl...
446
((tls.target_supports & minimum_options) != 0) && //...and "really" supports it
447
doSupportSSL && //client knows about ssl...
448
((client_supported & minimum_options) != 0 )&& //...and "really" supports it
449
( ((tls.target_requires & minimum_options) != 0) || //server ...
450
((client_required & minimum_options) != 0))) //...or client require it
451
{
452             if (logger.isDebugEnabled())
453             {
454                 logger.debug("Selecting TLS for connection");
455             }
456
457             use_ssl = true;
458             ssl_port = tls.addresses[0].port;
459             if (ssl_port < 0) ssl_port += 65536;
460         }
461         else if( ssl != null && // server knows about ssl...
462
((ssl.target_supports & minimum_options) != 0) && //...and "really" supports it
463
doSupportSSL && //client knows about ssl...
464
((client_supported & minimum_options) != 0 )&& //...and "really" supports it
465
( ((ssl.target_requires & minimum_options) != 0) || //server ...
466
((client_required & minimum_options) != 0))) //...or client require it
467
{
468             if (logger.isDebugEnabled())
469             {
470                 logger.debug("Selecting SSL for connection");
471             }
472
473             use_ssl = true;
474             ssl_port = ssl.port;
475             if (ssl_port < 0)
476                 ssl_port += 65536;
477         }
478         //prevent client policy violation, i.e. opening plain TCP
479
//connections when SSL is required
480
else if( // server doesn't know ssl...
481
doSupportSSL && //client knows about ssl...
482
((client_required & minimum_options) != 0)) //...and requires it
483
{
484             throw new org.omg.CORBA.NO_PERMISSION JavaDoc( "Client-side policy requires SSL/TLS, but server doesn't support it" );
485         }
486         else
487         {
488             use_ssl = false;
489             ssl_port = -1;
490         }
491     }
492 }
493
Popular Tags