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