Skip to content

Commit f151404

Browse files
garyrussellsbrannen
authored andcommitted
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
1 parent e0f012f commit f151404

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.util;
1818

1919
import java.net.DatagramSocket;
20+
import java.net.InetAddress;
2021
import java.net.ServerSocket;
2122
import java.util.Random;
2223
import java.util.SortedSet;
@@ -34,6 +35,7 @@
3435
* @author Ben Hale
3536
* @author Arjen Poutsma
3637
* @author Gunnar Hillert
38+
* @author Gary Russell
3739
* @since 4.0
3840
*/
3941
public class SocketUtils {
@@ -196,7 +198,8 @@ private static enum SocketType {
196198
@Override
197199
protected boolean isPortAvailable(int port) {
198200
try {
199-
ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket(port);
201+
ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket(port, 1,
202+
InetAddress.getByName("localhost"));
200203
serverSocket.close();
201204
return true;
202205
}
@@ -210,7 +213,7 @@ protected boolean isPortAvailable(int port) {
210213
@Override
211214
protected boolean isPortAvailable(int port) {
212215
try {
213-
DatagramSocket socket = new DatagramSocket(port);
216+
DatagramSocket socket = new DatagramSocket(port, InetAddress.getByName("localhost"));
214217
socket.close();
215218
return true;
216219
}

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

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,7 +16,11 @@
1616

1717
package org.springframework.util;
1818

19+
import java.net.DatagramSocket;
20+
import java.net.InetAddress;
21+
import java.net.ServerSocket;
1922
import java.util.SortedSet;
23+
import javax.net.ServerSocketFactory;
2024

2125
import org.junit.Test;
2226

@@ -27,6 +31,7 @@
2731
* Unit tests for {@link SocketUtils}.
2832
*
2933
* @author Sam Brannen
34+
* @author Gary Russell
3035
*/
3136
public class SocketUtilsTests {
3237

@@ -60,6 +65,19 @@ public void findAvailableTcpPort() {
6065
assertPortInRange(port, PORT_RANGE_MIN, PORT_RANGE_MAX);
6166
}
6267

68+
@Test(expected = IllegalStateException.class)
69+
public void findAvailableTcpPortWhenPortOnLoopbackInterfaceIsNotAvailable() throws Exception {
70+
int port = SocketUtils.findAvailableTcpPort();
71+
ServerSocket socket = ServerSocketFactory.getDefault().createServerSocket(port, 1, InetAddress.getByName("localhost"));
72+
try {
73+
// will only look for the exact port, since random.nextInt(1) always returns 0
74+
SocketUtils.findAvailableTcpPort(port, port + 1);
75+
}
76+
finally {
77+
socket.close();
78+
}
79+
}
80+
6381
@Test
6482
public void findAvailableTcpPortWithMin() {
6583
int port = SocketUtils.findAvailableTcpPort(50000);
@@ -127,6 +145,19 @@ public void findAvailableUdpPort() {
127145
assertPortInRange(port, PORT_RANGE_MIN, PORT_RANGE_MAX);
128146
}
129147

148+
@Test(expected = IllegalStateException.class)
149+
public void findAvailableUdpPortWhenPortOnLoopbackInterfaceIsNotAvailable() throws Exception {
150+
int port = SocketUtils.findAvailableUdpPort();
151+
DatagramSocket socket = new DatagramSocket(port, InetAddress.getByName("localhost"));
152+
try {
153+
// will only look for the exact port, since random.nextInt(1) always returns 0
154+
SocketUtils.findAvailableUdpPort(port, port + 1);
155+
}
156+
finally {
157+
socket.close();
158+
}
159+
}
160+
130161
@Test
131162
public void findAvailableUdpPortWithMin() {
132163
int port = SocketUtils.findAvailableUdpPort(50000);

0 commit comments

Comments
 (0)