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