blob: 7a497237bbd3365a077a67cf4aaee7caa702c379 [file] [log] [blame]
khenaidoo5fc5cea2021-08-11 17:39:16 -04001/*
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
19package grpc
20
21import (
22 "context"
23 "fmt"
24 "net"
25 "time"
26
27 "google.golang.org/grpc/backoff"
28 "google.golang.org/grpc/balancer"
29 "google.golang.org/grpc/credentials"
30 "google.golang.org/grpc/internal"
31 internalbackoff "google.golang.org/grpc/internal/backoff"
32 "google.golang.org/grpc/internal/envconfig"
33 "google.golang.org/grpc/internal/transport"
34 "google.golang.org/grpc/keepalive"
35 "google.golang.org/grpc/resolver"
36 "google.golang.org/grpc/stats"
37)
38
39// dialOptions configure a Dial call. dialOptions are set by the DialOption
40// values passed to Dial.
41type dialOptions struct {
42 unaryInt UnaryClientInterceptor
43 streamInt StreamClientInterceptor
44
45 chainUnaryInts []UnaryClientInterceptor
46 chainStreamInts []StreamClientInterceptor
47
48 cp Compressor
49 dc Decompressor
50 bs internalbackoff.Strategy
51 block bool
52 returnLastError bool
53 insecure bool
54 timeout time.Duration
55 scChan <-chan ServiceConfig
56 authority string
57 copts transport.ConnectOptions
58 callOptions []CallOption
59 // This is used by WithBalancerName dial option.
60 balancerBuilder balancer.Builder
61 channelzParentID int64
62 disableServiceConfig bool
63 disableRetry bool
64 disableHealthCheck bool
65 healthCheckFunc internal.HealthChecker
66 minConnectTimeout func() time.Duration
67 defaultServiceConfig *ServiceConfig // defaultServiceConfig is parsed from defaultServiceConfigRawJSON.
68 defaultServiceConfigRawJSON *string
69 resolvers []resolver.Builder
70}
71
72// DialOption configures how we set up the connection.
73type DialOption interface {
74 apply(*dialOptions)
75}
76
77// EmptyDialOption does not alter the dial configuration. It can be embedded in
78// another structure to build custom dial options.
79//
80// Experimental
81//
82// Notice: This type is EXPERIMENTAL and may be changed or removed in a
83// later release.
84type EmptyDialOption struct{}
85
86func (EmptyDialOption) apply(*dialOptions) {}
87
88// funcDialOption wraps a function that modifies dialOptions into an
89// implementation of the DialOption interface.
90type funcDialOption struct {
91 f func(*dialOptions)
92}
93
94func (fdo *funcDialOption) apply(do *dialOptions) {
95 fdo.f(do)
96}
97
98func newFuncDialOption(f func(*dialOptions)) *funcDialOption {
99 return &funcDialOption{
100 f: f,
101 }
102}
103
104// WithWriteBufferSize determines how much data can be batched before doing a
105// write on the wire. The corresponding memory allocation for this buffer will
106// be twice the size to keep syscalls low. The default value for this buffer is
107// 32KB.
108//
109// Zero will disable the write buffer such that each write will be on underlying
110// connection. Note: A Send call may not directly translate to a write.
111func WithWriteBufferSize(s int) DialOption {
112 return newFuncDialOption(func(o *dialOptions) {
113 o.copts.WriteBufferSize = s
114 })
115}
116
117// WithReadBufferSize lets you set the size of read buffer, this determines how
118// much data can be read at most for each read syscall.
119//
120// The default value for this buffer is 32KB. Zero will disable read buffer for
121// a connection so data framer can access the underlying conn directly.
122func WithReadBufferSize(s int) DialOption {
123 return newFuncDialOption(func(o *dialOptions) {
124 o.copts.ReadBufferSize = s
125 })
126}
127
128// WithInitialWindowSize returns a DialOption which sets the value for initial
129// window size on a stream. The lower bound for window size is 64K and any value
130// smaller than that will be ignored.
131func WithInitialWindowSize(s int32) DialOption {
132 return newFuncDialOption(func(o *dialOptions) {
133 o.copts.InitialWindowSize = s
134 })
135}
136
137// WithInitialConnWindowSize returns a DialOption which sets the value for
138// initial window size on a connection. The lower bound for window size is 64K
139// and any value smaller than that will be ignored.
140func WithInitialConnWindowSize(s int32) DialOption {
141 return newFuncDialOption(func(o *dialOptions) {
142 o.copts.InitialConnWindowSize = s
143 })
144}
145
146// WithMaxMsgSize returns a DialOption which sets the maximum message size the
147// client can receive.
148//
149// Deprecated: use WithDefaultCallOptions(MaxCallRecvMsgSize(s)) instead. Will
150// be supported throughout 1.x.
151func WithMaxMsgSize(s int) DialOption {
152 return WithDefaultCallOptions(MaxCallRecvMsgSize(s))
153}
154
155// WithDefaultCallOptions returns a DialOption which sets the default
156// CallOptions for calls over the connection.
157func WithDefaultCallOptions(cos ...CallOption) DialOption {
158 return newFuncDialOption(func(o *dialOptions) {
159 o.callOptions = append(o.callOptions, cos...)
160 })
161}
162
163// WithCodec returns a DialOption which sets a codec for message marshaling and
164// unmarshaling.
165//
166// Deprecated: use WithDefaultCallOptions(ForceCodec(_)) instead. Will be
167// supported throughout 1.x.
168func WithCodec(c Codec) DialOption {
169 return WithDefaultCallOptions(CallCustomCodec(c))
170}
171
172// WithCompressor returns a DialOption which sets a Compressor to use for
173// message compression. It has lower priority than the compressor set by the
174// UseCompressor CallOption.
175//
176// Deprecated: use UseCompressor instead. Will be supported throughout 1.x.
177func WithCompressor(cp Compressor) DialOption {
178 return newFuncDialOption(func(o *dialOptions) {
179 o.cp = cp
180 })
181}
182
183// WithDecompressor returns a DialOption which sets a Decompressor to use for
184// incoming message decompression. If incoming response messages are encoded
185// using the decompressor's Type(), it will be used. Otherwise, the message
186// encoding will be used to look up the compressor registered via
187// encoding.RegisterCompressor, which will then be used to decompress the
188// message. If no compressor is registered for the encoding, an Unimplemented
189// status error will be returned.
190//
191// Deprecated: use encoding.RegisterCompressor instead. Will be supported
192// throughout 1.x.
193func WithDecompressor(dc Decompressor) DialOption {
194 return newFuncDialOption(func(o *dialOptions) {
195 o.dc = dc
196 })
197}
198
199// WithBalancerName sets the balancer that the ClientConn will be initialized
200// with. Balancer registered with balancerName will be used. This function
201// panics if no balancer was registered by balancerName.
202//
203// The balancer cannot be overridden by balancer option specified by service
204// config.
205//
206// Deprecated: use WithDefaultServiceConfig and WithDisableServiceConfig
207// instead. Will be removed in a future 1.x release.
208func WithBalancerName(balancerName string) DialOption {
209 builder := balancer.Get(balancerName)
210 if builder == nil {
211 panic(fmt.Sprintf("grpc.WithBalancerName: no balancer is registered for name %v", balancerName))
212 }
213 return newFuncDialOption(func(o *dialOptions) {
214 o.balancerBuilder = builder
215 })
216}
217
218// WithServiceConfig returns a DialOption which has a channel to read the
219// service configuration.
220//
221// Deprecated: service config should be received through name resolver or via
222// WithDefaultServiceConfig, as specified at
223// https://github.com/grpc/grpc/blob/master/doc/service_config.md. Will be
224// removed in a future 1.x release.
225func WithServiceConfig(c <-chan ServiceConfig) DialOption {
226 return newFuncDialOption(func(o *dialOptions) {
227 o.scChan = c
228 })
229}
230
231// WithConnectParams configures the dialer to use the provided ConnectParams.
232//
233// The backoff configuration specified as part of the ConnectParams overrides
234// all defaults specified in
235// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. Consider
236// using the backoff.DefaultConfig as a base, in cases where you want to
237// override only a subset of the backoff configuration.
238//
239// Experimental
240//
241// Notice: This API is EXPERIMENTAL and may be changed or removed in a
242// later release.
243func WithConnectParams(p ConnectParams) DialOption {
244 return newFuncDialOption(func(o *dialOptions) {
245 o.bs = internalbackoff.Exponential{Config: p.Backoff}
246 o.minConnectTimeout = func() time.Duration {
247 return p.MinConnectTimeout
248 }
249 })
250}
251
252// WithBackoffMaxDelay configures the dialer to use the provided maximum delay
253// when backing off after failed connection attempts.
254//
255// Deprecated: use WithConnectParams instead. Will be supported throughout 1.x.
256func WithBackoffMaxDelay(md time.Duration) DialOption {
257 return WithBackoffConfig(BackoffConfig{MaxDelay: md})
258}
259
260// WithBackoffConfig configures the dialer to use the provided backoff
261// parameters after connection failures.
262//
263// Deprecated: use WithConnectParams instead. Will be supported throughout 1.x.
264func WithBackoffConfig(b BackoffConfig) DialOption {
265 bc := backoff.DefaultConfig
266 bc.MaxDelay = b.MaxDelay
267 return withBackoff(internalbackoff.Exponential{Config: bc})
268}
269
270// withBackoff sets the backoff strategy used for connectRetryNum after a failed
271// connection attempt.
272//
273// This can be exported if arbitrary backoff strategies are allowed by gRPC.
274func withBackoff(bs internalbackoff.Strategy) DialOption {
275 return newFuncDialOption(func(o *dialOptions) {
276 o.bs = bs
277 })
278}
279
280// WithBlock returns a DialOption which makes caller of Dial blocks until the
281// underlying connection is up. Without this, Dial returns immediately and
282// connecting the server happens in background.
283func WithBlock() DialOption {
284 return newFuncDialOption(func(o *dialOptions) {
285 o.block = true
286 })
287}
288
289// WithReturnConnectionError returns a DialOption which makes the client connection
290// return a string containing both the last connection error that occurred and
291// the context.DeadlineExceeded error.
292// Implies WithBlock()
293//
294// Experimental
295//
296// Notice: This API is EXPERIMENTAL and may be changed or removed in a
297// later release.
298func WithReturnConnectionError() DialOption {
299 return newFuncDialOption(func(o *dialOptions) {
300 o.block = true
301 o.returnLastError = true
302 })
303}
304
305// WithInsecure returns a DialOption which disables transport security for this
306// ClientConn. Note that transport security is required unless WithInsecure is
307// set.
308func WithInsecure() DialOption {
309 return newFuncDialOption(func(o *dialOptions) {
310 o.insecure = true
311 })
312}
313
314// WithNoProxy returns a DialOption which disables the use of proxies for this
315// ClientConn. This is ignored if WithDialer or WithContextDialer are used.
316//
317// Experimental
318//
319// Notice: This API is EXPERIMENTAL and may be changed or removed in a
320// later release.
321func WithNoProxy() DialOption {
322 return newFuncDialOption(func(o *dialOptions) {
323 o.copts.UseProxy = false
324 })
325}
326
327// WithTransportCredentials returns a DialOption which configures a connection
328// level security credentials (e.g., TLS/SSL). This should not be used together
329// with WithCredentialsBundle.
330func WithTransportCredentials(creds credentials.TransportCredentials) DialOption {
331 return newFuncDialOption(func(o *dialOptions) {
332 o.copts.TransportCredentials = creds
333 })
334}
335
336// WithPerRPCCredentials returns a DialOption which sets credentials and places
337// auth state on each outbound RPC.
338func WithPerRPCCredentials(creds credentials.PerRPCCredentials) DialOption {
339 return newFuncDialOption(func(o *dialOptions) {
340 o.copts.PerRPCCredentials = append(o.copts.PerRPCCredentials, creds)
341 })
342}
343
344// WithCredentialsBundle returns a DialOption to set a credentials bundle for
345// the ClientConn.WithCreds. This should not be used together with
346// WithTransportCredentials.
347//
348// Experimental
349//
350// Notice: This API is EXPERIMENTAL and may be changed or removed in a
351// later release.
352func WithCredentialsBundle(b credentials.Bundle) DialOption {
353 return newFuncDialOption(func(o *dialOptions) {
354 o.copts.CredsBundle = b
355 })
356}
357
358// WithTimeout returns a DialOption that configures a timeout for dialing a
359// ClientConn initially. This is valid if and only if WithBlock() is present.
360//
361// Deprecated: use DialContext instead of Dial and context.WithTimeout
362// instead. Will be supported throughout 1.x.
363func WithTimeout(d time.Duration) DialOption {
364 return newFuncDialOption(func(o *dialOptions) {
365 o.timeout = d
366 })
367}
368
369// WithContextDialer returns a DialOption that sets a dialer to create
370// connections. If FailOnNonTempDialError() is set to true, and an error is
371// returned by f, gRPC checks the error's Temporary() method to decide if it
372// should try to reconnect to the network address.
373func WithContextDialer(f func(context.Context, string) (net.Conn, error)) DialOption {
374 return newFuncDialOption(func(o *dialOptions) {
375 o.copts.Dialer = f
376 })
377}
378
379func init() {
380 internal.WithHealthCheckFunc = withHealthCheckFunc
381}
382
383// WithDialer returns a DialOption that specifies a function to use for dialing
384// network addresses. If FailOnNonTempDialError() is set to true, and an error
385// is returned by f, gRPC checks the error's Temporary() method to decide if it
386// should try to reconnect to the network address.
387//
388// Deprecated: use WithContextDialer instead. Will be supported throughout
389// 1.x.
390func WithDialer(f func(string, time.Duration) (net.Conn, error)) DialOption {
391 return WithContextDialer(
392 func(ctx context.Context, addr string) (net.Conn, error) {
393 if deadline, ok := ctx.Deadline(); ok {
394 return f(addr, time.Until(deadline))
395 }
396 return f(addr, 0)
397 })
398}
399
400// WithStatsHandler returns a DialOption that specifies the stats handler for
401// all the RPCs and underlying network connections in this ClientConn.
402func WithStatsHandler(h stats.Handler) DialOption {
403 return newFuncDialOption(func(o *dialOptions) {
404 o.copts.StatsHandler = h
405 })
406}
407
408// FailOnNonTempDialError returns a DialOption that specifies if gRPC fails on
409// non-temporary dial errors. If f is true, and dialer returns a non-temporary
410// error, gRPC will fail the connection to the network address and won't try to
411// reconnect. The default value of FailOnNonTempDialError is false.
412//
413// FailOnNonTempDialError only affects the initial dial, and does not do
414// anything useful unless you are also using WithBlock().
415//
416// Experimental
417//
418// Notice: This API is EXPERIMENTAL and may be changed or removed in a
419// later release.
420func FailOnNonTempDialError(f bool) DialOption {
421 return newFuncDialOption(func(o *dialOptions) {
422 o.copts.FailOnNonTempDialError = f
423 })
424}
425
426// WithUserAgent returns a DialOption that specifies a user agent string for all
427// the RPCs.
428func WithUserAgent(s string) DialOption {
429 return newFuncDialOption(func(o *dialOptions) {
430 o.copts.UserAgent = s
431 })
432}
433
434// WithKeepaliveParams returns a DialOption that specifies keepalive parameters
435// for the client transport.
436func WithKeepaliveParams(kp keepalive.ClientParameters) DialOption {
437 if kp.Time < internal.KeepaliveMinPingTime {
438 logger.Warningf("Adjusting keepalive ping interval to minimum period of %v", internal.KeepaliveMinPingTime)
439 kp.Time = internal.KeepaliveMinPingTime
440 }
441 return newFuncDialOption(func(o *dialOptions) {
442 o.copts.KeepaliveParams = kp
443 })
444}
445
446// WithUnaryInterceptor returns a DialOption that specifies the interceptor for
447// unary RPCs.
448func WithUnaryInterceptor(f UnaryClientInterceptor) DialOption {
449 return newFuncDialOption(func(o *dialOptions) {
450 o.unaryInt = f
451 })
452}
453
454// WithChainUnaryInterceptor returns a DialOption that specifies the chained
455// interceptor for unary RPCs. The first interceptor will be the outer most,
456// while the last interceptor will be the inner most wrapper around the real call.
457// All interceptors added by this method will be chained, and the interceptor
458// defined by WithUnaryInterceptor will always be prepended to the chain.
459func WithChainUnaryInterceptor(interceptors ...UnaryClientInterceptor) DialOption {
460 return newFuncDialOption(func(o *dialOptions) {
461 o.chainUnaryInts = append(o.chainUnaryInts, interceptors...)
462 })
463}
464
465// WithStreamInterceptor returns a DialOption that specifies the interceptor for
466// streaming RPCs.
467func WithStreamInterceptor(f StreamClientInterceptor) DialOption {
468 return newFuncDialOption(func(o *dialOptions) {
469 o.streamInt = f
470 })
471}
472
473// WithChainStreamInterceptor returns a DialOption that specifies the chained
474// interceptor for streaming RPCs. The first interceptor will be the outer most,
475// while the last interceptor will be the inner most wrapper around the real call.
476// All interceptors added by this method will be chained, and the interceptor
477// defined by WithStreamInterceptor will always be prepended to the chain.
478func WithChainStreamInterceptor(interceptors ...StreamClientInterceptor) DialOption {
479 return newFuncDialOption(func(o *dialOptions) {
480 o.chainStreamInts = append(o.chainStreamInts, interceptors...)
481 })
482}
483
484// WithAuthority returns a DialOption that specifies the value to be used as the
485// :authority pseudo-header. This value only works with WithInsecure and has no
486// effect if TransportCredentials are present.
487func WithAuthority(a string) DialOption {
488 return newFuncDialOption(func(o *dialOptions) {
489 o.authority = a
490 })
491}
492
493// WithChannelzParentID returns a DialOption that specifies the channelz ID of
494// current ClientConn's parent. This function is used in nested channel creation
495// (e.g. grpclb dial).
496//
497// Experimental
498//
499// Notice: This API is EXPERIMENTAL and may be changed or removed in a
500// later release.
501func WithChannelzParentID(id int64) DialOption {
502 return newFuncDialOption(func(o *dialOptions) {
503 o.channelzParentID = id
504 })
505}
506
507// WithDisableServiceConfig returns a DialOption that causes gRPC to ignore any
508// service config provided by the resolver and provides a hint to the resolver
509// to not fetch service configs.
510//
511// Note that this dial option only disables service config from resolver. If
512// default service config is provided, gRPC will use the default service config.
513func WithDisableServiceConfig() DialOption {
514 return newFuncDialOption(func(o *dialOptions) {
515 o.disableServiceConfig = true
516 })
517}
518
519// WithDefaultServiceConfig returns a DialOption that configures the default
520// service config, which will be used in cases where:
521//
522// 1. WithDisableServiceConfig is also used.
523// 2. Resolver does not return a service config or if the resolver returns an
524// invalid service config.
525//
526// Experimental
527//
528// Notice: This API is EXPERIMENTAL and may be changed or removed in a
529// later release.
530func WithDefaultServiceConfig(s string) DialOption {
531 return newFuncDialOption(func(o *dialOptions) {
532 o.defaultServiceConfigRawJSON = &s
533 })
534}
535
536// WithDisableRetry returns a DialOption that disables retries, even if the
537// service config enables them. This does not impact transparent retries, which
538// will happen automatically if no data is written to the wire or if the RPC is
539// unprocessed by the remote server.
540//
541// Retry support is currently disabled by default, but will be enabled by
542// default in the future. Until then, it may be enabled by setting the
543// environment variable "GRPC_GO_RETRY" to "on".
544//
545// Experimental
546//
547// Notice: This API is EXPERIMENTAL and may be changed or removed in a
548// later release.
549func WithDisableRetry() DialOption {
550 return newFuncDialOption(func(o *dialOptions) {
551 o.disableRetry = true
552 })
553}
554
555// WithMaxHeaderListSize returns a DialOption that specifies the maximum
556// (uncompressed) size of header list that the client is prepared to accept.
557func WithMaxHeaderListSize(s uint32) DialOption {
558 return newFuncDialOption(func(o *dialOptions) {
559 o.copts.MaxHeaderListSize = &s
560 })
561}
562
563// WithDisableHealthCheck disables the LB channel health checking for all
564// SubConns of this ClientConn.
565//
566// Experimental
567//
568// Notice: This API is EXPERIMENTAL and may be changed or removed in a
569// later release.
570func WithDisableHealthCheck() DialOption {
571 return newFuncDialOption(func(o *dialOptions) {
572 o.disableHealthCheck = true
573 })
574}
575
576// withHealthCheckFunc replaces the default health check function with the
577// provided one. It makes tests easier to change the health check function.
578//
579// For testing purpose only.
580func withHealthCheckFunc(f internal.HealthChecker) DialOption {
581 return newFuncDialOption(func(o *dialOptions) {
582 o.healthCheckFunc = f
583 })
584}
585
586func defaultDialOptions() dialOptions {
587 return dialOptions{
588 disableRetry: !envconfig.Retry,
589 healthCheckFunc: internal.HealthCheckFunc,
590 copts: transport.ConnectOptions{
591 WriteBufferSize: defaultWriteBufSize,
592 ReadBufferSize: defaultReadBufSize,
593 UseProxy: true,
594 },
595 }
596}
597
598// withGetMinConnectDeadline specifies the function that clientconn uses to
599// get minConnectDeadline. This can be used to make connection attempts happen
600// faster/slower.
601//
602// For testing purpose only.
603func withMinConnectDeadline(f func() time.Duration) DialOption {
604 return newFuncDialOption(func(o *dialOptions) {
605 o.minConnectTimeout = f
606 })
607}
608
609// WithResolvers allows a list of resolver implementations to be registered
610// locally with the ClientConn without needing to be globally registered via
611// resolver.Register. They will be matched against the scheme used for the
612// current Dial only, and will take precedence over the global registry.
613//
614// Experimental
615//
616// Notice: This API is EXPERIMENTAL and may be changed or removed in a
617// later release.
618func WithResolvers(rs ...resolver.Builder) DialOption {
619 return newFuncDialOption(func(o *dialOptions) {
620 o.resolvers = append(o.resolvers, rs...)
621 })
622}