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

grpc / grpc-java / #18883

03 Nov 2023 04:57PM UTC coverage: 88.246% (+0.03%) from 88.218%
#18883

push

github

web-flow
core, netty, okhttp: implement new logic for nameResolverFactory API in channelBuilder (#10590)

* core, netty, okhttp: implement new logic for nameResolverFactory API in channelBuilder
fix ManagedChannelImpl to use NameResolverRegistry instead of NameResolverFactory
fix the ManagedChannelImplBuilder and remove nameResolverFactory

* Integrate target parsing and NameResolverProvider searching

Actually creating the name resolver is now delayed to the end of
ManagedChannelImpl.getNameResolver; we don't want to call into the name
resolver to determine if we should use the name resolver.

Added getDefaultScheme() to NameResolverRegistry to avoid needing
NameResolver.Factory.
---------

Co-authored-by: Eric Anderson <ejona@google.com>

30370 of 34415 relevant lines covered (88.25%)

0.88 hits per line

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

79.13
/../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.concurrent.Executor;
67
import java.util.concurrent.ScheduledExecutorService;
68
import java.util.concurrent.TimeUnit;
69
import javax.annotation.Nullable;
70
import javax.net.ssl.SSLException;
71

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

521

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

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

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

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

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

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

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

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

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

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

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

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

632
  void setTracingEnabled(boolean value) {
633
    this.managedChannelImplBuilder.setTracingEnabled(value);
×
634
  }
×
635

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

817
    @Override
818
    public Collection<Class<? extends SocketAddress>> getSupportedSocketAddressTypes() {
819
      return transportSocketType == null ? null
1✔
820
          : Collections.singleton(transportSocketType);
1✔
821
    }
822
  }
823
}
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