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