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
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	// This is to support grpclb.
63	resolverBuilder             resolver.Builder
64	channelzParentID            int64
65	disableServiceConfig        bool
66	disableRetry                bool
67	disableHealthCheck          bool
68	healthCheckFunc             internal.HealthChecker
69	minConnectTimeout           func() time.Duration
70	defaultServiceConfig        *ServiceConfig // defaultServiceConfig is parsed from defaultServiceConfigRawJSON.
71	defaultServiceConfigRawJSON *string
72	// This is used by ccResolverWrapper to backoff between successive calls to
73	// resolver.ResolveNow(). The user will have no need to configure this, but
74	// we need to be able to configure this in tests.
75	resolveNowBackoff func(int) time.Duration
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// withResolverBuilder is only for grpclb.
235func withResolverBuilder(b resolver.Builder) DialOption {
236	return newFuncDialOption(func(o *dialOptions) {
237		o.resolverBuilder = b
238	})
239}
240
241// WithServiceConfig returns a DialOption which has a channel to read the
242// service configuration.
243//
244// Deprecated: service config should be received through name resolver or via
245// WithDefaultServiceConfig, as specified at
246// https://github.com/grpc/grpc/blob/master/doc/service_config.md.  Will be
247// removed in a future 1.x release.
248func WithServiceConfig(c <-chan ServiceConfig) DialOption {
249	return newFuncDialOption(func(o *dialOptions) {
250		o.scChan = c
251	})
252}
253
254// WithConnectParams configures the dialer to use the provided ConnectParams.
255//
256// The backoff configuration specified as part of the ConnectParams overrides
257// all defaults specified in
258// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. Consider
259// using the backoff.DefaultConfig as a base, in cases where you want to
260// override only a subset of the backoff configuration.
261//
262// This API is EXPERIMENTAL.
263func WithConnectParams(p ConnectParams) DialOption {
264	return newFuncDialOption(func(o *dialOptions) {
265		o.bs = internalbackoff.Exponential{Config: p.Backoff}
266		o.minConnectTimeout = func() time.Duration {
267			return p.MinConnectTimeout
268		}
269	})
270}
271
272// WithBackoffMaxDelay configures the dialer to use the provided maximum delay
273// when backing off after failed connection attempts.
274//
275// Deprecated: use WithConnectParams instead. Will be supported throughout 1.x.
276func WithBackoffMaxDelay(md time.Duration) DialOption {
277	return WithBackoffConfig(BackoffConfig{MaxDelay: md})
278}
279
280// WithBackoffConfig configures the dialer to use the provided backoff
281// parameters after connection failures.
282//
283// Deprecated: use WithConnectParams instead. Will be supported throughout 1.x.
284func WithBackoffConfig(b BackoffConfig) DialOption {
285	bc := backoff.DefaultConfig
286	bc.MaxDelay = b.MaxDelay
287	return withBackoff(internalbackoff.Exponential{Config: bc})
288}
289
290// withBackoff sets the backoff strategy used for connectRetryNum after a failed
291// connection attempt.
292//
293// This can be exported if arbitrary backoff strategies are allowed by gRPC.
294func withBackoff(bs internalbackoff.Strategy) DialOption {
295	return newFuncDialOption(func(o *dialOptions) {
296		o.bs = bs
297	})
298}
299
300// WithBlock returns a DialOption which makes caller of Dial blocks until the
301// underlying connection is up. Without this, Dial returns immediately and
302// connecting the server happens in background.
303func WithBlock() DialOption {
304	return newFuncDialOption(func(o *dialOptions) {
305		o.block = true
306	})
307}
308
309// WithInsecure returns a DialOption which disables transport security for this
310// ClientConn. Note that transport security is required unless WithInsecure is
311// set.
312func WithInsecure() DialOption {
313	return newFuncDialOption(func(o *dialOptions) {
314		o.insecure = true
315	})
316}
317
318// WithTransportCredentials returns a DialOption which configures a connection
319// level security credentials (e.g., TLS/SSL). This should not be used together
320// with WithCredentialsBundle.
321func WithTransportCredentials(creds credentials.TransportCredentials) DialOption {
322	return newFuncDialOption(func(o *dialOptions) {
323		o.copts.TransportCredentials = creds
324	})
325}
326
327// WithPerRPCCredentials returns a DialOption which sets credentials and places
328// auth state on each outbound RPC.
329func WithPerRPCCredentials(creds credentials.PerRPCCredentials) DialOption {
330	return newFuncDialOption(func(o *dialOptions) {
331		o.copts.PerRPCCredentials = append(o.copts.PerRPCCredentials, creds)
332	})
333}
334
335// WithCredentialsBundle returns a DialOption to set a credentials bundle for
336// the ClientConn.WithCreds. This should not be used together with
337// WithTransportCredentials.
338//
339// This API is experimental.
340func WithCredentialsBundle(b credentials.Bundle) DialOption {
341	return newFuncDialOption(func(o *dialOptions) {
342		o.copts.CredsBundle = b
343	})
344}
345
346// WithTimeout returns a DialOption that configures a timeout for dialing a
347// ClientConn initially. This is valid if and only if WithBlock() is present.
348//
349// Deprecated: use DialContext and context.WithTimeout instead.  Will be
350// supported throughout 1.x.
351func WithTimeout(d time.Duration) DialOption {
352	return newFuncDialOption(func(o *dialOptions) {
353		o.timeout = d
354	})
355}
356
357// WithContextDialer returns a DialOption that sets a dialer to create
358// connections. If FailOnNonTempDialError() is set to true, and an error is
359// returned by f, gRPC checks the error's Temporary() method to decide if it
360// should try to reconnect to the network address.
361func WithContextDialer(f func(context.Context, string) (net.Conn, error)) DialOption {
362	return newFuncDialOption(func(o *dialOptions) {
363		o.copts.Dialer = f
364	})
365}
366
367func init() {
368	internal.WithResolverBuilder = withResolverBuilder
369	internal.WithHealthCheckFunc = withHealthCheckFunc
370}
371
372// WithDialer returns a DialOption that specifies a function to use for dialing
373// network addresses. If FailOnNonTempDialError() is set to true, and an error
374// is returned by f, gRPC checks the error's Temporary() method to decide if it
375// should try to reconnect to the network address.
376//
377// Deprecated: use WithContextDialer instead.  Will be supported throughout
378// 1.x.
379func WithDialer(f func(string, time.Duration) (net.Conn, error)) DialOption {
380	return WithContextDialer(
381		func(ctx context.Context, addr string) (net.Conn, error) {
382			if deadline, ok := ctx.Deadline(); ok {
383				return f(addr, time.Until(deadline))
384			}
385			return f(addr, 0)
386		})
387}
388
389// WithStatsHandler returns a DialOption that specifies the stats handler for
390// all the RPCs and underlying network connections in this ClientConn.
391func WithStatsHandler(h stats.Handler) DialOption {
392	return newFuncDialOption(func(o *dialOptions) {
393		o.copts.StatsHandler = h
394	})
395}
396
397// FailOnNonTempDialError returns a DialOption that specifies if gRPC fails on
398// non-temporary dial errors. If f is true, and dialer returns a non-temporary
399// error, gRPC will fail the connection to the network address and won't try to
400// reconnect. The default value of FailOnNonTempDialError is false.
401//
402// FailOnNonTempDialError only affects the initial dial, and does not do
403// anything useful unless you are also using WithBlock().
404//
405// This is an EXPERIMENTAL API.
406func FailOnNonTempDialError(f bool) DialOption {
407	return newFuncDialOption(func(o *dialOptions) {
408		o.copts.FailOnNonTempDialError = f
409	})
410}
411
412// WithUserAgent returns a DialOption that specifies a user agent string for all
413// the RPCs.
414func WithUserAgent(s string) DialOption {
415	return newFuncDialOption(func(o *dialOptions) {
416		o.copts.UserAgent = s
417	})
418}
419
420// WithKeepaliveParams returns a DialOption that specifies keepalive parameters
421// for the client transport.
422func WithKeepaliveParams(kp keepalive.ClientParameters) DialOption {
423	if kp.Time < internal.KeepaliveMinPingTime {
424		grpclog.Warningf("Adjusting keepalive ping interval to minimum period of %v", internal.KeepaliveMinPingTime)
425		kp.Time = internal.KeepaliveMinPingTime
426	}
427	return newFuncDialOption(func(o *dialOptions) {
428		o.copts.KeepaliveParams = kp
429	})
430}
431
432// WithUnaryInterceptor returns a DialOption that specifies the interceptor for
433// unary RPCs.
434func WithUnaryInterceptor(f UnaryClientInterceptor) DialOption {
435	return newFuncDialOption(func(o *dialOptions) {
436		o.unaryInt = f
437	})
438}
439
440// WithChainUnaryInterceptor returns a DialOption that specifies the chained
441// interceptor for unary RPCs. The first interceptor will be the outer most,
442// while the last interceptor will be the inner most wrapper around the real call.
443// All interceptors added by this method will be chained, and the interceptor
444// defined by WithUnaryInterceptor will always be prepended to the chain.
445func WithChainUnaryInterceptor(interceptors ...UnaryClientInterceptor) DialOption {
446	return newFuncDialOption(func(o *dialOptions) {
447		o.chainUnaryInts = append(o.chainUnaryInts, interceptors...)
448	})
449}
450
451// WithStreamInterceptor returns a DialOption that specifies the interceptor for
452// streaming RPCs.
453func WithStreamInterceptor(f StreamClientInterceptor) DialOption {
454	return newFuncDialOption(func(o *dialOptions) {
455		o.streamInt = f
456	})
457}
458
459// WithChainStreamInterceptor returns a DialOption that specifies the chained
460// interceptor for unary RPCs. The first interceptor will be the outer most,
461// while the last interceptor will be the inner most wrapper around the real call.
462// All interceptors added by this method will be chained, and the interceptor
463// defined by WithStreamInterceptor will always be prepended to the chain.
464func WithChainStreamInterceptor(interceptors ...StreamClientInterceptor) DialOption {
465	return newFuncDialOption(func(o *dialOptions) {
466		o.chainStreamInts = append(o.chainStreamInts, interceptors...)
467	})
468}
469
470// WithAuthority returns a DialOption that specifies the value to be used as the
471// :authority pseudo-header. This value only works with WithInsecure and has no
472// effect if TransportCredentials are present.
473func WithAuthority(a string) DialOption {
474	return newFuncDialOption(func(o *dialOptions) {
475		o.authority = a
476	})
477}
478
479// WithChannelzParentID returns a DialOption that specifies the channelz ID of
480// current ClientConn's parent. This function is used in nested channel creation
481// (e.g. grpclb dial).
482func WithChannelzParentID(id int64) DialOption {
483	return newFuncDialOption(func(o *dialOptions) {
484		o.channelzParentID = id
485	})
486}
487
488// WithDisableServiceConfig returns a DialOption that causes gRPC to ignore any
489// service config provided by the resolver and provides a hint to the resolver
490// to not fetch service configs.
491//
492// Note that this dial option only disables service config from resolver. If
493// default service config is provided, gRPC will use the default service config.
494func WithDisableServiceConfig() DialOption {
495	return newFuncDialOption(func(o *dialOptions) {
496		o.disableServiceConfig = true
497	})
498}
499
500// WithDefaultServiceConfig returns a DialOption that configures the default
501// service config, which will be used in cases where:
502//
503// 1. WithDisableServiceConfig is also used.
504// 2. Resolver does not return a service config or if the resolver returns an
505//    invalid service config.
506//
507// This API is EXPERIMENTAL.
508func WithDefaultServiceConfig(s string) DialOption {
509	return newFuncDialOption(func(o *dialOptions) {
510		o.defaultServiceConfigRawJSON = &s
511	})
512}
513
514// WithDisableRetry returns a DialOption that disables retries, even if the
515// service config enables them.  This does not impact transparent retries, which
516// will happen automatically if no data is written to the wire or if the RPC is
517// unprocessed by the remote server.
518//
519// Retry support is currently disabled by default, but will be enabled by
520// default in the future.  Until then, it may be enabled by setting the
521// environment variable "GRPC_GO_RETRY" to "on".
522//
523// This API is EXPERIMENTAL.
524func WithDisableRetry() DialOption {
525	return newFuncDialOption(func(o *dialOptions) {
526		o.disableRetry = true
527	})
528}
529
530// WithMaxHeaderListSize returns a DialOption that specifies the maximum
531// (uncompressed) size of header list that the client is prepared to accept.
532func WithMaxHeaderListSize(s uint32) DialOption {
533	return newFuncDialOption(func(o *dialOptions) {
534		o.copts.MaxHeaderListSize = &s
535	})
536}
537
538// WithDisableHealthCheck disables the LB channel health checking for all
539// SubConns of this ClientConn.
540//
541// This API is EXPERIMENTAL.
542func WithDisableHealthCheck() DialOption {
543	return newFuncDialOption(func(o *dialOptions) {
544		o.disableHealthCheck = true
545	})
546}
547
548// withHealthCheckFunc replaces the default health check function with the
549// provided one. It makes tests easier to change the health check function.
550//
551// For testing purpose only.
552func withHealthCheckFunc(f internal.HealthChecker) DialOption {
553	return newFuncDialOption(func(o *dialOptions) {
554		o.healthCheckFunc = f
555	})
556}
557
558func defaultDialOptions() dialOptions {
559	return dialOptions{
560		disableRetry:    !envconfig.Retry,
561		healthCheckFunc: internal.HealthCheckFunc,
562		copts: transport.ConnectOptions{
563			WriteBufferSize: defaultWriteBufSize,
564			ReadBufferSize:  defaultReadBufSize,
565		},
566		resolveNowBackoff: internalbackoff.DefaultExponential.Backoff,
567	}
568}
569
570// withGetMinConnectDeadline specifies the function that clientconn uses to
571// get minConnectDeadline. This can be used to make connection attempts happen
572// faster/slower.
573//
574// For testing purpose only.
575func withMinConnectDeadline(f func() time.Duration) DialOption {
576	return newFuncDialOption(func(o *dialOptions) {
577		o.minConnectTimeout = f
578	})
579}
580
581// withResolveNowBackoff specifies the function that clientconn uses to backoff
582// between successive calls to resolver.ResolveNow().
583//
584// For testing purpose only.
585func withResolveNowBackoff(f func(int) time.Duration) DialOption {
586	return newFuncDialOption(func(o *dialOptions) {
587		o.resolveNowBackoff = f
588	})
589}
590