diff --git a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/NettyWebServer.java b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/NettyWebServer.java index 1d0c48deac8..1cf5a31b64d 100644 --- a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/NettyWebServer.java +++ b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/NettyWebServer.java @@ -65,6 +65,11 @@ public class NettyWebServer implements WebServer { */ private static final int ERROR_NO_EACCES = -13; + /** + * Address in use error code from {@code errno.h}. + */ + private static final int ERROR_ADDR_IN_USE = -98; + private static final Predicate ALWAYS = (request) -> true; private static final Log logger = LogFactory.getLog(NettyWebServer.class); @@ -119,11 +124,19 @@ public class NettyWebServer implements WebServer { this.disposableServer = disposableServer; } catch (Exception ex) { - PortInUseException.ifCausedBy(ex, ChannelBindException.class, (bindException) -> { - if (bindException.localPort() > 0 && !isPermissionDenied(bindException.getCause())) { - throw new PortInUseException(bindException.localPort(), ex); + PortInUseException.ifCausedBy(ex, ChannelBindException.class, (channelBindException) -> { + if (channelBindException.localPort() > 0 && !isPermissionDenied(channelBindException.getCause())) { + PortInUseException.throwIfPortBindingException(channelBindException, + channelBindException::localPort); } }); + if (ex instanceof ChannelBindException channelBindException) { + PortInUseException.ifCausedBy(ex, NativeIoException.class, (nativeIoException) -> { + if (nativeIoException.expectedErr() == ERROR_ADDR_IN_USE) { + throw new PortInUseException(channelBindException.localPort(), ex); + } + }); + } throw new WebServerException("Unable to start Netty", ex); } logger.info(getStartedOnMessage(disposableServer)); diff --git a/module/spring-boot-reactor-netty/src/test/java/org/springframework/boot/reactor/netty/NettyReactiveWebServerFactoryTests.java b/module/spring-boot-reactor-netty/src/test/java/org/springframework/boot/reactor/netty/NettyReactiveWebServerFactoryTests.java index cc93043de27..35a820ffcbc 100644 --- a/module/spring-boot-reactor-netty/src/test/java/org/springframework/boot/reactor/netty/NettyReactiveWebServerFactoryTests.java +++ b/module/spring-boot-reactor-netty/src/test/java/org/springframework/boot/reactor/netty/NettyReactiveWebServerFactoryTests.java @@ -17,7 +17,9 @@ package org.springframework.boot.reactor.netty; import java.net.ConnectException; +import java.net.InetAddress; import java.net.SocketAddress; +import java.net.UnknownHostException; import java.time.Duration; import java.util.Arrays; @@ -44,6 +46,7 @@ import org.springframework.boot.testsupport.classpath.resources.WithPackageResou import org.springframework.boot.web.server.PortInUseException; import org.springframework.boot.web.server.Shutdown; import org.springframework.boot.web.server.Ssl; +import org.springframework.boot.web.server.WebServerException; import org.springframework.boot.web.server.reactive.AbstractReactiveWebServerFactory; import org.springframework.boot.web.server.reactive.AbstractReactiveWebServerFactoryTests; import org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory; @@ -72,7 +75,7 @@ import static org.mockito.Mockito.mock; class NettyReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactoryTests { @Test - void exceptionIsThrownWhenPortIsAlreadyInUse() { + void portInUseExceptionIsThrownWhenPortIsAlreadyInUse() { AbstractReactiveWebServerFactory factory = getFactory(); factory.setPort(0); this.webServer = factory.getWebServer(new EchoHandler()); @@ -83,6 +86,14 @@ class NettyReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactor .withCauseInstanceOf(Throwable.class); } + @Test + void webServerExceptionIsThrownWhenAddressCannotBeAssigned() throws UnknownHostException { + AbstractReactiveWebServerFactory factory = getFactory(); + factory.setPort(8080); + factory.setAddress(InetAddress.getByName("1.2.3.4")); + assertThatExceptionOfType(WebServerException.class).isThrownBy(factory.getWebServer(new EchoHandler())::start); + } + @Test void getPortWhenDisposableServerPortOperationIsUnsupportedReturnsMinusOne() { NettyReactiveWebServerFactory factory = new NoPortNettyReactiveWebServerFactory(0);