19
19
20
20
package org .elasticsearch .nio ;
21
21
22
- import org .elasticsearch .common .CheckedRunnable ;
23
-
24
22
import java .io .Closeable ;
25
23
import java .io .IOException ;
26
24
import java .io .UncheckedIOException ;
27
25
import java .net .InetSocketAddress ;
28
- import java .net .SocketException ;
29
26
import java .nio .channels .ServerSocketChannel ;
30
27
import java .nio .channels .SocketChannel ;
31
- import java .security .AccessController ;
32
- import java .security .PrivilegedActionException ;
33
- import java .security .PrivilegedExceptionAction ;
28
+ import java .nio .channels .spi .AbstractSelectableChannel ;
34
29
import java .util .function .Supplier ;
35
30
36
31
public abstract class ChannelFactory <ServerSocket extends NioServerSocketChannel , Socket extends NioSocketChannel > {
37
32
33
+ private final boolean tcpNoDelay ;
34
+ private final boolean tcpKeepAlive ;
35
+ private final boolean tcpReuseAddress ;
36
+ private final int tcpSendBufferSize ;
37
+ private final int tcpReceiveBufferSize ;
38
38
private final ChannelFactory .RawChannelFactory rawChannelFactory ;
39
39
40
+ /**
41
+ * This will create a {@link ChannelFactory}.
42
+ */
43
+ protected ChannelFactory (boolean tcpNoDelay , boolean tcpKeepAlive , boolean tcpReuseAddress , int tcpSendBufferSize ,
44
+ int tcpReceiveBufferSize ) {
45
+ this (tcpNoDelay , tcpKeepAlive , tcpReuseAddress , tcpSendBufferSize , tcpReceiveBufferSize , new RawChannelFactory ());
46
+ }
47
+
40
48
/**
41
49
* This will create a {@link ChannelFactory} using the raw channel factory passed to the constructor.
42
- *
43
- * @param rawChannelFactory a factory that will construct the raw socket channels
44
50
*/
45
- protected ChannelFactory (RawChannelFactory rawChannelFactory ) {
51
+ protected ChannelFactory (boolean tcpNoDelay , boolean tcpKeepAlive , boolean tcpReuseAddress , int tcpSendBufferSize ,
52
+ int tcpReceiveBufferSize , RawChannelFactory rawChannelFactory ) {
53
+ this .tcpNoDelay = tcpNoDelay ;
54
+ this .tcpKeepAlive = tcpKeepAlive ;
55
+ this .tcpReuseAddress = tcpReuseAddress ;
56
+ this .tcpSendBufferSize = tcpSendBufferSize ;
57
+ this .tcpReceiveBufferSize = tcpReceiveBufferSize ;
46
58
this .rawChannelFactory = rawChannelFactory ;
47
59
}
48
60
49
61
public Socket openNioChannel (InetSocketAddress remoteAddress , Supplier <NioSelector > supplier ) throws IOException {
50
- SocketChannel rawChannel = rawChannelFactory .openNioChannel (remoteAddress );
62
+ SocketChannel rawChannel = rawChannelFactory .openNioChannel ();
63
+ setNonBlocking (rawChannel );
51
64
NioSelector selector = supplier .get ();
52
- Socket channel = internalCreateChannel (selector , rawChannel );
65
+ Socket channel = internalCreateChannel (selector , rawChannel , createSocketConfig ( remoteAddress , false ) );
53
66
scheduleChannel (channel , selector );
54
67
return channel ;
55
68
}
56
69
57
- public Socket acceptNioChannel (ServerChannelContext serverContext , Supplier <NioSelector > supplier ) throws IOException {
58
- SocketChannel rawChannel = rawChannelFactory .acceptNioChannel (serverContext );
59
- // Null is returned if there are no pending sockets to accept
60
- if (rawChannel == null ) {
61
- return null ;
62
- } else {
63
- NioSelector selector = supplier .get ();
64
- Socket channel = internalCreateChannel (selector , rawChannel );
65
- scheduleChannel (channel , selector );
66
- return channel ;
67
- }
70
+ public Socket acceptNioChannel (SocketChannel rawChannel , Supplier <NioSelector > supplier ) throws IOException {
71
+ setNonBlocking (rawChannel );
72
+ NioSelector selector = supplier .get ();
73
+ InetSocketAddress remoteAddress = getRemoteAddress (rawChannel );
74
+ Socket channel = internalCreateChannel (selector , rawChannel , createSocketConfig (remoteAddress , true ));
75
+ scheduleChannel (channel , selector );
76
+ return channel ;
68
77
}
69
78
70
- public ServerSocket openNioServerSocketChannel (InetSocketAddress address , Supplier <NioSelector > supplier ) throws IOException {
71
- ServerSocketChannel rawChannel = rawChannelFactory .openNioServerSocketChannel (address );
79
+ public ServerSocket openNioServerSocketChannel (InetSocketAddress localAddress , Supplier <NioSelector > supplier ) throws IOException {
80
+ ServerSocketChannel rawChannel = rawChannelFactory .openNioServerSocketChannel ();
81
+ setNonBlocking (rawChannel );
72
82
NioSelector selector = supplier .get ();
73
- ServerSocket serverChannel = internalCreateServerChannel (selector , rawChannel );
83
+ Config .ServerSocket config = new Config .ServerSocket (tcpReuseAddress , localAddress );
84
+ ServerSocket serverChannel = internalCreateServerChannel (selector , rawChannel , config );
74
85
scheduleServerChannel (serverChannel , selector );
75
86
return serverChannel ;
76
87
}
@@ -80,27 +91,38 @@ public ServerSocket openNioServerSocketChannel(InetSocketAddress address, Suppli
80
91
* returned, the channel should be fully created and setup. Read and write contexts and the channel
81
92
* exception handler should have been set.
82
93
*
83
- * @param selector the channel will be registered with
84
- * @param channel the raw channel
94
+ * @param selector the channel will be registered with
95
+ * @param channel the raw channel
96
+ * @param socketConfig the socket config
85
97
* @return the channel
86
98
* @throws IOException related to the creation of the channel
87
99
*/
88
- public abstract Socket createChannel (NioSelector selector , SocketChannel channel ) throws IOException ;
100
+ public abstract Socket createChannel (NioSelector selector , SocketChannel channel , Config . Socket socketConfig ) throws IOException ;
89
101
90
102
/**
91
103
* This method should return a new {@link NioServerSocketChannel} implementation. When this method has
92
104
* returned, the channel should be fully created and setup.
93
105
*
94
106
* @param selector the channel will be registered with
95
- * @param channel the raw channel
107
+ * @param channel the raw channel
108
+ * @param socketConfig the socket config
96
109
* @return the server channel
97
110
* @throws IOException related to the creation of the channel
98
111
*/
99
- public abstract ServerSocket createServerChannel (NioSelector selector , ServerSocketChannel channel ) throws IOException ;
112
+ public abstract ServerSocket createServerChannel (NioSelector selector , ServerSocketChannel channel , Config .ServerSocket socketConfig )
113
+ throws IOException ;
100
114
101
- private Socket internalCreateChannel (NioSelector selector , SocketChannel rawChannel ) throws IOException {
115
+ protected InetSocketAddress getRemoteAddress (SocketChannel rawChannel ) throws IOException {
116
+ InetSocketAddress remoteAddress = (InetSocketAddress ) rawChannel .socket ().getRemoteSocketAddress ();
117
+ if (remoteAddress == null ) {
118
+ throw new IOException ("Accepted socket does not have remote address" );
119
+ }
120
+ return remoteAddress ;
121
+ }
122
+
123
+ private Socket internalCreateChannel (NioSelector selector , SocketChannel rawChannel , Config .Socket config ) throws IOException {
102
124
try {
103
- Socket channel = createChannel (selector , rawChannel );
125
+ Socket channel = createChannel (selector , rawChannel , config );
104
126
assert channel .getContext () != null : "channel context should have been set on channel" ;
105
127
return channel ;
106
128
} catch (UncheckedIOException e ) {
@@ -114,9 +136,10 @@ private Socket internalCreateChannel(NioSelector selector, SocketChannel rawChan
114
136
}
115
137
}
116
138
117
- private ServerSocket internalCreateServerChannel (NioSelector selector , ServerSocketChannel rawChannel ) throws IOException {
139
+ private ServerSocket internalCreateServerChannel (NioSelector selector , ServerSocketChannel rawChannel , Config .ServerSocket config )
140
+ throws IOException {
118
141
try {
119
- return createServerChannel (selector , rawChannel );
142
+ return createServerChannel (selector , rawChannel , config );
120
143
} catch (Exception e ) {
121
144
closeRawChannel (rawChannel , e );
122
145
throw e ;
@@ -141,6 +164,15 @@ private void scheduleServerChannel(ServerSocket channel, NioSelector selector) {
141
164
}
142
165
}
143
166
167
+ private void setNonBlocking (AbstractSelectableChannel rawChannel ) throws IOException {
168
+ try {
169
+ rawChannel .configureBlocking (false );
170
+ } catch (IOException e ) {
171
+ closeRawChannel (rawChannel , e );
172
+ throw e ;
173
+ }
174
+ }
175
+
144
176
private static void closeRawChannel (Closeable c , Exception e ) {
145
177
try {
146
178
c .close ();
@@ -149,107 +181,19 @@ private static void closeRawChannel(Closeable c, Exception e) {
149
181
}
150
182
}
151
183
152
- public static class RawChannelFactory {
153
-
154
- private final boolean tcpNoDelay ;
155
- private final boolean tcpKeepAlive ;
156
- private final boolean tcpReusedAddress ;
157
- private final int tcpSendBufferSize ;
158
- private final int tcpReceiveBufferSize ;
159
-
160
- public RawChannelFactory (boolean tcpNoDelay , boolean tcpKeepAlive , boolean tcpReusedAddress , int tcpSendBufferSize ,
161
- int tcpReceiveBufferSize ) {
162
- this .tcpNoDelay = tcpNoDelay ;
163
- this .tcpKeepAlive = tcpKeepAlive ;
164
- this .tcpReusedAddress = tcpReusedAddress ;
165
- this .tcpSendBufferSize = tcpSendBufferSize ;
166
- this .tcpReceiveBufferSize = tcpReceiveBufferSize ;
167
- }
168
-
169
- SocketChannel openNioChannel (InetSocketAddress remoteAddress ) throws IOException {
170
- SocketChannel socketChannel = SocketChannel .open ();
171
- try {
172
- configureSocketChannel (socketChannel );
173
- connect (socketChannel , remoteAddress );
174
- } catch (IOException e ) {
175
- closeRawChannel (socketChannel , e );
176
- throw e ;
177
- }
178
- return socketChannel ;
179
- }
180
-
181
- SocketChannel acceptNioChannel (ServerChannelContext serverContext ) throws IOException {
182
- ServerSocketChannel rawChannel = serverContext .getChannel ().getRawChannel ();
183
- assert rawChannel .isBlocking () == false ;
184
- SocketChannel socketChannel = accept (rawChannel );
185
- assert rawChannel .isBlocking () == false ;
186
- if (socketChannel == null ) {
187
- return null ;
188
- }
189
- try {
190
- configureSocketChannel (socketChannel );
191
- } catch (IOException e ) {
192
- closeRawChannel (socketChannel , e );
193
- throw e ;
194
- }
195
- return socketChannel ;
196
- }
197
-
198
- ServerSocketChannel openNioServerSocketChannel (InetSocketAddress address ) throws IOException {
199
- ServerSocketChannel serverSocketChannel = ServerSocketChannel .open ();
200
- serverSocketChannel .configureBlocking (false );
201
- java .net .ServerSocket socket = serverSocketChannel .socket ();
202
- try {
203
- socket .setReuseAddress (tcpReusedAddress );
204
- serverSocketChannel .bind (address );
205
- } catch (IOException e ) {
206
- closeRawChannel (serverSocketChannel , e );
207
- throw e ;
208
- }
209
- return serverSocketChannel ;
210
- }
211
-
212
- private static final boolean MAC_OS_X = System .getProperty ("os.name" ).startsWith ("Mac OS X" );
213
-
214
- private static void setSocketOption (CheckedRunnable <SocketException > runnable ) throws SocketException {
215
- try {
216
- runnable .run ();
217
- } catch (SocketException e ) {
218
- if (MAC_OS_X == false ) {
219
- // ignore on Mac, see https://github.com/elastic/elasticsearch/issues/41071
220
- throw e ;
221
- }
222
- }
223
- }
184
+ private Config .Socket createSocketConfig (InetSocketAddress remoteAddress , boolean isAccepted ) {
185
+ return new Config .Socket (tcpNoDelay , tcpKeepAlive , tcpReuseAddress , tcpSendBufferSize , tcpReceiveBufferSize , remoteAddress ,
186
+ isAccepted );
187
+ }
224
188
225
- private void configureSocketChannel (SocketChannel channel ) throws IOException {
226
- channel .configureBlocking (false );
227
- java .net .Socket socket = channel .socket ();
228
- setSocketOption (() -> socket .setTcpNoDelay (tcpNoDelay ));
229
- setSocketOption (() -> socket .setKeepAlive (tcpKeepAlive ));
230
- setSocketOption (() -> socket .setReuseAddress (tcpReusedAddress ));
231
- if (tcpSendBufferSize > 0 ) {
232
- setSocketOption (() -> socket .setSendBufferSize (tcpSendBufferSize ));
233
- }
234
- if (tcpReceiveBufferSize > 0 ) {
235
- setSocketOption (() -> socket .setSendBufferSize (tcpReceiveBufferSize ));
236
- }
237
- }
189
+ public static class RawChannelFactory {
238
190
239
- public static SocketChannel accept (ServerSocketChannel serverSocketChannel ) throws IOException {
240
- try {
241
- return AccessController .doPrivileged ((PrivilegedExceptionAction <SocketChannel >) serverSocketChannel ::accept );
242
- } catch (PrivilegedActionException e ) {
243
- throw (IOException ) e .getCause ();
244
- }
191
+ SocketChannel openNioChannel () throws IOException {
192
+ return SocketChannel .open ();
245
193
}
246
194
247
- private static void connect (SocketChannel socketChannel , InetSocketAddress remoteAddress ) throws IOException {
248
- try {
249
- AccessController .doPrivileged ((PrivilegedExceptionAction <Boolean >) () -> socketChannel .connect (remoteAddress ));
250
- } catch (PrivilegedActionException e ) {
251
- throw (IOException ) e .getCause ();
252
- }
195
+ ServerSocketChannel openNioServerSocketChannel () throws IOException {
196
+ return ServerSocketChannel .open ();
253
197
}
254
198
}
255
199
}
0 commit comments