Package org.jacorb.orb.iiop

Source Code of org.jacorb.orb.iiop.ClientIIOPConnection

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

package org.jacorb.orb.iiop;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.avalon.framework.configuration.*;

import org.jacorb.orb.CDRInputStream;
import org.jacorb.orb.factory.SocketFactory;
import org.jacorb.orb.giop.TransportManager;

import org.omg.CSIIOP.*;
import org.omg.SSLIOP.*;
import org.omg.CORBA.*;


/**
* ClientIIOPConnection.java
*
*
* Created: Sun Aug 12 20:56:32 2002
*
* @author Nicolas Noffke / Andre Spiegel
* @version $Id: ClientIIOPConnection.java,v 1.21 2006/05/22 15:03:50 alphonse.bendt Exp $
*/

public class ClientIIOPConnection
    extends IIOPConnection
    implements Configurable
{
    //private IIOPProfile target_profile;
    private int timeout = 0;

    private int     ssl_port = -1;
    private int noOfRetries  = 5;
    private int retryInterval = 0;
    private boolean doSupportSSL = false;
    private TransportManager transportManager;

    //for testing purposes only: # of open transports
    //used by org.jacorb.test.orb.connection[Client|Server]ConnectionTimeoutTest
    public static int openTransports = 0;

    //for storing exceptions during connect
    private Exception exception = null;

    public ClientIIOPConnection()
    {
        use_ssl = false;
    }

    public void configure(Configuration configuration)
        throws ConfigurationException
    {
        super.configure(configuration);
        //get the client-side timeout property value

        timeout =
            configuration.getAttributeAsInteger("jacorb.connection.client.idle_timeout",0 );
        noOfRetries =
            configuration.getAttributeAsInteger("jacorb.retries", 5);
        retryInterval =
            configuration.getAttributeAsInteger("jacorb.retry_interval",500);
        doSupportSSL =
            configuration.getAttribute("jacorb.security.support_ssl","off").equals("on");
        transportManager =
            this.configuration.getORB().getTransportManager();

    }

    public ClientIIOPConnection (ClientIIOPConnection other)
    {
        super (other);
        this.timeout = other.timeout;
        this.ssl_port = other.ssl_port;
    }

    /**
     * Attempts to establish a 1-to-1 connection with a server using the
     * Listener endpoint from the given Profile description.  It shall
     * throw a COMM_FAILURE exception if it fails (e.g. if the endpoint
     * is unreachable) or a TIMEOUT exception if the given time_out period
     * has expired before a connection is established. If the connection
     * is successfully established it shall store the used Profile data.
     *
     */
    public synchronized void connect(org.omg.ETF.Profile server_profile, long time_out)
    {
        if( ! connected )
        {
            if (server_profile instanceof IIOPProfile)
            {
                this.profile = (IIOPProfile) server_profile;
            }
            else
            {
                throw new org.omg.CORBA.BAD_PARAM
                    ( "attempt to connect an IIOP connection "
                    + "to a non-IIOP profile: " + server_profile.getClass());
            }

            final IIOPLoopback loopback = getLocalLoopback() ;
            if (loopback != null)
            {
                final IIOPLoopbackInputStream lis = new IIOPLoopbackInputStream() ;
                final IIOPLoopbackOutputStream los = new IIOPLoopbackOutputStream() ;

                loopback.initLoopback(lis, los) ;

                in_stream = lis ;
                out_stream = los ;

                connected = true;

                //for testing purposes
                ++openTransports;

                return;
            }

            checkSSL();

            int retries = noOfRetries;
            while( retries >= 0 )
            {
                try
                {
                    createSocket(time_out);

                    if( timeout != 0 )
                    {
                        /* re-set the socket timeout */
                        socket.setSoTimeout( timeout /*note: this is another timeout!*/ );
                    }

                    in_stream =
                        socket.getInputStream();

                    out_stream =
                        new BufferedOutputStream( socket.getOutputStream());

                    if (logger.isInfoEnabled())
                    {
                        logger.info("Connected to " + connection_info +
                                    " from local port " +
                                    socket.getLocalPort() +
                                    ( this.isSSL() ? " via SSL" : "" ) +
                                    ( (timeout != 0) ? " Timeout: " + timeout : ""));
                    }

                    connected = true;

                    //for testing purposes
                    ++openTransports;

                    return;
                }
                catch ( IOException c )
                {
                    if (logger.isDebugEnabled())
                        logger.debug("Exception", c );

                    //only sleep and print message if we're actually
                    //going to retry
                    retries--;
                    if( retries >= 0 )
                    {
                        if (logger.isInfoEnabled())
                            logger.info("Retrying to connect to " +
                                        connection_info );
                        try
                        {
                            Thread.sleep( retryInterval );
                        }
                        catch( InterruptedException i )
                        {
                        }
                    }
                }
                catch (TIMEOUT e)
                {
                    //thrown if timeout is expired
                    profile = null;
                    use_ssl = false;
                    ssl_port = -1;
                    throw e;
                }

            }

            if( retries < 0 )
            {
                profile = null;
                use_ssl = false;
                ssl_port = -1;
                throw new org.omg.CORBA.TRANSIENT
                    ( "Retries exceeded, couldn't reconnect to " +
                      connection_info );
            }
        }
    }

    private IIOPLoopback getLocalLoopback()
    {
        final IIOPProfile iiopProfile = (IIOPProfile)profile ;
        final List addressList = new ArrayList() ;
        addressList.add(iiopProfile.getAddress());
        addressList.addAll(iiopProfile.getAlternateAddresses());

        final Iterator addressIterator = addressList.iterator() ;
        final IIOPLoopbackRegistry registry =
            IIOPLoopbackRegistry.getRegistry() ;

        while (addressIterator.hasNext())
        {
            final IIOPAddress address = (IIOPAddress)addressIterator.next() ;
            final IIOPLoopback loopback = registry.getLoopback(address) ;
            if (loopback != null)
            {
                return loopback ;
            }
        }

        return null ;
    }

    /**
     * Tries to create a socket connection to any of the addresses in
     * the target profile, starting with the primary IIOP address,
     * and then any alternate IIOP addresses that have been specified.
     */
    private void createSocket(long time_out)
        throws IOException
    {
        List addressList = new ArrayList();
        addressList.add(((IIOPProfile)profile).getAddress());
        addressList.addAll(((IIOPProfile)profile).getAlternateAddresses());

        Iterator addressIterator = addressList.iterator();

        exception = null;
        socket = null;
        while (socket == null && addressIterator.hasNext())
        {
            try
            {
                IIOPAddress address = (IIOPAddress)addressIterator.next();

                final SocketFactory factory =
                    (use_ssl) ? transportManager.getSSLSocketFactory() :
                    transportManager.getSocketFactory();

                final String ipAddress = address.getIP();
                final int port = (use_ssl) ? ssl_port : address.getPort();
                if (ipAddress.indexOf(':') == -1)
                    connection_info = ipAddress + ":" + port;
                else
                    connection_info = "[" + ipAddress + "]:" + port;

                if (logger.isDebugEnabled())
                {
                    logger.debug("Trying to connect to " + connection_info + " with timeout=" + time_out);
                }
                exception = null;
                socket = null;

                if( time_out > 0 )
                {
                    //set up connect with an extra thread
                    //if thread returns within time_out it notifies current thread
                    //if not this thread will cancel the connect-thread
                    //this is necessary since earlier JDKs didnt support connect()
                    //with time_out
                    final ClientIIOPConnection self = this;
                    Thread thread = new Thread ( new Runnable()
                    {
                        public void run()
                        {
                            try
                            {
                                socket = factory.createSocket(ipAddress, port);
                            }
                            catch (Exception e)
                            {
                                exception = e;
                            }
                            finally
                            {
                                synchronized (self)
                                {
                                    self.notify();
                                }
                            }
                        }
                    } );

                    thread.setName("SocketConnectorThread");

                   thread.setDaemon(true);
                   try
                   {
                       synchronized (self)
                       {
                           thread.start();
                           self.wait(time_out);
                       }
                   }
                   catch (InterruptedException _ex)
                   { }

                   if (socket == null)
                   {
                       if (exception == null)
                       {
                           if (logger.isDebugEnabled())
                           {
                               logger.debug("connect to " + connection_info +
                                            " with timeout=" + time_out + " timed out");
                           }
                           thread.interrupt();
                           exception =
                               new TIMEOUT("connection timeout of " + time_out + " milliseconds expired");
                       }
                       else
                       {
                           if (logger.isDebugEnabled())
                           {
                               logger.debug("connect to " + connection_info + " with timeout="
                                            + time_out + " raised exception: " + exception.toString());
                           }
                       }
                   }
                }
                else
                {
                    //no timeout --> may hang forever!
                    socket = factory.createSocket(ipAddress, port);
                }
            }
            catch (Exception e)
            {
                exception = e;
            }
        }

        if (exception != null)
        {
            if( exception instanceof IOException )
            {
                throw (IOException)exception;
            }
            else if( exception instanceof org.omg.CORBA.TIMEOUT )
            {
                throw (org.omg.CORBA.TIMEOUT)exception;
            }
            else
            {
                //not expected, because all used methods just throw IOExceptions or TIMEOUT
                //but... never say never ;o)
                throw new IOException ( "Unexpected exception occured: " + exception.toString() );
            }
        }
    }


    public synchronized void close()
    {
        try
        {
            if (connected)
            {
                if (socket != null)
                    socket.close();

                //this will cause exceptions when trying to read from
                //the streams. Better than "nulling" them.
                if( in_stream != null )
                {
                    in_stream.close();
                }
                if( out_stream != null )
                {
                    out_stream.close();
                }

                //for testing purposes
                --openTransports;
            }

            connected = false;
        }
        catch (IOException ex)
        {
            throw to_COMM_FAILURE (ex);
        }

        if (logger.isInfoEnabled())
        {
            logger.info("Client-side TCP transport to " +
                        connection_info + " closed.");
        }
    }




    /**
     * Check if this client should use SSL when connecting to
     * the server described by the 'profile'.  The result
     * is stored in the private fields use_ssl and ssl_port.
     */
    private void checkSSL()
    {
        CompoundSecMechList sas;
        try {
            sas = (CompoundSecMechList)((IIOPProfile)profile).getComponent
                                           (TAG_CSI_SEC_MECH_LIST.value,
                                            CompoundSecMechListHelper.class);
        } catch (Throwable ex) {
            logger.info("Not able to process security mech. component");
            return;
        }

        TLS_SEC_TRANS tls = null;
        if (sas != null && sas.mechanism_list[0].transport_mech.tag == TAG_TLS_SEC_TRANS.value) {
            try
            {
                byte[] tagData = sas.mechanism_list[0].transport_mech.component_data;
                CDRInputStream in = new CDRInputStream( (org.omg.CORBA.ORB)null, tagData );
                in.openEncapsulatedArray();
                tls = TLS_SEC_TRANSHelper.read( in );
            }
            catch ( Exception ex )
            {
                logger.warn("Error parsing TLS_SEC_TRANS: "+ex);
            }
        }

        SSL ssl = (SSL)((IIOPProfile)profile).getComponent
                                           (TAG_SSL_SEC_TRANS.value,
                                            SSLHelper.class);
        //if( sas != null &&
        //    ssl != null )
        //{
        //    ssl.target_requires |= sas.mechanism_list[0].target_requires;
        //}

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

        //the following is used as a bit mask to check, if any of
        //these options are set
        int minimum_options =
            Integrity.value |
            Confidentiality.value |
            DetectReplay.value |
            DetectMisordering.value |
            EstablishTrustInTarget.value |
            EstablishTrustInClient.value;

        int client_required = 0;
        int client_supported = 0;

        //only read in the properties if ssl is really supported.
        if( doSupportSSL )
        {
            client_required =
                configuration.getAttributeAsInteger("jacorb.security.ssl.client.required_options", 16);
            client_supported =
                configuration.getAttributeAsInteger("jacorb.security.ssl.client.supported_options",16);
        }

        if( tls != null && // server knows about ssl...
            ((tls.target_supports & minimum_options) != 0) && //...and "really" supports it
            doSupportSSL && //client knows about ssl...
            ((client_supported & minimum_options) != 0 )&& //...and "really" supports it
            ( ((tls.target_requires & minimum_options) != 0) || //server ...
              ((client_required & minimum_options) != 0))) //...or client require it
        {
            if (logger.isDebugEnabled())
            {
                logger.debug("Selecting TLS for connection");
            }

            use_ssl  = true;
            ssl_port = tls.addresses[0].port;
            if (ssl_port < 0) ssl_port += 65536;
        }
        else if( ssl != null && // server knows about ssl...
            ((ssl.target_supports & minimum_options) != 0) && //...and "really" supports it
            doSupportSSL && //client knows about ssl...
            ((client_supported & minimum_options) != 0 )&& //...and "really" supports it
            ( ((ssl.target_requires & minimum_options) != 0) || //server ...
              ((client_required & minimum_options) != 0))) //...or client require it
        {
            if (logger.isDebugEnabled())
            {
                logger.debug("Selecting SSL for connection");
            }

            use_ssl  = true;
            ssl_port = ssl.port;
            if (ssl_port < 0)
                ssl_port += 65536;
        }
        //prevent client policy violation, i.e. opening plain TCP
        //connections when SSL is required
        else if( // server doesn't know ssl...
                 doSupportSSL && //client knows about ssl...
                 ((client_required & minimum_options) != 0)) //...and requires it
        {
            throw new org.omg.CORBA.NO_PERMISSION( "Client-side policy requires SSL/TLS, but server doesn't support it" );
        }
        else
        {
            use_ssl = false;
            ssl_port = -1;
        }
    }
}
TOP

Related Classes of org.jacorb.orb.iiop.ClientIIOPConnection

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.