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
This commit is contained in:
Gary Russell
2015-08-05 12:35:55 -04:00
committed by Sam Brannen
parent e0f012f32d
commit f15140415a
2 changed files with 38 additions and 4 deletions

View File

@@ -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 @@
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.*;
* Unit tests for {@link SocketUtils}.
*
* @author Sam Brannen
* @author Gary Russell
*/
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 {
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);