• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #19504

10 Oct 2024 11:31PM UTC coverage: 84.654% (-0.01%) from 84.668%
#19504

push

github

web-flow
s2a: Add S2AStub cleanup handler. (#11600)

* Add S2AStub cleanup handler.

* Give TLS and Cleanup handlers name + update comment.

* Don't add TLS handler twice.

* Don't remove explicitly, since done by fireProtocolNegotiationEvent.

* plumb S2AStub close to handshake end + add integration test.

* close stub when TLS negotiation fails.

33781 of 39905 relevant lines covered (84.65%)

0.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.0
/../netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java
1
/*
2
 * Copyright 2014 The gRPC Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package io.grpc.netty;
18

19
import static com.google.common.base.Preconditions.checkArgument;
20
import static com.google.common.base.Preconditions.checkNotNull;
21
import static com.google.common.base.Preconditions.checkState;
22
import static io.grpc.internal.GrpcUtil.DEFAULT_KEEPALIVE_TIMEOUT_NANOS;
23
import static io.grpc.internal.GrpcUtil.KEEPALIVE_TIME_NANOS_DISABLED;
24

25
import com.google.common.annotations.VisibleForTesting;
26
import com.google.common.base.Ticker;
27
import com.google.errorprone.annotations.CanIgnoreReturnValue;
28
import com.google.errorprone.annotations.CheckReturnValue;
29
import com.google.errorprone.annotations.InlineMe;
30
import io.grpc.Attributes;
31
import io.grpc.CallCredentials;
32
import io.grpc.ChannelCredentials;
33
import io.grpc.ChannelLogger;
34
import io.grpc.EquivalentAddressGroup;
35
import io.grpc.ExperimentalApi;
36
import io.grpc.ForwardingChannelBuilder2;
37
import io.grpc.HttpConnectProxiedSocketAddress;
38
import io.grpc.Internal;
39
import io.grpc.ManagedChannelBuilder;
40
import io.grpc.internal.AtomicBackoff;
41
import io.grpc.internal.ClientTransportFactory;
42
import io.grpc.internal.ConnectionClientTransport;
43
import io.grpc.internal.FixedObjectPool;
44
import io.grpc.internal.GrpcUtil;
45
import io.grpc.internal.KeepAliveManager;
46
import io.grpc.internal.ManagedChannelImplBuilder;
47
import io.grpc.internal.ManagedChannelImplBuilder.ChannelBuilderDefaultPortProvider;
48
import io.grpc.internal.ManagedChannelImplBuilder.ClientTransportFactoryBuilder;
49
import io.grpc.internal.ObjectPool;
50
import io.grpc.internal.SharedResourcePool;
51
import io.grpc.internal.TransportTracer;
52
import io.grpc.netty.ProtocolNegotiators.FromChannelCredentialsResult;
53
import io.netty.channel.Channel;
54
import io.netty.channel.ChannelFactory;
55
import io.netty.channel.ChannelOption;
56
import io.netty.channel.EventLoopGroup;
57
import io.netty.channel.ReflectiveChannelFactory;
58
import io.netty.channel.socket.nio.NioSocketChannel;
59
import io.netty.handler.ssl.SslContext;
60
import java.net.InetSocketAddress;
61
import java.net.SocketAddress;
62
import java.util.Collection;
63
import java.util.Collections;
64
import java.util.HashMap;
65
import java.util.Map;
66
import java.util.Optional;
67
import java.util.concurrent.Executor;
68
import java.util.concurrent.ScheduledExecutorService;
69
import java.util.concurrent.TimeUnit;
70
import javax.annotation.Nullable;
71
import javax.net.ssl.SSLException;
72

73
/**
74
 * A builder to help simplify construction of channels using the Netty transport.
75
 */
76
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1784")
77
@CheckReturnValue
78
public final class NettyChannelBuilder extends ForwardingChannelBuilder2<NettyChannelBuilder> {
79

80
  // 1MiB.
81
  public static final int DEFAULT_FLOW_CONTROL_WINDOW = 1024 * 1024;
82
  private static final boolean DEFAULT_AUTO_FLOW_CONTROL;
83

84
  private static final long AS_LARGE_AS_INFINITE = TimeUnit.DAYS.toNanos(1000L);
1✔
85

86
  private static final ChannelFactory<? extends Channel> DEFAULT_CHANNEL_FACTORY =
1✔
87
      new ReflectiveChannelFactory<>(Utils.DEFAULT_CLIENT_CHANNEL_TYPE);
88
  private static final ObjectPool<? extends EventLoopGroup> DEFAULT_EVENT_LOOP_GROUP_POOL =
1✔
89
      SharedResourcePool.forResource(Utils.DEFAULT_WORKER_EVENT_LOOP_GROUP);
1✔
90

91
  static {
92
    String autoFlowControl = System.getenv("GRPC_EXPERIMENTAL_AUTOFLOWCONTROL");
1✔
93
    if (autoFlowControl == null) {
1✔
94
      autoFlowControl = "true";
1✔
95
    }
96
    DEFAULT_AUTO_FLOW_CONTROL = Boolean.parseBoolean(autoFlowControl);
1✔
97
  }
1✔
98

99
  private final ManagedChannelImplBuilder managedChannelImplBuilder;
100
  private TransportTracer.Factory transportTracerFactory = TransportTracer.getDefaultFactory();
1✔
101
  private final Map<ChannelOption<?>, Object> channelOptions = new HashMap<>();
1✔
102
  private ChannelFactory<? extends Channel> channelFactory = DEFAULT_CHANNEL_FACTORY;
1✔
103
  private ObjectPool<? extends EventLoopGroup> eventLoopGroupPool = DEFAULT_EVENT_LOOP_GROUP_POOL;
1✔
104
  private boolean autoFlowControl = DEFAULT_AUTO_FLOW_CONTROL;
1✔
105
  private int flowControlWindow = DEFAULT_FLOW_CONTROL_WINDOW;
1✔
106
  private int maxHeaderListSize = GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE;
1✔
107
  private int maxInboundMessageSize = GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE;
1✔
108
  private long keepAliveTimeNanos = KEEPALIVE_TIME_NANOS_DISABLED;
1✔
109
  private long keepAliveTimeoutNanos = DEFAULT_KEEPALIVE_TIMEOUT_NANOS;
1✔
110
  private boolean keepAliveWithoutCalls;
111
  private ProtocolNegotiator.ClientFactory protocolNegotiatorFactory
1✔
112
      = new DefaultProtocolNegotiator();
113
  private final boolean freezeProtocolNegotiatorFactory;
114
  private LocalSocketPicker localSocketPicker;
115

116
  /**
117
   * If true, indicates that the transport may use the GET method for RPCs, and may include the
118
   * request body in the query params.
119
   */
120
  private final boolean useGetForSafeMethods = false;
1✔
121

122
  private Class<? extends SocketAddress> transportSocketType = InetSocketAddress.class;
1✔
123

124
  /**
125
   * Creates a new builder with the given server address. This factory method is primarily intended
126
   * for using Netty Channel types other than SocketChannel. {@link #forAddress(String, int)} should
127
   * generally be preferred over this method, since that API permits delaying DNS lookups and
128
   * noticing changes to DNS. If an unresolved InetSocketAddress is passed in, then it will remain
129
   * unresolved.
130
   */
131
  public static NettyChannelBuilder forAddress(SocketAddress serverAddress) {
132
    return new NettyChannelBuilder(serverAddress);
1✔
133
  }
134

135
  /**
136
   * Creates a new builder with the given server address. This factory method is primarily intended
137
   * for using Netty Channel types other than SocketChannel.
138
   * {@link #forAddress(String, int, ChannelCredentials)} should generally be preferred over this
139
   * method, since that API permits delaying DNS lookups and noticing changes to DNS. If an
140
   * unresolved InetSocketAddress is passed in, then it will remain unresolved.
141
   */
142
  public static NettyChannelBuilder forAddress(SocketAddress serverAddress,
143
      ChannelCredentials creds) {
144
    FromChannelCredentialsResult result = ProtocolNegotiators.from(creds);
1✔
145
    if (result.error != null) {
1✔
146
      throw new IllegalArgumentException(result.error);
×
147
    }
148
    return new NettyChannelBuilder(serverAddress, creds, result.callCredentials, result.negotiator);
1✔
149
  }
150

151
  /**
152
   * Creates a new builder with the given host and port.
153
   */
154
  public static NettyChannelBuilder forAddress(String host, int port) {
155
    return forTarget(GrpcUtil.authorityFromHostAndPort(host, port));
1✔
156
  }
157

158
  /**
159
   * Creates a new builder with the given host and port.
160
   */
161
  public static NettyChannelBuilder forAddress(String host, int port, ChannelCredentials creds) {
162
    return forTarget(GrpcUtil.authorityFromHostAndPort(host, port), creds);
1✔
163
  }
164

165
  /**
166
   * Creates a new builder with the given target string that will be resolved by
167
   * {@link io.grpc.NameResolver}.
168
   */
169
  public static NettyChannelBuilder forTarget(String target) {
170
    return new NettyChannelBuilder(target);
1✔
171
  }
172

173
  /**
174
   * Creates a new builder with the given target string that will be resolved by
175
   * {@link io.grpc.NameResolver}.
176
   */
177
  public static NettyChannelBuilder forTarget(String target, ChannelCredentials creds) {
178
    FromChannelCredentialsResult result = ProtocolNegotiators.from(creds);
1✔
179
    if (result.error != null) {
1✔
180
      throw new IllegalArgumentException(result.error);
×
181
    }
182
    return new NettyChannelBuilder(target, creds, result.callCredentials, result.negotiator);
1✔
183
  }
184

185
  private final class NettyChannelTransportFactoryBuilder implements ClientTransportFactoryBuilder {
1✔
186
    @Override
187
    public ClientTransportFactory buildClientTransportFactory() {
188
      return buildTransportFactory();
1✔
189
    }
190
  }
191

192
  private final class NettyChannelDefaultPortProvider implements ChannelBuilderDefaultPortProvider {
1✔
193
    @Override
194
    public int getDefaultPort() {
195
      return protocolNegotiatorFactory.getDefaultPort();
1✔
196
    }
197
  }
198

199
  NettyChannelBuilder(String target) {
1✔
200
    managedChannelImplBuilder = new ManagedChannelImplBuilder(target,
1✔
201
        new NettyChannelTransportFactoryBuilder(),
202
        new NettyChannelDefaultPortProvider());
203
    this.freezeProtocolNegotiatorFactory = false;
1✔
204
  }
1✔
205

206
  NettyChannelBuilder(
207
      String target, ChannelCredentials channelCreds, CallCredentials callCreds,
208
      ProtocolNegotiator.ClientFactory negotiator) {
1✔
209
    managedChannelImplBuilder = new ManagedChannelImplBuilder(
1✔
210
        target, channelCreds, callCreds,
211
        new NettyChannelTransportFactoryBuilder(),
212
        new NettyChannelDefaultPortProvider());
213
    this.protocolNegotiatorFactory = checkNotNull(negotiator, "negotiator");
1✔
214
    this.freezeProtocolNegotiatorFactory = true;
1✔
215
  }
1✔
216

217
  NettyChannelBuilder(SocketAddress address) {
1✔
218
    managedChannelImplBuilder = new ManagedChannelImplBuilder(address,
1✔
219
        getAuthorityFromAddress(address),
1✔
220
        new NettyChannelTransportFactoryBuilder(),
221
        new NettyChannelDefaultPortProvider());
222
    this.freezeProtocolNegotiatorFactory = false;
1✔
223
  }
1✔
224

225
  NettyChannelBuilder(
226
      SocketAddress address, ChannelCredentials channelCreds, CallCredentials callCreds,
227
      ProtocolNegotiator.ClientFactory negotiator) {
1✔
228
    managedChannelImplBuilder = new ManagedChannelImplBuilder(address,
1✔
229
        getAuthorityFromAddress(address),
1✔
230
        channelCreds, callCreds,
231
        new NettyChannelTransportFactoryBuilder(),
232
        new NettyChannelDefaultPortProvider());
233
    this.protocolNegotiatorFactory = checkNotNull(negotiator, "negotiator");
1✔
234
    this.freezeProtocolNegotiatorFactory = true;
1✔
235
  }
1✔
236

237
  @Internal
238
  @Override
239
  protected ManagedChannelBuilder<?> delegate() {
240
    return managedChannelImplBuilder;
1✔
241
  }
242

243
  private static String getAuthorityFromAddress(SocketAddress address) {
244
    if (address instanceof InetSocketAddress) {
1✔
245
      InetSocketAddress inetAddress = (InetSocketAddress) address;
1✔
246
      return GrpcUtil.authorityFromHostAndPort(inetAddress.getHostString(), inetAddress.getPort());
1✔
247
    } else {
248
      return address.toString();
1✔
249
    }
250
  }
251

252
  /**
253
   * Specifies the channel type to use, by default we use {@code EpollSocketChannel} if available,
254
   * otherwise using {@link NioSocketChannel}.
255
   *
256
   * <p>You either use this or {@link #channelFactory(io.netty.channel.ChannelFactory)} if your
257
   * {@link Channel} implementation has no no-args constructor.
258
   *
259
   * <p>It's an optional parameter. If the user has not provided an Channel type or ChannelFactory
260
   * when the channel is built, the builder will use the default one which is static.
261
   *
262
   * <p>You must also provide corresponding {@link #eventLoopGroup(EventLoopGroup)}. For example,
263
   * {@link NioSocketChannel} must use {@link io.netty.channel.nio.NioEventLoopGroup}, otherwise
264
   * your application won't start.
265
   */
266
  @CanIgnoreReturnValue
267
  public NettyChannelBuilder channelType(Class<? extends Channel> channelType) {
268
    return channelType(channelType, null);
×
269
  }
270

271
  /**
272
   * Similar to {@link #channelType(Class)} above but allows the
273
   * caller to specify the socket-type associated with the channelType.
274
   *
275
   * @param channelType the type of {@link Channel} to use.
276
   * @param transportSocketType the associated {@link SocketAddress} type. If {@code null}, then
277
   *     no compatibility check is performed between channel transport and name-resolver addresses.
278
   */
279
  @CanIgnoreReturnValue
280
  public NettyChannelBuilder channelType(Class<? extends Channel> channelType,
281
      @Nullable Class<? extends SocketAddress> transportSocketType) {
282
    checkNotNull(channelType, "channelType");
1✔
283
    return channelFactory(new ReflectiveChannelFactory<>(channelType),
1✔
284
        transportSocketType);
285
  }
286

287
  /**
288
   * Specifies the {@link ChannelFactory} to create {@link Channel} instances. This method is
289
   * usually only used if the specific {@code Channel} requires complex logic which requires
290
   * additional information to create the {@code Channel}. Otherwise, recommend to use {@link
291
   * #channelType(Class)}.
292
   *
293
   * <p>It's an optional parameter. If the user has not provided an Channel type or ChannelFactory
294
   * when the channel is built, the builder will use the default one which is static.
295
   *
296
   * <p>You must also provide corresponding {@link #eventLoopGroup(EventLoopGroup)}. For example,
297
   * {@link NioSocketChannel} based {@link ChannelFactory} must use {@link
298
   * io.netty.channel.nio.NioEventLoopGroup}, otherwise your application won't start.
299
   */
300
  @CanIgnoreReturnValue
301
  public NettyChannelBuilder channelFactory(ChannelFactory<? extends Channel> channelFactory) {
302
    return channelFactory(channelFactory, null);
1✔
303
  }
304

305
  /**
306
   * Similar to {@link #channelFactory(ChannelFactory)} above but allows the
307
   * caller to specify the socket-type associated with the channelFactory.
308
   *
309
   * @param channelFactory the {@link ChannelFactory} to use.
310
   * @param transportSocketType the associated {@link SocketAddress} type. If {@code null}, then
311
   *     no compatibility check is performed between channel transport and name-resolver addresses.
312
   */
313
  @CanIgnoreReturnValue
314
  public NettyChannelBuilder channelFactory(ChannelFactory<? extends Channel> channelFactory,
315
      @Nullable Class<? extends SocketAddress> transportSocketType) {
316
    this.channelFactory = checkNotNull(channelFactory, "channelFactory");
1✔
317
    this.transportSocketType = transportSocketType;
1✔
318
    return this;
1✔
319
  }
320

321
  /**
322
   * Specifies a channel option. As the underlying channel as well as network implementation may
323
   * ignore this value applications should consider it a hint.
324
   */
325
  @CanIgnoreReturnValue
326
  public <T> NettyChannelBuilder withOption(ChannelOption<T> option, T value) {
327
    channelOptions.put(option, value);
×
328
    return this;
×
329
  }
330

331
  /**
332
   * Sets the negotiation type for the HTTP/2 connection.
333
   *
334
   * <p>Default: <code>TLS</code>
335
   */
336
  @CanIgnoreReturnValue
337
  public NettyChannelBuilder negotiationType(NegotiationType type) {
338
    checkState(!freezeProtocolNegotiatorFactory,
1✔
339
               "Cannot change security when using ChannelCredentials");
340
    if (!(protocolNegotiatorFactory instanceof DefaultProtocolNegotiator)) {
1✔
341
      // Do nothing for compatibility
342
      return this;
×
343
    }
344
    ((DefaultProtocolNegotiator) protocolNegotiatorFactory).negotiationType = type;
1✔
345
    return this;
1✔
346
  }
347

348
  /**
349
   * Provides an EventGroupLoop to be used by the netty transport.
350
   *
351
   * <p>It's an optional parameter. If the user has not provided an EventGroupLoop when the channel
352
   * is built, the builder will use the default one which is static.
353
   *
354
   * <p>You must also provide corresponding {@link #channelType(Class)} or {@link
355
   * #channelFactory(ChannelFactory)} corresponding to the given {@code EventLoopGroup}. For
356
   * example, {@link io.netty.channel.nio.NioEventLoopGroup} requires {@link NioSocketChannel}
357
   *
358
   * <p>The channel won't take ownership of the given EventLoopGroup. It's caller's responsibility
359
   * to shut it down when it's desired.
360
   */
361
  @CanIgnoreReturnValue
362
  public NettyChannelBuilder eventLoopGroup(@Nullable EventLoopGroup eventLoopGroup) {
363
    if (eventLoopGroup != null) {
1✔
364
      return eventLoopGroupPool(new FixedObjectPool<>(eventLoopGroup));
1✔
365
    }
366
    return eventLoopGroupPool(DEFAULT_EVENT_LOOP_GROUP_POOL);
×
367
  }
368

369
  @CanIgnoreReturnValue
370
  NettyChannelBuilder eventLoopGroupPool(ObjectPool<? extends EventLoopGroup> eventLoopGroupPool) {
371
    this.eventLoopGroupPool = checkNotNull(eventLoopGroupPool, "eventLoopGroupPool");
1✔
372
    return this;
1✔
373
  }
374

375
  /**
376
   * SSL/TLS context to use instead of the system default. It must have been configured with {@link
377
   * GrpcSslContexts}, but options could have been overridden.
378
   */
379
  @CanIgnoreReturnValue
380
  public NettyChannelBuilder sslContext(SslContext sslContext) {
381
    checkState(!freezeProtocolNegotiatorFactory,
1✔
382
               "Cannot change security when using ChannelCredentials");
383
    if (sslContext != null) {
1✔
384
      checkArgument(sslContext.isClient(),
1✔
385
          "Server SSL context can not be used for client channel");
386
      GrpcSslContexts.ensureAlpnAndH2Enabled(sslContext.applicationProtocolNegotiator());
1✔
387
    }
388
    if (!(protocolNegotiatorFactory instanceof DefaultProtocolNegotiator)) {
1✔
389
      // Do nothing for compatibility
390
      return this;
×
391
    }
392
    ((DefaultProtocolNegotiator) protocolNegotiatorFactory).sslContext = sslContext;
1✔
393
    return this;
1✔
394
  }
395

396
  /**
397
   * Sets the initial flow control window in bytes. Setting initial flow control window enables auto
398
   * flow control tuning using bandwidth-delay product algorithm. To disable auto flow control
399
   * tuning, use {@link #flowControlWindow(int)}. By default, auto flow control is enabled with
400
   * initial flow control window size of {@link #DEFAULT_FLOW_CONTROL_WINDOW}.
401
   */
402
  @CanIgnoreReturnValue
403
  public NettyChannelBuilder initialFlowControlWindow(int initialFlowControlWindow) {
404
    checkArgument(initialFlowControlWindow > 0, "initialFlowControlWindow must be positive");
1✔
405
    this.flowControlWindow = initialFlowControlWindow;
1✔
406
    this.autoFlowControl = true;
1✔
407
    return this;
1✔
408
  }
409

410
  /**
411
   * Sets the flow control window in bytes. Setting flowControlWindow disables auto flow control
412
   * tuning; use {@link #initialFlowControlWindow(int)} to enable auto flow control tuning. If not
413
   * called, the default value is {@link #DEFAULT_FLOW_CONTROL_WINDOW}) with auto flow control
414
   * tuning.
415
   */
416
  @CanIgnoreReturnValue
417
  public NettyChannelBuilder flowControlWindow(int flowControlWindow) {
418
    checkArgument(flowControlWindow > 0, "flowControlWindow must be positive");
1✔
419
    this.flowControlWindow = flowControlWindow;
1✔
420
    this.autoFlowControl = false;
1✔
421
    return this;
1✔
422
  }
423

424
  /**
425
   * Sets the maximum size of header list allowed to be received. This is cumulative size of the
426
   * headers with some overhead, as defined for
427
   * <a href="http://httpwg.org/specs/rfc7540.html#rfc.section.6.5.2">
428
   * HTTP/2's SETTINGS_MAX_HEADER_LIST_SIZE</a>. The default is 8 KiB.
429
   *
430
   * @deprecated Use {@link #maxInboundMetadataSize} instead
431
   */
432
  @CanIgnoreReturnValue
433
  @Deprecated
434
  @InlineMe(replacement = "this.maxInboundMetadataSize(maxHeaderListSize)")
435
  public NettyChannelBuilder maxHeaderListSize(int maxHeaderListSize) {
436
    return maxInboundMetadataSize(maxHeaderListSize);
×
437
  }
438

439
  /**
440
   * Sets the maximum size of metadata allowed to be received. This is cumulative size of the
441
   * entries with some overhead, as defined for
442
   * <a href="http://httpwg.org/specs/rfc7540.html#rfc.section.6.5.2">
443
   * HTTP/2's SETTINGS_MAX_HEADER_LIST_SIZE</a>. The default is 8 KiB.
444
   *
445
   * @param bytes the maximum size of received metadata
446
   * @return this
447
   * @throws IllegalArgumentException if bytes is non-positive
448
   * @since 1.17.0
449
   */
450
  @CanIgnoreReturnValue
451
  @Override
452
  public NettyChannelBuilder maxInboundMetadataSize(int bytes) {
453
    checkArgument(bytes > 0, "maxInboundMetadataSize must be > 0");
×
454
    this.maxHeaderListSize = bytes;
×
455
    return this;
×
456
  }
457

458
  /**
459
   * Equivalent to using {@link #negotiationType(NegotiationType)} with {@code PLAINTEXT}.
460
   */
461
  @CanIgnoreReturnValue
462
  @Override
463
  public NettyChannelBuilder usePlaintext() {
464
    negotiationType(NegotiationType.PLAINTEXT);
1✔
465
    return this;
1✔
466
  }
467

468
  /**
469
   * Equivalent to using {@link #negotiationType(NegotiationType)} with {@code TLS}.
470
   */
471
  @CanIgnoreReturnValue
472
  @Override
473
  public NettyChannelBuilder useTransportSecurity() {
474
    negotiationType(NegotiationType.TLS);
×
475
    return this;
×
476
  }
477

478
  /**
479
   * {@inheritDoc}
480
   *
481
   * @since 1.3.0
482
   */
483
  @CanIgnoreReturnValue
484
  @Override
485
  public NettyChannelBuilder keepAliveTime(long keepAliveTime, TimeUnit timeUnit) {
486
    checkArgument(keepAliveTime > 0L, "keepalive time must be positive");
1✔
487
    keepAliveTimeNanos = timeUnit.toNanos(keepAliveTime);
×
488
    keepAliveTimeNanos = KeepAliveManager.clampKeepAliveTimeInNanos(keepAliveTimeNanos);
×
489
    if (keepAliveTimeNanos >= AS_LARGE_AS_INFINITE) {
×
490
      // Bump keepalive time to infinite. This disables keepalive.
491
      keepAliveTimeNanos = KEEPALIVE_TIME_NANOS_DISABLED;
×
492
    }
493
    return this;
×
494
  }
495

496
  /**
497
   * {@inheritDoc}
498
   *
499
   * @since 1.3.0
500
   */
501
  @CanIgnoreReturnValue
502
  @Override
503
  public NettyChannelBuilder keepAliveTimeout(long keepAliveTimeout, TimeUnit timeUnit) {
504
    checkArgument(keepAliveTimeout > 0L, "keepalive timeout must be positive");
1✔
505
    keepAliveTimeoutNanos = timeUnit.toNanos(keepAliveTimeout);
×
506
    keepAliveTimeoutNanos = KeepAliveManager.clampKeepAliveTimeoutInNanos(keepAliveTimeoutNanos);
×
507
    return this;
×
508
  }
509

510
  /**
511
   * {@inheritDoc}
512
   *
513
   * @since 1.3.0
514
   */
515
  @CanIgnoreReturnValue
516
  @Override
517
  public NettyChannelBuilder keepAliveWithoutCalls(boolean enable) {
518
    keepAliveWithoutCalls = enable;
×
519
    return this;
×
520
  }
521

522

523
  /**
524
   * If non-{@code null}, attempts to create connections bound to a local port.
525
   */
526
  @CanIgnoreReturnValue
527
  public NettyChannelBuilder localSocketPicker(@Nullable LocalSocketPicker localSocketPicker) {
528
    this.localSocketPicker = localSocketPicker;
×
529
    return this;
×
530
  }
531

532
  /**
533
   * This class is meant to be overriden with a custom implementation of
534
   * {@link #createSocketAddress}.  The default implementation is a no-op.
535
   *
536
   * @since 1.16.0
537
   */
538
  @ExperimentalApi("https://github.com/grpc/grpc-java/issues/4917")
539
  public static class LocalSocketPicker {
1✔
540

541
    /**
542
     * Called by gRPC to pick local socket to bind to.  This may be called multiple times.
543
     * Subclasses are expected to override this method.
544
     *
545
     * @param remoteAddress the remote address to connect to.
546
     * @param attrs the Attributes present on the {@link io.grpc.EquivalentAddressGroup} associated
547
     *        with the address.
548
     * @return a {@link SocketAddress} suitable for binding, or else {@code null}.
549
     * @since 1.16.0
550
     */
551
    @Nullable
552
    public SocketAddress createSocketAddress(
553
        SocketAddress remoteAddress, @EquivalentAddressGroup.Attr Attributes attrs) {
554
      return null;
1✔
555
    }
556
  }
557

558
  /**
559
   * Sets the maximum message size allowed for a single gRPC frame. If an inbound messages larger
560
   * than this limit is received it will not be processed and the RPC will fail with
561
   * RESOURCE_EXHAUSTED.
562
   */
563
  @CanIgnoreReturnValue
564
  @Override
565
  public NettyChannelBuilder maxInboundMessageSize(int max) {
566
    checkArgument(max >= 0, "negative max");
1✔
567
    maxInboundMessageSize = max;
1✔
568
    return this;
1✔
569
  }
570

571
  ClientTransportFactory buildTransportFactory() {
572
    assertEventLoopAndChannelType();
1✔
573

574
    ProtocolNegotiator negotiator = protocolNegotiatorFactory.newNegotiator();
1✔
575
    return new NettyTransportFactory(
1✔
576
        negotiator, channelFactory, channelOptions,
577
        eventLoopGroupPool, autoFlowControl, flowControlWindow, maxInboundMessageSize,
578
        maxHeaderListSize, keepAliveTimeNanos, keepAliveTimeoutNanos, keepAliveWithoutCalls,
579
        transportTracerFactory, localSocketPicker, useGetForSafeMethods, transportSocketType);
580
  }
581

582
  @VisibleForTesting
583
  void assertEventLoopAndChannelType() {
584
    boolean bothProvided = channelFactory != DEFAULT_CHANNEL_FACTORY
1✔
585
        && eventLoopGroupPool != DEFAULT_EVENT_LOOP_GROUP_POOL;
586
    boolean nonProvided = channelFactory == DEFAULT_CHANNEL_FACTORY
1✔
587
        && eventLoopGroupPool == DEFAULT_EVENT_LOOP_GROUP_POOL;
588
    checkState(
1✔
589
        bothProvided || nonProvided,
590
        "Both EventLoopGroup and ChannelType should be provided or neither should be");
591
  }
1✔
592

593
  int getDefaultPort() {
594
    return protocolNegotiatorFactory.getDefaultPort();
×
595
  }
596

597
  @VisibleForTesting
598
  static ProtocolNegotiator createProtocolNegotiatorByType(
599
      NegotiationType negotiationType,
600
      SslContext sslContext,
601
      ObjectPool<? extends Executor> executorPool) {
602
    switch (negotiationType) {
1✔
603
      case PLAINTEXT:
604
        return ProtocolNegotiators.plaintext();
1✔
605
      case PLAINTEXT_UPGRADE:
606
        return ProtocolNegotiators.plaintextUpgrade();
1✔
607
      case TLS:
608
        return ProtocolNegotiators.tls(sslContext, executorPool, Optional.empty());
1✔
609
      default:
610
        throw new IllegalArgumentException("Unsupported negotiationType: " + negotiationType);
×
611
    }
612
  }
613

614
  @CanIgnoreReturnValue
615
  NettyChannelBuilder disableCheckAuthority() {
616
    this.managedChannelImplBuilder.disableCheckAuthority();
1✔
617
    return this;
1✔
618
  }
619

620
  @CanIgnoreReturnValue
621
  NettyChannelBuilder enableCheckAuthority() {
622
    this.managedChannelImplBuilder.enableCheckAuthority();
1✔
623
    return this;
1✔
624
  }
625

626
  void protocolNegotiatorFactory(ProtocolNegotiator.ClientFactory protocolNegotiatorFactory) {
627
    checkState(!freezeProtocolNegotiatorFactory,
1✔
628
               "Cannot change security when using ChannelCredentials");
629
    this.protocolNegotiatorFactory
1✔
630
        = checkNotNull(protocolNegotiatorFactory, "protocolNegotiatorFactory");
1✔
631
  }
1✔
632

633
  void setTracingEnabled(boolean value) {
634
    this.managedChannelImplBuilder.setTracingEnabled(value);
1✔
635
  }
1✔
636

637
  void setStatsEnabled(boolean value) {
638
    this.managedChannelImplBuilder.setStatsEnabled(value);
1✔
639
  }
1✔
640

641
  void setStatsRecordStartedRpcs(boolean value) {
642
    this.managedChannelImplBuilder.setStatsRecordStartedRpcs(value);
×
643
  }
×
644

645
  void setStatsRecordFinishedRpcs(boolean value) {
646
    this.managedChannelImplBuilder.setStatsRecordFinishedRpcs(value);
×
647
  }
×
648

649
  void setStatsRecordRealTimeMetrics(boolean value) {
650
    this.managedChannelImplBuilder.setStatsRecordRealTimeMetrics(value);
×
651
  }
×
652

653
  void setStatsRecordRetryMetrics(boolean value) {
654
    this.managedChannelImplBuilder.setStatsRecordRetryMetrics(value);
×
655
  }
×
656

657
  @CanIgnoreReturnValue
658
  @VisibleForTesting
659
  NettyChannelBuilder setTransportTracerFactory(TransportTracer.Factory transportTracerFactory) {
660
    this.transportTracerFactory = transportTracerFactory;
1✔
661
    return this;
1✔
662
  }
663

664
  static Collection<Class<? extends SocketAddress>> getSupportedSocketAddressTypes() {
665
    return Collections.singleton(InetSocketAddress.class);
1✔
666
  }
667

668
  private final class DefaultProtocolNegotiator implements ProtocolNegotiator.ClientFactory {
1✔
669
    private NegotiationType negotiationType = NegotiationType.TLS;
1✔
670
    private SslContext sslContext;
671

672
    @Override
673
    public ProtocolNegotiator newNegotiator() {
674
      SslContext localSslContext = sslContext;
1✔
675
      if (negotiationType == NegotiationType.TLS && localSslContext == null) {
1✔
676
        try {
677
          localSslContext = GrpcSslContexts.forClient().build();
1✔
678
        } catch (SSLException ex) {
×
679
          throw new RuntimeException(ex);
×
680
        }
1✔
681
      }
682
      return createProtocolNegotiatorByType(negotiationType, localSslContext,
1✔
683
          managedChannelImplBuilder.getOffloadExecutorPool());
1✔
684
    }
685

686
    @Override
687
    public int getDefaultPort() {
688
      switch (negotiationType) {
1✔
689
        case PLAINTEXT:
690
        case PLAINTEXT_UPGRADE:
691
          return GrpcUtil.DEFAULT_PORT_PLAINTEXT;
1✔
692
        case TLS:
693
          return GrpcUtil.DEFAULT_PORT_SSL;
1✔
694
        default:
695
          throw new AssertionError(negotiationType + " not handled");
×
696
      }
697
    }
698
  }
699

700
  /**
701
   * Creates Netty transports. Exposed for internal use, as it should be private.
702
   */
703
  private static final class NettyTransportFactory implements ClientTransportFactory {
704
    private final ProtocolNegotiator protocolNegotiator;
705
    private final ChannelFactory<? extends Channel> channelFactory;
706
    private final Map<ChannelOption<?>, ?> channelOptions;
707
    private final ObjectPool<? extends EventLoopGroup> groupPool;
708
    private final EventLoopGroup group;
709
    private final boolean autoFlowControl;
710
    private final int flowControlWindow;
711
    private final int maxMessageSize;
712
    private final int maxHeaderListSize;
713
    private final long keepAliveTimeNanos;
714
    private final AtomicBackoff keepAliveBackoff;
715
    private final long keepAliveTimeoutNanos;
716
    private final boolean keepAliveWithoutCalls;
717
    private final TransportTracer.Factory transportTracerFactory;
718
    private final LocalSocketPicker localSocketPicker;
719
    private final boolean useGetForSafeMethods;
720

721
    private boolean closed;
722
    private final Class<? extends SocketAddress> transportSocketType;
723

724
    NettyTransportFactory(
725
        ProtocolNegotiator protocolNegotiator,
726
        ChannelFactory<? extends Channel> channelFactory,
727
        Map<ChannelOption<?>, ?> channelOptions, ObjectPool<? extends EventLoopGroup> groupPool,
728
        boolean autoFlowControl, int flowControlWindow, int maxMessageSize, int maxHeaderListSize,
729
        long keepAliveTimeNanos, long keepAliveTimeoutNanos, boolean keepAliveWithoutCalls,
730
        TransportTracer.Factory transportTracerFactory, LocalSocketPicker localSocketPicker,
731
        boolean useGetForSafeMethods, Class<? extends SocketAddress> transportSocketType) {
1✔
732
      this.protocolNegotiator = checkNotNull(protocolNegotiator, "protocolNegotiator");
1✔
733
      this.channelFactory = channelFactory;
1✔
734
      this.channelOptions = new HashMap<ChannelOption<?>, Object>(channelOptions);
1✔
735
      this.groupPool = groupPool;
1✔
736
      this.group = groupPool.getObject();
1✔
737
      this.autoFlowControl = autoFlowControl;
1✔
738
      this.flowControlWindow = flowControlWindow;
1✔
739
      this.maxMessageSize = maxMessageSize;
1✔
740
      this.maxHeaderListSize = maxHeaderListSize;
1✔
741
      this.keepAliveTimeNanos = keepAliveTimeNanos;
1✔
742
      this.keepAliveBackoff = new AtomicBackoff("keepalive time nanos", keepAliveTimeNanos);
1✔
743
      this.keepAliveTimeoutNanos = keepAliveTimeoutNanos;
1✔
744
      this.keepAliveWithoutCalls = keepAliveWithoutCalls;
1✔
745
      this.transportTracerFactory = transportTracerFactory;
1✔
746
      this.localSocketPicker =
1✔
747
          localSocketPicker != null ? localSocketPicker : new LocalSocketPicker();
1✔
748
      this.useGetForSafeMethods = useGetForSafeMethods;
1✔
749
      this.transportSocketType = transportSocketType;
1✔
750
    }
1✔
751

752
    @Override
753
    public ConnectionClientTransport newClientTransport(
754
        SocketAddress serverAddress, ClientTransportOptions options, ChannelLogger channelLogger) {
755
      checkState(!closed, "The transport factory is closed.");
1✔
756

757
      ProtocolNegotiator localNegotiator = protocolNegotiator;
1✔
758
      HttpConnectProxiedSocketAddress proxiedAddr = options.getHttpConnectProxiedSocketAddress();
1✔
759
      if (proxiedAddr != null) {
1✔
760
        serverAddress = proxiedAddr.getTargetAddress();
×
761
        localNegotiator = ProtocolNegotiators.httpProxy(
×
762
            proxiedAddr.getProxyAddress(),
×
763
            proxiedAddr.getUsername(),
×
764
            proxiedAddr.getPassword(),
×
765
            protocolNegotiator);
766
      }
767

768
      final AtomicBackoff.State keepAliveTimeNanosState = keepAliveBackoff.getState();
1✔
769
      Runnable tooManyPingsRunnable = new Runnable() {
1✔
770
        @Override
771
        public void run() {
772
          keepAliveTimeNanosState.backoff();
×
773
        }
×
774
      };
775

776
      // TODO(carl-mastrangelo): Pass channelLogger in.
777
      NettyClientTransport transport = new NettyClientTransport(
1✔
778
          serverAddress, channelFactory, channelOptions, group,
779
          localNegotiator, autoFlowControl, flowControlWindow,
780
          maxMessageSize, maxHeaderListSize, keepAliveTimeNanosState.get(), keepAliveTimeoutNanos,
1✔
781
          keepAliveWithoutCalls, options.getAuthority(), options.getUserAgent(),
1✔
782
          tooManyPingsRunnable, transportTracerFactory.create(), options.getEagAttributes(),
1✔
783
          localSocketPicker, channelLogger, useGetForSafeMethods, Ticker.systemTicker());
1✔
784
      return transport;
1✔
785
    }
786

787
    @Override
788
    public ScheduledExecutorService getScheduledExecutorService() {
789
      return group;
1✔
790
    }
791

792
    @Override
793
    public SwapChannelCredentialsResult swapChannelCredentials(ChannelCredentials channelCreds) {
794
      checkNotNull(channelCreds, "channelCreds");
1✔
795
      FromChannelCredentialsResult result = ProtocolNegotiators.from(channelCreds);
1✔
796
      if (result.error != null) {
1✔
797
        return null;
1✔
798
      }
799
      ClientTransportFactory factory = new NettyTransportFactory(
1✔
800
          result.negotiator.newNegotiator(), channelFactory, channelOptions, groupPool,
1✔
801
          autoFlowControl, flowControlWindow, maxMessageSize, maxHeaderListSize, keepAliveTimeNanos,
802
          keepAliveTimeoutNanos, keepAliveWithoutCalls, transportTracerFactory,  localSocketPicker,
803
          useGetForSafeMethods, transportSocketType);
804
      return new SwapChannelCredentialsResult(factory, result.callCredentials);
1✔
805
    }
806

807
    @Override
808
    public void close() {
809
      if (closed) {
1✔
810
        return;
1✔
811
      }
812
      closed = true;
1✔
813

814
      protocolNegotiator.close();
1✔
815
      groupPool.returnObject(group);
1✔
816
    }
1✔
817

818
    @Override
819
    public Collection<Class<? extends SocketAddress>> getSupportedSocketAddressTypes() {
820
      return transportSocketType == null ? null
1✔
821
          : Collections.singleton(transportSocketType);
1✔
822
    }
823
  }
824
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc