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