Skip to content

Commit

Permalink
Add explicit bind exception (reactor#398)
Browse files Browse the repository at this point in the history
Remove unused code
  • Loading branch information
smaldini authored Jul 24, 2018
1 parent d6074d4 commit e4afa9e
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 38 deletions.
84 changes: 84 additions & 0 deletions src/main/java/reactor/netty/ChannelBindException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright (c) 2011-2018 Pivotal Software Inc, All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package reactor.netty;

import java.net.InetSocketAddress;
import java.util.Objects;

import io.netty.bootstrap.AbstractBootstrap;
import reactor.util.annotation.Nullable;

/**
* Represents a failing attempt to bind a local socket address
*
* @author Stephane Maldini
*/
public class ChannelBindException extends RuntimeException {

/**
* Build a {@link ChannelBindException}
*
* @param bootstrap a netty bootstrap
* @param cause a root cause
*
* @return a new {@link ChannelBindException}
*/
public static ChannelBindException fail(AbstractBootstrap<?, ?> bootstrap, @Nullable Throwable cause) {
Objects.requireNonNull(bootstrap, "bootstrap");
if (cause instanceof java.net.BindException) {
cause = null;
}
if (!(bootstrap.config().localAddress() instanceof InetSocketAddress)) {
return new ChannelBindException(bootstrap.config().localAddress().toString(), -1, cause);
}
InetSocketAddress address = (InetSocketAddress)bootstrap.config().localAddress();

return new ChannelBindException(address.getHostString(), address.getPort(), cause);
}

final String localHost;
final int localPort;

protected ChannelBindException(String localHost, int localPort, @Nullable Throwable cause) {
super("Failed to bind on ["+localHost+":"+localPort+"]", cause);
this.localHost = localHost;
this.localPort = localPort;
}

@Override
public synchronized Throwable fillInStackTrace() {
return this;
}

/**
* Return the configured binding host
*
* @return the configured binding host
*/
public String localHost() {
return localHost;
}

/**
* Return the configured binding port
*
* @return the configured local binding port
*/
public int localPort() {
return localPort;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ final class HttpServerConfiguration {
static final AttributeKey<HttpServerConfiguration> CONF_KEY =
AttributeKey.newInstance("httpServerConf");

static final HttpProtocol[] HTTP11 = {HttpProtocol.HTTP11};

BiPredicate<HttpServerRequest, HttpServerResponse> compressPredicate = null;

int minCompressionSize = -1;
Expand Down
40 changes: 13 additions & 27 deletions src/main/java/reactor/netty/resources/NewConnectionProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@
package reactor.netty.resources;

import java.io.IOException;
import java.net.BindException;
import java.net.SocketAddress;
import java.util.Objects;
import java.util.function.Supplier;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import reactor.core.Disposable;
import reactor.core.publisher.Mono;
import reactor.core.publisher.MonoSink;
import reactor.netty.ChannelBindException;
import reactor.netty.Connection;
import reactor.netty.ConnectionObserver;
import reactor.netty.channel.BootstrapHandlers;
Expand Down Expand Up @@ -70,7 +71,7 @@ public Mono<? extends Connection> acquire(Bootstrap b) {
else {
f = bootstrap.bind();
}
DisposableConnect disposableConnect = new DisposableConnect(sink, f);
DisposableConnect disposableConnect = new DisposableConnect(sink, f, bootstrap);
f.addListener(disposableConnect);
sink.onCancel(disposableConnect);
});
Expand Down Expand Up @@ -103,11 +104,14 @@ static final class DisposableConnect

final MonoSink<Connection> sink;
final ChannelFuture f;
final Bootstrap bootstrap;


DisposableConnect(MonoSink<Connection> sink, ChannelFuture f) {
DisposableConnect(MonoSink<Connection> sink, ChannelFuture f, Bootstrap
bootstrap) {
this.sink = sink;
this.f = f;
this.bootstrap = bootstrap;
}

@Override
Expand Down Expand Up @@ -138,7 +142,12 @@ public final void operationComplete(ChannelFuture f) {
return;
}
if (f.cause() != null) {
sink.error(f.cause());
if (f.cause() instanceof BindException) {
sink.error(ChannelBindException.fail(bootstrap, f.cause()));
}
else {
sink.error(f.cause());
}
}
else {
sink.error(new IOException("error while connecting to " + f.channel()));
Expand All @@ -153,29 +162,6 @@ public final void operationComplete(ChannelFuture f) {
}
}

static final class NewConnection implements Connection {
final Channel channel;

NewConnection(Channel channel) {
this.channel = channel;
}

@Override
public Channel channel() {
return channel;
}

@Override
public boolean isPersistent() {
return false;
}

@Override
public String toString() {
return "NewConnection{" + "channel=" + channel + '}';
}
}


static final class NewConnectionObserver implements ConnectionObserver {

Expand Down
16 changes: 7 additions & 9 deletions src/main/java/reactor/netty/tcp/TcpServerBind.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package reactor.netty.tcp;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Objects;
Expand All @@ -32,6 +31,7 @@
import reactor.core.Disposable;
import reactor.core.publisher.Mono;
import reactor.core.publisher.MonoSink;
import reactor.netty.ChannelBindException;
import reactor.netty.Connection;
import reactor.netty.ConnectionObserver;
import reactor.netty.DisposableServer;
Expand Down Expand Up @@ -83,7 +83,7 @@ public Mono<? extends DisposableServer> bind(ServerBootstrap b) {

ChannelFuture f = bootstrap.bind();

DisposableBind disposableServer = new DisposableBind(sink, f, obs);
DisposableBind disposableServer = new DisposableBind(sink, f, obs, bootstrap);
f.addListener(disposableServer);
sink.onCancel(disposableServer);
});
Expand Down Expand Up @@ -141,11 +141,14 @@ static final class DisposableBind

final MonoSink<DisposableServer> sink;
final ChannelFuture f;
final ServerBootstrap bootstrap;
final ConnectionObserver selectorObserver;

DisposableBind(MonoSink<DisposableServer> sink, ChannelFuture f,
ConnectionObserver selectorObserver) {
ConnectionObserver selectorObserver,
ServerBootstrap bootstrap) {
this.sink = sink;
this.bootstrap = bootstrap;
this.f = f;
this.selectorObserver = selectorObserver;
}
Expand Down Expand Up @@ -179,12 +182,7 @@ public final void operationComplete(ChannelFuture f) {
}
return;
}
if (f.cause() != null) {
sink.error(f.cause());
}
else {
sink.error(new IOException("error while binding to " + f.channel()));
}
sink.error(ChannelBindException.fail(bootstrap, f.cause()));
}
else {
if (log.isDebugEnabled()) {
Expand Down
20 changes: 20 additions & 0 deletions src/test/java/reactor/netty/http/server/HttpServerTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.netty.ByteBufFlux;
import reactor.netty.ChannelBindException;
import reactor.netty.Connection;
import reactor.netty.DisposableServer;
import reactor.netty.FutureMono;
Expand Down Expand Up @@ -779,6 +780,25 @@ public void testIssue309() {
.httpRequestDecoder(c -> c.maxInitialLineLength(20)));
}

@Test
public void portBindingException() {
DisposableServer d = HttpServer.create()
.port(0)
.bindNow();

try {
HttpServer.create()
.port(d.port())
.bindNow();
Assert.fail("illegal-success");
}
catch (ChannelBindException e){
Assert.assertEquals(e.localPort(), d.port());
e.printStackTrace();
}
d.dispose();
}

private void doTestIssue309(String path, HttpServer httpServer) {
DisposableServer server =
httpServer.handle((req, res) -> res.sendString(Mono.just("Should not be reached")))
Expand Down

0 comments on commit e4afa9e

Please sign in to comment.