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/grpclog" 31 "google.golang.org/grpc/internal" 32 internalbackoff "google.golang.org/grpc/internal/backoff" 33 "google.golang.org/grpc/internal/envconfig" 34 "google.golang.org/grpc/internal/transport" 35 "google.golang.org/grpc/keepalive" 36 "google.golang.org/grpc/resolver" 37 "google.golang.org/grpc/stats" 38) 39 40// dialOptions configure a Dial call. dialOptions are set by the DialOption 41// values passed to Dial. 42type dialOptions struct { 43 unaryInt UnaryClientInterceptor 44 streamInt StreamClientInterceptor 45 46 chainUnaryInts []UnaryClientInterceptor 47 chainStreamInts []StreamClientInterceptor 48 49 cp Compressor 50 dc Decompressor 51 bs internalbackoff.Strategy 52 block 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 v1 balancer dial option WithBalancer to support v1 60 // balancer, and also by WithBalancerName dial option. 61 balancerBuilder balancer.Builder 62 channelzParentID int64 63 disableServiceConfig bool 64 disableRetry bool 65 disableHealthCheck bool 66 healthCheckFunc internal.HealthChecker 67 minConnectTimeout func() time.Duration 68 defaultServiceConfig *ServiceConfig // defaultServiceConfig is parsed from defaultServiceConfigRawJSON. 69 defaultServiceConfigRawJSON *string 70 // This is used by ccResolverWrapper to backoff between successive calls to 71 // resolver.ResolveNow(). The user will have no need to configure this, but 72 // we need to be able to configure this in tests. 73 resolveNowBackoff func(int) time.Duration 74 resolvers []resolver.Builder 75 withProxy bool 76} 77 78// DialOption configures how we set up the connection. 79type DialOption interface { 80 apply(*dialOptions) 81} 82 83// EmptyDialOption does not alter the dial configuration. It can be embedded in 84// another structure to build custom dial options. 85// 86// This API is EXPERIMENTAL. 87type EmptyDialOption struct{} 88 89func (EmptyDialOption) apply(*dialOptions) {} 90 91// funcDialOption wraps a function that modifies dialOptions into an 92// implementation of the DialOption interface. 93type funcDialOption struct { 94 f func(*dialOptions) 95} 96 97func (fdo *funcDialOption) apply(do *dialOptions) { 98 fdo.f(do) 99} 100 101func newFuncDialOption(f func(*dialOptions)) *funcDialOption { 102 return &funcDialOption{ 103 f: f, 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. Will 153// be supported throughout 1.x. 154func WithMaxMsgSize(s int) DialOption { 155 return WithDefaultCallOptions(MaxCallRecvMsgSize(s)) 156} 157 158// WithDefaultCallOptions returns a DialOption which sets the default 159// CallOptions for calls over the connection. 160func WithDefaultCallOptions(cos ...CallOption) DialOption { 161 return newFuncDialOption(func(o *dialOptions) { 162 o.callOptions = append(o.callOptions, cos...) 163 }) 164} 165 166// WithCodec returns a DialOption which sets a codec for message marshaling and 167// unmarshaling. 168// 169// Deprecated: use WithDefaultCallOptions(ForceCodec(_)) instead. Will be 170// supported throughout 1.x. 171func WithCodec(c Codec) DialOption { 172 return WithDefaultCallOptions(CallCustomCodec(c)) 173} 174 175// WithCompressor returns a DialOption which sets a Compressor to use for 176// message compression. It has lower priority than the compressor set by the 177// UseCompressor CallOption. 178// 179// Deprecated: use UseCompressor instead. Will be supported throughout 1.x. 180func WithCompressor(cp Compressor) DialOption { 181 return newFuncDialOption(func(o *dialOptions) { 182 o.cp = cp 183 }) 184} 185 186// WithDecompressor returns a DialOption which sets a Decompressor to use for 187// incoming message decompression. If incoming response messages are encoded 188// using the decompressor's Type(), it will be used. Otherwise, the message 189// encoding will be used to look up the compressor registered via 190// encoding.RegisterCompressor, which will then be used to decompress the 191// message. If no compressor is registered for the encoding, an Unimplemented 192// status error will be returned. 193// 194// Deprecated: use encoding.RegisterCompressor instead. Will be supported 195// throughout 1.x. 196func WithDecompressor(dc Decompressor) DialOption { 197 return newFuncDialOption(func(o *dialOptions) { 198 o.dc = dc 199 }) 200} 201 202// WithBalancer returns a DialOption which sets a load balancer with the v1 API. 203// Name resolver will be ignored if this DialOption is specified. 204// 205// Deprecated: use the new balancer APIs in balancer package and 206// WithBalancerName. Will be removed in a future 1.x release. 207func WithBalancer(b Balancer) DialOption { 208 return newFuncDialOption(func(o *dialOptions) { 209 o.balancerBuilder = &balancerWrapperBuilder{ 210 b: b, 211 } 212 }) 213} 214 215// WithBalancerName sets the balancer that the ClientConn will be initialized 216// with. Balancer registered with balancerName will be used. This function 217// panics if no balancer was registered by balancerName. 218// 219// The balancer cannot be overridden by balancer option specified by service 220// config. 221// 222// Deprecated: use WithDefaultServiceConfig and WithDisableServiceConfig 223// instead. Will be removed in a future 1.x release. 224func WithBalancerName(balancerName string) DialOption { 225 builder := balancer.Get(balancerName) 226 if builder == nil { 227 panic(fmt.Sprintf("grpc.WithBalancerName: no balancer is registered for name %v", balancerName)) 228 } 229 return newFuncDialOption(func(o *dialOptions) { 230 o.balancerBuilder = builder 231 }) 232} 233 234// WithServiceConfig returns a DialOption which has a channel to read the 235// service configuration. 236// 237// Deprecated: service config should be received through name resolver or via 238// WithDefaultServiceConfig, as specified at 239// https://github.com/grpc/grpc/blob/master/doc/service_config.md. Will be 240// removed in a future 1.x release. 241func WithServiceConfig(c <-chan ServiceConfig) DialOption { 242 return newFuncDialOption(func(o *dialOptions) { 243 o.scChan = c 244 }) 245} 246 247// WithConnectParams configures the dialer to use the provided ConnectParams. 248// 249// The backoff configuration specified as part of the ConnectParams overrides 250// all defaults specified in 251// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. Consider 252// using the backoff.DefaultConfig as a base, in cases where you want to 253// override only a subset of the backoff configuration. 254// 255// This API is EXPERIMENTAL. 256func WithConnectParams(p ConnectParams) DialOption { 257 return newFuncDialOption(func(o *dialOptions) { 258 o.bs = internalbackoff.Exponential{Config: p.Backoff} 259 o.minConnectTimeout = func() time.Duration { 260 return p.MinConnectTimeout 261 } 262 }) 263} 264 265// WithBackoffMaxDelay configures the dialer to use the provided maximum delay 266// when backing off after failed connection attempts. 267// 268// Deprecated: use WithConnectParams instead. Will be supported throughout 1.x. 269func WithBackoffMaxDelay(md time.Duration) DialOption { 270 return WithBackoffConfig(BackoffConfig{MaxDelay: md}) 271} 272 273// WithBackoffConfig configures the dialer to use the provided backoff 274// parameters after connection failures. 275// 276// Deprecated: use WithConnectParams instead. Will be supported throughout 1.x. 277func WithBackoffConfig(b BackoffConfig) DialOption { 278 bc := backoff.DefaultConfig 279 bc.MaxDelay = b.MaxDelay 280 return withBackoff(internalbackoff.Exponential{Config: bc}) 281} 282 283// withBackoff sets the backoff strategy used for connectRetryNum after a failed 284// connection attempt. 285// 286// This can be exported if arbitrary backoff strategies are allowed by gRPC. 287func withBackoff(bs internalbackoff.Strategy) DialOption { 288 return newFuncDialOption(func(o *dialOptions) { 289 o.bs = bs 290 }) 291} 292 293// WithBlock returns a DialOption which makes caller of Dial blocks until the 294// underlying connection is up. Without this, Dial returns immediately and 295// connecting the server happens in background. 296func WithBlock() DialOption { 297 return newFuncDialOption(func(o *dialOptions) { 298 o.block = true 299 }) 300} 301 302// WithInsecure returns a DialOption which disables transport security for this 303// ClientConn. Note that transport security is required unless WithInsecure is 304// set. 305func WithInsecure() DialOption { 306 return newFuncDialOption(func(o *dialOptions) { 307 o.insecure = true 308 }) 309} 310 311// WithNoProxy returns a DialOption which disables the use of proxies for this 312// ClientConn. This is ignored if WithDialer or WithContextDialer are used. 313// 314// This API is EXPERIMENTAL. 315func WithNoProxy() DialOption { 316 return newFuncDialOption(func(o *dialOptions) { 317 o.withProxy = false 318 }) 319} 320 321// WithTransportCredentials returns a DialOption which configures a connection 322// level security credentials (e.g., TLS/SSL). This should not be used together 323// with WithCredentialsBundle. 324func WithTransportCredentials(creds credentials.TransportCredentials) DialOption { 325 return newFuncDialOption(func(o *dialOptions) { 326 o.copts.TransportCredentials = creds 327 }) 328} 329 330// WithPerRPCCredentials returns a DialOption which sets credentials and places 331// auth state on each outbound RPC. 332func WithPerRPCCredentials(creds credentials.PerRPCCredentials) DialOption { 333 return newFuncDialOption(func(o *dialOptions) { 334 o.copts.PerRPCCredentials = append(o.copts.PerRPCCredentials, creds) 335 }) 336} 337 338// WithCredentialsBundle returns a DialOption to set a credentials bundle for 339// the ClientConn.WithCreds. This should not be used together with 340// WithTransportCredentials. 341// 342// This API is experimental. 343func WithCredentialsBundle(b credentials.Bundle) DialOption { 344 return newFuncDialOption(func(o *dialOptions) { 345 o.copts.CredsBundle = b 346 }) 347} 348 349// WithTimeout returns a DialOption that configures a timeout for dialing a 350// ClientConn initially. This is valid if and only if WithBlock() is present. 351// 352// Deprecated: use DialContext instead of Dial and context.WithTimeout 353// instead. Will be supported throughout 1.x. 354func WithTimeout(d time.Duration) DialOption { 355 return newFuncDialOption(func(o *dialOptions) { 356 o.timeout = d 357 }) 358} 359 360// WithContextDialer returns a DialOption that sets a dialer to create 361// connections. If FailOnNonTempDialError() is set to true, and an error is 362// returned by f, gRPC checks the error's Temporary() method to decide if it 363// should try to reconnect to the network address. 364func WithContextDialer(f func(context.Context, string) (net.Conn, error)) DialOption { 365 return newFuncDialOption(func(o *dialOptions) { 366 o.copts.Dialer = f 367 }) 368} 369 370func init() { 371 internal.WithHealthCheckFunc = withHealthCheckFunc 372} 373 374// WithDialer returns a DialOption that specifies a function to use for dialing 375// network addresses. If FailOnNonTempDialError() is set to true, and an error 376// is returned by f, gRPC checks the error's Temporary() method to decide if it 377// should try to reconnect to the network address. 378// 379// Deprecated: use WithContextDialer instead. Will be supported throughout 380// 1.x. 381func WithDialer(f func(string, time.Duration) (net.Conn, error)) DialOption { 382 return WithContextDialer( 383 func(ctx context.Context, addr string) (net.Conn, error) { 384 if deadline, ok := ctx.Deadline(); ok { 385 return f(addr, time.Until(deadline)) 386 } 387 return f(addr, 0) 388 }) 389} 390 391// WithStatsHandler returns a DialOption that specifies the stats handler for 392// all the RPCs and underlying network connections in this ClientConn. 393func WithStatsHandler(h stats.Handler) DialOption { 394 return newFuncDialOption(func(o *dialOptions) { 395 o.copts.StatsHandler = h 396 }) 397} 398 399// FailOnNonTempDialError returns a DialOption that specifies if gRPC fails on 400// non-temporary dial errors. If f is true, and dialer returns a non-temporary 401// error, gRPC will fail the connection to the network address and won't try to 402// reconnect. The default value of FailOnNonTempDialError is false. 403// 404// FailOnNonTempDialError only affects the initial dial, and does not do 405// anything useful unless you are also using WithBlock(). 406// 407// This is an EXPERIMENTAL API. 408func FailOnNonTempDialError(f bool) DialOption { 409 return newFuncDialOption(func(o *dialOptions) { 410 o.copts.FailOnNonTempDialError = f 411 }) 412} 413 414// WithUserAgent returns a DialOption that specifies a user agent string for all 415// the RPCs. 416func WithUserAgent(s string) DialOption { 417 return newFuncDialOption(func(o *dialOptions) { 418 o.copts.UserAgent = s 419 }) 420} 421 422// WithKeepaliveParams returns a DialOption that specifies keepalive parameters 423// for the client transport. 424func WithKeepaliveParams(kp keepalive.ClientParameters) DialOption { 425 if kp.Time < internal.KeepaliveMinPingTime { 426 grpclog.Warningf("Adjusting keepalive ping interval to minimum period of %v", internal.KeepaliveMinPingTime) 427 kp.Time = internal.KeepaliveMinPingTime 428 } 429 return newFuncDialOption(func(o *dialOptions) { 430 o.copts.KeepaliveParams = kp 431 }) 432} 433 434// WithUnaryInterceptor returns a DialOption that specifies the interceptor for 435// unary RPCs. 436func WithUnaryInterceptor(f UnaryClientInterceptor) DialOption { 437 return newFuncDialOption(func(o *dialOptions) { 438 o.unaryInt = f 439 }) 440} 441 442// WithChainUnaryInterceptor returns a DialOption that specifies the chained 443// interceptor for unary RPCs. The first interceptor will be the outer most, 444// while the last interceptor will be the inner most wrapper around the real call. 445// All interceptors added by this method will be chained, and the interceptor 446// defined by WithUnaryInterceptor will always be prepended to the chain. 447func WithChainUnaryInterceptor(interceptors ...UnaryClientInterceptor) DialOption { 448 return newFuncDialOption(func(o *dialOptions) { 449 o.chainUnaryInts = append(o.chainUnaryInts, interceptors...) 450 }) 451} 452 453// WithStreamInterceptor returns a DialOption that specifies the interceptor for 454// streaming RPCs. 455func WithStreamInterceptor(f StreamClientInterceptor) DialOption { 456 return newFuncDialOption(func(o *dialOptions) { 457 o.streamInt = f 458 }) 459} 460 461// WithChainStreamInterceptor returns a DialOption that specifies the chained 462// interceptor for unary RPCs. The first interceptor will be the outer most, 463// while the last interceptor will be the inner most wrapper around the real call. 464// All interceptors added by this method will be chained, and the interceptor 465// defined by WithStreamInterceptor will always be prepended to the chain. 466func WithChainStreamInterceptor(interceptors ...StreamClientInterceptor) DialOption { 467 return newFuncDialOption(func(o *dialOptions) { 468 o.chainStreamInts = append(o.chainStreamInts, interceptors...) 469 }) 470} 471 472// WithAuthority returns a DialOption that specifies the value to be used as the 473// :authority pseudo-header. This value only works with WithInsecure and has no 474// effect if TransportCredentials are present. 475func WithAuthority(a string) DialOption { 476 return newFuncDialOption(func(o *dialOptions) { 477 o.authority = a 478 }) 479} 480 481// WithChannelzParentID returns a DialOption that specifies the channelz ID of 482// current ClientConn's parent. This function is used in nested channel creation 483// (e.g. grpclb dial). 484// 485// This API is EXPERIMENTAL. 486func WithChannelzParentID(id int64) DialOption { 487 return newFuncDialOption(func(o *dialOptions) { 488 o.channelzParentID = id 489 }) 490} 491 492// WithDisableServiceConfig returns a DialOption that causes gRPC to ignore any 493// service config provided by the resolver and provides a hint to the resolver 494// to not fetch service configs. 495// 496// Note that this dial option only disables service config from resolver. If 497// default service config is provided, gRPC will use the default service config. 498func WithDisableServiceConfig() DialOption { 499 return newFuncDialOption(func(o *dialOptions) { 500 o.disableServiceConfig = true 501 }) 502} 503 504// WithDefaultServiceConfig returns a DialOption that configures the default 505// service config, which will be used in cases where: 506// 507// 1. WithDisableServiceConfig is also used. 508// 2. Resolver does not return a service config or if the resolver returns an 509// invalid service config. 510// 511// This API is EXPERIMENTAL. 512func WithDefaultServiceConfig(s string) DialOption { 513 return newFuncDialOption(func(o *dialOptions) { 514 o.defaultServiceConfigRawJSON = &s 515 }) 516} 517 518// WithDisableRetry returns a DialOption that disables retries, even if the 519// service config enables them. This does not impact transparent retries, which 520// will happen automatically if no data is written to the wire or if the RPC is 521// unprocessed by the remote server. 522// 523// Retry support is currently disabled by default, but will be enabled by 524// default in the future. Until then, it may be enabled by setting the 525// environment variable "GRPC_GO_RETRY" to "on". 526// 527// This API is EXPERIMENTAL. 528func WithDisableRetry() DialOption { 529 return newFuncDialOption(func(o *dialOptions) { 530 o.disableRetry = true 531 }) 532} 533 534// WithMaxHeaderListSize returns a DialOption that specifies the maximum 535// (uncompressed) size of header list that the client is prepared to accept. 536func WithMaxHeaderListSize(s uint32) DialOption { 537 return newFuncDialOption(func(o *dialOptions) { 538 o.copts.MaxHeaderListSize = &s 539 }) 540} 541 542// WithDisableHealthCheck disables the LB channel health checking for all 543// SubConns of this ClientConn. 544// 545// This API is EXPERIMENTAL. 546func WithDisableHealthCheck() DialOption { 547 return newFuncDialOption(func(o *dialOptions) { 548 o.disableHealthCheck = true 549 }) 550} 551 552// withHealthCheckFunc replaces the default health check function with the 553// provided one. It makes tests easier to change the health check function. 554// 555// For testing purpose only. 556func withHealthCheckFunc(f internal.HealthChecker) DialOption { 557 return newFuncDialOption(func(o *dialOptions) { 558 o.healthCheckFunc = f 559 }) 560} 561 562func defaultDialOptions() dialOptions { 563 return dialOptions{ 564 disableRetry: !envconfig.Retry, 565 healthCheckFunc: internal.HealthCheckFunc, 566 copts: transport.ConnectOptions{ 567 WriteBufferSize: defaultWriteBufSize, 568 ReadBufferSize: defaultReadBufSize, 569 }, 570 resolveNowBackoff: internalbackoff.DefaultExponential.Backoff, 571 withProxy: true, 572 } 573} 574 575// withGetMinConnectDeadline specifies the function that clientconn uses to 576// get minConnectDeadline. This can be used to make connection attempts happen 577// faster/slower. 578// 579// For testing purpose only. 580func withMinConnectDeadline(f func() time.Duration) DialOption { 581 return newFuncDialOption(func(o *dialOptions) { 582 o.minConnectTimeout = f 583 }) 584} 585 586// withResolveNowBackoff specifies the function that clientconn uses to backoff 587// between successive calls to resolver.ResolveNow(). 588// 589// For testing purpose only. 590func withResolveNowBackoff(f func(int) time.Duration) DialOption { 591 return newFuncDialOption(func(o *dialOptions) { 592 o.resolveNowBackoff = f 593 }) 594} 595 596// WithResolvers allows a list of resolver implementations to be registered 597// locally with the ClientConn without needing to be globally registered via 598// resolver.Register. They will be matched against the scheme used for the 599// current Dial only, and will take precedence over the global registry. 600// 601// This API is EXPERIMENTAL. 602func WithResolvers(rs ...resolver.Builder) DialOption { 603 return newFuncDialOption(func(o *dialOptions) { 604 o.resolvers = append(o.resolvers, rs...) 605 }) 606} 607