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