dialoptions.go raw

   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  
  19  package grpc
  20  
  21  import (
  22  	"context"
  23  	"net"
  24  	"net/url"
  25  	"time"
  26  
  27  	"google.golang.org/grpc/backoff"
  28  	"google.golang.org/grpc/channelz"
  29  	"google.golang.org/grpc/credentials"
  30  	"google.golang.org/grpc/credentials/insecure"
  31  	"google.golang.org/grpc/internal"
  32  	internalbackoff "google.golang.org/grpc/internal/backoff"
  33  	"google.golang.org/grpc/internal/binarylog"
  34  	"google.golang.org/grpc/internal/transport"
  35  	"google.golang.org/grpc/keepalive"
  36  	"google.golang.org/grpc/mem"
  37  	"google.golang.org/grpc/resolver"
  38  	"google.golang.org/grpc/stats"
  39  )
  40  
  41  const (
  42  	// https://github.com/grpc/proposal/blob/master/A6-client-retries.md#limits-on-retries-and-hedges
  43  	defaultMaxCallAttempts = 5
  44  )
  45  
  46  func init() {
  47  	internal.AddGlobalDialOptions = func(opt ...DialOption) {
  48  		globalDialOptions = append(globalDialOptions, opt...)
  49  	}
  50  	internal.ClearGlobalDialOptions = func() {
  51  		globalDialOptions = nil
  52  	}
  53  	internal.AddGlobalPerTargetDialOptions = func(opt any) {
  54  		if ptdo, ok := opt.(perTargetDialOption); ok {
  55  			globalPerTargetDialOptions = append(globalPerTargetDialOptions, ptdo)
  56  		}
  57  	}
  58  	internal.ClearGlobalPerTargetDialOptions = func() {
  59  		globalPerTargetDialOptions = nil
  60  	}
  61  	internal.WithBinaryLogger = withBinaryLogger
  62  	internal.JoinDialOptions = newJoinDialOption
  63  	internal.DisableGlobalDialOptions = newDisableGlobalDialOptions
  64  	internal.WithBufferPool = withBufferPool
  65  }
  66  
  67  // dialOptions configure a Dial call. dialOptions are set by the DialOption
  68  // values passed to Dial.
  69  type dialOptions struct {
  70  	unaryInt  UnaryClientInterceptor
  71  	streamInt StreamClientInterceptor
  72  
  73  	chainUnaryInts  []UnaryClientInterceptor
  74  	chainStreamInts []StreamClientInterceptor
  75  
  76  	compressorV0                Compressor
  77  	dc                          Decompressor
  78  	bs                          internalbackoff.Strategy
  79  	block                       bool
  80  	returnLastError             bool
  81  	timeout                     time.Duration
  82  	authority                   string
  83  	binaryLogger                binarylog.Logger
  84  	copts                       transport.ConnectOptions
  85  	callOptions                 []CallOption
  86  	channelzParent              channelz.Identifier
  87  	disableServiceConfig        bool
  88  	disableRetry                bool
  89  	disableHealthCheck          bool
  90  	minConnectTimeout           func() time.Duration
  91  	defaultServiceConfig        *ServiceConfig // defaultServiceConfig is parsed from defaultServiceConfigRawJSON.
  92  	defaultServiceConfigRawJSON *string
  93  	resolvers                   []resolver.Builder
  94  	idleTimeout                 time.Duration
  95  	defaultScheme               string
  96  	maxCallAttempts             int
  97  	enableLocalDNSResolution    bool // Specifies if target hostnames should be resolved when proxying is enabled.
  98  	useProxy                    bool // Specifies if a server should be connected via proxy.
  99  }
 100  
 101  // DialOption configures how we set up the connection.
 102  type DialOption interface {
 103  	apply(*dialOptions)
 104  }
 105  
 106  var globalDialOptions []DialOption
 107  
 108  // perTargetDialOption takes a parsed target and returns a dial option to apply.
 109  //
 110  // This gets called after NewClient() parses the target, and allows per target
 111  // configuration set through a returned DialOption. The DialOption will not take
 112  // effect if specifies a resolver builder, as that Dial Option is factored in
 113  // while parsing target.
 114  type perTargetDialOption interface {
 115  	// DialOption returns a Dial Option to apply.
 116  	DialOptionForTarget(parsedTarget url.URL) DialOption
 117  }
 118  
 119  var globalPerTargetDialOptions []perTargetDialOption
 120  
 121  // EmptyDialOption does not alter the dial configuration. It can be embedded in
 122  // another structure to build custom dial options.
 123  //
 124  // # Experimental
 125  //
 126  // Notice: This type is EXPERIMENTAL and may be changed or removed in a
 127  // later release.
 128  type EmptyDialOption struct{}
 129  
 130  func (EmptyDialOption) apply(*dialOptions) {}
 131  
 132  type disableGlobalDialOptions struct{}
 133  
 134  func (disableGlobalDialOptions) apply(*dialOptions) {}
 135  
 136  // newDisableGlobalDialOptions returns a DialOption that prevents the ClientConn
 137  // from applying the global DialOptions (set via AddGlobalDialOptions).
 138  func newDisableGlobalDialOptions() DialOption {
 139  	return &disableGlobalDialOptions{}
 140  }
 141  
 142  // funcDialOption wraps a function that modifies dialOptions into an
 143  // implementation of the DialOption interface.
 144  type funcDialOption struct {
 145  	f func(*dialOptions)
 146  }
 147  
 148  func (fdo *funcDialOption) apply(do *dialOptions) {
 149  	fdo.f(do)
 150  }
 151  
 152  func newFuncDialOption(f func(*dialOptions)) *funcDialOption {
 153  	return &funcDialOption{
 154  		f: f,
 155  	}
 156  }
 157  
 158  type joinDialOption struct {
 159  	opts []DialOption
 160  }
 161  
 162  func (jdo *joinDialOption) apply(do *dialOptions) {
 163  	for _, opt := range jdo.opts {
 164  		opt.apply(do)
 165  	}
 166  }
 167  
 168  func newJoinDialOption(opts ...DialOption) DialOption {
 169  	return &joinDialOption{opts: opts}
 170  }
 171  
 172  // WithSharedWriteBuffer allows reusing per-connection transport write buffer.
 173  // If this option is set to true every connection will release the buffer after
 174  // flushing the data on the wire.
 175  //
 176  // # Experimental
 177  //
 178  // Notice: This API is EXPERIMENTAL and may be changed or removed in a
 179  // later release.
 180  func WithSharedWriteBuffer(val bool) DialOption {
 181  	return newFuncDialOption(func(o *dialOptions) {
 182  		o.copts.SharedWriteBuffer = val
 183  	})
 184  }
 185  
 186  // WithWriteBufferSize determines how much data can be batched before doing a
 187  // write on the wire. The default value for this buffer is 32KB.
 188  //
 189  // Zero or negative values will disable the write buffer such that each write
 190  // will be on underlying connection. Note: A Send call may not directly
 191  // translate to a write.
 192  func WithWriteBufferSize(s int) DialOption {
 193  	return newFuncDialOption(func(o *dialOptions) {
 194  		o.copts.WriteBufferSize = s
 195  	})
 196  }
 197  
 198  // WithReadBufferSize lets you set the size of read buffer, this determines how
 199  // much data can be read at most for each read syscall.
 200  //
 201  // The default value for this buffer is 32KB. Zero or negative values will
 202  // disable read buffer for a connection so data framer can access the
 203  // underlying conn directly.
 204  func WithReadBufferSize(s int) DialOption {
 205  	return newFuncDialOption(func(o *dialOptions) {
 206  		o.copts.ReadBufferSize = s
 207  	})
 208  }
 209  
 210  // WithInitialWindowSize returns a DialOption which sets the value for initial
 211  // window size on a stream. The lower bound for window size is 64K and any value
 212  // smaller than that will be ignored.
 213  func WithInitialWindowSize(s int32) DialOption {
 214  	return newFuncDialOption(func(o *dialOptions) {
 215  		o.copts.InitialWindowSize = s
 216  		o.copts.StaticWindowSize = true
 217  	})
 218  }
 219  
 220  // WithInitialConnWindowSize returns a DialOption which sets the value for
 221  // initial window size on a connection. The lower bound for window size is 64K
 222  // and any value smaller than that will be ignored.
 223  func WithInitialConnWindowSize(s int32) DialOption {
 224  	return newFuncDialOption(func(o *dialOptions) {
 225  		o.copts.InitialConnWindowSize = s
 226  		o.copts.StaticWindowSize = true
 227  	})
 228  }
 229  
 230  // WithStaticStreamWindowSize returns a DialOption which sets the initial
 231  // stream window size to the value provided and disables dynamic flow control.
 232  func WithStaticStreamWindowSize(s int32) DialOption {
 233  	return newFuncDialOption(func(o *dialOptions) {
 234  		o.copts.InitialWindowSize = s
 235  		o.copts.StaticWindowSize = true
 236  	})
 237  }
 238  
 239  // WithStaticConnWindowSize returns a DialOption which sets the initial
 240  // connection window size to the value provided and disables dynamic flow
 241  // control.
 242  func WithStaticConnWindowSize(s int32) DialOption {
 243  	return newFuncDialOption(func(o *dialOptions) {
 244  		o.copts.InitialConnWindowSize = s
 245  		o.copts.StaticWindowSize = true
 246  	})
 247  }
 248  
 249  // WithMaxMsgSize returns a DialOption which sets the maximum message size the
 250  // client can receive.
 251  //
 252  // Deprecated: use WithDefaultCallOptions(MaxCallRecvMsgSize(s)) instead.  Will
 253  // be supported throughout 1.x.
 254  func WithMaxMsgSize(s int) DialOption {
 255  	return WithDefaultCallOptions(MaxCallRecvMsgSize(s))
 256  }
 257  
 258  // WithDefaultCallOptions returns a DialOption which sets the default
 259  // CallOptions for calls over the connection.
 260  func WithDefaultCallOptions(cos ...CallOption) DialOption {
 261  	return newFuncDialOption(func(o *dialOptions) {
 262  		o.callOptions = append(o.callOptions, cos...)
 263  	})
 264  }
 265  
 266  // WithCodec returns a DialOption which sets a codec for message marshaling and
 267  // unmarshaling.
 268  //
 269  // Deprecated: use WithDefaultCallOptions(ForceCodec(_)) instead.  Will be
 270  // supported throughout 1.x.
 271  func WithCodec(c Codec) DialOption {
 272  	return WithDefaultCallOptions(CallCustomCodec(c))
 273  }
 274  
 275  // WithCompressor returns a DialOption which sets a Compressor to use for
 276  // message compression. It has lower priority than the compressor set by the
 277  // UseCompressor CallOption.
 278  //
 279  // Deprecated: use UseCompressor instead.  Will be supported throughout 1.x.
 280  func WithCompressor(cp Compressor) DialOption {
 281  	return newFuncDialOption(func(o *dialOptions) {
 282  		o.compressorV0 = cp
 283  	})
 284  }
 285  
 286  // WithDecompressor returns a DialOption which sets a Decompressor to use for
 287  // incoming message decompression.  If incoming response messages are encoded
 288  // using the decompressor's Type(), it will be used.  Otherwise, the message
 289  // encoding will be used to look up the compressor registered via
 290  // encoding.RegisterCompressor, which will then be used to decompress the
 291  // message.  If no compressor is registered for the encoding, an Unimplemented
 292  // status error will be returned.
 293  //
 294  // Deprecated: use encoding.RegisterCompressor instead.  Will be supported
 295  // throughout 1.x.
 296  func WithDecompressor(dc Decompressor) DialOption {
 297  	return newFuncDialOption(func(o *dialOptions) {
 298  		o.dc = dc
 299  	})
 300  }
 301  
 302  // WithConnectParams configures the ClientConn to use the provided ConnectParams
 303  // for creating and maintaining connections to servers.
 304  //
 305  // The backoff configuration specified as part of the ConnectParams overrides
 306  // all defaults specified in
 307  // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. Consider
 308  // using the backoff.DefaultConfig as a base, in cases where you want to
 309  // override only a subset of the backoff configuration.
 310  func WithConnectParams(p ConnectParams) DialOption {
 311  	return newFuncDialOption(func(o *dialOptions) {
 312  		o.bs = internalbackoff.Exponential{Config: p.Backoff}
 313  		o.minConnectTimeout = func() time.Duration {
 314  			return p.MinConnectTimeout
 315  		}
 316  	})
 317  }
 318  
 319  // WithBackoffMaxDelay configures the dialer to use the provided maximum delay
 320  // when backing off after failed connection attempts.
 321  //
 322  // Deprecated: use WithConnectParams instead. Will be supported throughout 1.x.
 323  func WithBackoffMaxDelay(md time.Duration) DialOption {
 324  	return WithBackoffConfig(BackoffConfig{MaxDelay: md})
 325  }
 326  
 327  // WithBackoffConfig configures the dialer to use the provided backoff
 328  // parameters after connection failures.
 329  //
 330  // Deprecated: use WithConnectParams instead. Will be supported throughout 1.x.
 331  func WithBackoffConfig(b BackoffConfig) DialOption {
 332  	bc := backoff.DefaultConfig
 333  	bc.MaxDelay = b.MaxDelay
 334  	return withBackoff(internalbackoff.Exponential{Config: bc})
 335  }
 336  
 337  // withBackoff sets the backoff strategy used for connectRetryNum after a failed
 338  // connection attempt.
 339  //
 340  // This can be exported if arbitrary backoff strategies are allowed by gRPC.
 341  func withBackoff(bs internalbackoff.Strategy) DialOption {
 342  	return newFuncDialOption(func(o *dialOptions) {
 343  		o.bs = bs
 344  	})
 345  }
 346  
 347  // WithBlock returns a DialOption which makes callers of Dial block until the
 348  // underlying connection is up. Without this, Dial returns immediately and
 349  // connecting the server happens in background.
 350  //
 351  // Use of this feature is not recommended.  For more information, please see:
 352  // https://github.com/grpc/grpc-go/blob/master/Documentation/anti-patterns.md
 353  //
 354  // Deprecated: this DialOption is not supported by NewClient.
 355  // Will be supported throughout 1.x.
 356  func WithBlock() DialOption {
 357  	return newFuncDialOption(func(o *dialOptions) {
 358  		o.block = true
 359  	})
 360  }
 361  
 362  // WithReturnConnectionError returns a DialOption which makes the client connection
 363  // return a string containing both the last connection error that occurred and
 364  // the context.DeadlineExceeded error.
 365  // Implies WithBlock()
 366  //
 367  // Use of this feature is not recommended.  For more information, please see:
 368  // https://github.com/grpc/grpc-go/blob/master/Documentation/anti-patterns.md
 369  //
 370  // Deprecated: this DialOption is not supported by NewClient.
 371  // Will be supported throughout 1.x.
 372  func WithReturnConnectionError() DialOption {
 373  	return newFuncDialOption(func(o *dialOptions) {
 374  		o.block = true
 375  		o.returnLastError = true
 376  	})
 377  }
 378  
 379  // WithInsecure returns a DialOption which disables transport security for this
 380  // ClientConn. Under the hood, it uses insecure.NewCredentials().
 381  //
 382  // Note that using this DialOption with per-RPC credentials (through
 383  // WithCredentialsBundle or WithPerRPCCredentials) which require transport
 384  // security is incompatible and will cause RPCs to fail.
 385  //
 386  // Deprecated: use WithTransportCredentials and insecure.NewCredentials()
 387  // instead. Will be supported throughout 1.x.
 388  func WithInsecure() DialOption {
 389  	return newFuncDialOption(func(o *dialOptions) {
 390  		o.copts.TransportCredentials = insecure.NewCredentials()
 391  	})
 392  }
 393  
 394  // WithNoProxy returns a DialOption which disables the use of proxies for this
 395  // ClientConn. This is ignored if WithDialer or WithContextDialer are used.
 396  //
 397  // # Experimental
 398  //
 399  // Notice: This API is EXPERIMENTAL and may be changed or removed in a
 400  // later release.
 401  func WithNoProxy() DialOption {
 402  	return newFuncDialOption(func(o *dialOptions) {
 403  		o.useProxy = false
 404  	})
 405  }
 406  
 407  // WithLocalDNSResolution forces local DNS name resolution even when a proxy is
 408  // specified in the environment.  By default, the server name is provided
 409  // directly to the proxy as part of the CONNECT handshake. This is ignored if
 410  // WithNoProxy is used.
 411  //
 412  // # Experimental
 413  //
 414  // Notice: This API is EXPERIMENTAL and may be changed or removed in a
 415  // later release.
 416  func WithLocalDNSResolution() DialOption {
 417  	return newFuncDialOption(func(o *dialOptions) {
 418  		o.enableLocalDNSResolution = true
 419  	})
 420  }
 421  
 422  // WithTransportCredentials returns a DialOption which configures a connection
 423  // level security credentials (e.g., TLS/SSL). This should not be used together
 424  // with WithCredentialsBundle.
 425  func WithTransportCredentials(creds credentials.TransportCredentials) DialOption {
 426  	return newFuncDialOption(func(o *dialOptions) {
 427  		o.copts.TransportCredentials = creds
 428  	})
 429  }
 430  
 431  // WithPerRPCCredentials returns a DialOption which sets credentials and places
 432  // auth state on each outbound RPC.
 433  func WithPerRPCCredentials(creds credentials.PerRPCCredentials) DialOption {
 434  	return newFuncDialOption(func(o *dialOptions) {
 435  		o.copts.PerRPCCredentials = append(o.copts.PerRPCCredentials, creds)
 436  	})
 437  }
 438  
 439  // WithCredentialsBundle returns a DialOption to set a credentials bundle for
 440  // the ClientConn.WithCreds. This should not be used together with
 441  // WithTransportCredentials.
 442  //
 443  // # Experimental
 444  //
 445  // Notice: This API is EXPERIMENTAL and may be changed or removed in a
 446  // later release.
 447  func WithCredentialsBundle(b credentials.Bundle) DialOption {
 448  	return newFuncDialOption(func(o *dialOptions) {
 449  		o.copts.CredsBundle = b
 450  	})
 451  }
 452  
 453  // WithTimeout returns a DialOption that configures a timeout for dialing a
 454  // ClientConn initially. This is valid if and only if WithBlock() is present.
 455  //
 456  // Deprecated: this DialOption is not supported by NewClient.
 457  // Will be supported throughout 1.x.
 458  func WithTimeout(d time.Duration) DialOption {
 459  	return newFuncDialOption(func(o *dialOptions) {
 460  		o.timeout = d
 461  	})
 462  }
 463  
 464  // WithContextDialer returns a DialOption that sets a dialer to create
 465  // connections. If FailOnNonTempDialError() is set to true, and an error is
 466  // returned by f, gRPC checks the error's Temporary() method to decide if it
 467  // should try to reconnect to the network address.
 468  //
 469  // Note that gRPC by default performs name resolution on the target passed to
 470  // NewClient. To bypass name resolution and cause the target string to be
 471  // passed directly to the dialer here instead, use the "passthrough" resolver
 472  // by specifying it in the target string, e.g. "passthrough:target".
 473  //
 474  // Note: All supported releases of Go (as of December 2023) override the OS
 475  // defaults for TCP keepalive time and interval to 15s. To enable TCP keepalive
 476  // with OS defaults for keepalive time and interval, use a net.Dialer that sets
 477  // the KeepAlive field to a negative value, and sets the SO_KEEPALIVE socket
 478  // option to true from the Control field. For a concrete example of how to do
 479  // this, see internal.NetDialerWithTCPKeepalive().
 480  //
 481  // For more information, please see [issue 23459] in the Go GitHub repo.
 482  //
 483  // [issue 23459]: https://github.com/golang/go/issues/23459
 484  func WithContextDialer(f func(context.Context, string) (net.Conn, error)) DialOption {
 485  	return newFuncDialOption(func(o *dialOptions) {
 486  		o.copts.Dialer = f
 487  	})
 488  }
 489  
 490  // WithDialer returns a DialOption that specifies a function to use for dialing
 491  // network addresses. If FailOnNonTempDialError() is set to true, and an error
 492  // is returned by f, gRPC checks the error's Temporary() method to decide if it
 493  // should try to reconnect to the network address.
 494  //
 495  // Deprecated: use WithContextDialer instead.  Will be supported throughout
 496  // 1.x.
 497  func WithDialer(f func(string, time.Duration) (net.Conn, error)) DialOption {
 498  	return WithContextDialer(
 499  		func(ctx context.Context, addr string) (net.Conn, error) {
 500  			if deadline, ok := ctx.Deadline(); ok {
 501  				return f(addr, time.Until(deadline))
 502  			}
 503  			return f(addr, 0)
 504  		})
 505  }
 506  
 507  // WithStatsHandler returns a DialOption that specifies the stats handler for
 508  // all the RPCs and underlying network connections in this ClientConn.
 509  func WithStatsHandler(h stats.Handler) DialOption {
 510  	return newFuncDialOption(func(o *dialOptions) {
 511  		if h == nil {
 512  			logger.Error("ignoring nil parameter in grpc.WithStatsHandler ClientOption")
 513  			// Do not allow a nil stats handler, which would otherwise cause
 514  			// panics.
 515  			return
 516  		}
 517  		o.copts.StatsHandlers = append(o.copts.StatsHandlers, h)
 518  	})
 519  }
 520  
 521  // withBinaryLogger returns a DialOption that specifies the binary logger for
 522  // this ClientConn.
 523  func withBinaryLogger(bl binarylog.Logger) DialOption {
 524  	return newFuncDialOption(func(o *dialOptions) {
 525  		o.binaryLogger = bl
 526  	})
 527  }
 528  
 529  // FailOnNonTempDialError returns a DialOption that specifies if gRPC fails on
 530  // non-temporary dial errors. If f is true, and dialer returns a non-temporary
 531  // error, gRPC will fail the connection to the network address and won't try to
 532  // reconnect. The default value of FailOnNonTempDialError is false.
 533  //
 534  // FailOnNonTempDialError only affects the initial dial, and does not do
 535  // anything useful unless you are also using WithBlock().
 536  //
 537  // Use of this feature is not recommended.  For more information, please see:
 538  // https://github.com/grpc/grpc-go/blob/master/Documentation/anti-patterns.md
 539  //
 540  // Deprecated: this DialOption is not supported by NewClient.
 541  // This API may be changed or removed in a
 542  // later release.
 543  func FailOnNonTempDialError(f bool) DialOption {
 544  	return newFuncDialOption(func(o *dialOptions) {
 545  		o.copts.FailOnNonTempDialError = f
 546  	})
 547  }
 548  
 549  // WithUserAgent returns a DialOption that specifies a user agent string for all
 550  // the RPCs.
 551  func WithUserAgent(s string) DialOption {
 552  	return newFuncDialOption(func(o *dialOptions) {
 553  		o.copts.UserAgent = s + " " + grpcUA
 554  	})
 555  }
 556  
 557  // WithKeepaliveParams returns a DialOption that specifies keepalive parameters
 558  // for the client transport.
 559  //
 560  // Keepalive is disabled by default.
 561  func WithKeepaliveParams(kp keepalive.ClientParameters) DialOption {
 562  	if kp.Time < internal.KeepaliveMinPingTime {
 563  		logger.Warningf("Adjusting keepalive ping interval to minimum period of %v", internal.KeepaliveMinPingTime)
 564  		kp.Time = internal.KeepaliveMinPingTime
 565  	}
 566  	return newFuncDialOption(func(o *dialOptions) {
 567  		o.copts.KeepaliveParams = kp
 568  	})
 569  }
 570  
 571  // WithUnaryInterceptor returns a DialOption that specifies the interceptor for
 572  // unary RPCs.
 573  func WithUnaryInterceptor(f UnaryClientInterceptor) DialOption {
 574  	return newFuncDialOption(func(o *dialOptions) {
 575  		o.unaryInt = f
 576  	})
 577  }
 578  
 579  // WithChainUnaryInterceptor returns a DialOption that specifies the chained
 580  // interceptor for unary RPCs. The first interceptor will be the outer most,
 581  // while the last interceptor will be the inner most wrapper around the real call.
 582  // All interceptors added by this method will be chained, and the interceptor
 583  // defined by WithUnaryInterceptor will always be prepended to the chain.
 584  func WithChainUnaryInterceptor(interceptors ...UnaryClientInterceptor) DialOption {
 585  	return newFuncDialOption(func(o *dialOptions) {
 586  		o.chainUnaryInts = append(o.chainUnaryInts, interceptors...)
 587  	})
 588  }
 589  
 590  // WithStreamInterceptor returns a DialOption that specifies the interceptor for
 591  // streaming RPCs.
 592  func WithStreamInterceptor(f StreamClientInterceptor) DialOption {
 593  	return newFuncDialOption(func(o *dialOptions) {
 594  		o.streamInt = f
 595  	})
 596  }
 597  
 598  // WithChainStreamInterceptor returns a DialOption that specifies the chained
 599  // interceptor for streaming RPCs. The first interceptor will be the outer most,
 600  // while the last interceptor will be the inner most wrapper around the real call.
 601  // All interceptors added by this method will be chained, and the interceptor
 602  // defined by WithStreamInterceptor will always be prepended to the chain.
 603  func WithChainStreamInterceptor(interceptors ...StreamClientInterceptor) DialOption {
 604  	return newFuncDialOption(func(o *dialOptions) {
 605  		o.chainStreamInts = append(o.chainStreamInts, interceptors...)
 606  	})
 607  }
 608  
 609  // WithAuthority returns a DialOption that specifies the value to be used as the
 610  // :authority pseudo-header and as the server name in authentication handshake.
 611  // This overrides all other ways of setting authority on the channel, but can be
 612  // overridden per-call by using grpc.CallAuthority.
 613  func WithAuthority(a string) DialOption {
 614  	return newFuncDialOption(func(o *dialOptions) {
 615  		o.authority = a
 616  	})
 617  }
 618  
 619  // WithChannelzParentID returns a DialOption that specifies the channelz ID of
 620  // current ClientConn's parent. This function is used in nested channel creation
 621  // (e.g. grpclb dial).
 622  //
 623  // # Experimental
 624  //
 625  // Notice: This API is EXPERIMENTAL and may be changed or removed in a
 626  // later release.
 627  func WithChannelzParentID(c channelz.Identifier) DialOption {
 628  	return newFuncDialOption(func(o *dialOptions) {
 629  		o.channelzParent = c
 630  	})
 631  }
 632  
 633  // WithDisableServiceConfig returns a DialOption that causes gRPC to ignore any
 634  // service config provided by the resolver and provides a hint to the resolver
 635  // to not fetch service configs.
 636  //
 637  // Note that this dial option only disables service config from resolver. If
 638  // default service config is provided, gRPC will use the default service config.
 639  func WithDisableServiceConfig() DialOption {
 640  	return newFuncDialOption(func(o *dialOptions) {
 641  		o.disableServiceConfig = true
 642  	})
 643  }
 644  
 645  // WithDefaultServiceConfig returns a DialOption that configures the default
 646  // service config, which will be used in cases where:
 647  //
 648  // 1. WithDisableServiceConfig is also used, or
 649  //
 650  // 2. The name resolver does not provide a service config or provides an
 651  // invalid service config.
 652  //
 653  // The parameter s is the JSON representation of the default service config.
 654  // For more information about service configs, see:
 655  // https://github.com/grpc/grpc/blob/master/doc/service_config.md
 656  // For a simple example of usage, see:
 657  // examples/features/load_balancing/client/main.go
 658  func WithDefaultServiceConfig(s string) DialOption {
 659  	return newFuncDialOption(func(o *dialOptions) {
 660  		o.defaultServiceConfigRawJSON = &s
 661  	})
 662  }
 663  
 664  // WithDisableRetry returns a DialOption that disables retries, even if the
 665  // service config enables them.  This does not impact transparent retries, which
 666  // will happen automatically if no data is written to the wire or if the RPC is
 667  // unprocessed by the remote server.
 668  func WithDisableRetry() DialOption {
 669  	return newFuncDialOption(func(o *dialOptions) {
 670  		o.disableRetry = true
 671  	})
 672  }
 673  
 674  // MaxHeaderListSizeDialOption is a DialOption that specifies the maximum
 675  // (uncompressed) size of header list that the client is prepared to accept.
 676  type MaxHeaderListSizeDialOption struct {
 677  	MaxHeaderListSize uint32
 678  }
 679  
 680  func (o MaxHeaderListSizeDialOption) apply(do *dialOptions) {
 681  	do.copts.MaxHeaderListSize = &o.MaxHeaderListSize
 682  }
 683  
 684  // WithMaxHeaderListSize returns a DialOption that specifies the maximum
 685  // (uncompressed) size of header list that the client is prepared to accept.
 686  func WithMaxHeaderListSize(s uint32) DialOption {
 687  	return MaxHeaderListSizeDialOption{
 688  		MaxHeaderListSize: s,
 689  	}
 690  }
 691  
 692  // WithDisableHealthCheck disables the LB channel health checking for all
 693  // SubConns of this ClientConn.
 694  //
 695  // # Experimental
 696  //
 697  // Notice: This API is EXPERIMENTAL and may be changed or removed in a
 698  // later release.
 699  func WithDisableHealthCheck() DialOption {
 700  	return newFuncDialOption(func(o *dialOptions) {
 701  		o.disableHealthCheck = true
 702  	})
 703  }
 704  
 705  func defaultDialOptions() dialOptions {
 706  	return dialOptions{
 707  		copts: transport.ConnectOptions{
 708  			ReadBufferSize:  defaultReadBufSize,
 709  			WriteBufferSize: defaultWriteBufSize,
 710  			UserAgent:       grpcUA,
 711  			BufferPool:      mem.DefaultBufferPool(),
 712  		},
 713  		bs:                       internalbackoff.DefaultExponential,
 714  		idleTimeout:              30 * time.Minute,
 715  		defaultScheme:            "dns",
 716  		maxCallAttempts:          defaultMaxCallAttempts,
 717  		useProxy:                 true,
 718  		enableLocalDNSResolution: false,
 719  	}
 720  }
 721  
 722  // withMinConnectDeadline specifies the function that clientconn uses to
 723  // get minConnectDeadline. This can be used to make connection attempts happen
 724  // faster/slower.
 725  //
 726  // For testing purpose only.
 727  func withMinConnectDeadline(f func() time.Duration) DialOption {
 728  	return newFuncDialOption(func(o *dialOptions) {
 729  		o.minConnectTimeout = f
 730  	})
 731  }
 732  
 733  // withDefaultScheme is used to allow Dial to use "passthrough" as the default
 734  // name resolver, while NewClient uses "dns" otherwise.
 735  func withDefaultScheme(s string) DialOption {
 736  	return newFuncDialOption(func(o *dialOptions) {
 737  		o.defaultScheme = s
 738  	})
 739  }
 740  
 741  // WithResolvers allows a list of resolver implementations to be registered
 742  // locally with the ClientConn without needing to be globally registered via
 743  // resolver.Register.  They will be matched against the scheme used for the
 744  // current Dial only, and will take precedence over the global registry.
 745  //
 746  // # Experimental
 747  //
 748  // Notice: This API is EXPERIMENTAL and may be changed or removed in a
 749  // later release.
 750  func WithResolvers(rs ...resolver.Builder) DialOption {
 751  	return newFuncDialOption(func(o *dialOptions) {
 752  		o.resolvers = append(o.resolvers, rs...)
 753  	})
 754  }
 755  
 756  // WithIdleTimeout returns a DialOption that configures an idle timeout for the
 757  // channel. If the channel is idle for the configured timeout, i.e there are no
 758  // ongoing RPCs and no new RPCs are initiated, the channel will enter idle mode
 759  // and as a result the name resolver and load balancer will be shut down. The
 760  // channel will exit idle mode when the Connect() method is called or when an
 761  // RPC is initiated.
 762  //
 763  // A default timeout of 30 minutes will be used if this dial option is not set
 764  // at dial time and idleness can be disabled by passing a timeout of zero.
 765  //
 766  // # Experimental
 767  //
 768  // Notice: This API is EXPERIMENTAL and may be changed or removed in a
 769  // later release.
 770  func WithIdleTimeout(d time.Duration) DialOption {
 771  	return newFuncDialOption(func(o *dialOptions) {
 772  		o.idleTimeout = d
 773  	})
 774  }
 775  
 776  // WithMaxCallAttempts returns a DialOption that configures the maximum number
 777  // of attempts per call (including retries and hedging) using the channel.
 778  // Service owners may specify a higher value for these parameters, but higher
 779  // values will be treated as equal to the maximum value by the client
 780  // implementation. This mitigates security concerns related to the service
 781  // config being transferred to the client via DNS.
 782  //
 783  // A value of 5 will be used if this dial option is not set or n < 2.
 784  func WithMaxCallAttempts(n int) DialOption {
 785  	return newFuncDialOption(func(o *dialOptions) {
 786  		if n < 2 {
 787  			n = defaultMaxCallAttempts
 788  		}
 789  		o.maxCallAttempts = n
 790  	})
 791  }
 792  
 793  func withBufferPool(bufferPool mem.BufferPool) DialOption {
 794  	return newFuncDialOption(func(o *dialOptions) {
 795  		o.copts.BufferPool = bufferPool
 796  	})
 797  }
 798