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