/** * Copyright (c) 2005-2013 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Eclipse Public License (EPL). * Please see the license.txt included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ /* * Author: atotic * Created on Mar 22, 2004 */ package org.python.pydev.shared_core.net; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.SocketAddress; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; import org.python.pydev.shared_core.log.Log; /** * Utility class to find a port to debug on. * * Based on org.eclipse.jdt.launching.SocketUtil. */ public class SocketUtil { /** * Returns free ports on the local host. * * @param ports: number of ports to return. */ public static Integer[] findUnusedLocalPorts(final int ports) { Throwable firstFoundExc = null; final List<ServerSocket> socket = new ArrayList<ServerSocket>(); final List<Integer> portsFound = new ArrayList<Integer>(); try { try { for (int i = 0; i < ports; i++) { ServerSocket s = new ServerSocket(0); socket.add(s); int localPort = s.getLocalPort(); checkValidPort(localPort); portsFound.add(localPort); } } catch (Throwable e) { firstFoundExc = e; // Try a different approach... final Set<Integer> searched = new HashSet<Integer>(); try { for (int i = 0; i < ports && portsFound.size() < ports; i++) { int localPort = findUnusedLocalPort(20000, 65535, searched); checkValidPort(localPort); portsFound.add(localPort); } } catch (Exception e1) { Log.log(e1); // log this one (but the outer one will be thrown). } } finally { for (ServerSocket s : socket) { if (s != null) { try { s.close(); } catch (Exception e) { //Just ignore errors closing sockets } } } } if (portsFound.size() != ports) { throw firstFoundExc; } } catch (Throwable e) { String message = "Unable to find an unused local port (is there an enabled firewall?)"; throw new RuntimeException(message, e); } return portsFound.toArray(new Integer[portsFound.size()]); } public static void checkValidPort(int port) throws IOException { if (port == -1) { throw new IOException("Port not bound (found port -1). Is there an enabled firewall?"); } if (port == 0) { throw new IOException("Port not bound (found port 0). Is there an enabled firewall?"); } } private static final Random fgRandom = new Random(System.currentTimeMillis()); /** * Returns a free port number on the specified host within the given range, * or -1 if none found. */ private static int findUnusedLocalPort(int searchFrom, int searchTo, Set<Integer> searched) { for (int i = 0; i < 15; i++) { int port = getRandomPort(searchFrom, searchTo); if (searched.contains(i)) { continue; } searched.add(i); ServerSocket s = null; try { s = new ServerSocket(); SocketAddress sa = new InetSocketAddress(InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 }), port); s.bind(sa); // throws IOException (which can be ignored as this is in use...) return s.getLocalPort(); } catch (IOException e) { } finally { if (s != null) { try { s.close(); } catch (IOException ioe) { } } } } return -1; } private static int getRandomPort(int low, int high) { return (int) (fgRandom.nextFloat() * (high - low)) + low; } public static ServerSocket createLocalServerSocket() throws IOException { ServerSocket serverSocket = new ServerSocket(0); int localPort = serverSocket.getLocalPort(); try { SocketUtil.checkValidPort(localPort); } catch (Exception e) { // 0 did not give us a valid local port... close this one and try a different approach. try { serverSocket.close(); } catch (Exception e1) { } serverSocket = new ServerSocket(SocketUtil.findUnusedLocalPorts(1)[0]); localPort = serverSocket.getLocalPort(); try { SocketUtil.checkValidPort(localPort); } catch (IOException invalidPortException) { // Still invalid: close the socket and throw error! try { serverSocket.close(); } catch (Exception e1) { } throw invalidPortException; } } return serverSocket; } }