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 // This is to support grpclb. 63 resolverBuilder resolver.Builder 64 channelzParentID int64 65 disableServiceConfig bool 66 disableRetry bool 67 disableHealthCheck bool 68 healthCheckFunc internal.HealthChecker 69 minConnectTimeout func() time.Duration 70 defaultServiceConfig *ServiceConfig // defaultServiceConfig is parsed from defaultServiceConfigRawJSON. 71 defaultServiceConfigRawJSON *string 72 // This is used by ccResolverWrapper to backoff between successive calls to 73 // resolver.ResolveNow(). The user will have no need to configure this, but 74 // we need to be able to configure this in tests. 75 resolveNowBackoff func(int) time.Duration 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// withResolverBuilder is only for grpclb. 235func withResolverBuilder(b resolver.Builder) DialOption { 236 return newFuncDialOption(func(o *dialOptions) { 237 o.resolverBuilder = b 238 }) 239} 240 241// WithServiceConfig returns a DialOption which has a channel to read the 242// service configuration. 243// 244// Deprecated: service config should be received through name resolver or via 245// WithDefaultServiceConfig, as specified at 246// https://github.com/grpc/grpc/blob/master/doc/service_config.md. Will be 247// removed in a future 1.x release. 248func WithServiceConfig(c <-chan ServiceConfig) DialOption { 249 return newFuncDialOption(func(o *dialOptions) { 250 o.scChan = c 251 }) 252} 253 254// WithConnectParams configures the dialer to use the provided ConnectParams. 255// 256// The backoff configuration specified as part of the ConnectParams overrides 257// all defaults specified in 258// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. Consider 259// using the backoff.DefaultConfig as a base, in cases where you want to 260// override only a subset of the backoff configuration. 261// 262// This API is EXPERIMENTAL. 263func WithConnectParams(p ConnectParams) DialOption { 264 return newFuncDialOption(func(o *dialOptions) { 265 o.bs = internalbackoff.Exponential{Config: p.Backoff} 266 o.minConnectTimeout = func() time.Duration { 267 return p.MinConnectTimeout 268 } 269 }) 270} 271 272// WithBackoffMaxDelay configures the dialer to use the provided maximum delay 273// when backing off after failed connection attempts. 274// 275// Deprecated: use WithConnectParams instead. Will be supported throughout 1.x. 276func WithBackoffMaxDelay(md time.Duration) DialOption { 277 return WithBackoffConfig(BackoffConfig{MaxDelay: md}) 278} 279 280// WithBackoffConfig configures the dialer to use the provided backoff 281// parameters after connection failures. 282// 283// Deprecated: use WithConnectParams instead. Will be supported throughout 1.x. 284func WithBackoffConfig(b BackoffConfig) DialOption { 285 bc := backoff.DefaultConfig 286 bc.MaxDelay = b.MaxDelay 287 return withBackoff(internalbackoff.Exponential{Config: bc}) 288} 289 290// withBackoff sets the backoff strategy used for connectRetryNum after a failed 291// connection attempt. 292// 293// This can be exported if arbitrary backoff strategies are allowed by gRPC. 294func withBackoff(bs internalbackoff.Strategy) DialOption { 295 return newFuncDialOption(func(o *dialOptions) { 296 o.bs = bs 297 }) 298} 299 300// WithBlock returns a DialOption which makes caller of Dial blocks until the 301// underlying connection is up. Without this, Dial returns immediately and 302// connecting the server happens in background. 303func WithBlock() DialOption { 304 return newFuncDialOption(func(o *dialOptions) { 305 o.block = true 306 }) 307} 308 309// WithInsecure returns a DialOption which disables transport security for this 310// ClientConn. Note that transport security is required unless WithInsecure is 311// set. 312func WithInsecure() DialOption { 313 return newFuncDialOption(func(o *dialOptions) { 314 o.insecure = true 315 }) 316} 317 318// WithTransportCredentials returns a DialOption which configures a connection 319// level security credentials (e.g., TLS/SSL). This should not be used together 320// with WithCredentialsBundle. 321func WithTransportCredentials(creds credentials.TransportCredentials) DialOption { 322 return newFuncDialOption(func(o *dialOptions) { 323 o.copts.TransportCredentials = creds 324 }) 325} 326 327// WithPerRPCCredentials returns a DialOption which sets credentials and places 328// auth state on each outbound RPC. 329func WithPerRPCCredentials(creds credentials.PerRPCCredentials) DialOption { 330 return newFuncDialOption(func(o *dialOptions) { 331 o.copts.PerRPCCredentials = append(o.copts.PerRPCCredentials, creds) 332 }) 333} 334 335// WithCredentialsBundle returns a DialOption to set a credentials bundle for 336// the ClientConn.WithCreds. This should not be used together with 337// WithTransportCredentials. 338// 339// This API is experimental. 340func WithCredentialsBundle(b credentials.Bundle) DialOption { 341 return newFuncDialOption(func(o *dialOptions) { 342 o.copts.CredsBundle = b 343 }) 344} 345 346// WithTimeout returns a DialOption that configures a timeout for dialing a 347// ClientConn initially. This is valid if and only if WithBlock() is present. 348// 349// Deprecated: use DialContext and context.WithTimeout instead. Will be 350// supported throughout 1.x. 351func WithTimeout(d time.Duration) DialOption { 352 return newFuncDialOption(func(o *dialOptions) { 353 o.timeout = d 354 }) 355} 356 357// WithContextDialer returns a DialOption that sets a dialer to create 358// connections. If FailOnNonTempDialError() is set to true, and an error is 359// returned by f, gRPC checks the error's Temporary() method to decide if it 360// should try to reconnect to the network address. 361func WithContextDialer(f func(context.Context, string) (net.Conn, error)) DialOption { 362 return newFuncDialOption(func(o *dialOptions) { 363 o.copts.Dialer = f 364 }) 365} 366 367func init() { 368 internal.WithResolverBuilder = withResolverBuilder 369 internal.WithHealthCheckFunc = withHealthCheckFunc 370} 371 372// WithDialer returns a DialOption that specifies a function to use for dialing 373// network addresses. If FailOnNonTempDialError() is set to true, and an error 374// is returned by f, gRPC checks the error's Temporary() method to decide if it 375// should try to reconnect to the network address. 376// 377// Deprecated: use WithContextDialer instead. Will be supported throughout 378// 1.x. 379func WithDialer(f func(string, time.Duration) (net.Conn, error)) DialOption { 380 return WithContextDialer( 381 func(ctx context.Context, addr string) (net.Conn, error) { 382 if deadline, ok := ctx.Deadline(); ok { 383 return f(addr, time.Until(deadline)) 384 } 385 return f(addr, 0) 386 }) 387} 388 389// WithStatsHandler returns a DialOption that specifies the stats handler for 390// all the RPCs and underlying network connections in this ClientConn. 391func WithStatsHandler(h stats.Handler) DialOption { 392 return newFuncDialOption(func(o *dialOptions) { 393 o.copts.StatsHandler = h 394 }) 395} 396 397// FailOnNonTempDialError returns a DialOption that specifies if gRPC fails on 398// non-temporary dial errors. If f is true, and dialer returns a non-temporary 399// error, gRPC will fail the connection to the network address and won't try to 400// reconnect. The default value of FailOnNonTempDialError is false. 401// 402// FailOnNonTempDialError only affects the initial dial, and does not do 403// anything useful unless you are also using WithBlock(). 404// 405// This is an EXPERIMENTAL API. 406func FailOnNonTempDialError(f bool) DialOption { 407 return newFuncDialOption(func(o *dialOptions) { 408 o.copts.FailOnNonTempDialError = f 409 }) 410} 411 412// WithUserAgent returns a DialOption that specifies a user agent string for all 413// the RPCs. 414func WithUserAgent(s string) DialOption { 415 return newFuncDialOption(func(o *dialOptions) { 416 o.copts.UserAgent = s 417 }) 418} 419 420// WithKeepaliveParams returns a DialOption that specifies keepalive parameters 421// for the client transport. 422func WithKeepaliveParams(kp keepalive.ClientParameters) DialOption { 423 if kp.Time < internal.KeepaliveMinPingTime { 424 grpclog.Warningf("Adjusting keepalive ping interval to minimum period of %v", internal.KeepaliveMinPingTime) 425 kp.Time = internal.KeepaliveMinPingTime 426 } 427 return newFuncDialOption(func(o *dialOptions) { 428 o.copts.KeepaliveParams = kp 429 }) 430} 431 432// WithUnaryInterceptor returns a DialOption that specifies the interceptor for 433// unary RPCs. 434func WithUnaryInterceptor(f UnaryClientInterceptor) DialOption { 435 return newFuncDialOption(func(o *dialOptions) { 436 o.unaryInt = f 437 }) 438} 439 440// WithChainUnaryInterceptor returns a DialOption that specifies the chained 441// interceptor for unary RPCs. The first interceptor will be the outer most, 442// while the last interceptor will be the inner most wrapper around the real call. 443// All interceptors added by this method will be chained, and the interceptor 444// defined by WithUnaryInterceptor will always be prepended to the chain. 445func WithChainUnaryInterceptor(interceptors ...UnaryClientInterceptor) DialOption { 446 return newFuncDialOption(func(o *dialOptions) { 447 o.chainUnaryInts = append(o.chainUnaryInts, interceptors...) 448 }) 449} 450 451// WithStreamInterceptor returns a DialOption that specifies the interceptor for 452// streaming RPCs. 453func WithStreamInterceptor(f StreamClientInterceptor) DialOption { 454 return newFuncDialOption(func(o *dialOptions) { 455 o.streamInt = f 456 }) 457} 458 459// WithChainStreamInterceptor 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 WithStreamInterceptor will always be prepended to the chain. 464func WithChainStreamInterceptor(interceptors ...StreamClientInterceptor) DialOption { 465 return newFuncDialOption(func(o *dialOptions) { 466 o.chainStreamInts = append(o.chainStreamInts, interceptors...) 467 }) 468} 469 470// WithAuthority returns a DialOption that specifies the value to be used as the 471// :authority pseudo-header. This value only works with WithInsecure and has no 472// effect if TransportCredentials are present. 473func WithAuthority(a string) DialOption { 474 return newFuncDialOption(func(o *dialOptions) { 475 o.authority = a 476 }) 477} 478 479// WithChannelzParentID returns a DialOption that specifies the channelz ID of 480// current ClientConn's parent. This function is used in nested channel creation 481// (e.g. grpclb dial). 482func WithChannelzParentID(id int64) DialOption { 483 return newFuncDialOption(func(o *dialOptions) { 484 o.channelzParentID = id 485 }) 486} 487 488// WithDisableServiceConfig returns a DialOption that causes gRPC to ignore any 489// service config provided by the resolver and provides a hint to the resolver 490// to not fetch service configs. 491// 492// Note that this dial option only disables service config from resolver. If 493// default service config is provided, gRPC will use the default service config. 494func WithDisableServiceConfig() DialOption { 495 return newFuncDialOption(func(o *dialOptions) { 496 o.disableServiceConfig = true 497 }) 498} 499 500// WithDefaultServiceConfig returns a DialOption that configures the default 501// service config, which will be used in cases where: 502// 503// 1. WithDisableServiceConfig is also used. 504// 2. Resolver does not return a service config or if the resolver returns an 505// invalid service config. 506// 507// This API is EXPERIMENTAL. 508func WithDefaultServiceConfig(s string) DialOption { 509 return newFuncDialOption(func(o *dialOptions) { 510 o.defaultServiceConfigRawJSON = &s 511 }) 512} 513 514// WithDisableRetry returns a DialOption that disables retries, even if the 515// service config enables them. This does not impact transparent retries, which 516// will happen automatically if no data is written to the wire or if the RPC is 517// unprocessed by the remote server. 518// 519// Retry support is currently disabled by default, but will be enabled by 520// default in the future. Until then, it may be enabled by setting the 521// environment variable "GRPC_GO_RETRY" to "on". 522// 523// This API is EXPERIMENTAL. 524func WithDisableRetry() DialOption { 525 return newFuncDialOption(func(o *dialOptions) { 526 o.disableRetry = true 527 }) 528} 529 530// WithMaxHeaderListSize returns a DialOption that specifies the maximum 531// (uncompressed) size of header list that the client is prepared to accept. 532func WithMaxHeaderListSize(s uint32) DialOption { 533 return newFuncDialOption(func(o *dialOptions) { 534 o.copts.MaxHeaderListSize = &s 535 }) 536} 537 538// WithDisableHealthCheck disables the LB channel health checking for all 539// SubConns of this ClientConn. 540// 541// This API is EXPERIMENTAL. 542func WithDisableHealthCheck() DialOption { 543 return newFuncDialOption(func(o *dialOptions) { 544 o.disableHealthCheck = true 545 }) 546} 547 548// withHealthCheckFunc replaces the default health check function with the 549// provided one. It makes tests easier to change the health check function. 550// 551// For testing purpose only. 552func withHealthCheckFunc(f internal.HealthChecker) DialOption { 553 return newFuncDialOption(func(o *dialOptions) { 554 o.healthCheckFunc = f 555 }) 556} 557 558func defaultDialOptions() dialOptions { 559 return dialOptions{ 560 disableRetry: !envconfig.Retry, 561 healthCheckFunc: internal.HealthCheckFunc, 562 copts: transport.ConnectOptions{ 563 WriteBufferSize: defaultWriteBufSize, 564 ReadBufferSize: defaultReadBufSize, 565 }, 566 resolveNowBackoff: internalbackoff.DefaultExponential.Backoff, 567 } 568} 569 570// withGetMinConnectDeadline specifies the function that clientconn uses to 571// get minConnectDeadline. This can be used to make connection attempts happen 572// faster/slower. 573// 574// For testing purpose only. 575func withMinConnectDeadline(f func() time.Duration) DialOption { 576 return newFuncDialOption(func(o *dialOptions) { 577 o.minConnectTimeout = f 578 }) 579} 580 581// withResolveNowBackoff specifies the function that clientconn uses to backoff 582// between successive calls to resolver.ResolveNow(). 583// 584// For testing purpose only. 585func withResolveNowBackoff(f func(int) time.Duration) DialOption { 586 return newFuncDialOption(func(o *dialOptions) { 587 o.resolveNowBackoff = f 588 }) 589} 590