1 /*
2 *
3 * Copyright 2018 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18 19 package grpc
20 21 import (
22 "context"
23 "net"
24 "net/url"
25 "time"
26 27 "google.golang.org/grpc/backoff"
28 "google.golang.org/grpc/channelz"
29 "google.golang.org/grpc/credentials"
30 "google.golang.org/grpc/credentials/insecure"
31 "google.golang.org/grpc/internal"
32 internalbackoff "google.golang.org/grpc/internal/backoff"
33 "google.golang.org/grpc/internal/binarylog"
34 "google.golang.org/grpc/internal/transport"
35 "google.golang.org/grpc/keepalive"
36 "google.golang.org/grpc/mem"
37 "google.golang.org/grpc/resolver"
38 "google.golang.org/grpc/stats"
39 )
40 41 const (
42 // https://github.com/grpc/proposal/blob/master/A6-client-retries.md#limits-on-retries-and-hedges
43 defaultMaxCallAttempts = 5
44 )
45 46 func init() {
47 internal.AddGlobalDialOptions = func(opt ...DialOption) {
48 globalDialOptions = append(globalDialOptions, opt...)
49 }
50 internal.ClearGlobalDialOptions = func() {
51 globalDialOptions = nil
52 }
53 internal.AddGlobalPerTargetDialOptions = func(opt any) {
54 if ptdo, ok := opt.(perTargetDialOption); ok {
55 globalPerTargetDialOptions = append(globalPerTargetDialOptions, ptdo)
56 }
57 }
58 internal.ClearGlobalPerTargetDialOptions = func() {
59 globalPerTargetDialOptions = nil
60 }
61 internal.WithBinaryLogger = withBinaryLogger
62 internal.JoinDialOptions = newJoinDialOption
63 internal.DisableGlobalDialOptions = newDisableGlobalDialOptions
64 internal.WithBufferPool = withBufferPool
65 }
66 67 // dialOptions configure a Dial call. dialOptions are set by the DialOption
68 // values passed to Dial.
69 type dialOptions struct {
70 unaryInt UnaryClientInterceptor
71 streamInt StreamClientInterceptor
72 73 chainUnaryInts []UnaryClientInterceptor
74 chainStreamInts []StreamClientInterceptor
75 76 compressorV0 Compressor
77 dc Decompressor
78 bs internalbackoff.Strategy
79 block bool
80 returnLastError bool
81 timeout time.Duration
82 authority string
83 binaryLogger binarylog.Logger
84 copts transport.ConnectOptions
85 callOptions []CallOption
86 channelzParent channelz.Identifier
87 disableServiceConfig bool
88 disableRetry bool
89 disableHealthCheck bool
90 minConnectTimeout func() time.Duration
91 defaultServiceConfig *ServiceConfig // defaultServiceConfig is parsed from defaultServiceConfigRawJSON.
92 defaultServiceConfigRawJSON *string
93 resolvers []resolver.Builder
94 idleTimeout time.Duration
95 defaultScheme string
96 maxCallAttempts int
97 enableLocalDNSResolution bool // Specifies if target hostnames should be resolved when proxying is enabled.
98 useProxy bool // Specifies if a server should be connected via proxy.
99 }
100 101 // DialOption configures how we set up the connection.
102 type DialOption interface {
103 apply(*dialOptions)
104 }
105 106 var globalDialOptions []DialOption
107 108 // perTargetDialOption takes a parsed target and returns a dial option to apply.
109 //
110 // This gets called after NewClient() parses the target, and allows per target
111 // configuration set through a returned DialOption. The DialOption will not take
112 // effect if specifies a resolver builder, as that Dial Option is factored in
113 // while parsing target.
114 type perTargetDialOption interface {
115 // DialOption returns a Dial Option to apply.
116 DialOptionForTarget(parsedTarget url.URL) DialOption
117 }
118 119 var globalPerTargetDialOptions []perTargetDialOption
120 121 // EmptyDialOption does not alter the dial configuration. It can be embedded in
122 // another structure to build custom dial options.
123 //
124 // # Experimental
125 //
126 // Notice: This type is EXPERIMENTAL and may be changed or removed in a
127 // later release.
128 type EmptyDialOption struct{}
129 130 func (EmptyDialOption) apply(*dialOptions) {}
131 132 type disableGlobalDialOptions struct{}
133 134 func (disableGlobalDialOptions) apply(*dialOptions) {}
135 136 // newDisableGlobalDialOptions returns a DialOption that prevents the ClientConn
137 // from applying the global DialOptions (set via AddGlobalDialOptions).
138 func newDisableGlobalDialOptions() DialOption {
139 return &disableGlobalDialOptions{}
140 }
141 142 // funcDialOption wraps a function that modifies dialOptions into an
143 // implementation of the DialOption interface.
144 type funcDialOption struct {
145 f func(*dialOptions)
146 }
147 148 func (fdo *funcDialOption) apply(do *dialOptions) {
149 fdo.f(do)
150 }
151 152 func newFuncDialOption(f func(*dialOptions)) *funcDialOption {
153 return &funcDialOption{
154 f: f,
155 }
156 }
157 158 type joinDialOption struct {
159 opts []DialOption
160 }
161 162 func (jdo *joinDialOption) apply(do *dialOptions) {
163 for _, opt := range jdo.opts {
164 opt.apply(do)
165 }
166 }
167 168 func newJoinDialOption(opts ...DialOption) DialOption {
169 return &joinDialOption{opts: opts}
170 }
171 172 // WithSharedWriteBuffer allows reusing per-connection transport write buffer.
173 // If this option is set to true every connection will release the buffer after
174 // flushing the data on the wire.
175 //
176 // # Experimental
177 //
178 // Notice: This API is EXPERIMENTAL and may be changed or removed in a
179 // later release.
180 func WithSharedWriteBuffer(val bool) DialOption {
181 return newFuncDialOption(func(o *dialOptions) {
182 o.copts.SharedWriteBuffer = val
183 })
184 }
185 186 // WithWriteBufferSize determines how much data can be batched before doing a
187 // write on the wire. The default value for this buffer is 32KB.
188 //
189 // Zero or negative values will disable the write buffer such that each write
190 // will be on underlying connection. Note: A Send call may not directly
191 // translate to a write.
192 func WithWriteBufferSize(s int) DialOption {
193 return newFuncDialOption(func(o *dialOptions) {
194 o.copts.WriteBufferSize = s
195 })
196 }
197 198 // WithReadBufferSize lets you set the size of read buffer, this determines how
199 // much data can be read at most for each read syscall.
200 //
201 // The default value for this buffer is 32KB. Zero or negative values will
202 // disable read buffer for a connection so data framer can access the
203 // underlying conn directly.
204 func WithReadBufferSize(s int) DialOption {
205 return newFuncDialOption(func(o *dialOptions) {
206 o.copts.ReadBufferSize = s
207 })
208 }
209 210 // WithInitialWindowSize returns a DialOption which sets the value for initial
211 // window size on a stream. The lower bound for window size is 64K and any value
212 // smaller than that will be ignored.
213 func WithInitialWindowSize(s int32) DialOption {
214 return newFuncDialOption(func(o *dialOptions) {
215 o.copts.InitialWindowSize = s
216 o.copts.StaticWindowSize = true
217 })
218 }
219 220 // WithInitialConnWindowSize returns a DialOption which sets the value for
221 // initial window size on a connection. The lower bound for window size is 64K
222 // and any value smaller than that will be ignored.
223 func WithInitialConnWindowSize(s int32) DialOption {
224 return newFuncDialOption(func(o *dialOptions) {
225 o.copts.InitialConnWindowSize = s
226 o.copts.StaticWindowSize = true
227 })
228 }
229 230 // WithStaticStreamWindowSize returns a DialOption which sets the initial
231 // stream window size to the value provided and disables dynamic flow control.
232 func WithStaticStreamWindowSize(s int32) DialOption {
233 return newFuncDialOption(func(o *dialOptions) {
234 o.copts.InitialWindowSize = s
235 o.copts.StaticWindowSize = true
236 })
237 }
238 239 // WithStaticConnWindowSize returns a DialOption which sets the initial
240 // connection window size to the value provided and disables dynamic flow
241 // control.
242 func WithStaticConnWindowSize(s int32) DialOption {
243 return newFuncDialOption(func(o *dialOptions) {
244 o.copts.InitialConnWindowSize = s
245 o.copts.StaticWindowSize = true
246 })
247 }
248 249 // WithMaxMsgSize returns a DialOption which sets the maximum message size the
250 // client can receive.
251 //
252 // Deprecated: use WithDefaultCallOptions(MaxCallRecvMsgSize(s)) instead. Will
253 // be supported throughout 1.x.
254 func WithMaxMsgSize(s int) DialOption {
255 return WithDefaultCallOptions(MaxCallRecvMsgSize(s))
256 }
257 258 // WithDefaultCallOptions returns a DialOption which sets the default
259 // CallOptions for calls over the connection.
260 func WithDefaultCallOptions(cos ...CallOption) DialOption {
261 return newFuncDialOption(func(o *dialOptions) {
262 o.callOptions = append(o.callOptions, cos...)
263 })
264 }
265 266 // WithCodec returns a DialOption which sets a codec for message marshaling and
267 // unmarshaling.
268 //
269 // Deprecated: use WithDefaultCallOptions(ForceCodec(_)) instead. Will be
270 // supported throughout 1.x.
271 func WithCodec(c Codec) DialOption {
272 return WithDefaultCallOptions(CallCustomCodec(c))
273 }
274 275 // WithCompressor returns a DialOption which sets a Compressor to use for
276 // message compression. It has lower priority than the compressor set by the
277 // UseCompressor CallOption.
278 //
279 // Deprecated: use UseCompressor instead. Will be supported throughout 1.x.
280 func WithCompressor(cp Compressor) DialOption {
281 return newFuncDialOption(func(o *dialOptions) {
282 o.compressorV0 = cp
283 })
284 }
285 286 // WithDecompressor returns a DialOption which sets a Decompressor to use for
287 // incoming message decompression. If incoming response messages are encoded
288 // using the decompressor's Type(), it will be used. Otherwise, the message
289 // encoding will be used to look up the compressor registered via
290 // encoding.RegisterCompressor, which will then be used to decompress the
291 // message. If no compressor is registered for the encoding, an Unimplemented
292 // status error will be returned.
293 //
294 // Deprecated: use encoding.RegisterCompressor instead. Will be supported
295 // throughout 1.x.
296 func WithDecompressor(dc Decompressor) DialOption {
297 return newFuncDialOption(func(o *dialOptions) {
298 o.dc = dc
299 })
300 }
301 302 // WithConnectParams configures the ClientConn to use the provided ConnectParams
303 // for creating and maintaining connections to servers.
304 //
305 // The backoff configuration specified as part of the ConnectParams overrides
306 // all defaults specified in
307 // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. Consider
308 // using the backoff.DefaultConfig as a base, in cases where you want to
309 // override only a subset of the backoff configuration.
310 func WithConnectParams(p ConnectParams) DialOption {
311 return newFuncDialOption(func(o *dialOptions) {
312 o.bs = internalbackoff.Exponential{Config: p.Backoff}
313 o.minConnectTimeout = func() time.Duration {
314 return p.MinConnectTimeout
315 }
316 })
317 }
318 319 // WithBackoffMaxDelay configures the dialer to use the provided maximum delay
320 // when backing off after failed connection attempts.
321 //
322 // Deprecated: use WithConnectParams instead. Will be supported throughout 1.x.
323 func WithBackoffMaxDelay(md time.Duration) DialOption {
324 return WithBackoffConfig(BackoffConfig{MaxDelay: md})
325 }
326 327 // WithBackoffConfig configures the dialer to use the provided backoff
328 // parameters after connection failures.
329 //
330 // Deprecated: use WithConnectParams instead. Will be supported throughout 1.x.
331 func WithBackoffConfig(b BackoffConfig) DialOption {
332 bc := backoff.DefaultConfig
333 bc.MaxDelay = b.MaxDelay
334 return withBackoff(internalbackoff.Exponential{Config: bc})
335 }
336 337 // withBackoff sets the backoff strategy used for connectRetryNum after a failed
338 // connection attempt.
339 //
340 // This can be exported if arbitrary backoff strategies are allowed by gRPC.
341 func withBackoff(bs internalbackoff.Strategy) DialOption {
342 return newFuncDialOption(func(o *dialOptions) {
343 o.bs = bs
344 })
345 }
346 347 // WithBlock returns a DialOption which makes callers of Dial block until the
348 // underlying connection is up. Without this, Dial returns immediately and
349 // connecting the server happens in background.
350 //
351 // Use of this feature is not recommended. For more information, please see:
352 // https://github.com/grpc/grpc-go/blob/master/Documentation/anti-patterns.md
353 //
354 // Deprecated: this DialOption is not supported by NewClient.
355 // Will be supported throughout 1.x.
356 func WithBlock() DialOption {
357 return newFuncDialOption(func(o *dialOptions) {
358 o.block = true
359 })
360 }
361 362 // WithReturnConnectionError returns a DialOption which makes the client connection
363 // return a string containing both the last connection error that occurred and
364 // the context.DeadlineExceeded error.
365 // Implies WithBlock()
366 //
367 // Use of this feature is not recommended. For more information, please see:
368 // https://github.com/grpc/grpc-go/blob/master/Documentation/anti-patterns.md
369 //
370 // Deprecated: this DialOption is not supported by NewClient.
371 // Will be supported throughout 1.x.
372 func WithReturnConnectionError() DialOption {
373 return newFuncDialOption(func(o *dialOptions) {
374 o.block = true
375 o.returnLastError = true
376 })
377 }
378 379 // WithInsecure returns a DialOption which disables transport security for this
380 // ClientConn. Under the hood, it uses insecure.NewCredentials().
381 //
382 // Note that using this DialOption with per-RPC credentials (through
383 // WithCredentialsBundle or WithPerRPCCredentials) which require transport
384 // security is incompatible and will cause RPCs to fail.
385 //
386 // Deprecated: use WithTransportCredentials and insecure.NewCredentials()
387 // instead. Will be supported throughout 1.x.
388 func WithInsecure() DialOption {
389 return newFuncDialOption(func(o *dialOptions) {
390 o.copts.TransportCredentials = insecure.NewCredentials()
391 })
392 }
393 394 // WithNoProxy returns a DialOption which disables the use of proxies for this
395 // ClientConn. This is ignored if WithDialer or WithContextDialer are used.
396 //
397 // # Experimental
398 //
399 // Notice: This API is EXPERIMENTAL and may be changed or removed in a
400 // later release.
401 func WithNoProxy() DialOption {
402 return newFuncDialOption(func(o *dialOptions) {
403 o.useProxy = false
404 })
405 }
406 407 // WithLocalDNSResolution forces local DNS name resolution even when a proxy is
408 // specified in the environment. By default, the server name is provided
409 // directly to the proxy as part of the CONNECT handshake. This is ignored if
410 // WithNoProxy is used.
411 //
412 // # Experimental
413 //
414 // Notice: This API is EXPERIMENTAL and may be changed or removed in a
415 // later release.
416 func WithLocalDNSResolution() DialOption {
417 return newFuncDialOption(func(o *dialOptions) {
418 o.enableLocalDNSResolution = true
419 })
420 }
421 422 // WithTransportCredentials returns a DialOption which configures a connection
423 // level security credentials (e.g., TLS/SSL). This should not be used together
424 // with WithCredentialsBundle.
425 func WithTransportCredentials(creds credentials.TransportCredentials) DialOption {
426 return newFuncDialOption(func(o *dialOptions) {
427 o.copts.TransportCredentials = creds
428 })
429 }
430 431 // WithPerRPCCredentials returns a DialOption which sets credentials and places
432 // auth state on each outbound RPC.
433 func WithPerRPCCredentials(creds credentials.PerRPCCredentials) DialOption {
434 return newFuncDialOption(func(o *dialOptions) {
435 o.copts.PerRPCCredentials = append(o.copts.PerRPCCredentials, creds)
436 })
437 }
438 439 // WithCredentialsBundle returns a DialOption to set a credentials bundle for
440 // the ClientConn.WithCreds. This should not be used together with
441 // WithTransportCredentials.
442 //
443 // # Experimental
444 //
445 // Notice: This API is EXPERIMENTAL and may be changed or removed in a
446 // later release.
447 func WithCredentialsBundle(b credentials.Bundle) DialOption {
448 return newFuncDialOption(func(o *dialOptions) {
449 o.copts.CredsBundle = b
450 })
451 }
452 453 // WithTimeout returns a DialOption that configures a timeout for dialing a
454 // ClientConn initially. This is valid if and only if WithBlock() is present.
455 //
456 // Deprecated: this DialOption is not supported by NewClient.
457 // Will be supported throughout 1.x.
458 func WithTimeout(d time.Duration) DialOption {
459 return newFuncDialOption(func(o *dialOptions) {
460 o.timeout = d
461 })
462 }
463 464 // WithContextDialer returns a DialOption that sets a dialer to create
465 // connections. If FailOnNonTempDialError() is set to true, and an error is
466 // returned by f, gRPC checks the error's Temporary() method to decide if it
467 // should try to reconnect to the network address.
468 //
469 // Note that gRPC by default performs name resolution on the target passed to
470 // NewClient. To bypass name resolution and cause the target string to be
471 // passed directly to the dialer here instead, use the "passthrough" resolver
472 // by specifying it in the target string, e.g. "passthrough:target".
473 //
474 // Note: All supported releases of Go (as of December 2023) override the OS
475 // defaults for TCP keepalive time and interval to 15s. To enable TCP keepalive
476 // with OS defaults for keepalive time and interval, use a net.Dialer that sets
477 // the KeepAlive field to a negative value, and sets the SO_KEEPALIVE socket
478 // option to true from the Control field. For a concrete example of how to do
479 // this, see internal.NetDialerWithTCPKeepalive().
480 //
481 // For more information, please see [issue 23459] in the Go GitHub repo.
482 //
483 // [issue 23459]: https://github.com/golang/go/issues/23459
484 func WithContextDialer(f func(context.Context, string) (net.Conn, error)) DialOption {
485 return newFuncDialOption(func(o *dialOptions) {
486 o.copts.Dialer = f
487 })
488 }
489 490 // WithDialer returns a DialOption that specifies a function to use for dialing
491 // network addresses. If FailOnNonTempDialError() is set to true, and an error
492 // is returned by f, gRPC checks the error's Temporary() method to decide if it
493 // should try to reconnect to the network address.
494 //
495 // Deprecated: use WithContextDialer instead. Will be supported throughout
496 // 1.x.
497 func WithDialer(f func(string, time.Duration) (net.Conn, error)) DialOption {
498 return WithContextDialer(
499 func(ctx context.Context, addr string) (net.Conn, error) {
500 if deadline, ok := ctx.Deadline(); ok {
501 return f(addr, time.Until(deadline))
502 }
503 return f(addr, 0)
504 })
505 }
506 507 // WithStatsHandler returns a DialOption that specifies the stats handler for
508 // all the RPCs and underlying network connections in this ClientConn.
509 func WithStatsHandler(h stats.Handler) DialOption {
510 return newFuncDialOption(func(o *dialOptions) {
511 if h == nil {
512 logger.Error("ignoring nil parameter in grpc.WithStatsHandler ClientOption")
513 // Do not allow a nil stats handler, which would otherwise cause
514 // panics.
515 return
516 }
517 o.copts.StatsHandlers = append(o.copts.StatsHandlers, h)
518 })
519 }
520 521 // withBinaryLogger returns a DialOption that specifies the binary logger for
522 // this ClientConn.
523 func withBinaryLogger(bl binarylog.Logger) DialOption {
524 return newFuncDialOption(func(o *dialOptions) {
525 o.binaryLogger = bl
526 })
527 }
528 529 // FailOnNonTempDialError returns a DialOption that specifies if gRPC fails on
530 // non-temporary dial errors. If f is true, and dialer returns a non-temporary
531 // error, gRPC will fail the connection to the network address and won't try to
532 // reconnect. The default value of FailOnNonTempDialError is false.
533 //
534 // FailOnNonTempDialError only affects the initial dial, and does not do
535 // anything useful unless you are also using WithBlock().
536 //
537 // Use of this feature is not recommended. For more information, please see:
538 // https://github.com/grpc/grpc-go/blob/master/Documentation/anti-patterns.md
539 //
540 // Deprecated: this DialOption is not supported by NewClient.
541 // This API may be changed or removed in a
542 // later release.
543 func FailOnNonTempDialError(f bool) DialOption {
544 return newFuncDialOption(func(o *dialOptions) {
545 o.copts.FailOnNonTempDialError = f
546 })
547 }
548 549 // WithUserAgent returns a DialOption that specifies a user agent string for all
550 // the RPCs.
551 func WithUserAgent(s string) DialOption {
552 return newFuncDialOption(func(o *dialOptions) {
553 o.copts.UserAgent = s + " " + grpcUA
554 })
555 }
556 557 // WithKeepaliveParams returns a DialOption that specifies keepalive parameters
558 // for the client transport.
559 //
560 // Keepalive is disabled by default.
561 func WithKeepaliveParams(kp keepalive.ClientParameters) DialOption {
562 if kp.Time < internal.KeepaliveMinPingTime {
563 logger.Warningf("Adjusting keepalive ping interval to minimum period of %v", internal.KeepaliveMinPingTime)
564 kp.Time = internal.KeepaliveMinPingTime
565 }
566 return newFuncDialOption(func(o *dialOptions) {
567 o.copts.KeepaliveParams = kp
568 })
569 }
570 571 // WithUnaryInterceptor returns a DialOption that specifies the interceptor for
572 // unary RPCs.
573 func WithUnaryInterceptor(f UnaryClientInterceptor) DialOption {
574 return newFuncDialOption(func(o *dialOptions) {
575 o.unaryInt = f
576 })
577 }
578 579 // WithChainUnaryInterceptor returns a DialOption that specifies the chained
580 // interceptor for unary RPCs. The first interceptor will be the outer most,
581 // while the last interceptor will be the inner most wrapper around the real call.
582 // All interceptors added by this method will be chained, and the interceptor
583 // defined by WithUnaryInterceptor will always be prepended to the chain.
584 func WithChainUnaryInterceptor(interceptors ...UnaryClientInterceptor) DialOption {
585 return newFuncDialOption(func(o *dialOptions) {
586 o.chainUnaryInts = append(o.chainUnaryInts, interceptors...)
587 })
588 }
589 590 // WithStreamInterceptor returns a DialOption that specifies the interceptor for
591 // streaming RPCs.
592 func WithStreamInterceptor(f StreamClientInterceptor) DialOption {
593 return newFuncDialOption(func(o *dialOptions) {
594 o.streamInt = f
595 })
596 }
597 598 // WithChainStreamInterceptor returns a DialOption that specifies the chained
599 // interceptor for streaming RPCs. The first interceptor will be the outer most,
600 // while the last interceptor will be the inner most wrapper around the real call.
601 // All interceptors added by this method will be chained, and the interceptor
602 // defined by WithStreamInterceptor will always be prepended to the chain.
603 func WithChainStreamInterceptor(interceptors ...StreamClientInterceptor) DialOption {
604 return newFuncDialOption(func(o *dialOptions) {
605 o.chainStreamInts = append(o.chainStreamInts, interceptors...)
606 })
607 }
608 609 // WithAuthority returns a DialOption that specifies the value to be used as the
610 // :authority pseudo-header and as the server name in authentication handshake.
611 // This overrides all other ways of setting authority on the channel, but can be
612 // overridden per-call by using grpc.CallAuthority.
613 func WithAuthority(a string) DialOption {
614 return newFuncDialOption(func(o *dialOptions) {
615 o.authority = a
616 })
617 }
618 619 // WithChannelzParentID returns a DialOption that specifies the channelz ID of
620 // current ClientConn's parent. This function is used in nested channel creation
621 // (e.g. grpclb dial).
622 //
623 // # Experimental
624 //
625 // Notice: This API is EXPERIMENTAL and may be changed or removed in a
626 // later release.
627 func WithChannelzParentID(c channelz.Identifier) DialOption {
628 return newFuncDialOption(func(o *dialOptions) {
629 o.channelzParent = c
630 })
631 }
632 633 // WithDisableServiceConfig returns a DialOption that causes gRPC to ignore any
634 // service config provided by the resolver and provides a hint to the resolver
635 // to not fetch service configs.
636 //
637 // Note that this dial option only disables service config from resolver. If
638 // default service config is provided, gRPC will use the default service config.
639 func WithDisableServiceConfig() DialOption {
640 return newFuncDialOption(func(o *dialOptions) {
641 o.disableServiceConfig = true
642 })
643 }
644 645 // WithDefaultServiceConfig returns a DialOption that configures the default
646 // service config, which will be used in cases where:
647 //
648 // 1. WithDisableServiceConfig is also used, or
649 //
650 // 2. The name resolver does not provide a service config or provides an
651 // invalid service config.
652 //
653 // The parameter s is the JSON representation of the default service config.
654 // For more information about service configs, see:
655 // https://github.com/grpc/grpc/blob/master/doc/service_config.md
656 // For a simple example of usage, see:
657 // examples/features/load_balancing/client/main.go
658 func WithDefaultServiceConfig(s string) DialOption {
659 return newFuncDialOption(func(o *dialOptions) {
660 o.defaultServiceConfigRawJSON = &s
661 })
662 }
663 664 // WithDisableRetry returns a DialOption that disables retries, even if the
665 // service config enables them. This does not impact transparent retries, which
666 // will happen automatically if no data is written to the wire or if the RPC is
667 // unprocessed by the remote server.
668 func WithDisableRetry() DialOption {
669 return newFuncDialOption(func(o *dialOptions) {
670 o.disableRetry = true
671 })
672 }
673 674 // MaxHeaderListSizeDialOption is a DialOption that specifies the maximum
675 // (uncompressed) size of header list that the client is prepared to accept.
676 type MaxHeaderListSizeDialOption struct {
677 MaxHeaderListSize uint32
678 }
679 680 func (o MaxHeaderListSizeDialOption) apply(do *dialOptions) {
681 do.copts.MaxHeaderListSize = &o.MaxHeaderListSize
682 }
683 684 // WithMaxHeaderListSize returns a DialOption that specifies the maximum
685 // (uncompressed) size of header list that the client is prepared to accept.
686 func WithMaxHeaderListSize(s uint32) DialOption {
687 return MaxHeaderListSizeDialOption{
688 MaxHeaderListSize: s,
689 }
690 }
691 692 // WithDisableHealthCheck disables the LB channel health checking for all
693 // SubConns of this ClientConn.
694 //
695 // # Experimental
696 //
697 // Notice: This API is EXPERIMENTAL and may be changed or removed in a
698 // later release.
699 func WithDisableHealthCheck() DialOption {
700 return newFuncDialOption(func(o *dialOptions) {
701 o.disableHealthCheck = true
702 })
703 }
704 705 func defaultDialOptions() dialOptions {
706 return dialOptions{
707 copts: transport.ConnectOptions{
708 ReadBufferSize: defaultReadBufSize,
709 WriteBufferSize: defaultWriteBufSize,
710 UserAgent: grpcUA,
711 BufferPool: mem.DefaultBufferPool(),
712 },
713 bs: internalbackoff.DefaultExponential,
714 idleTimeout: 30 * time.Minute,
715 defaultScheme: "dns",
716 maxCallAttempts: defaultMaxCallAttempts,
717 useProxy: true,
718 enableLocalDNSResolution: false,
719 }
720 }
721 722 // withMinConnectDeadline specifies the function that clientconn uses to
723 // get minConnectDeadline. This can be used to make connection attempts happen
724 // faster/slower.
725 //
726 // For testing purpose only.
727 func withMinConnectDeadline(f func() time.Duration) DialOption {
728 return newFuncDialOption(func(o *dialOptions) {
729 o.minConnectTimeout = f
730 })
731 }
732 733 // withDefaultScheme is used to allow Dial to use "passthrough" as the default
734 // name resolver, while NewClient uses "dns" otherwise.
735 func withDefaultScheme(s string) DialOption {
736 return newFuncDialOption(func(o *dialOptions) {
737 o.defaultScheme = s
738 })
739 }
740 741 // WithResolvers allows a list of resolver implementations to be registered
742 // locally with the ClientConn without needing to be globally registered via
743 // resolver.Register. They will be matched against the scheme used for the
744 // current Dial only, and will take precedence over the global registry.
745 //
746 // # Experimental
747 //
748 // Notice: This API is EXPERIMENTAL and may be changed or removed in a
749 // later release.
750 func WithResolvers(rs ...resolver.Builder) DialOption {
751 return newFuncDialOption(func(o *dialOptions) {
752 o.resolvers = append(o.resolvers, rs...)
753 })
754 }
755 756 // WithIdleTimeout returns a DialOption that configures an idle timeout for the
757 // channel. If the channel is idle for the configured timeout, i.e there are no
758 // ongoing RPCs and no new RPCs are initiated, the channel will enter idle mode
759 // and as a result the name resolver and load balancer will be shut down. The
760 // channel will exit idle mode when the Connect() method is called or when an
761 // RPC is initiated.
762 //
763 // A default timeout of 30 minutes will be used if this dial option is not set
764 // at dial time and idleness can be disabled by passing a timeout of zero.
765 //
766 // # Experimental
767 //
768 // Notice: This API is EXPERIMENTAL and may be changed or removed in a
769 // later release.
770 func WithIdleTimeout(d time.Duration) DialOption {
771 return newFuncDialOption(func(o *dialOptions) {
772 o.idleTimeout = d
773 })
774 }
775 776 // WithMaxCallAttempts returns a DialOption that configures the maximum number
777 // of attempts per call (including retries and hedging) using the channel.
778 // Service owners may specify a higher value for these parameters, but higher
779 // values will be treated as equal to the maximum value by the client
780 // implementation. This mitigates security concerns related to the service
781 // config being transferred to the client via DNS.
782 //
783 // A value of 5 will be used if this dial option is not set or n < 2.
784 func WithMaxCallAttempts(n int) DialOption {
785 return newFuncDialOption(func(o *dialOptions) {
786 if n < 2 {
787 n = defaultMaxCallAttempts
788 }
789 o.maxCallAttempts = n
790 })
791 }
792 793 func withBufferPool(bufferPool mem.BufferPool) DialOption {
794 return newFuncDialOption(func(o *dialOptions) {
795 o.copts.BufferPool = bufferPool
796 })
797 }
798