opends/src/server/org/opends/server/protocols/jmx/JmxConnectionHandler.java
@@ -36,8 +36,6 @@ import static org.opends.server.util.StaticUtils.*; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; @@ -60,6 +58,7 @@ import org.opends.server.types.HostPort; import org.opends.server.types.InitializationException; import org.opends.server.types.ResultCode; import org.opends.server.util.StaticUtils; @@ -328,48 +327,16 @@ // Configuration is ok. currentConfig = config; // Attempt to bind to the listen port to verify whether the connection // handler will be able to start. ServerSocket s = null; try { // HACK: // With dual stacks we can have a situation when INADDR_ANY/PORT // is bound in TCP4 space but available in TCP6 space and since // JavaServerSocket implemantation will always use TCP46 on dual // stacks the bind below will always succeed in such cases thus // shadowing anything that is already bound to INADDR_ANY/PORT. // While technically correct, with IPv4 and IPv6 being separate // address spaces, it presents a problem to end users because a // common case scenario is to have a single service serving both // address spaces ie listening to the same port in both spaces // on wildcard addresses 0 and ::. ServerSocket implemantation // does not provide any means of working with each address space // separately such as doing TCP4 or TCP6 only binds thus we have // to do a dummy connect to INADDR_ANY/PORT to check if it is // bound to something already. This is only needed for wildcard // addresses as specific IPv4 or IPv6 addresses will always be // handled in their respective address space. Socket clientSocket = new Socket(); try { // This might fail on some stacks but this is the best we // can do. No need for explicit timeout since it is local // address and we have to know for sure unless it fails. clientSocket.connect(new InetSocketAddress( config.getListenPort())); } catch (IOException e) { // Expected, ignore. } if (clientSocket.isConnected()) { clientSocket.close(); if (StaticUtils.isAddressInUse( new InetSocketAddress(config.getListenPort()).getAddress(), config.getListenPort(), true)) { throw new IOException( ERR_CONNHANDLER_ADDRESS_INUSE.get().toString()); } s = new ServerSocket(); s.setReuseAddress(true); s.bind(new InetSocketAddress(config.getListenPort())); } catch (Exception e) { @@ -379,13 +346,6 @@ logError(message); throw new InitializationException(message); } finally { try { s.close(); } catch (Exception e) {} } if (config.isUseSSL()) { protocol = "JMX+SSL"; @@ -441,6 +401,27 @@ List<Message> unacceptableReasons) { JMXConnectionHandlerCfg config = (JMXConnectionHandlerCfg) configuration; // Attempt to bind to the listen port to verify whether the connection // handler will be able to start. try { if (StaticUtils.isAddressInUse( new InetSocketAddress(config.getListenPort()).getAddress(), config.getListenPort(), true)) { throw new IOException( ERR_CONNHANDLER_ADDRESS_INUSE.get().toString()); } } catch (Exception e) { Message message = ERR_JMX_CONNHANDLER_CANNOT_BIND. get(String.valueOf(config.dn()), config.getListenPort(), getExceptionMessage(e)); unacceptableReasons.add(message); return false; } return isConfigurationChangeAcceptable(config, unacceptableReasons); } opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
@@ -41,8 +41,6 @@ import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; @@ -80,6 +78,7 @@ import org.opends.server.types.InitializationException; import org.opends.server.types.ResultCode; import org.opends.server.types.SSLClientAuthPolicy; import org.opends.server.util.StaticUtils; @@ -704,81 +703,26 @@ // Perform any additional initialization that might be required. statTracker = new LDAPStatistics(handlerName + " Statistics"); // Attempt to bind to the listen port on all configured addresses to // verify whether the connection handler will be able to start. LinkedList<ServerSocket> testListenSockets = new LinkedList<ServerSocket>(); try { for (InetAddress a : listenAddresses) { try { // HACK: // With dual stacks we can have a situation when INADDR_ANY/PORT // is bound in TCP4 space but available in TCP6 space and since // JavaServerSocket implemantation will always use TCP46 on dual // stacks the bind below will always succeed in such cases thus // shadowing anything that is already bound to INADDR_ANY/PORT. // While technically correct, with IPv4 and IPv6 being separate // address spaces, it presents a problem to end users because a // common case scenario is to have a single service serving both // address spaces ie listening to the same port in both spaces // on wildcard addresses 0 and ::. ServerSocket implemantation // does not provide any means of working with each address space // separately such as doing TCP4 or TCP6 only binds thus we have // to do a dummy connect to INADDR_ANY/PORT to check if it is // bound to something already. This is only needed for wildcard // addresses as specific IPv4 or IPv6 addresses will always be // handled in their respective address space. if (a.isAnyLocalAddress()) { Socket s = new Socket(); try { // This might fail on some stacks but this is the best we // can do. No need for explicit timeout since it is local // address and we have to know for sure unless it fails. s.connect(new InetSocketAddress(a, listenPort)); } catch (IOException e) { // Expected, ignore. } if (s.isConnected()) { s.close(); throw new IOException( ERR_CONNHANDLER_ADDRESS_INUSE.get().toString()); } } ServerSocket s = new ServerSocket(); s.setReuseAddress(allowReuseAddress); s.bind(new InetSocketAddress(a, listenPort)); testListenSockets.add(s); for (InetAddress a : listenAddresses) { try { if (StaticUtils.isAddressInUse(a, listenPort, allowReuseAddress)) { throw new IOException( ERR_CONNHANDLER_ADDRESS_INUSE.get().toString()); } catch (IOException e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } Message message = ERR_LDAP_CONNHANDLER_CANNOT_BIND. get(String.valueOf(config.dn()), a.getHostAddress(), listenPort, getExceptionMessage(e)); logError(message); throw new InitializationException(message); } catch (IOException e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } Message message = ERR_LDAP_CONNHANDLER_CANNOT_BIND.get( String.valueOf(config.dn()), a.getHostAddress(), listenPort, getExceptionMessage(e)); logError(message); throw new InitializationException(message); } } finally { for (ServerSocket s : testListenSockets) { try { s.close(); } catch (Exception e) {} } } // Create and start the request handlers. requestHandlers = new LDAPRequestHandler[numRequestHandlers]; @@ -790,7 +734,6 @@ requestHandlers[i].start(); } // Register the set of supported LDAP versions. DirectoryServer.registerSupportedLDAPVersion(3, this); if (config.isAllowLDAPV2()) @@ -798,7 +741,6 @@ DirectoryServer.registerSupportedLDAPVersion(2, this); } // Register this as a change listener. config.addLDAPChangeListener(this); } @@ -813,6 +755,32 @@ List<Message> unacceptableReasons) { LDAPConnectionHandlerCfg config = (LDAPConnectionHandlerCfg) configuration; // Attempt to bind to the listen port on all configured addresses to // verify whether the connection handler will be able to start. listenPort = config.getListenPort(); listenAddresses = config.getListenAddress(); allowReuseAddress = config.isAllowTCPReuseAddress(); for (InetAddress a : listenAddresses) { try { if (StaticUtils.isAddressInUse(a, listenPort, allowReuseAddress)) { throw new IOException( ERR_CONNHANDLER_ADDRESS_INUSE.get().toString()); } } catch (IOException e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } Message message = ERR_LDAP_CONNHANDLER_CANNOT_BIND.get( String.valueOf(config.dn()), a.getHostAddress(), listenPort, getExceptionMessage(e)); unacceptableReasons.add(message); return false; } } return isConfigurationChangeAcceptable(config, unacceptableReasons); } opends/src/server/org/opends/server/util/StaticUtils.java
@@ -40,6 +40,10 @@ import java.io.InputStreamReader; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.nio.ByteBuffer; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -2624,6 +2628,82 @@ /** * Indicates whether the provided TCP address is already in use. * * @param address IP address of the TCP address for which to make * the determination. * @param port TCP port number of the TCP address for which to * make the determination. * @param allowReuse Whether or not TCP address reuse is allowed when * making the determination. * * @return <CODE>true</CODE> if the provided TCP address is already in * use, or <CODE>false</CODE> otherwise. */ public static boolean isAddressInUse( InetAddress address, int port, boolean allowReuse) { // Return pessimistic. boolean isInUse = true; Socket clientSocket = null; ServerSocket serverSocket = null; try { // HACK: // With dual stacks we can have a situation when INADDR_ANY/PORT // is bound in TCP4 space but available in TCP6 space and since // JavaServerSocket implemantation will always use TCP46 on dual // stacks the bind below will always succeed in such cases thus // shadowing anything that is already bound to INADDR_ANY/PORT. // While technically correct, with IPv4 and IPv6 being separate // address spaces, it presents a problem to end users because a // common case scenario is to have a single service serving both // address spaces ie listening to the same port in both spaces // on wildcard addresses 0 and ::. ServerSocket implemantation // does not provide any means of working with each address space // separately such as doing TCP4 or TCP6 only binds thus we have // to do a dummy connect to INADDR_ANY/PORT to check if it is // bound to something already. This is only needed for wildcard // addresses as specific IPv4 or IPv6 addresses will always be // handled in their respective address space. if (address.isAnyLocalAddress()) { clientSocket = new Socket(); try { // This might fail on some stacks but this is the best we // can do. No need for explicit timeout since it is local // address and we have to know for sure unless it fails. clientSocket.connect(new InetSocketAddress(address, port)); } catch (IOException e) { // Expected, ignore. } if (clientSocket.isConnected()) { isInUse = true; } } serverSocket = new ServerSocket(); serverSocket.setReuseAddress(allowReuse); serverSocket.bind(new InetSocketAddress(address, port)); isInUse = false; } catch (IOException e) { isInUse = true; } finally { try { if (serverSocket != null) { serverSocket.close(); } } catch (Exception e) {} try { if (clientSocket != null) { clientSocket.close(); } } catch (Exception e) {} } return isInUse; } /** * Retrieves a lowercase representation of the given string. This * implementation presumes that the provided string will contain only ASCII * characters and is optimized for that case. However, if a non-ASCII