33
33
import io .grpc .Status ;
34
34
import io .grpc .internal .GrpcAttributes ;
35
35
import io .grpc .internal .GrpcUtil ;
36
+ import io .grpc .internal .ObjectPool ;
36
37
import io .netty .channel .ChannelDuplexHandler ;
37
38
import io .netty .channel .ChannelFutureListener ;
38
39
import io .netty .channel .ChannelHandler ;
58
59
import java .net .SocketAddress ;
59
60
import java .net .URI ;
60
61
import java .util .Arrays ;
62
+ import java .util .concurrent .Executor ;
61
63
import java .util .logging .Level ;
62
64
import java .util .logging .Logger ;
63
65
import javax .annotation .Nullable ;
@@ -106,20 +108,35 @@ public static ProtocolNegotiator serverPlaintext() {
106
108
107
109
/**
108
110
* Create a server TLS handler for HTTP/2 capable of using ALPN/NPN.
111
+ * @param executorPool a dedicated {@link Executor} pool for time-consuming TLS tasks
109
112
*/
110
- public static ProtocolNegotiator serverTls (final SslContext sslContext ) {
113
+ public static ProtocolNegotiator serverTls (final SslContext sslContext ,
114
+ final ObjectPool <? extends Executor > executorPool ) {
111
115
Preconditions .checkNotNull (sslContext , "sslContext" );
116
+ final Executor executor ;
117
+ if (executorPool != null ) {
118
+ // The handlers here can out-live the {@link ProtocolNegotiator}.
119
+ // To keep their own reference to executor from executorPool, we use an extra (unused)
120
+ // reference here forces the executor to stay alive, which prevents it from being re-created
121
+ // for every connection.
122
+ executor = executorPool .getObject ();
123
+ } else {
124
+ executor = null ;
125
+ }
112
126
return new ProtocolNegotiator () {
113
127
@ Override
114
128
public ChannelHandler newHandler (GrpcHttp2ConnectionHandler handler ) {
115
129
ChannelHandler gnh = new GrpcNegotiationHandler (handler );
116
- ChannelHandler sth = new ServerTlsHandler (gnh , sslContext );
130
+ ChannelHandler sth = new ServerTlsHandler (gnh , sslContext , executorPool );
117
131
return new WaitUntilActiveHandler (sth );
118
132
}
119
133
120
134
@ Override
121
- public void close () {}
122
-
135
+ public void close () {
136
+ if (executorPool != null && executor != null ) {
137
+ executorPool .returnObject (executor );
138
+ }
139
+ }
123
140
124
141
@ Override
125
142
public AsciiString scheme () {
@@ -128,22 +145,37 @@ public AsciiString scheme() {
128
145
};
129
146
}
130
147
148
+ /**
149
+ * Create a server TLS handler for HTTP/2 capable of using ALPN/NPN.
150
+ */
151
+ public static ProtocolNegotiator serverTls (final SslContext sslContext ) {
152
+ return serverTls (sslContext , null );
153
+ }
154
+
131
155
static final class ServerTlsHandler extends ChannelInboundHandlerAdapter {
156
+ private Executor executor ;
132
157
private final ChannelHandler next ;
133
158
private final SslContext sslContext ;
134
159
135
160
private ProtocolNegotiationEvent pne = ProtocolNegotiationEvent .DEFAULT ;
136
161
137
- ServerTlsHandler (ChannelHandler next , SslContext sslContext ) {
162
+ ServerTlsHandler (ChannelHandler next ,
163
+ SslContext sslContext ,
164
+ final ObjectPool <? extends Executor > executorPool ) {
138
165
this .sslContext = checkNotNull (sslContext , "sslContext" );
139
166
this .next = checkNotNull (next , "next" );
167
+ if (executorPool != null ) {
168
+ this .executor = executorPool .getObject ();
169
+ }
140
170
}
141
171
142
172
@ Override
143
173
public void handlerAdded (ChannelHandlerContext ctx ) throws Exception {
144
174
super .handlerAdded (ctx );
145
175
SSLEngine sslEngine = sslContext .newEngine (ctx .alloc ());
146
- ctx .pipeline ().addBefore (ctx .name (), null , new SslHandler (sslEngine , false ));
176
+ ctx .pipeline ().addBefore (ctx .name (), /* name= */ null , this .executor != null
177
+ ? new SslHandler (sslEngine , false , this .executor )
178
+ : new SslHandler (sslEngine , false ));
147
179
}
148
180
149
181
@ Override
@@ -259,11 +291,18 @@ protected void userEventTriggered0(ChannelHandlerContext ctx, Object evt) throws
259
291
260
292
static final class ClientTlsProtocolNegotiator implements ProtocolNegotiator {
261
293
262
- public ClientTlsProtocolNegotiator (SslContext sslContext ) {
294
+ public ClientTlsProtocolNegotiator (SslContext sslContext ,
295
+ ObjectPool <? extends Executor > executorPool ) {
263
296
this .sslContext = checkNotNull (sslContext , "sslContext" );
297
+ this .executorPool = executorPool ;
298
+ if (this .executorPool != null ) {
299
+ this .executor = this .executorPool .getObject ();
300
+ }
264
301
}
265
302
266
303
private final SslContext sslContext ;
304
+ private final ObjectPool <? extends Executor > executorPool ;
305
+ private Executor executor ;
267
306
268
307
@ Override
269
308
public AsciiString scheme () {
@@ -273,26 +312,34 @@ public AsciiString scheme() {
273
312
@ Override
274
313
public ChannelHandler newHandler (GrpcHttp2ConnectionHandler grpcHandler ) {
275
314
ChannelHandler gnh = new GrpcNegotiationHandler (grpcHandler );
276
- ChannelHandler cth = new ClientTlsHandler (gnh , sslContext , grpcHandler .getAuthority ());
315
+ ChannelHandler cth = new ClientTlsHandler (gnh , sslContext , grpcHandler .getAuthority (),
316
+ this .executor );
277
317
return new WaitUntilActiveHandler (cth );
278
318
}
279
319
280
320
@ Override
281
- public void close () {}
321
+ public void close () {
322
+ if (this .executorPool != null && this .executor != null ) {
323
+ this .executorPool .returnObject (this .executor );
324
+ }
325
+ }
282
326
}
283
327
284
328
static final class ClientTlsHandler extends ProtocolNegotiationHandler {
285
329
286
330
private final SslContext sslContext ;
287
331
private final String host ;
288
332
private final int port ;
333
+ private Executor executor ;
289
334
290
- ClientTlsHandler (ChannelHandler next , SslContext sslContext , String authority ) {
335
+ ClientTlsHandler (ChannelHandler next , SslContext sslContext , String authority ,
336
+ Executor executor ) {
291
337
super (next );
292
338
this .sslContext = checkNotNull (sslContext , "sslContext" );
293
339
HostPort hostPort = parseAuthority (authority );
294
340
this .host = hostPort .host ;
295
341
this .port = hostPort .port ;
342
+ this .executor = executor ;
296
343
}
297
344
298
345
@ Override
@@ -301,7 +348,9 @@ protected void handlerAdded0(ChannelHandlerContext ctx) {
301
348
SSLParameters sslParams = sslEngine .getSSLParameters ();
302
349
sslParams .setEndpointIdentificationAlgorithm ("HTTPS" );
303
350
sslEngine .setSSLParameters (sslParams );
304
- ctx .pipeline ().addBefore (ctx .name (), /* name= */ null , new SslHandler (sslEngine , false ));
351
+ ctx .pipeline ().addBefore (ctx .name (), /* name= */ null , this .executor != null
352
+ ? new SslHandler (sslEngine , false , this .executor )
353
+ : new SslHandler (sslEngine , false ));
305
354
}
306
355
307
356
@ Override
@@ -363,13 +412,24 @@ static HostPort parseAuthority(String authority) {
363
412
return new HostPort (host , port );
364
413
}
365
414
415
+ /**
416
+ * Returns a {@link ProtocolNegotiator} that ensures the pipeline is set up so that TLS will
417
+ * be negotiated, the {@code handler} is added and writes to the {@link io.netty.channel.Channel}
418
+ * may happen immediately, even before the TLS Handshake is complete.
419
+ * @param executorPool a dedicated {@link Executor} pool for time-consuming TLS tasks
420
+ */
421
+ public static ProtocolNegotiator tls (SslContext sslContext ,
422
+ ObjectPool <? extends Executor > executorPool ) {
423
+ return new ClientTlsProtocolNegotiator (sslContext , executorPool );
424
+ }
425
+
366
426
/**
367
427
* Returns a {@link ProtocolNegotiator} that ensures the pipeline is set up so that TLS will
368
428
* be negotiated, the {@code handler} is added and writes to the {@link io.netty.channel.Channel}
369
429
* may happen immediately, even before the TLS Handshake is complete.
370
430
*/
371
431
public static ProtocolNegotiator tls (SslContext sslContext ) {
372
- return new ClientTlsProtocolNegotiator (sslContext );
432
+ return tls (sslContext , null );
373
433
}
374
434
375
435
/** A tuple of (host, port). */
0 commit comments