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