public void pickAddress() throws Exception {
if (publicAddress != null || bindAddress != null) {
return;
}
try {
final NetworkConfig networkConfig = node.getConfig().getNetworkConfig();
final AddressDefinition bindAddressDef = pickAddress(networkConfig);
final boolean reuseAddress = networkConfig.isReuseAddress();
final boolean bindAny = node.getGroupProperties().SOCKET_SERVER_BIND_ANY.getBoolean();
final int portCount = networkConfig.getPortCount();
/**
* why setReuseAddress(true)?
* when the member is shutdown,
* the server socket port will be in TIME_WAIT state for the next
* 2 minutes or so. If you start the member right after shutting it down
* you may not be able to bind to the same port because it is in TIME_WAIT
* state. if you set reuseAddress=true then TIME_WAIT will be ignored and
* you will be able to bind to the same port again.
*
* this will cause problem on windows
* see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6421091
* http://www.hsc.fr/ressources/articles/win_net_srv/multiple_bindings.html
*
* By default if the OS is Windows then reuseAddress will be false.
*/
log(Level.FINEST, "inet reuseAddress:" + reuseAddress);
InetSocketAddress inetSocketAddress;
ServerSocket serverSocket = null;
int port = networkConfig.getPort();
Throwable error = null;
for (int i = 0; i < portCount; i++) {
/**
* Instead of reusing the ServerSocket/ServerSocketChannel, we are going to close and replace them on
* every attempt to find a free port. The reason to do this is because in some cases, when concurrent
* threads/processes try to acquire the same port, the ServerSocket gets corrupted and isn't able to find
* any free port at all (no matter if there are more than enough free ports available). We have seen this
* happening on Linux and Windows environments.
*/
serverSocketChannel = ServerSocketChannel.open();
serverSocket = serverSocketChannel.socket();
serverSocket.setReuseAddress(reuseAddress);
serverSocket.setSoTimeout(1000);
try {
if (bindAny) {
inetSocketAddress = new InetSocketAddress(port);
} else {
inetSocketAddress = new InetSocketAddress(bindAddressDef.inetAddress, port);
}
log(Level.FINEST, "Trying to bind inet socket address:" + inetSocketAddress);
serverSocket.bind(inetSocketAddress, 100);
log(Level.FINEST, "Bind successful to inet socket address:" + inetSocketAddress);
break;
} catch (final Exception e) {
serverSocket.close();
serverSocketChannel.close();
if (networkConfig.isPortAutoIncrement()) {
port++;
error = e;
} else {
String msg = "Port [" + port + "] is already in use and auto-increment is " +
"disabled. Hazelcast cannot start.";
logger.severe(msg, e);
throw new HazelcastException(msg, error);
}
}
}
if (serverSocket == null || !serverSocket.isBound()) {
throw new HazelcastException("ServerSocket bind has failed. Hazelcast cannot start! " +
"config-port: " + networkConfig.getPort() + ", latest-port: " + port, error);
}
serverSocketChannel.configureBlocking(false);
bindAddress = createAddress(bindAddressDef, port);
log(Level.INFO, "Picked " + bindAddress + ", using socket " + serverSocket + ", bind any local is " + bindAny);
AddressDefinition publicAddressDef = getPublicAddress(node.getConfig(), port);