KickJava   Java API By Example, From Geeks To Geeks.

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


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

23
24 import java.io.*;
25 import java.net.InetAddress JavaDoc;
26 import java.net.Socket JavaDoc;
27 import java.net.ServerSocket JavaDoc;
28
29 import org.omg.ETF.*;
30 import org.omg.CSIIOP.*;
31 import org.omg.SSLIOP.*;
32
33 import org.apache.avalon.framework.configuration.*;
34
35 import org.jacorb.orb.factory.*;
36 import org.jacorb.orb.*;
37
38 /**
39  * @author Andre Spiegel
40  * @version $Id: IIOPListener.java,v 1.22 2004/12/20 11:35:11 simon.mcqueen Exp $
41  */

42 public class IIOPListener
43     extends org.jacorb.orb.etf.ListenerBase
44 {
45     /** the maximum set of security options supported by the SSL mechanism */
46     private static final int MAX_SSL_OPTIONS = Integrity.value |
47                                                Confidentiality.value |
48                                                DetectReplay.value |
49                                                DetectMisordering.value |
50                                                EstablishTrustInTarget.value |
51                                                EstablishTrustInClient.value;
52
53     /** the minimum set of security options supported by the SSL mechanism
54      * which cannot be turned off, so they are always supported
55      */

56     private static final int MIN_SSL_OPTIONS = Integrity.value |
57                                                DetectReplay.value |
58                                                DetectMisordering.value;
59
60     
61     private SocketFactoryManager socketFactoryManager = null;
62     private ServerSocketFactory serverSocketFactory = null;
63     private SSLServerSocketFactory sslServerSocketFactory = null;
64
65     private SSLAcceptor sslAcceptor = null;
66
67     private boolean supportSSL = false;
68     private boolean dnsEnabled = false;
69     private int serverTimeout = 0;
70     private int oaPort = 0;
71     private int sslPort = 0;
72     private int target_supports = 0;
73     private int target_requires = 0;
74     private boolean generateSSLComponents = true;
75
76     public IIOPListener()
77     {
78     }
79     
80     /**
81     * @deprecated Use no-args version and then configure().
82     */

83     public IIOPListener(ORB orb)
84     {
85         super(orb);
86         socketFactoryManager = new SocketFactoryManager(orb);
87     }
88
89
90     public void configure(Configuration configuration)
91         throws ConfigurationException
92     {
93         this.configuration = (org.jacorb.config.Configuration)configuration;
94         
95         if (orb == null)
96         {
97             // c.f. with the constructor taking an ORB param.
98
this.orb = this.configuration.getORB();
99             socketFactoryManager = new SocketFactoryManager(this.orb);
100         }
101         
102         logger = this.configuration.getNamedLogger("jacorb.iiop.listener");
103  
104         socketFactoryManager.configure(configuration);
105
106         oaPort = configuration.getAttributeAsInteger("OAPort",0);
107         sslPort = configuration.getAttributeAsInteger("OASSLPort",0);
108  
109         dnsEnabled =
110             configuration.getAttribute("jacorb.dns.enable","off").equals("on");
111
112         serverTimeout =
113             configuration.getAttributeAsInteger("jacorb.connection.server.timeout",0);
114
115         supportSSL =
116             configuration.getAttribute("jacorb.security.support_ssl","off").equals("on");
117
118         target_supports =
119             Integer.parseInt(
120                 configuration.getAttribute("jacorb.security.ssl.server.supported_options","20"),
121                 16); // 16 is the base as we take the string value as hex!
122

123         // make sure that the minimum options are always in the set of supported options
124
target_supports |= MIN_SSL_OPTIONS;
125
126         target_requires =
127             Integer.parseInt(
128                 configuration.getAttribute("jacorb.security.ssl.server.required_options","0"),
129                 16);
130
131
132         generateSSLComponents =
133             configuration.getAttribute("jacorb.security.ssl_components_added_by_ior_interceptor","off").equals("off");
134
135
136         if (!isSSLRequired() ||
137             configuration.getAttributeAsBoolean("jacorb.security.ssl.always_open_unsecured_endpoint", false))
138         {
139             acceptor = new Acceptor();
140             ((Acceptor)acceptor).init();
141         }
142
143         if (supportSSL)
144         {
145             sslAcceptor = new SSLAcceptor();
146             sslAcceptor.init();
147         }
148
149         endpoint = createEndPointProfile();
150
151     }
152
153     
154     /**
155      * It is possible that connection requests arrive <i>after</i> the
156      * initial creation of the Listener instance but <i>before</i> the
157      * conclusion of the configuration of the specific endpoint in this
158      * plugin. In order to provide a clear end of this configuration state,
159      * we added the listen() method. It is called by the ORB when it ready
160      * for incoming connection and thus signals the Listener instance to
161      * start processing the incoming connection requests. Therefore,
162      * a Listener instance shall not deliver incoming connections to the
163      * ORB before this method was called.
164      */

165     public void listen()
166     {
167         super.listen();
168         
169         if (sslAcceptor != null)
170             sslAcceptor.start();
171     }
172
173     /**
174      * The Listener is instructed to close its endpoint. It shall no
175      * longer accept any connection requests and shall close all
176      * connections opened by it.
177      */

178     public void destroy()
179     {
180         if (sslAcceptor != null)
181             sslAcceptor.terminate();
182
183         super.destroy();
184     }
185
186     // internal methods below this line
187

188     /**
189      * Returns true if this Listener should support SSL connections.
190      */

191     private boolean isSSLSupported()
192     {
193         return supportSSL;
194     }
195
196     /**
197      * Returns true if this Listener should <i>require</i> SSL, and not
198      * offer plain connections.
199      */

200     private boolean isSSLRequired()
201         throws ConfigurationException
202     {
203         if (isSSLSupported())
204         {
205             // the following is used as a bit mask to check if any SSL
206
// options are required
207
return ((target_requires & MAX_SSL_OPTIONS ) != 0);
208         }
209         return false;
210     }
211
212     /**
213      * Returns the server timeout that has been specified, or zero if none
214      * has been set.
215      */

216     private int getServerTimeout()
217     {
218         return serverTimeout;
219     }
220
221     private ServerSocketFactory getServerSocketFactory()
222     {
223         if (serverSocketFactory == null)
224         {
225             serverSocketFactory =
226                 socketFactoryManager.getServerSocketFactory();
227         }
228         return serverSocketFactory;
229     }
230
231     /**
232      * Returns the SSLServerSocketFactory that has been configured.
233      * If no such factory is available, org.omg.CORBA.INITIALIZE() is thrown.
234      */

235     private SSLServerSocketFactory getSSLServerSocketFactory()
236     {
237         if (sslServerSocketFactory == null)
238         {
239             sslServerSocketFactory =
240                 orb.getBasicAdapter().getSSLSocketFactory();
241
242             if (sslServerSocketFactory == null)
243                 throw new org.omg.CORBA.INITIALIZE JavaDoc("No SSL server socket factory found");
244         }
245         return sslServerSocketFactory;
246     }
247
248     /**
249      * Creates a new IIOPProfile that describes this transport endpoint.
250      */

251     private IIOPProfile createEndPointProfile()
252         throws ConfigurationException
253     {
254         int port=0;
255         if (acceptor != null)
256         {
257             port = getConfiguredPort();
258             if (port == 0)
259                 port = ((Acceptor)acceptor).getLocalAddress().getPort();
260         }
261         else if (sslAcceptor == null)
262             throw new org.omg.CORBA.INITIALIZE JavaDoc
263                 ("no acceptors found, cannot create endpoint profile");
264
265         IIOPProfile result = new IIOPProfile
266         (
267             new IIOPAddress
268             (
269                 // Construct the address either from the symbolic or
270
// numeric host address, depending on what we need later.
271
// Otherwise, we might get an unnecessary DNS lookup
272
// at IOR creation time, which might break the setting
273
// of OAIAddr on a multi-homed host.
274
dnsEnabled ? getHost().getHostName() : getHost().getHostAddress(),
275                 port // will be 0 if there is only an SSLAcceptor
276
),
277             null
278         );
279         if (sslAcceptor != null && generateSSLComponents)
280         {
281              result.addComponent (TAG_SSL_SEC_TRANS.value,
282                                   createSSL(), SSLHelper.class);
283         }
284         
285         result.configure(configuration);
286         return result;
287     }
288
289     private SSL createSSL()
290     {
291         return new SSL
292         (
293             (short)target_supports,
294             (short)target_requires,
295             (short)sslAcceptor.getLocalAddress().getPort()
296         );
297     }
298
299     /**
300      * Returns the IP address that this listener should listen on, if one has
301      * been configured explicitly. In the absence of an explicit configuration
302      * (through the <code>"OAIAddr"</code> property), returns null. Eventually
303      * the returned address will be passed as the `bindAddr' argument to a
304      * <code>java.net.ServerSocket</code> constructor, so a null address (no
305      * explicit configuration) means that this listener will accept connections
306      * on any/all local addresses. On the other hand, a non-null address means
307      * that this listener will only accept connect requests to the configured
308      * IP address.
309      *
310      * @return an <code>InetAddress</code>object with the IP address
311      * specified by the <code>"OAIAddr"</code> property, or
312      * <code>null</code> if this property has not been defined.
313      */

314     private InetAddress JavaDoc getConfiguredHost()
315     {
316         try
317         {
318             String JavaDoc oa_addr = configuration.getAttribute("OAIAddr","");
319             return (oa_addr.length() == 0) ? null : InetAddress.getByName(oa_addr);
320         }
321 // catch (ConfigurationException e)
322
// {
323
// throw new org.omg.CORBA.INITIALIZE("Could not resolve configured listener host" +
324
// e.getMessage());
325
// }
326
catch (java.net.UnknownHostException JavaDoc e)
327         {
328             throw new org.omg.CORBA.INITIALIZE JavaDoc
329                              ("Could not resolve configured listener host");
330         }
331     }
332
333     /**
334      * Returns the IP address to be placed in this listener's endpoint
335      * profile. The returned value is either an explicitly configured IP
336      * address or (in the absence of an explicit configuration) is the IP
337      * address of the local host.
338      *
339      * @return an <code>InetAddress</code>object with the IP address
340      * specified by the <code>"OAIAddr"</code> property, or
341      * (if this property has not been defined) an
342      * <code>InetAddress</code>object for the local host.
343      */

344     private InetAddress JavaDoc getHost()
345     {
346         try
347         {
348             InetAddress JavaDoc configuredHost = getConfiguredHost();
349             return (configuredHost == null) ? InetAddress.getLocalHost()
350                                             : configuredHost;
351         }
352         catch (java.net.UnknownHostException JavaDoc e)
353         {
354             throw new org.omg.CORBA.INITIALIZE JavaDoc
355                              ("Could not resolve configured listener host");
356         }
357     }
358
359     /**
360      * Returns the number of the port that this Listener should listen on.
361      * If no port has been specified, returns zero.
362      */

363     private int getConfiguredPort()
364     {
365         return oaPort;
366
367     }
368
369     private int getConfiguredSSLPort()
370     {
371         return sslPort;
372     }
373
374     /**
375      * Creates an ETF connection around a live socket and passes it
376      * up to the ORB, using either the upcall mechanism or the
377      * polling mechanism.
378      */

379     private void deliverConnection (Socket JavaDoc socket, boolean isSSL)
380     {
381         Connection result = null;
382         try
383         {
384             result = createServerConnection(socket, isSSL);
385         }
386         catch (IOException ex)
387         {
388             if (logger.isErrorEnabled())
389             {
390                 logger.error("Could not create connection from socket: " + ex);
391             }
392             return;
393         }
394
395         deliverConnection(result);
396     }
397
398     /**
399      * Template method to create a server-side ETF Connection.
400      * This can be overridden by subclasses to pass a different
401      * kind of Connection up to the ORB.
402      */

403     protected Connection createServerConnection (Socket JavaDoc socket,
404                                                  boolean is_ssl)
405         throws IOException
406     {
407         ServerIIOPConnection result = new ServerIIOPConnection(socket, is_ssl);
408         try
409         {
410             result.configure(configuration);
411         }
412         catch( ConfigurationException ce )
413         {
414             throw new org.omg.CORBA.INTERNAL JavaDoc("ConfigurationException: " + ce.getMessage());
415         }
416         return result;
417     }
418
419     // Acceptor classes below this line
420

421     protected class Acceptor
422         extends org.jacorb.orb.etf.ListenerBase.Acceptor
423     {
424         protected ServerSocket JavaDoc serverSocket;
425         
426         protected boolean terminated = false;
427         
428         public Acceptor()
429         {
430             // initialization deferred to init() method due to JDK bug
431
setDaemon(true);
432         }
433
434         public void init()
435         {
436             serverSocket = createServerSocket();
437
438             if( logger.isDebugEnabled() )
439             {
440                 logger.debug( "Created socket listener on " + serverSocket.getInetAddress() );
441             }
442        }
443
444         public void run()
445         {
446             while (!terminated)
447             {
448                 try
449                 {
450                     Socket JavaDoc socket = serverSocket.accept();
451                     setup (socket);
452                     deliverConnection (socket);
453                 }
454                 catch (Exception JavaDoc e)
455                 {
456                     if (!terminated)
457                     {
458                         if (logger.isWarnEnabled())
459                         {
460                             logger.warn(e.getMessage());
461                         }
462                     }
463                 }
464             }
465             if (logger.isInfoEnabled())
466             {
467                 logger.info( "Listener exited");
468             }
469         }
470
471         /**
472          * Terminates this Acceptor by closing the ServerSocket.
473          */

474         public void terminate()
475         {
476             terminated = true;
477             try
478             {
479                 serverSocket.close();
480             }
481             catch (java.io.IOException JavaDoc e)
482             {
483                 if (logger.isWarnEnabled())
484                 {
485                     logger.warn(e.getMessage());
486                 }
487             }
488         }
489
490         public IIOPAddress getLocalAddress()
491         {
492             return new IIOPAddress
493             (
494                 serverSocket.getInetAddress().getHostAddress(),
495                 serverSocket.getLocalPort()
496             );
497         }
498
499         /**
500          * Template method that creates the server socket.
501          */

502         protected ServerSocket JavaDoc createServerSocket()
503         {
504             try
505             {
506                 return getServerSocketFactory()
507                            .createServerSocket (getConfiguredPort(),
508                                                 20,
509                                                 getConfiguredHost());
510             }
511             catch (IOException ex)
512             {
513                 logger.warn(ex.getMessage());
514                 throw new org.omg.CORBA.INITIALIZE JavaDoc ("Could not create server socket");
515             }
516         }
517
518         /**
519          * Template method that sets up the socket right after the
520          * connection has been established. Subclass implementations
521          * must call super.setup() first.
522          */

523         protected void setup(Socket JavaDoc socket)
524             throws IOException
525         {
526              socket.setSoTimeout(serverTimeout);
527         }
528
529         protected void deliverConnection(Socket JavaDoc socket)
530         {
531             IIOPListener.this.deliverConnection (socket, false);
532         }
533     }
534
535     private class SSLAcceptor
536         extends Acceptor
537     {
538         protected ServerSocket JavaDoc createServerSocket()
539         {
540             try
541             {
542                 return getSSLServerSocketFactory()
543                             .createServerSocket (getConfiguredSSLPort(),
544                                                  20,
545                                                  getConfiguredHost());
546             }
547             catch (IOException e)
548             {
549                 logger.warn(e.getMessage());
550                 throw new org.omg.CORBA.INITIALIZE JavaDoc
551                                            ("Could not create SSL server socket");
552             }
553         }
554
555         protected void deliverConnection(Socket JavaDoc socket)
556         {
557             IIOPListener.this.deliverConnection (socket, true);
558         }
559     }
560
561 }
562
Popular Tags