Skip to content

Commit 86423f9

Browse files
authored
Ensure local addresses aren't null (#31440)
Currently we set local addresses on the creation time of a NioChannel. However, this may return null as the local address may not have been set yet. An example is the local address has not been set on a client channel as the connection process is not yet complete. This PR modifies the getter to set the local field if it is currently null.
1 parent 00283a6 commit 86423f9

File tree

9 files changed

+54
-33
lines changed

9 files changed

+54
-33
lines changed

libs/nio/src/main/java/org/elasticsearch/nio/ChannelFactory.java

+6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import java.io.Closeable;
2323
import java.io.IOException;
24+
import java.io.UncheckedIOException;
2425
import java.net.InetSocketAddress;
2526
import java.nio.channels.ServerSocketChannel;
2627
import java.nio.channels.SocketChannel;
@@ -99,6 +100,11 @@ private Socket internalCreateChannel(NioSelector selector, SocketChannel rawChan
99100
Socket channel = createChannel(selector, rawChannel);
100101
assert channel.getContext() != null : "channel context should have been set on channel";
101102
return channel;
103+
} catch (UncheckedIOException e) {
104+
// This can happen if getRemoteAddress throws IOException.
105+
IOException cause = e.getCause();
106+
closeRawChannel(rawChannel, cause);
107+
throw cause;
102108
} catch (Exception e) {
103109
closeRawChannel(rawChannel, e);
104110
throw e;

libs/nio/src/main/java/org/elasticsearch/nio/NioChannel.java

+2-11
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
package org.elasticsearch.nio;
2121

22-
import java.io.IOException;
2322
import java.net.InetSocketAddress;
2423
import java.nio.channels.NetworkChannel;
2524
import java.util.function.BiConsumer;
@@ -32,20 +31,10 @@
3231
*/
3332
public abstract class NioChannel {
3433

35-
private final InetSocketAddress localAddress;
36-
37-
NioChannel(NetworkChannel socketChannel) throws IOException {
38-
this.localAddress = (InetSocketAddress) socketChannel.getLocalAddress();
39-
}
40-
4134
public boolean isOpen() {
4235
return getContext().isOpen();
4336
}
4437

45-
public InetSocketAddress getLocalAddress() {
46-
return localAddress;
47-
}
48-
4938
/**
5039
* Adds a close listener to the channel. Multiple close listeners can be added. There is no guarantee
5140
* about the order in which close listeners will be executed. If the channel is already closed, the
@@ -64,6 +53,8 @@ public void close() {
6453
getContext().closeChannel();
6554
}
6655

56+
public abstract InetSocketAddress getLocalAddress();
57+
6758
public abstract NetworkChannel getRawChannel();
6859

6960
public abstract ChannelContext<?> getContext();

libs/nio/src/main/java/org/elasticsearch/nio/NioServerSocketChannel.java

+19-6
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,20 @@
1919

2020
package org.elasticsearch.nio;
2121

22-
import java.io.IOException;
22+
import java.net.InetSocketAddress;
2323
import java.nio.channels.ServerSocketChannel;
2424
import java.util.concurrent.atomic.AtomicBoolean;
2525

2626
public class NioServerSocketChannel extends NioChannel {
2727

28-
private final ServerSocketChannel socketChannel;
28+
private final ServerSocketChannel serverSocketChannel;
2929
private final AtomicBoolean contextSet = new AtomicBoolean(false);
30+
private volatile InetSocketAddress localAddress;
3031
private ServerChannelContext context;
3132

32-
public NioServerSocketChannel(ServerSocketChannel socketChannel) throws IOException {
33-
super(socketChannel);
34-
this.socketChannel = socketChannel;
33+
public NioServerSocketChannel(ServerSocketChannel serverSocketChannel) {
34+
this.serverSocketChannel = serverSocketChannel;
35+
attemptToSetLocalAddress();
3536
}
3637

3738
/**
@@ -48,9 +49,15 @@ public void setContext(ServerChannelContext context) {
4849
}
4950
}
5051

52+
@Override
53+
public InetSocketAddress getLocalAddress() {
54+
attemptToSetLocalAddress();
55+
return localAddress;
56+
}
57+
5158
@Override
5259
public ServerSocketChannel getRawChannel() {
53-
return socketChannel;
60+
return serverSocketChannel;
5461
}
5562

5663
@Override
@@ -64,4 +71,10 @@ public String toString() {
6471
"localAddress=" + getLocalAddress() +
6572
'}';
6673
}
74+
75+
private void attemptToSetLocalAddress() {
76+
if (localAddress == null) {
77+
localAddress = (InetSocketAddress) serverSocketChannel.socket().getLocalSocketAddress();
78+
}
79+
}
6780
}

libs/nio/src/main/java/org/elasticsearch/nio/NioSocketChannel.java

+17-4
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,27 @@
2020
package org.elasticsearch.nio;
2121

2222
import java.io.IOException;
23+
import java.io.UncheckedIOException;
2324
import java.net.InetSocketAddress;
2425
import java.nio.channels.SocketChannel;
2526
import java.util.concurrent.atomic.AtomicBoolean;
2627
import java.util.function.BiConsumer;
2728

2829
public class NioSocketChannel extends NioChannel {
2930

30-
private final InetSocketAddress remoteAddress;
3131
private final AtomicBoolean contextSet = new AtomicBoolean(false);
3232
private final SocketChannel socketChannel;
33+
private final InetSocketAddress remoteAddress;
34+
private volatile InetSocketAddress localAddress;
3335
private SocketChannelContext context;
3436

35-
public NioSocketChannel(SocketChannel socketChannel) throws IOException {
36-
super(socketChannel);
37+
public NioSocketChannel(SocketChannel socketChannel) {
3738
this.socketChannel = socketChannel;
38-
this.remoteAddress = (InetSocketAddress) socketChannel.getRemoteAddress();
39+
try {
40+
this.remoteAddress = (InetSocketAddress) socketChannel.getRemoteAddress();
41+
} catch (IOException e) {
42+
throw new UncheckedIOException(e);
43+
}
3944
}
4045

4146
public void setContext(SocketChannelContext context) {
@@ -46,6 +51,14 @@ public void setContext(SocketChannelContext context) {
4651
}
4752
}
4853

54+
@Override
55+
public InetSocketAddress getLocalAddress() {
56+
if (localAddress == null) {
57+
localAddress = (InetSocketAddress) socketChannel.socket().getLocalSocketAddress();
58+
}
59+
return localAddress;
60+
}
61+
4962
@Override
5063
public SocketChannel getRawChannel() {
5164
return socketChannel;

libs/nio/src/test/java/org/elasticsearch/nio/EventHandlerTests.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.junit.Before;
2424

2525
import java.io.IOException;
26+
import java.net.ServerSocket;
2627
import java.nio.channels.CancelledKeyException;
2728
import java.nio.channels.SelectionKey;
2829
import java.nio.channels.ServerSocketChannel;
@@ -69,7 +70,9 @@ public void setUpHandler() throws IOException {
6970
channel.setContext(context);
7071
handler.handleRegistration(context);
7172

72-
NioServerSocketChannel serverChannel = new NioServerSocketChannel(mock(ServerSocketChannel.class));
73+
ServerSocketChannel serverSocketChannel = mock(ServerSocketChannel.class);
74+
when(serverSocketChannel.socket()).thenReturn(mock(ServerSocket.class));
75+
NioServerSocketChannel serverChannel = new NioServerSocketChannel(serverSocketChannel);
7376
serverContext = new DoNotRegisterServerContext(serverChannel, mock(NioSelector.class), mock(Consumer.class));
7477
serverChannel.setContext(serverContext);
7578

plugins/transport-nio/src/main/java/org/elasticsearch/http/nio/NioHttpChannel.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,11 @@
2424
import org.elasticsearch.http.HttpResponse;
2525
import org.elasticsearch.nio.NioSocketChannel;
2626

27-
import java.io.IOException;
2827
import java.nio.channels.SocketChannel;
2928

3029
public class NioHttpChannel extends NioSocketChannel implements HttpChannel {
3130

32-
NioHttpChannel(SocketChannel socketChannel) throws IOException {
31+
NioHttpChannel(SocketChannel socketChannel) {
3332
super(socketChannel);
3433
}
3534

plugins/transport-nio/src/main/java/org/elasticsearch/transport/nio/NioTcpChannel.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public class NioTcpChannel extends NioSocketChannel implements TcpChannel {
3232

3333
private final String profile;
3434

35-
public NioTcpChannel(String profile, SocketChannel socketChannel) throws IOException {
35+
public NioTcpChannel(String profile, SocketChannel socketChannel) {
3636
super(socketChannel);
3737
this.profile = profile;
3838
}

plugins/transport-nio/src/main/java/org/elasticsearch/transport/nio/NioTcpServerChannel.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import org.elasticsearch.nio.NioServerSocketChannel;
2424
import org.elasticsearch.transport.TcpServerChannel;
2525

26-
import java.io.IOException;
2726
import java.nio.channels.ServerSocketChannel;
2827

2928
/**
@@ -34,12 +33,11 @@ public class NioTcpServerChannel extends NioServerSocketChannel implements TcpSe
3433

3534
private final String profile;
3635

37-
public NioTcpServerChannel(String profile, ServerSocketChannel socketChannel) throws IOException {
36+
public NioTcpServerChannel(String profile, ServerSocketChannel socketChannel) {
3837
super(socketChannel);
3938
this.profile = profile;
4039
}
4140

42-
@Override
4341
public void close() {
4442
getContext().closeChannel();
4543
}

test/framework/src/main/java/org/elasticsearch/transport/nio/MockNioTransport.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ public MockSocketChannel createChannel(NioSelector selector, SocketChannel chann
165165

166166
@Override
167167
public MockServerChannel createServerChannel(NioSelector selector, ServerSocketChannel channel) throws IOException {
168-
MockServerChannel nioServerChannel = new MockServerChannel(profileName, channel, this, selector);
168+
MockServerChannel nioServerChannel = new MockServerChannel(profileName, channel);
169169
Consumer<Exception> exceptionHandler = (e) -> logger.error(() ->
170170
new ParameterizedMessage("exception from server channel caught on transport layer [{}]", channel), e);
171171
ServerChannelContext context = new ServerChannelContext(nioServerChannel, this, selector, MockNioTransport.this::acceptChannel,
@@ -196,8 +196,7 @@ private static class MockServerChannel extends NioServerSocketChannel implements
196196

197197
private final String profile;
198198

199-
MockServerChannel(String profile, ServerSocketChannel channel, ChannelFactory<?, ?> channelFactory, NioSelector selector)
200-
throws IOException {
199+
MockServerChannel(String profile, ServerSocketChannel channel) {
201200
super(channel);
202201
this.profile = profile;
203202
}
@@ -222,8 +221,7 @@ private static class MockSocketChannel extends NioSocketChannel implements TcpCh
222221

223222
private final String profile;
224223

225-
private MockSocketChannel(String profile, java.nio.channels.SocketChannel socketChannel, NioSelector selector)
226-
throws IOException {
224+
private MockSocketChannel(String profile, java.nio.channels.SocketChannel socketChannel, NioSelector selector) {
227225
super(socketChannel);
228226
this.profile = profile;
229227
}

0 commit comments

Comments
 (0)