Browse Source

Properly detect available port on localhost in SocketUtils

SocketUtils is used to find available ports on localhost; however,
prior to this commit, SocketUtils incorrectly reported a port as
available on localhost if another process was already bound to
localhost on the given port but not to other network interfaces. In
other words, SocketUtils determined that a given port was available for
some interface though not necessarily for the loopback interface.

This commit addresses this issue by refactoring SocketUtils so that it
tests the loopback interface to ensure that the port is actually
available for localhost.

Issue: SPR-13321
pull/856/head
Gary Russell 9 years ago committed by Sam Brannen
parent
commit
f15140415a
  1. 9
      spring-core/src/main/java/org/springframework/util/SocketUtils.java
  2. 33
      spring-core/src/test/java/org/springframework/util/SocketUtilsTests.java

9
spring-core/src/main/java/org/springframework/util/SocketUtils.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
package org.springframework.util;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.util.Random;
import java.util.SortedSet;
@ -34,6 +35,7 @@ import javax.net.ServerSocketFactory; @@ -34,6 +35,7 @@ import javax.net.ServerSocketFactory;
* @author Ben Hale
* @author Arjen Poutsma
* @author Gunnar Hillert
* @author Gary Russell
* @since 4.0
*/
public class SocketUtils {
@ -196,7 +198,8 @@ public class SocketUtils { @@ -196,7 +198,8 @@ public class SocketUtils {
@Override
protected boolean isPortAvailable(int port) {
try {
ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket(port);
ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket(port, 1,
InetAddress.getByName("localhost"));
serverSocket.close();
return true;
}
@ -210,7 +213,7 @@ public class SocketUtils { @@ -210,7 +213,7 @@ public class SocketUtils {
@Override
protected boolean isPortAvailable(int port) {
try {
DatagramSocket socket = new DatagramSocket(port);
DatagramSocket socket = new DatagramSocket(port, InetAddress.getByName("localhost"));
socket.close();
return true;
}

33
spring-core/src/test/java/org/springframework/util/SocketUtilsTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,7 +16,11 @@ @@ -16,7 +16,11 @@
package org.springframework.util;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.util.SortedSet;
import javax.net.ServerSocketFactory;
import org.junit.Test;
@ -27,6 +31,7 @@ import static org.springframework.util.SocketUtils.*; @@ -27,6 +31,7 @@ import static org.springframework.util.SocketUtils.*;
* Unit tests for {@link SocketUtils}.
*
* @author Sam Brannen
* @author Gary Russell
*/
public class SocketUtilsTests {
@ -60,6 +65,19 @@ public class SocketUtilsTests { @@ -60,6 +65,19 @@ public class SocketUtilsTests {
assertPortInRange(port, PORT_RANGE_MIN, PORT_RANGE_MAX);
}
@Test(expected = IllegalStateException.class)
public void findAvailableTcpPortWhenPortOnLoopbackInterfaceIsNotAvailable() throws Exception {
int port = SocketUtils.findAvailableTcpPort();
ServerSocket socket = ServerSocketFactory.getDefault().createServerSocket(port, 1, InetAddress.getByName("localhost"));
try {
// will only look for the exact port, since random.nextInt(1) always returns 0
SocketUtils.findAvailableTcpPort(port, port + 1);
}
finally {
socket.close();
}
}
@Test
public void findAvailableTcpPortWithMin() {
int port = SocketUtils.findAvailableTcpPort(50000);
@ -127,6 +145,19 @@ public class SocketUtilsTests { @@ -127,6 +145,19 @@ public class SocketUtilsTests {
assertPortInRange(port, PORT_RANGE_MIN, PORT_RANGE_MAX);
}
@Test(expected = IllegalStateException.class)
public void findAvailableUdpPortWhenPortOnLoopbackInterfaceIsNotAvailable() throws Exception {
int port = SocketUtils.findAvailableUdpPort();
DatagramSocket socket = new DatagramSocket(port, InetAddress.getByName("localhost"));
try {
// will only look for the exact port, since random.nextInt(1) always returns 0
SocketUtils.findAvailableUdpPort(port, port + 1);
}
finally {
socket.close();
}
}
@Test
public void findAvailableUdpPortWithMin() {
int port = SocketUtils.findAvailableUdpPort(50000);

Loading…
Cancel
Save