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 "fmt" 23 "net" 24 "time" 25 26 "golang.org/x/net/context" 27 "google.golang.org/grpc/balancer" 28 "google.golang.org/grpc/credentials" 29 "google.golang.org/grpc/internal" 30 "google.golang.org/grpc/internal/backoff" 31 "google.golang.org/grpc/internal/envconfig" 32 "google.golang.org/grpc/internal/transport" 33 "google.golang.org/grpc/keepalive" 34 "google.golang.org/grpc/resolver" 35 "google.golang.org/grpc/stats" 36) 37 38// dialOptions configure a Dial call. dialOptions are set by the DialOption 39// values passed to Dial. 40type dialOptions struct { 41 unaryInt UnaryClientInterceptor 42 streamInt StreamClientInterceptor 43 cp Compressor 44 dc Decompressor 45 bs backoff.Strategy 46 block bool 47 insecure bool 48 timeout time.Duration 49 scChan <-chan ServiceConfig 50 authority string 51 copts transport.ConnectOptions 52 callOptions []CallOption 53 // This is used by v1 balancer dial option WithBalancer to support v1 54 // balancer, and also by WithBalancerName dial option. 55 balancerBuilder balancer.Builder 56 // This is to support grpclb. 57 resolverBuilder resolver.Builder 58 waitForHandshake bool 59 channelzParentID int64 60 disableServiceConfig bool 61 disableRetry bool 62} 63 64// DialOption configures how we set up the connection. 65type DialOption func(*dialOptions) 66 67// WithWaitForHandshake blocks until the initial settings frame is received from 68// the server before assigning RPCs to the connection. Experimental API. 69func WithWaitForHandshake() DialOption { 70 return func(o *dialOptions) { 71 o.waitForHandshake = true 72 } 73} 74 75// WithWriteBufferSize determines how much data can be batched before doing a 76// write on the wire. The corresponding memory allocation for this buffer will 77// be twice the size to keep syscalls low. The default value for this buffer is 78// 32KB. 79// 80// Zero will disable the write buffer such that each write will be on underlying 81// connection. Note: A Send call may not directly translate to a write. 82func WithWriteBufferSize(s int) DialOption { 83 return func(o *dialOptions) { 84 o.copts.WriteBufferSize = s 85 } 86} 87 88// WithReadBufferSize lets you set the size of read buffer, this determines how 89// much data can be read at most for each read syscall. 90// 91// The default value for this buffer is 32KB. Zero will disable read buffer for 92// a connection so data framer can access the underlying conn directly. 93func WithReadBufferSize(s int) DialOption { 94 return func(o *dialOptions) { 95 o.copts.ReadBufferSize = s 96 } 97} 98 99// WithInitialWindowSize returns a DialOption which sets the value for initial 100// window size on a stream. The lower bound for window size is 64K and any value 101// smaller than that will be ignored. 102func WithInitialWindowSize(s int32) DialOption { 103 return func(o *dialOptions) { 104 o.copts.InitialWindowSize = s 105 } 106} 107 108// WithInitialConnWindowSize returns a DialOption which sets the value for 109// initial window size on a connection. The lower bound for window size is 64K 110// and any value smaller than that will be ignored. 111func WithInitialConnWindowSize(s int32) DialOption { 112 return func(o *dialOptions) { 113 o.copts.InitialConnWindowSize = s 114 } 115} 116 117// WithMaxMsgSize returns a DialOption which sets the maximum message size the 118// client can receive. 119// 120// Deprecated: use WithDefaultCallOptions(MaxCallRecvMsgSize(s)) instead. 121func WithMaxMsgSize(s int) DialOption { 122 return WithDefaultCallOptions(MaxCallRecvMsgSize(s)) 123} 124 125// WithDefaultCallOptions returns a DialOption which sets the default 126// CallOptions for calls over the connection. 127func WithDefaultCallOptions(cos ...CallOption) DialOption { 128 return func(o *dialOptions) { 129 o.callOptions = append(o.callOptions, cos...) 130 } 131} 132 133// WithCodec returns a DialOption which sets a codec for message marshaling and 134// unmarshaling. 135// 136// Deprecated: use WithDefaultCallOptions(CallCustomCodec(c)) instead. 137func WithCodec(c Codec) DialOption { 138 return WithDefaultCallOptions(CallCustomCodec(c)) 139} 140 141// WithCompressor returns a DialOption which sets a Compressor to use for 142// message compression. It has lower priority than the compressor set by the 143// UseCompressor CallOption. 144// 145// Deprecated: use UseCompressor instead. 146func WithCompressor(cp Compressor) DialOption { 147 return func(o *dialOptions) { 148 o.cp = cp 149 } 150} 151 152// WithDecompressor returns a DialOption which sets a Decompressor to use for 153// incoming message decompression. If incoming response messages are encoded 154// using the decompressor's Type(), it will be used. Otherwise, the message 155// encoding will be used to look up the compressor registered via 156// encoding.RegisterCompressor, which will then be used to decompress the 157// message. If no compressor is registered for the encoding, an Unimplemented 158// status error will be returned. 159// 160// Deprecated: use encoding.RegisterCompressor instead. 161func WithDecompressor(dc Decompressor) DialOption { 162 return func(o *dialOptions) { 163 o.dc = dc 164 } 165} 166 167// WithBalancer returns a DialOption which sets a load balancer with the v1 API. 168// Name resolver will be ignored if this DialOption is specified. 169// 170// Deprecated: use the new balancer APIs in balancer package and 171// WithBalancerName. 172func WithBalancer(b Balancer) DialOption { 173 return func(o *dialOptions) { 174 o.balancerBuilder = &balancerWrapperBuilder{ 175 b: b, 176 } 177 } 178} 179 180// WithBalancerName sets the balancer that the ClientConn will be initialized 181// with. Balancer registered with balancerName will be used. This function 182// panics if no balancer was registered by balancerName. 183// 184// The balancer cannot be overridden by balancer option specified by service 185// config. 186// 187// This is an EXPERIMENTAL API. 188func WithBalancerName(balancerName string) DialOption { 189 builder := balancer.Get(balancerName) 190 if builder == nil { 191 panic(fmt.Sprintf("grpc.WithBalancerName: no balancer is registered for name %v", balancerName)) 192 } 193 return func(o *dialOptions) { 194 o.balancerBuilder = builder 195 } 196} 197 198// withResolverBuilder is only for grpclb. 199func withResolverBuilder(b resolver.Builder) DialOption { 200 return func(o *dialOptions) { 201 o.resolverBuilder = b 202 } 203} 204 205// WithServiceConfig returns a DialOption which has a channel to read the 206// service configuration. 207// 208// Deprecated: service config should be received through name resolver, as 209// specified here. 210// https://github.com/grpc/grpc/blob/master/doc/service_config.md 211func WithServiceConfig(c <-chan ServiceConfig) DialOption { 212 return func(o *dialOptions) { 213 o.scChan = c 214 } 215} 216 217// WithBackoffMaxDelay configures the dialer to use the provided maximum delay 218// when backing off after failed connection attempts. 219func WithBackoffMaxDelay(md time.Duration) DialOption { 220 return WithBackoffConfig(BackoffConfig{MaxDelay: md}) 221} 222 223// WithBackoffConfig configures the dialer to use the provided backoff 224// parameters after connection failures. 225// 226// Use WithBackoffMaxDelay until more parameters on BackoffConfig are opened up 227// for use. 228func WithBackoffConfig(b BackoffConfig) DialOption { 229 return withBackoff(backoff.Exponential{ 230 MaxDelay: b.MaxDelay, 231 }) 232} 233 234// withBackoff sets the backoff strategy used for connectRetryNum after a failed 235// connection attempt. 236// 237// This can be exported if arbitrary backoff strategies are allowed by gRPC. 238func withBackoff(bs backoff.Strategy) DialOption { 239 return func(o *dialOptions) { 240 o.bs = bs 241 } 242} 243 244// WithBlock returns a DialOption which makes caller of Dial blocks until the 245// underlying connection is up. Without this, Dial returns immediately and 246// connecting the server happens in background. 247func WithBlock() DialOption { 248 return func(o *dialOptions) { 249 o.block = true 250 } 251} 252 253// WithInsecure returns a DialOption which disables transport security for this 254// ClientConn. Note that transport security is required unless WithInsecure is 255// set. 256func WithInsecure() DialOption { 257 return func(o *dialOptions) { 258 o.insecure = true 259 } 260} 261 262// WithTransportCredentials returns a DialOption which configures a connection 263// level security credentials (e.g., TLS/SSL). 264func WithTransportCredentials(creds credentials.TransportCredentials) DialOption { 265 return func(o *dialOptions) { 266 o.copts.TransportCredentials = creds 267 } 268} 269 270// WithPerRPCCredentials returns a DialOption which sets credentials and places 271// auth state on each outbound RPC. 272func WithPerRPCCredentials(creds credentials.PerRPCCredentials) DialOption { 273 return func(o *dialOptions) { 274 o.copts.PerRPCCredentials = append(o.copts.PerRPCCredentials, creds) 275 } 276} 277 278// WithTimeout returns a DialOption that configures a timeout for dialing a 279// ClientConn initially. This is valid if and only if WithBlock() is present. 280// 281// Deprecated: use DialContext and context.WithTimeout instead. 282func WithTimeout(d time.Duration) DialOption { 283 return func(o *dialOptions) { 284 o.timeout = d 285 } 286} 287 288func withContextDialer(f func(context.Context, string) (net.Conn, error)) DialOption { 289 return func(o *dialOptions) { 290 o.copts.Dialer = f 291 } 292} 293 294func init() { 295 internal.WithContextDialer = withContextDialer 296 internal.WithResolverBuilder = withResolverBuilder 297} 298 299// WithDialer returns a DialOption that specifies a function to use for dialing 300// network addresses. If FailOnNonTempDialError() is set to true, and an error 301// is returned by f, gRPC checks the error's Temporary() method to decide if it 302// should try to reconnect to the network address. 303func WithDialer(f func(string, time.Duration) (net.Conn, error)) DialOption { 304 return withContextDialer( 305 func(ctx context.Context, addr string) (net.Conn, error) { 306 if deadline, ok := ctx.Deadline(); ok { 307 return f(addr, deadline.Sub(time.Now())) 308 } 309 return f(addr, 0) 310 }) 311} 312 313// WithStatsHandler returns a DialOption that specifies the stats handler for 314// all the RPCs and underlying network connections in this ClientConn. 315func WithStatsHandler(h stats.Handler) DialOption { 316 return func(o *dialOptions) { 317 o.copts.StatsHandler = h 318 } 319} 320 321// FailOnNonTempDialError returns a DialOption that specifies if gRPC fails on 322// non-temporary dial errors. If f is true, and dialer returns a non-temporary 323// error, gRPC will fail the connection to the network address and won't try to 324// reconnect. The default value of FailOnNonTempDialError is false. 325// 326// This is an EXPERIMENTAL API. 327func FailOnNonTempDialError(f bool) DialOption { 328 return func(o *dialOptions) { 329 o.copts.FailOnNonTempDialError = f 330 } 331} 332 333// WithUserAgent returns a DialOption that specifies a user agent string for all 334// the RPCs. 335func WithUserAgent(s string) DialOption { 336 return func(o *dialOptions) { 337 o.copts.UserAgent = s 338 } 339} 340 341// WithKeepaliveParams returns a DialOption that specifies keepalive parameters 342// for the client transport. 343func WithKeepaliveParams(kp keepalive.ClientParameters) DialOption { 344 return func(o *dialOptions) { 345 o.copts.KeepaliveParams = kp 346 } 347} 348 349// WithUnaryInterceptor returns a DialOption that specifies the interceptor for 350// unary RPCs. 351func WithUnaryInterceptor(f UnaryClientInterceptor) DialOption { 352 return func(o *dialOptions) { 353 o.unaryInt = f 354 } 355} 356 357// WithStreamInterceptor returns a DialOption that specifies the interceptor for 358// streaming RPCs. 359func WithStreamInterceptor(f StreamClientInterceptor) DialOption { 360 return func(o *dialOptions) { 361 o.streamInt = f 362 } 363} 364 365// WithAuthority returns a DialOption that specifies the value to be used as the 366// :authority pseudo-header. This value only works with WithInsecure and has no 367// effect if TransportCredentials are present. 368func WithAuthority(a string) DialOption { 369 return func(o *dialOptions) { 370 o.authority = a 371 } 372} 373 374// WithChannelzParentID returns a DialOption that specifies the channelz ID of 375// current ClientConn's parent. This function is used in nested channel creation 376// (e.g. grpclb dial). 377func WithChannelzParentID(id int64) DialOption { 378 return func(o *dialOptions) { 379 o.channelzParentID = id 380 } 381} 382 383// WithDisableServiceConfig returns a DialOption that causes grpc to ignore any 384// service config provided by the resolver and provides a hint to the resolver 385// to not fetch service configs. 386func WithDisableServiceConfig() DialOption { 387 return func(o *dialOptions) { 388 o.disableServiceConfig = true 389 } 390} 391 392// WithDisableRetry returns a DialOption that disables retries, even if the 393// service config enables them. This does not impact transparent retries, which 394// will happen automatically if no data is written to the wire or if the RPC is 395// unprocessed by the remote server. 396// 397// Retry support is currently disabled by default, but will be enabled by 398// default in the future. Until then, it may be enabled by setting the 399// environment variable "GRPC_GO_RETRY" to "on". 400// 401// This API is EXPERIMENTAL. 402func WithDisableRetry() DialOption { 403 return func(o *dialOptions) { 404 o.disableRetry = true 405 } 406} 407 408// WithMaxHeaderListSize returns a DialOption that specifies the maximum 409// (uncompressed) size of header list that the client is prepared to accept. 410func WithMaxHeaderListSize(s uint32) DialOption { 411 return func(o *dialOptions) { 412 o.copts.MaxHeaderListSize = &s 413 } 414} 415 416func defaultDialOptions() dialOptions { 417 return dialOptions{ 418 disableRetry: !envconfig.Retry, 419 copts: transport.ConnectOptions{ 420 WriteBufferSize: defaultWriteBufSize, 421 ReadBufferSize: defaultReadBufSize, 422 }, 423 } 424} 425