blob: fe00a254d065b44cff440acb401569bb5105101a [file] [log] [blame]
khenaidooac637102019-01-14 15:44:34 -05001/*
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/internal"
30 "google.golang.org/grpc/internal/backoff"
31 "google.golang.org/grpc/internal/envconfig"
32 "google.golang.org/grpc/internal/transport"
33 "google.golang.org/grpc/keepalive"
34 "google.golang.org/grpc/resolver"
35 "google.golang.org/grpc/stats"
36)
37
38// dialOptions configure a Dial call. dialOptions are set by the DialOption
39// values passed to Dial.
40type dialOptions struct {
41 unaryInt UnaryClientInterceptor
42 streamInt StreamClientInterceptor
43 cp Compressor
44 dc Decompressor
45 bs backoff.Strategy
46 block bool
47 insecure bool
48 timeout time.Duration
49 scChan <-chan ServiceConfig
50 authority string
51 copts transport.ConnectOptions
52 callOptions []CallOption
53 // This is used by v1 balancer dial option WithBalancer to support v1
54 // balancer, and also by WithBalancerName dial option.
55 balancerBuilder balancer.Builder
56 // This is to support grpclb.
57 resolverBuilder resolver.Builder
58 reqHandshake envconfig.RequireHandshakeSetting
59 channelzParentID int64
60 disableServiceConfig bool
61 disableRetry bool
62 disableHealthCheck bool
63}
64
65// DialOption configures how we set up the connection.
66type DialOption interface {
67 apply(*dialOptions)
68}
69
70// EmptyDialOption does not alter the dial configuration. It can be embedded in
71// another structure to build custom dial options.
72//
73// This API is EXPERIMENTAL.
74type EmptyDialOption struct{}
75
76func (EmptyDialOption) apply(*dialOptions) {}
77
78// funcDialOption wraps a function that modifies dialOptions into an
79// implementation of the DialOption interface.
80type funcDialOption struct {
81 f func(*dialOptions)
82}
83
84func (fdo *funcDialOption) apply(do *dialOptions) {
85 fdo.f(do)
86}
87
88func newFuncDialOption(f func(*dialOptions)) *funcDialOption {
89 return &funcDialOption{
90 f: f,
91 }
92}
93
94// WithWaitForHandshake blocks until the initial settings frame is received from
95// the server before assigning RPCs to the connection.
96//
97// Deprecated: this will become the default behavior in the 1.17 release, and
98// will be removed after the 1.18 release. To override the default behavior in
99// the 1.17 release, either use this dial option or set the environment
100// variable GRPC_GO_READY_BEFORE_HANDSHAKE=on.
101func WithWaitForHandshake() DialOption {
102 return newFuncDialOption(func(o *dialOptions) {
103 o.reqHandshake = envconfig.RequireHandshakeOn
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.
153func WithMaxMsgSize(s int) DialOption {
154 return WithDefaultCallOptions(MaxCallRecvMsgSize(s))
155}
156
157// WithDefaultCallOptions returns a DialOption which sets the default
158// CallOptions for calls over the connection.
159func WithDefaultCallOptions(cos ...CallOption) DialOption {
160 return newFuncDialOption(func(o *dialOptions) {
161 o.callOptions = append(o.callOptions, cos...)
162 })
163}
164
165// WithCodec returns a DialOption which sets a codec for message marshaling and
166// unmarshaling.
167//
168// Deprecated: use WithDefaultCallOptions(CallCustomCodec(c)) instead.
169func WithCodec(c Codec) DialOption {
170 return WithDefaultCallOptions(CallCustomCodec(c))
171}
172
173// WithCompressor returns a DialOption which sets a Compressor to use for
174// message compression. It has lower priority than the compressor set by the
175// UseCompressor CallOption.
176//
177// Deprecated: use UseCompressor instead.
178func WithCompressor(cp Compressor) DialOption {
179 return newFuncDialOption(func(o *dialOptions) {
180 o.cp = cp
181 })
182}
183
184// WithDecompressor returns a DialOption which sets a Decompressor to use for
185// incoming message decompression. If incoming response messages are encoded
186// using the decompressor's Type(), it will be used. Otherwise, the message
187// encoding will be used to look up the compressor registered via
188// encoding.RegisterCompressor, which will then be used to decompress the
189// message. If no compressor is registered for the encoding, an Unimplemented
190// status error will be returned.
191//
192// Deprecated: use encoding.RegisterCompressor instead.
193func WithDecompressor(dc Decompressor) DialOption {
194 return newFuncDialOption(func(o *dialOptions) {
195 o.dc = dc
196 })
197}
198
199// WithBalancer returns a DialOption which sets a load balancer with the v1 API.
200// Name resolver will be ignored if this DialOption is specified.
201//
202// Deprecated: use the new balancer APIs in balancer package and
203// WithBalancerName.
204func WithBalancer(b Balancer) DialOption {
205 return newFuncDialOption(func(o *dialOptions) {
206 o.balancerBuilder = &balancerWrapperBuilder{
207 b: b,
208 }
209 })
210}
211
212// WithBalancerName sets the balancer that the ClientConn will be initialized
213// with. Balancer registered with balancerName will be used. This function
214// panics if no balancer was registered by balancerName.
215//
216// The balancer cannot be overridden by balancer option specified by service
217// config.
218//
219// This is an EXPERIMENTAL API.
220func WithBalancerName(balancerName string) DialOption {
221 builder := balancer.Get(balancerName)
222 if builder == nil {
223 panic(fmt.Sprintf("grpc.WithBalancerName: no balancer is registered for name %v", balancerName))
224 }
225 return newFuncDialOption(func(o *dialOptions) {
226 o.balancerBuilder = builder
227 })
228}
229
230// withResolverBuilder is only for grpclb.
231func withResolverBuilder(b resolver.Builder) DialOption {
232 return newFuncDialOption(func(o *dialOptions) {
233 o.resolverBuilder = b
234 })
235}
236
237// WithServiceConfig returns a DialOption which has a channel to read the
238// service configuration.
239//
240// Deprecated: service config should be received through name resolver, as
241// specified here.
242// https://github.com/grpc/grpc/blob/master/doc/service_config.md
243func WithServiceConfig(c <-chan ServiceConfig) DialOption {
244 return newFuncDialOption(func(o *dialOptions) {
245 o.scChan = c
246 })
247}
248
249// WithBackoffMaxDelay configures the dialer to use the provided maximum delay
250// when backing off after failed connection attempts.
251func WithBackoffMaxDelay(md time.Duration) DialOption {
252 return WithBackoffConfig(BackoffConfig{MaxDelay: md})
253}
254
255// WithBackoffConfig configures the dialer to use the provided backoff
256// parameters after connection failures.
257//
258// Use WithBackoffMaxDelay until more parameters on BackoffConfig are opened up
259// for use.
260func WithBackoffConfig(b BackoffConfig) DialOption {
261 return withBackoff(backoff.Exponential{
262 MaxDelay: b.MaxDelay,
263 })
264}
265
266// withBackoff sets the backoff strategy used for connectRetryNum after a failed
267// connection attempt.
268//
269// This can be exported if arbitrary backoff strategies are allowed by gRPC.
270func withBackoff(bs backoff.Strategy) DialOption {
271 return newFuncDialOption(func(o *dialOptions) {
272 o.bs = bs
273 })
274}
275
276// WithBlock returns a DialOption which makes caller of Dial blocks until the
277// underlying connection is up. Without this, Dial returns immediately and
278// connecting the server happens in background.
279func WithBlock() DialOption {
280 return newFuncDialOption(func(o *dialOptions) {
281 o.block = true
282 })
283}
284
285// WithInsecure returns a DialOption which disables transport security for this
286// ClientConn. Note that transport security is required unless WithInsecure is
287// set.
288func WithInsecure() DialOption {
289 return newFuncDialOption(func(o *dialOptions) {
290 o.insecure = true
291 })
292}
293
294// WithTransportCredentials returns a DialOption which configures a connection
295// level security credentials (e.g., TLS/SSL). This should not be used together
296// with WithCredentialsBundle.
297func WithTransportCredentials(creds credentials.TransportCredentials) DialOption {
298 return newFuncDialOption(func(o *dialOptions) {
299 o.copts.TransportCredentials = creds
300 })
301}
302
303// WithPerRPCCredentials returns a DialOption which sets credentials and places
304// auth state on each outbound RPC.
305func WithPerRPCCredentials(creds credentials.PerRPCCredentials) DialOption {
306 return newFuncDialOption(func(o *dialOptions) {
307 o.copts.PerRPCCredentials = append(o.copts.PerRPCCredentials, creds)
308 })
309}
310
311// WithCredentialsBundle returns a DialOption to set a credentials bundle for
312// the ClientConn.WithCreds. This should not be used together with
313// WithTransportCredentials.
314//
315// This API is experimental.
316func WithCredentialsBundle(b credentials.Bundle) DialOption {
317 return newFuncDialOption(func(o *dialOptions) {
318 o.copts.CredsBundle = b
319 })
320}
321
322// WithTimeout returns a DialOption that configures a timeout for dialing a
323// ClientConn initially. This is valid if and only if WithBlock() is present.
324//
325// Deprecated: use DialContext and context.WithTimeout instead.
326func WithTimeout(d time.Duration) DialOption {
327 return newFuncDialOption(func(o *dialOptions) {
328 o.timeout = d
329 })
330}
331
332func withContextDialer(f func(context.Context, string) (net.Conn, error)) DialOption {
333 return newFuncDialOption(func(o *dialOptions) {
334 o.copts.Dialer = f
335 })
336}
337
338func init() {
339 internal.WithContextDialer = withContextDialer
340 internal.WithResolverBuilder = withResolverBuilder
341}
342
343// WithDialer returns a DialOption that specifies a function to use for dialing
344// network addresses. If FailOnNonTempDialError() is set to true, and an error
345// is returned by f, gRPC checks the error's Temporary() method to decide if it
346// should try to reconnect to the network address.
347func WithDialer(f func(string, time.Duration) (net.Conn, error)) DialOption {
348 return withContextDialer(
349 func(ctx context.Context, addr string) (net.Conn, error) {
350 if deadline, ok := ctx.Deadline(); ok {
351 return f(addr, deadline.Sub(time.Now()))
352 }
353 return f(addr, 0)
354 })
355}
356
357// WithStatsHandler returns a DialOption that specifies the stats handler for
358// all the RPCs and underlying network connections in this ClientConn.
359func WithStatsHandler(h stats.Handler) DialOption {
360 return newFuncDialOption(func(o *dialOptions) {
361 o.copts.StatsHandler = h
362 })
363}
364
365// FailOnNonTempDialError returns a DialOption that specifies if gRPC fails on
366// non-temporary dial errors. If f is true, and dialer returns a non-temporary
367// error, gRPC will fail the connection to the network address and won't try to
368// reconnect. The default value of FailOnNonTempDialError is false.
369//
370// FailOnNonTempDialError only affects the initial dial, and does not do
371// anything useful unless you are also using WithBlock().
372//
373// This is an EXPERIMENTAL API.
374func FailOnNonTempDialError(f bool) DialOption {
375 return newFuncDialOption(func(o *dialOptions) {
376 o.copts.FailOnNonTempDialError = f
377 })
378}
379
380// WithUserAgent returns a DialOption that specifies a user agent string for all
381// the RPCs.
382func WithUserAgent(s string) DialOption {
383 return newFuncDialOption(func(o *dialOptions) {
384 o.copts.UserAgent = s
385 })
386}
387
388// WithKeepaliveParams returns a DialOption that specifies keepalive parameters
389// for the client transport.
390func WithKeepaliveParams(kp keepalive.ClientParameters) DialOption {
391 return newFuncDialOption(func(o *dialOptions) {
392 o.copts.KeepaliveParams = kp
393 })
394}
395
396// WithUnaryInterceptor returns a DialOption that specifies the interceptor for
397// unary RPCs.
398func WithUnaryInterceptor(f UnaryClientInterceptor) DialOption {
399 return newFuncDialOption(func(o *dialOptions) {
400 o.unaryInt = f
401 })
402}
403
404// WithStreamInterceptor returns a DialOption that specifies the interceptor for
405// streaming RPCs.
406func WithStreamInterceptor(f StreamClientInterceptor) DialOption {
407 return newFuncDialOption(func(o *dialOptions) {
408 o.streamInt = f
409 })
410}
411
412// WithAuthority returns a DialOption that specifies the value to be used as the
413// :authority pseudo-header. This value only works with WithInsecure and has no
414// effect if TransportCredentials are present.
415func WithAuthority(a string) DialOption {
416 return newFuncDialOption(func(o *dialOptions) {
417 o.authority = a
418 })
419}
420
421// WithChannelzParentID returns a DialOption that specifies the channelz ID of
422// current ClientConn's parent. This function is used in nested channel creation
423// (e.g. grpclb dial).
424func WithChannelzParentID(id int64) DialOption {
425 return newFuncDialOption(func(o *dialOptions) {
426 o.channelzParentID = id
427 })
428}
429
430// WithDisableServiceConfig returns a DialOption that causes grpc to ignore any
431// service config provided by the resolver and provides a hint to the resolver
432// to not fetch service configs.
433func WithDisableServiceConfig() DialOption {
434 return newFuncDialOption(func(o *dialOptions) {
435 o.disableServiceConfig = true
436 })
437}
438
439// WithDisableRetry returns a DialOption that disables retries, even if the
440// service config enables them. This does not impact transparent retries, which
441// will happen automatically if no data is written to the wire or if the RPC is
442// unprocessed by the remote server.
443//
444// Retry support is currently disabled by default, but will be enabled by
445// default in the future. Until then, it may be enabled by setting the
446// environment variable "GRPC_GO_RETRY" to "on".
447//
448// This API is EXPERIMENTAL.
449func WithDisableRetry() DialOption {
450 return newFuncDialOption(func(o *dialOptions) {
451 o.disableRetry = true
452 })
453}
454
455// WithMaxHeaderListSize returns a DialOption that specifies the maximum
456// (uncompressed) size of header list that the client is prepared to accept.
457func WithMaxHeaderListSize(s uint32) DialOption {
458 return newFuncDialOption(func(o *dialOptions) {
459 o.copts.MaxHeaderListSize = &s
460 })
461}
462
463// WithDisableHealthCheck disables the LB channel health checking for all SubConns of this ClientConn.
464//
465// This API is EXPERIMENTAL.
466func WithDisableHealthCheck() DialOption {
467 return newFuncDialOption(func(o *dialOptions) {
468 o.disableHealthCheck = true
469 })
470}
471func defaultDialOptions() dialOptions {
472 return dialOptions{
473 disableRetry: !envconfig.Retry,
474 reqHandshake: envconfig.RequireHandshake,
475 copts: transport.ConnectOptions{
476 WriteBufferSize: defaultWriteBufSize,
477 ReadBufferSize: defaultReadBufSize,
478 },
479 }
480}