package org.jacorb.orb.factory; /* * Written for JacORB - a free Java ORB * * Copyright (C) 2000-2014 Gerald Brose / The JacORB Team. * * 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. */ import java.io.IOException; import java.net.BindException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketTimeoutException; import java.net.UnknownHostException; import javax.net.ssl.SSLSocket; import org.jacorb.config.Configuration; import org.jacorb.config.ConfigurationException; import org.jacorb.orb.iiop.IIOPAddress; import org.omg.CORBA.TIMEOUT; /** * a SocketFactory implementation that allows to specify the range * of local ports that should be used by a created socket. * the factory will read the attributes jacorb.net.socket_factory.port.min and * jacorb.net.socket_factory.port.max from the configuration and use the specified * values to configure the created sockets. * * @author Steve Osselton */ public class PortRangeSocketFactory extends AbstractSocketFactory { public static final String MIN_PROP = "jacorb.net.socket_factory.port.min"; public static final String MAX_PROP = "jacorb.net.socket_factory.port.max"; private int portMin; private int portMax; /** * <code>localEndpoint</code> allows OAIAddr to set which host to use on a multihomed * host. May be null. */ private InetAddress localEndpoint; @Override public void configure(Configuration config) throws ConfigurationException { super.configure(config); String oaiAddr = config.getAttribute("OAIAddr", ""); if (oaiAddr.length() > 0) { localEndpoint = (new IIOPAddress(oaiAddr, -1)).getConfiguredHost (); } // Get configured max and min port numbers portMin = getPortProperty(config, MIN_PROP); portMax = getPortProperty(config, MAX_PROP); // Check min < max if (portMin > portMax) { throw new ConfigurationException("PortRangeFactory: minimum port number not less than or equal to maximum"); } } @Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException { int localPort; for (localPort = portMin; localPort <= portMax; localPort++) { try { //use null as local InetAddress so InetSocketAddress will set the IP address to //the any/wildcard address final Socket socket = new Socket(); socket.bind (new InetSocketAddress(localEndpoint, localPort)); socket.connect(new InetSocketAddress(host, port)); if (logger.isDebugEnabled()) { logger.debug("PortRangeSocketFactory: Created socket at " + localPort + " with socket " + socket); } return socket; } catch (IOException ex) // NOPMD { // Ignore and continue } } if (logger.isWarnEnabled()) { logger.warn("Cannot bind socket between ports " + portMin + " and " + portMax + " to target " + host + ":" + port); } throw new BindException ("PortRangeSocketFactory: no free port between " + portMin + " and " + portMax); } @Override public boolean isSSL(Socket socket) { return false; } private int getPortProperty(Configuration config, String name) throws ConfigurationException { int port = config.getAttributeAsInteger(name); // Check sensible port number if (port < 0) { port += 65536; } if ((port <= 0) || (port > 65535)) { throw new ConfigurationException("PortRangeFactory: " + name + " invalid port number"); } return port; } @Override protected Socket doCreateSocket(String host, int port, int timeout) throws IOException { int localPort; Socket socket; final boolean useTimeout = timeout != 0; final long expireTime = useTimeout ? System.currentTimeMillis() + timeout : Long.MAX_VALUE; for (localPort = portMin; localPort <= portMax; localPort++) { socket = new Socket(); try { socket.bind (new InetSocketAddress (localEndpoint, localPort)); socket.connect(new InetSocketAddress(host, port), timeout); if (logger.isWarnEnabled()) { logger.warn("PortRangeSocketFactory: Created socket between " + socket.getLocalAddress().getHostAddress () + ":" + localPort + " and " + host + ":" + port); } return socket; } catch (SocketTimeoutException e) { tryToClose(socket); throw e; } catch (IOException ex) { tryToClose(socket); if (useTimeout && System.currentTimeMillis() > expireTime) { throw new TIMEOUT("couldn't open socket within " + timeout + ". Last exception details: " + ex.toString()); } } } if (logger.isWarnEnabled()) { logger.warn("Cannot bind socket between ports " + portMin + " and " + portMax + " to target " + host + ":" + port); } throw new BindException ("PortRangeSocketFactory: no free port between " + portMin + " and " + portMax); } private void tryToClose(Socket socket) { try { if ( ! (socket instanceof SSLSocket) && ! socket.isClosed() && socket.isConnected()) { socket.shutdownOutput(); } socket.close(); } catch(IOException e) { logger.warn("unable to close socket", e); } } }