Skip to content

Commit

Permalink
Helper function to bind same random port multiple times in Netty
Browse files Browse the repository at this point in the history
  • Loading branch information
szysas committed Aug 30, 2024
1 parent 7102a2e commit fcc2737
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
import java.net.InetSocketAddress;
import java.time.Duration;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.AfterAll;
Expand All @@ -61,27 +60,14 @@
@EnabledOnOs(OS.LINUX)
public class MultithreadedMbedtlsNettyTest {
private final int threads = 4;
private final int serverPort = new Random().nextInt(32000) + 32000;
private final EventLoopGroup eventLoopGroup = new EpollEventLoopGroup(threads, new DefaultThreadFactory("pool", true));

private final SslConfig clientConf = SslConfig.client(new PskAuth("test", of("secret").getBytes()));
private final SslConfig serverConf = SslConfig.server(new PskAuth("test", of("secret").getBytes()));

private final Bootstrap clientBootstrap = new Bootstrap()
.group(eventLoopGroup)
.localAddress(0)
.channel(EpollDatagramChannel.class)
.handler(new ChannelInitializer<DatagramChannel>() {
@Override
protected void initChannel(DatagramChannel ch) {
InetSocketAddress destinationAddress = localhost(serverPort);
ch.pipeline().addFirst("DTLS", new DtlsClientHandshakeChannelHandler(clientConf.newContext(destinationAddress), destinationAddress, SessionWriter.NO_OPS));
}
});

private final Bootstrap serverBootstrap = new Bootstrap()
.group(eventLoopGroup)
.localAddress(serverPort)
.localAddress(0)
.channel(EpollDatagramChannel.class)
.option(UnixChannelOption.SO_REUSEPORT, true)
.handler(new ChannelInitializer<DatagramChannel>() {
Expand Down Expand Up @@ -120,10 +106,22 @@ void multi_thread_server() throws Exception {
}

private String connectAndReadCurrentThreadName() throws IOException, CoapException {
InetSocketAddress serverAddress = localhost(((InetSocketAddress) serverBootstrap.config().localAddress()).getPort());
Bootstrap clientBootstrap = new Bootstrap()
.group(eventLoopGroup)
.localAddress(0)
.channel(EpollDatagramChannel.class)
.handler(new ChannelInitializer<DatagramChannel>() {
@Override
protected void initChannel(DatagramChannel ch) {
ch.pipeline().addFirst("DTLS", new DtlsClientHandshakeChannelHandler(clientConf.newContext(serverAddress), serverAddress, SessionWriter.NO_OPS));
}
});

CoapClient client = CoapServer.builder()
.executor(eventLoopGroup)
.transport(new NettyCoapTransport(clientBootstrap, EMPTY_RESOLVER))
.buildClient(localhost(serverPort));
.buildClient(serverAddress);

String threadName = client.sendSync(get("/currentThread")).getPayloadString();
client.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.unix.UnixChannelOption;
import java.net.InetSocketAddress;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
Expand All @@ -52,6 +53,19 @@ public NettyCoapTransport(Bootstrap bootstrap, Function<DatagramPacket, Transpor
@Override
public void start() {
init(bootstrap.bind().syncUninterruptibly().channel());

// for random port update bootstrap with actual port but only if SO_REUSEPORT is enabled
if (bindToRandomPort() && reusePortIsEnabled()) {
bootstrap.localAddress(channel.localAddress());
}
}

private Boolean reusePortIsEnabled() {
return (Boolean) bootstrap.config().options().getOrDefault(UnixChannelOption.SO_REUSEPORT, Boolean.FALSE);
}

private boolean bindToRandomPort() {
return ((InetSocketAddress) bootstrap.config().localAddress()).getPort() == 0;
}

void init(Channel channel) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ private Bootstrap createEpollBootstrap() {
return new Bootstrap()
.group(eventLoopGroup)
.option(UnixChannelOption.SO_REUSEPORT, true)
.localAddress(65001) // bind multiple times on single port
.localAddress(0) // bind multiple times on single port
.channel(EpollDatagramChannel.class)
.handler(new ChannelInitializer<DatagramChannel>() {
@Override
Expand Down

0 comments on commit fcc2737

Please sign in to comment.