dev@glassfish.java.net

Re: proposed patch for appserv-commons NetUtils.java

From: Soon Leong <Soon-Leong.Yap_at_Sun.COM>
Date: Wed, 05 Oct 2005 00:36:08 +0800

agreed.

Kedar Mhaswade wrote:

> Hello Soon,
> Thanks for your patch. But there must be a careful refactoring
> before this could be incorporated. If you see, this method takes a
> host-name parameter and the reason it is doing so is not quite evident
> because one would think it is the host that this code executing on,
> that matters. But this code is also used to make a best-case attempt
> to determine if a port is free on a remote host!
>
> Localhost is just the default. If, in fact the host is not localhost,
> one should not open a ServerSocket to determine the port availability,
> but a listen socket for the same.
>
> I agree that if the host is "localhost", then one could open a
> "ServerSocket" instead of just a "Socket" to determine port availability.
>
> What do you think?
>
> Regards,
> Kedar
>
>
> Soon Leong wrote:
>
>> The current implementation for isPortFree() method in NetUtils does
>> not determine correctly that a specific port is in use on a machine.
>> Also, it was found that on machines with a client firewall, putting
>> in rules to unblock the port or even disabling the firewall will not
>> work.
>>
>> One area in glassfish that is affected by this problem is the
>> setup.xml, which is used to setup glassfish binary. The following
>> message is displayed.
>>
>> [exec] CLI130 Could not create domain, domain1
>> [exec] Port 8080 is in use.
>>
>> The proposed patch for isPortFree() method will be able to determine
>> the correct status on whether a specific port is in use even when a
>> client firewall is present on the machine.
>>
>>
>>
>> ------------------------------------------------------------------------
>>
>> /*
>> * The contents of this file are subject to the terms
>> * of the Common Development and Distribution License
>> * (the "License"). You may not use this file except
>> * in compliance with the License.
>> *
>> * You can obtain a copy of the license at
>> * glassfish/bootstrap/legal/CDDLv1.0.txt or
>> * https://glassfish.dev.java.net/public/CDDLv1.0.html.
>> * See the License for the specific language governing
>> * permissions and limitations under the License.
>> *
>> * When distributing Covered Code, include this CDDL
>> * HEADER in each file and include the License file at
>> * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
>> * add the following below this CDDL HEADER, with the
>> * fields enclosed by brackets "[]" replaced with your
>> * own identifying information: Portions Copyright [yyyy]
>> * [name of copyright owner]
>> */
>>
>> /*
>> * NetUtils.java
>> *
>> * Created on April 2, 2002, 9:19 PM
>> *
>> * @author bnevins
>> * @version $Revision: 1.2 $
>> * <BR> <I>$Source:
>> /opt/sourcecast/data/ccvs/repository/glassfish/appserv-commons/src/java/com/sun/enterprise/util/net/NetUtils.java,v
>> $
>> *
>> * Copyright 2000-2001 by iPlanet/Sun Microsystems, Inc.,
>> * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
>> * All rights reserved.
>> *
>> * This software is the confidential and proprietary information
>> * of iPlanet/Sun Microsystems, Inc. ("Confidential Information").
>> * You shall not disclose such Confidential Information and shall
>> * use it only in accordance with the terms of the license
>> * agreement you entered into with iPlanet/Sun Microsystems.
>> *
>> */
>>
>> package com.sun.enterprise.util.net;
>> import java.net.*;
>> import java.util.*;
>> import java.io.*;
>>
>> public class NetUtils
>> {
>> private NetUtils()
>> {
>> }
>>
>> public static final int MAX_PORT = 65535;
>>
>> ///////////////////////////////////////////////////////////////////////////
>>
>>
>> public static String getHostName()
>> {
>> try
>> {
>> return InetAddress.getLocalHost().getHostName();
>> }
>> catch(Exception e)
>> {
>> return null;
>> }
>> }
>>
>>
>> ///////////////////////////////////////////////////////////////////////////
>>
>>
>>
>> /**
>> * This method returns the fully qualified name of the host. If
>> * the name can't be resolved (on windows if there isn't a
>> domain specified), just
>> * host name is returned
>> *
>> * @throws UnknownHostException so it can be handled on a
>> case by case basis
>> */
>> public static String getCanonicalHostName() throws
>> UnknownHostException {
>> String hostname=null;
>> String
>> defaultHostname=InetAddress.getLocalHost().getHostName();
>> // look for full name
>> hostname=InetAddress.getLocalHost().getCanonicalHostName();
>>
>> // check to see if ip returned or canonical hostname is
>> different than hostname
>> // It is possible for dhcp connected computers to have an
>> erroneous name returned
>> // that is created by the dhcp server. If that happens,
>> return just the default hostname
>> if
>> (hostname.equals(InetAddress.getLocalHost().getHostAddress()) ||
>> !hostname.startsWith(defaultHostname)) {
>> // don't want IP or canonical hostname, this will
>> cause a lot of problems for dhcp users
>> // get just plan host name instead
>> hostname=defaultHostname;
>> }
>>
>> return hostname;
>> }
>>
>> ///////////////////////////////////////////////////////////////////////////
>>
>>
>> public static InetAddress[] getHostAddresses()
>> {
>> try
>> {
>> String hname = getHostName();
>>
>> if(hname == null)
>> return null;
>>
>> return InetAddress.getAllByName(hname);
>> }
>> catch(Exception e)
>> {
>> return null;
>> }
>> }
>>
>> ///////////////////////////////////////////////////////////////////////////
>>
>>
>> public static String[] getHostIPs()
>> {
>> try
>> {
>> InetAddress[] adds = getHostAddresses();
>>
>> if(adds == null)
>> return null;
>>
>> String[] ips = new String[adds.length];
>>
>> for(int i = 0; i < adds.length; i++)
>> {
>> String ip = trimIP(adds[i].toString());
>> ips[i] = ip;
>> }
>>
>> return ips;
>> }
>> catch(Exception e)
>> {
>> return null;
>> }
>> }
>>
>> ///////////////////////////////////////////////////////////////////////////
>>
>>
>> public static String trimIP(String ip)
>> {
>> if(ip == null || ip.length() <= 0)
>> return ip;
>>
>> int index = ip.lastIndexOf('/');
>>
>> if(index >= 0)
>> return ip.substring(++index);
>>
>> return ip;
>> }
>>
>> ///////////////////////////////////////////////////////////////////////////
>>
>>
>> public static byte[] ip2bytes(String ip)
>> {
>> try
>> {
>> // possibilities: "1.1.1.1", "frodo/1.1.1.1",
>> "frodo.foo.com/1.1.1.1"
>>
>> ip = trimIP(ip);
>> StringTokenizer stk = new StringTokenizer(ip, ".");
>>
>> byte[] bytes = new byte[stk.countTokens()];
>>
>> for(int i = 0; stk.hasMoreTokens(); i++)
>> {
>> String num = stk.nextToken();
>> int inum = Integer.parseInt(num);
>> bytes[i] = (byte)inum;
>> //System.out.println("token: " + inum);
>> }
>> return bytes;
>> }
>> catch(NumberFormatException nfe)
>> {
>> return null;
>> }
>> }
>>
>> ///////////////////////////////////////////////////////////////////////////
>>
>>
>> public static boolean isLocalHost(String ip)
>> {
>> if(ip == null)
>> return false;
>>
>> ip = trimIP(ip);
>>
>> return ip.equals(LOCALHOST_IP);
>> }
>>
>> ///////////////////////////////////////////////////////////////////////////
>>
>>
>> public static boolean isLocal(String ip)
>> {
>> if(ip == null)
>> return false;
>>
>> ip = trimIP(ip);
>>
>> if(isLocalHost(ip))
>> return true;
>>
>> String[] myIPs = getHostIPs();
>>
>> if(myIPs == null)
>> return false;
>>
>> for(int i = 0; i < myIPs.length; i++)
>> {
>> if(ip.equals(myIPs[i]))
>> return true;
>> }
>>
>> return false;
>> }
>>
>> ///////////////////////////////////////////////////////////////////////////
>>
>>
>> public static boolean isRemote(String ip)
>> {
>> return !isLocal(ip);
>> }
>>
>>
>> /**
>> * Get the next free port (incrementing by 1)
>> * @param hostName The host name on which the port is to be obtained
>> * @param port The port number
>> * @return The next incremental port number or 0 if a port cannot
>> be found.
>> */
>> public static int getNextFreePort(String hostName, int port)
>> {
>> while (port++ < MAX_PORT) {
>> if (isPortFree(hostName, port)) {
>> return port;
>> }
>> }
>> return 0;
>> }
>>
>> /**
>> * Returns a random port in the specified range
>> * @param hostName The host on which the port is to be obtained.
>> * @param startingPort starting port in the range
>> * @param endingPort ending port in the range
>> * @return the new port or 0 if the range is invalid.
>> */
>> public static int getFreePort(String hostName, int startingPort,
>> int endingPort)
>> {
>> int range = endingPort - startingPort;
>> int port = 0;
>> if (range > 0) {
>> Random r = new Random();
>> while (true) {
>> port = r.nextInt(range + 1) + startingPort;
>> if (isPortFree(hostName, port)) {
>> break;
>> }
>> }
>> }
>> return port;
>> }
>>
>> public static boolean isPortValid(int portNumber)
>> {
>> if (portNumber >=0 && portNumber <= MAX_PORT) {
>> return true;
>> } else {
>> return false;
>> }
>> }
>>
>> public static boolean isPortStringValid(String portNumber)
>> {
>> try {
>> return isPortValid(Integer.parseInt(portNumber));
>> } catch (NumberFormatException ex) {
>> return false;
>> }
>> }
>>
>> ///////////////////////////////////////////////////////////////////////////
>>
>>
>> public static boolean isPortFree(String hostName, int portNumber)
>> {
>> if(portNumber <= 0 || portNumber > MAX_PORT)
>> return false;
>> try
>> {
>> // WBN - I have no idea why I'm messing with these streams!
>> // I lifted the code from installer. Apparently if you just
>> // open a socket on a free port and catch the exception
>> something
>> // will go wrong in Windows.
>> // Feel free to change it if you know EXACTLY what
>> you'return doing
>>
>> //If the host name is null, assume localhost
>> if (hostName == null) {
>> hostName = getHostName();
>> }
>> ServerSocket socket = new ServerSocket(portNumber);
>> socket.close();
>> socket = null;
>> }
>> catch (Exception e)
>> {
>> // this port is in use
>> return false;
>> }
>>
>> return true;
>> }
>>
>> public static boolean isPortFree(int portNumber)
>> {
>> return isPortFree(null, portNumber);
>> }
>>
>> /**
>> Gets a free port at the time of call to this method.
>> The logic leverages the built in java.net.ServerSocket
>> implementation
>> which binds a server socket to a free port when instantiated
>> with
>> a port <code> 0 </code>.
>> <P> Note that this method guarantees the availability of the
>> port
>> only at the time of call. The method does not bind to this port.
>> <p> Checking for free port can fail for several reasons which
>> may
>> indicate potential problems with the system. This method
>> acknowledges
>> the fact and following is the general contract:
>> <li> Best effort is made to find a port which can be bound
>> to. All
>> the exceptional conditions in the due course are considered
>> SEVERE.
>> <li> If any exceptional condition is experienced, <code> 0
>> </code>
>> is returned, indicating that the method failed for some
>> reasons and
>> the callers should take the corrective action. (The method
>> need not
>> always throw an exception for this).
>> <li> Method is synchronized on this class.
>> @return integer depicting the free port number available at
>> this time
>> 0 otherwise.
>> */
>> public static int getFreePort()
>> {
>> int freePort = 0;
>> boolean portFound = false;
>> ServerSocket serverSocket = null;
>>
>> synchronized (NetUtils.class)
>> {
>> try
>> {
>> /*following call normally returns the free port,
>> to which the ServerSocket is bound. */
>> serverSocket = new ServerSocket(0);
>> freePort = serverSocket.getLocalPort();
>> portFound = true;
>> }
>> catch(Exception e)
>> {
>> //squelch the exception
>> }
>> finally
>> {
>> if (!portFound)
>> {
>> freePort = 0;
>> }
>> try
>> {
>> if (serverSocket != null)
>> {
>> serverSocket.close();
>> if (! serverSocket.isClosed())
>> {
>> throw new Exception("local exception ...");
>> }
>> }
>> }
>> catch(Exception e)
>> {
>> //squelch the exception
>> freePort = 0;
>> }
>> }
>> return freePort;
>> }
>> }
>>
>> ///////////////////////////////////////////////////////////////////////////
>>
>>
>> private static final String LOCALHOST_IP = "127.0.0.1";
>>
>> ///////////////////////////////////////////////////////////////////////////
>>
>>
>> public static void main(String[] args)
>> {
>> System.out.println("80: " + isPortFree(80));
>> System.out.println("777: " + isPortFree(777));
>> System.out.println("8000: " + isPortFree(8000));
>> System.out.println("8080: " + isPortFree(8080));
>> }
>> }
>>
>>
>>
>>
>>
>>
>>
>> ------------------------------------------------------------------------
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe_at_glassfish.dev.java.net
>> For additional commands, e-mail: dev-help_at_glassfish.dev.java.net
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe_at_glassfish.dev.java.net
> For additional commands, e-mail: dev-help_at_glassfish.dev.java.net
>