blob: 537b2586054f23a8194ac1647b0e7c81321b6f11 [file] [log] [blame]
Scott Bakereee8dd82019-09-24 12:52:34 -07001/*
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 cp Compressor
45 dc Decompressor
46 bs backoff.Strategy
47 block bool
48 insecure bool
49 timeout time.Duration
50 scChan <-chan ServiceConfig
51 authority string
52 copts transport.ConnectOptions
53 callOptions []CallOption
54 // This is used by v1 balancer dial option WithBalancer to support v1
55 // balancer, and also by WithBalancerName dial option.
56 balancerBuilder balancer.Builder
57 // This is to support grpclb.
58 resolverBuilder resolver.Builder
59 reqHandshake envconfig.RequireHandshakeSetting
60 channelzParentID int64
61 disableServiceConfig bool
62 disableRetry bool
63 disableHealthCheck bool
64 healthCheckFunc internal.HealthChecker
65}
66
67// DialOption configures how we set up the connection.
68type DialOption interface {
69 apply(*dialOptions)
70}
71
72// EmptyDialOption does not alter the dial configuration. It can be embedded in
73// another structure to build custom dial options.
74//
75// This API is EXPERIMENTAL.
76type EmptyDialOption struct{}
77
78func (EmptyDialOption) apply(*dialOptions) {}
79
80// funcDialOption wraps a function that modifies dialOptions into an
81// implementation of the DialOption interface.
82type funcDialOption struct {
83 f func(*dialOptions)
84}
85
86func (fdo *funcDialOption) apply(do *dialOptions) {
87 fdo.f(do)
88}
89
90func newFuncDialOption(f func(*dialOptions)) *funcDialOption {
91 return &funcDialOption{
92 f: f,
93 }
94}
95
96// WithWaitForHandshake blocks until the initial settings frame is received from
97// the server before assigning RPCs to the connection.
98//
99// Deprecated: this is the default behavior, and this option will be removed
100// after the 1.18 release.
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(ForceCodec(_)) 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
332// WithContextDialer returns a DialOption that sets a dialer to create
333// connections. If FailOnNonTempDialError() is set to true, and an error is
334// returned by f, gRPC checks the error's Temporary() method to decide if it
335// should try to reconnect to the network address.
336func WithContextDialer(f func(context.Context, string) (net.Conn, error)) DialOption {
337 return newFuncDialOption(func(o *dialOptions) {
338 o.copts.Dialer = f
339 })
340}
341
342func init() {
343 internal.WithResolverBuilder = withResolverBuilder
344 internal.WithHealthCheckFunc = withHealthCheckFunc
345}
346
347// WithDialer returns a DialOption that specifies a function to use for dialing
348// network addresses. If FailOnNonTempDialError() is set to true, and an error
349// is returned by f, gRPC checks the error's Temporary() method to decide if it
350// should try to reconnect to the network address.
351//
352// Deprecated: use WithContextDialer instead
353func WithDialer(f func(string, time.Duration) (net.Conn, error)) DialOption {
354 return WithContextDialer(
355 func(ctx context.Context, addr string) (net.Conn, error) {
356 if deadline, ok := ctx.Deadline(); ok {
357 return f(addr, time.Until(deadline))
358 }
359 return f(addr, 0)
360 })
361}
362
363// WithStatsHandler returns a DialOption that specifies the stats handler for
364// all the RPCs and underlying network connections in this ClientConn.
365func WithStatsHandler(h stats.Handler) DialOption {
366 return newFuncDialOption(func(o *dialOptions) {
367 o.copts.StatsHandler = h
368 })
369}
370
371// FailOnNonTempDialError returns a DialOption that specifies if gRPC fails on
372// non-temporary dial errors. If f is true, and dialer returns a non-temporary
373// error, gRPC will fail the connection to the network address and won't try to
374// reconnect. The default value of FailOnNonTempDialError is false.
375//
376// FailOnNonTempDialError only affects the initial dial, and does not do
377// anything useful unless you are also using WithBlock().
378//
379// This is an EXPERIMENTAL API.
380func FailOnNonTempDialError(f bool) DialOption {
381 return newFuncDialOption(func(o *dialOptions) {
382 o.copts.FailOnNonTempDialError = f
383 })
384}
385
386// WithUserAgent returns a DialOption that specifies a user agent string for all
387// the RPCs.
388func WithUserAgent(s string) DialOption {
389 return newFuncDialOption(func(o *dialOptions) {
390 o.copts.UserAgent = s
391 })
392}
393
394// WithKeepaliveParams returns a DialOption that specifies keepalive parameters
395// for the client transport.
396func WithKeepaliveParams(kp keepalive.ClientParameters) DialOption {
397 if kp.Time < internal.KeepaliveMinPingTime {
398 grpclog.Warningf("Adjusting keepalive ping interval to minimum period of %v", internal.KeepaliveMinPingTime)
399 kp.Time = internal.KeepaliveMinPingTime
400 }
401 return newFuncDialOption(func(o *dialOptions) {
402 o.copts.KeepaliveParams = kp
403 })
404}
405
406// WithUnaryInterceptor returns a DialOption that specifies the interceptor for
407// unary RPCs.
408func WithUnaryInterceptor(f UnaryClientInterceptor) DialOption {
409 return newFuncDialOption(func(o *dialOptions) {
410 o.unaryInt = f
411 })
412}
413
414// WithStreamInterceptor returns a DialOption that specifies the interceptor for
415// streaming RPCs.
416func WithStreamInterceptor(f StreamClientInterceptor) DialOption {
417 return newFuncDialOption(func(o *dialOptions) {
418 o.streamInt = f
419 })
420}
421
422// WithAuthority returns a DialOption that specifies the value to be used as the
423// :authority pseudo-header. This value only works with WithInsecure and has no
424// effect if TransportCredentials are present.
425func WithAuthority(a string) DialOption {
426 return newFuncDialOption(func(o *dialOptions) {
427 o.authority = a
428 })
429}
430
431// WithChannelzParentID returns a DialOption that specifies the channelz ID of
432// current ClientConn's parent. This function is used in nested channel creation
433// (e.g. grpclb dial).
434func WithChannelzParentID(id int64) DialOption {
435 return newFuncDialOption(func(o *dialOptions) {
436 o.channelzParentID = id
437 })
438}
439
440// WithDisableServiceConfig returns a DialOption that causes grpc to ignore any
441// service config provided by the resolver and provides a hint to the resolver
442// to not fetch service configs.
443func WithDisableServiceConfig() DialOption {
444 return newFuncDialOption(func(o *dialOptions) {
445 o.disableServiceConfig = true
446 })
447}
448
449// WithDisableRetry returns a DialOption that disables retries, even if the
450// service config enables them. This does not impact transparent retries, which
451// will happen automatically if no data is written to the wire or if the RPC is
452// unprocessed by the remote server.
453//
454// Retry support is currently disabled by default, but will be enabled by
455// default in the future. Until then, it may be enabled by setting the
456// environment variable "GRPC_GO_RETRY" to "on".
457//
458// This API is EXPERIMENTAL.
459func WithDisableRetry() DialOption {
460 return newFuncDialOption(func(o *dialOptions) {
461 o.disableRetry = true
462 })
463}
464
465// WithMaxHeaderListSize returns a DialOption that specifies the maximum
466// (uncompressed) size of header list that the client is prepared to accept.
467func WithMaxHeaderListSize(s uint32) DialOption {
468 return newFuncDialOption(func(o *dialOptions) {
469 o.copts.MaxHeaderListSize = &s
470 })
471}
472
473// WithDisableHealthCheck disables the LB channel health checking for all SubConns of this ClientConn.
474//
475// This API is EXPERIMENTAL.
476func WithDisableHealthCheck() DialOption {
477 return newFuncDialOption(func(o *dialOptions) {
478 o.disableHealthCheck = true
479 })
480}
481
482// withHealthCheckFunc replaces the default health check function with the provided one. It makes
483// tests easier to change the health check function.
484//
485// For testing purpose only.
486func withHealthCheckFunc(f internal.HealthChecker) DialOption {
487 return newFuncDialOption(func(o *dialOptions) {
488 o.healthCheckFunc = f
489 })
490}
491
492func defaultDialOptions() dialOptions {
493 return dialOptions{
494 disableRetry: !envconfig.Retry,
495 reqHandshake: envconfig.RequireHandshake,
496 healthCheckFunc: internal.HealthCheckFunc,
497 copts: transport.ConnectOptions{
498 WriteBufferSize: defaultWriteBufSize,
499 ReadBufferSize: defaultReadBufSize,
500 },
501 }
502}