github.com/blixtra/rkt@v0.8.1-0.20160204105720-ab0d1add1a43/Godeps/_workspace/src/google.golang.org/grpc/clientconn.go (about)

     1  /*
     2   *
     3   * Copyright 2014, Google Inc.
     4   * All rights reserved.
     5   *
     6   * Redistribution and use in source and binary forms, with or without
     7   * modification, are permitted provided that the following conditions are
     8   * met:
     9   *
    10   *     * Redistributions of source code must retain the above copyright
    11   * notice, this list of conditions and the following disclaimer.
    12   *     * Redistributions in binary form must reproduce the above
    13   * copyright notice, this list of conditions and the following disclaimer
    14   * in the documentation and/or other materials provided with the
    15   * distribution.
    16   *     * Neither the name of Google Inc. nor the names of its
    17   * contributors may be used to endorse or promote products derived from
    18   * this software without specific prior written permission.
    19   *
    20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    21   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    22   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    23   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    24   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    25   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    26   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    28   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    29   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    30   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31   *
    32   */
    33  
    34  package grpc
    35  
    36  import (
    37  	"errors"
    38  	"fmt"
    39  	"net"
    40  	"strings"
    41  	"sync"
    42  	"time"
    43  
    44  	"golang.org/x/net/context"
    45  	"golang.org/x/net/trace"
    46  	"google.golang.org/grpc/credentials"
    47  	"google.golang.org/grpc/grpclog"
    48  	"google.golang.org/grpc/transport"
    49  )
    50  
    51  var (
    52  	// ErrUnspecTarget indicates that the target address is unspecified.
    53  	ErrUnspecTarget = errors.New("grpc: target is unspecified")
    54  	// ErrNoTransportSecurity indicates that there is no transport security
    55  	// being set for ClientConn. Users should either set one or explicityly
    56  	// call WithInsecure DialOption to disable security.
    57  	ErrNoTransportSecurity = errors.New("grpc: no transport security set (use grpc.WithInsecure() explicitly or set credentials)")
    58  	// ErrCredentialsMisuse indicates that users want to transmit security infomation
    59  	// (e.g., oauth2 token) which requires secure connection on an insecure
    60  	// connection.
    61  	ErrCredentialsMisuse = errors.New("grpc: the credentials require transport level security (use grpc.WithTransportAuthenticator() to set)")
    62  	// ErrClientConnClosing indicates that the operation is illegal because
    63  	// the session is closing.
    64  	ErrClientConnClosing = errors.New("grpc: the client connection is closing")
    65  	// ErrClientConnTimeout indicates that the connection could not be
    66  	// established or re-established within the specified timeout.
    67  	ErrClientConnTimeout = errors.New("grpc: timed out trying to connect")
    68  	// minimum time to give a connection to complete
    69  	minConnectTimeout = 20 * time.Second
    70  )
    71  
    72  // dialOptions configure a Dial call. dialOptions are set by the DialOption
    73  // values passed to Dial.
    74  type dialOptions struct {
    75  	codec    Codec
    76  	picker   Picker
    77  	block    bool
    78  	insecure bool
    79  	copts    transport.ConnectOptions
    80  }
    81  
    82  // DialOption configures how we set up the connection.
    83  type DialOption func(*dialOptions)
    84  
    85  // WithCodec returns a DialOption which sets a codec for message marshaling and unmarshaling.
    86  func WithCodec(c Codec) DialOption {
    87  	return func(o *dialOptions) {
    88  		o.codec = c
    89  	}
    90  }
    91  
    92  // WithPicker returns a DialOption which sets a picker for connection selection.
    93  func WithPicker(p Picker) DialOption {
    94  	return func(o *dialOptions) {
    95  		o.picker = p
    96  	}
    97  }
    98  
    99  // WithBlock returns a DialOption which makes caller of Dial blocks until the underlying
   100  // connection is up. Without this, Dial returns immediately and connecting the server
   101  // happens in background.
   102  func WithBlock() DialOption {
   103  	return func(o *dialOptions) {
   104  		o.block = true
   105  	}
   106  }
   107  
   108  // WithInsecure returns a DialOption which disables transport security for this ClientConn.
   109  // Note that transport security is required unless WithInsecure is set.
   110  func WithInsecure() DialOption {
   111  	return func(o *dialOptions) {
   112  		o.insecure = true
   113  	}
   114  }
   115  
   116  // WithTransportCredentials returns a DialOption which configures a
   117  // connection level security credentials (e.g., TLS/SSL).
   118  func WithTransportCredentials(creds credentials.TransportAuthenticator) DialOption {
   119  	return func(o *dialOptions) {
   120  		o.copts.AuthOptions = append(o.copts.AuthOptions, creds)
   121  	}
   122  }
   123  
   124  // WithPerRPCCredentials returns a DialOption which sets
   125  // credentials which will place auth state on each outbound RPC.
   126  func WithPerRPCCredentials(creds credentials.Credentials) DialOption {
   127  	return func(o *dialOptions) {
   128  		o.copts.AuthOptions = append(o.copts.AuthOptions, creds)
   129  	}
   130  }
   131  
   132  // WithTimeout returns a DialOption that configures a timeout for dialing a client connection.
   133  func WithTimeout(d time.Duration) DialOption {
   134  	return func(o *dialOptions) {
   135  		o.copts.Timeout = d
   136  	}
   137  }
   138  
   139  // WithDialer returns a DialOption that specifies a function to use for dialing network addresses.
   140  func WithDialer(f func(addr string, timeout time.Duration) (net.Conn, error)) DialOption {
   141  	return func(o *dialOptions) {
   142  		o.copts.Dialer = f
   143  	}
   144  }
   145  
   146  // WithUserAgent returns a DialOption that specifies a user agent string for all the RPCs.
   147  func WithUserAgent(s string) DialOption {
   148  	return func(o *dialOptions) {
   149  		o.copts.UserAgent = s
   150  	}
   151  }
   152  
   153  // Dial creates a client connection the given target.
   154  func Dial(target string, opts ...DialOption) (*ClientConn, error) {
   155  	cc := &ClientConn{
   156  		target: target,
   157  	}
   158  	for _, opt := range opts {
   159  		opt(&cc.dopts)
   160  	}
   161  	if cc.dopts.codec == nil {
   162  		// Set the default codec.
   163  		cc.dopts.codec = protoCodec{}
   164  	}
   165  	if cc.dopts.picker == nil {
   166  		cc.dopts.picker = &unicastPicker{
   167  			target: target,
   168  		}
   169  	}
   170  	if err := cc.dopts.picker.Init(cc); err != nil {
   171  		return nil, err
   172  	}
   173  	colonPos := strings.LastIndex(target, ":")
   174  	if colonPos == -1 {
   175  		colonPos = len(target)
   176  	}
   177  	cc.authority = target[:colonPos]
   178  	return cc, nil
   179  }
   180  
   181  // ConnectivityState indicates the state of a client connection.
   182  type ConnectivityState int
   183  
   184  const (
   185  	// Idle indicates the ClientConn is idle.
   186  	Idle ConnectivityState = iota
   187  	// Connecting indicates the ClienConn is connecting.
   188  	Connecting
   189  	// Ready indicates the ClientConn is ready for work.
   190  	Ready
   191  	// TransientFailure indicates the ClientConn has seen a failure but expects to recover.
   192  	TransientFailure
   193  	// Shutdown indicates the ClientConn has started shutting down.
   194  	Shutdown
   195  )
   196  
   197  func (s ConnectivityState) String() string {
   198  	switch s {
   199  	case Idle:
   200  		return "IDLE"
   201  	case Connecting:
   202  		return "CONNECTING"
   203  	case Ready:
   204  		return "READY"
   205  	case TransientFailure:
   206  		return "TRANSIENT_FAILURE"
   207  	case Shutdown:
   208  		return "SHUTDOWN"
   209  	default:
   210  		panic(fmt.Sprintf("unknown connectivity state: %d", s))
   211  	}
   212  }
   213  
   214  // ClientConn represents a client connection to an RPC service.
   215  type ClientConn struct {
   216  	target    string
   217  	authority string
   218  	dopts     dialOptions
   219  }
   220  
   221  // State returns the connectivity state of cc.
   222  // This is EXPERIMENTAL API.
   223  func (cc *ClientConn) State() (ConnectivityState, error) {
   224  	return cc.dopts.picker.State()
   225  }
   226  
   227  // WaitForStateChange blocks until the state changes to something other than the sourceState.
   228  // It returns the new state or error.
   229  // This is EXPERIMENTAL API.
   230  func (cc *ClientConn) WaitForStateChange(ctx context.Context, sourceState ConnectivityState) (ConnectivityState, error) {
   231  	return cc.dopts.picker.WaitForStateChange(ctx, sourceState)
   232  }
   233  
   234  // Close starts to tear down the ClientConn.
   235  func (cc *ClientConn) Close() error {
   236  	return cc.dopts.picker.Close()
   237  }
   238  
   239  // Conn is a client connection to a single destination.
   240  type Conn struct {
   241  	target       string
   242  	dopts        dialOptions
   243  	resetChan    chan int
   244  	shutdownChan chan struct{}
   245  	events       trace.EventLog
   246  
   247  	mu      sync.Mutex
   248  	state   ConnectivityState
   249  	stateCV *sync.Cond
   250  	// ready is closed and becomes nil when a new transport is up or failed
   251  	// due to timeout.
   252  	ready     chan struct{}
   253  	transport transport.ClientTransport
   254  }
   255  
   256  // NewConn creates a Conn.
   257  func NewConn(cc *ClientConn) (*Conn, error) {
   258  	if cc.target == "" {
   259  		return nil, ErrUnspecTarget
   260  	}
   261  	c := &Conn{
   262  		target:       cc.target,
   263  		dopts:        cc.dopts,
   264  		resetChan:    make(chan int, 1),
   265  		shutdownChan: make(chan struct{}),
   266  	}
   267  	if EnableTracing {
   268  		c.events = trace.NewEventLog("grpc.ClientConn", c.target)
   269  	}
   270  	if !c.dopts.insecure {
   271  		var ok bool
   272  		for _, cd := range c.dopts.copts.AuthOptions {
   273  			if _, ok := cd.(credentials.TransportAuthenticator); !ok {
   274  				continue
   275  			}
   276  			ok = true
   277  		}
   278  		if !ok {
   279  			return nil, ErrNoTransportSecurity
   280  		}
   281  	} else {
   282  		for _, cd := range c.dopts.copts.AuthOptions {
   283  			if cd.RequireTransportSecurity() {
   284  				return nil, ErrCredentialsMisuse
   285  			}
   286  		}
   287  	}
   288  	c.stateCV = sync.NewCond(&c.mu)
   289  	if c.dopts.block {
   290  		if err := c.resetTransport(false); err != nil {
   291  			c.Close()
   292  			return nil, err
   293  		}
   294  		// Start to monitor the error status of transport.
   295  		go c.transportMonitor()
   296  	} else {
   297  		// Start a goroutine connecting to the server asynchronously.
   298  		go func() {
   299  			if err := c.resetTransport(false); err != nil {
   300  				grpclog.Printf("Failed to dial %s: %v; please retry.", c.target, err)
   301  				c.Close()
   302  				return
   303  			}
   304  			c.transportMonitor()
   305  		}()
   306  	}
   307  	return c, nil
   308  }
   309  
   310  // printf records an event in cc's event log, unless cc has been closed.
   311  // REQUIRES cc.mu is held.
   312  func (cc *Conn) printf(format string, a ...interface{}) {
   313  	if cc.events != nil {
   314  		cc.events.Printf(format, a...)
   315  	}
   316  }
   317  
   318  // errorf records an error in cc's event log, unless cc has been closed.
   319  // REQUIRES cc.mu is held.
   320  func (cc *Conn) errorf(format string, a ...interface{}) {
   321  	if cc.events != nil {
   322  		cc.events.Errorf(format, a...)
   323  	}
   324  }
   325  
   326  // State returns the connectivity state of the Conn
   327  func (cc *Conn) State() ConnectivityState {
   328  	cc.mu.Lock()
   329  	defer cc.mu.Unlock()
   330  	return cc.state
   331  }
   332  
   333  // WaitForStateChange blocks until the state changes to something other than the sourceState.
   334  func (cc *Conn) WaitForStateChange(ctx context.Context, sourceState ConnectivityState) (ConnectivityState, error) {
   335  	cc.mu.Lock()
   336  	defer cc.mu.Unlock()
   337  	if sourceState != cc.state {
   338  		return cc.state, nil
   339  	}
   340  	done := make(chan struct{})
   341  	var err error
   342  	go func() {
   343  		select {
   344  		case <-ctx.Done():
   345  			cc.mu.Lock()
   346  			err = ctx.Err()
   347  			cc.stateCV.Broadcast()
   348  			cc.mu.Unlock()
   349  		case <-done:
   350  		}
   351  	}()
   352  	defer close(done)
   353  	for sourceState == cc.state {
   354  		cc.stateCV.Wait()
   355  		if err != nil {
   356  			return cc.state, err
   357  		}
   358  	}
   359  	return cc.state, nil
   360  }
   361  
   362  // NotifyReset tries to signal the underlying transport needs to be reset due to
   363  // for example a name resolution change in flight.
   364  func (cc *Conn) NotifyReset() {
   365  	select {
   366  	case cc.resetChan <- 0:
   367  	default:
   368  	}
   369  }
   370  
   371  func (cc *Conn) resetTransport(closeTransport bool) error {
   372  	var retries int
   373  	start := time.Now()
   374  	for {
   375  		cc.mu.Lock()
   376  		cc.printf("connecting")
   377  		if cc.state == Shutdown {
   378  			// cc.Close() has been invoked.
   379  			cc.mu.Unlock()
   380  			return ErrClientConnClosing
   381  		}
   382  		cc.state = Connecting
   383  		cc.stateCV.Broadcast()
   384  		cc.mu.Unlock()
   385  		if closeTransport {
   386  			cc.transport.Close()
   387  		}
   388  		// Adjust timeout for the current try.
   389  		copts := cc.dopts.copts
   390  		if copts.Timeout < 0 {
   391  			cc.Close()
   392  			return ErrClientConnTimeout
   393  		}
   394  		if copts.Timeout > 0 {
   395  			copts.Timeout -= time.Since(start)
   396  			if copts.Timeout <= 0 {
   397  				cc.Close()
   398  				return ErrClientConnTimeout
   399  			}
   400  		}
   401  		sleepTime := backoff(retries)
   402  		timeout := sleepTime
   403  		if timeout < minConnectTimeout {
   404  			timeout = minConnectTimeout
   405  		}
   406  		if copts.Timeout == 0 || copts.Timeout > timeout {
   407  			copts.Timeout = timeout
   408  		}
   409  		connectTime := time.Now()
   410  		addr, err := cc.dopts.picker.PickAddr()
   411  		var newTransport transport.ClientTransport
   412  		if err == nil {
   413  			newTransport, err = transport.NewClientTransport(addr, &copts)
   414  		}
   415  		if err != nil {
   416  			cc.mu.Lock()
   417  			if cc.state == Shutdown {
   418  				// cc.Close() has been invoked.
   419  				cc.mu.Unlock()
   420  				return ErrClientConnClosing
   421  			}
   422  			cc.errorf("transient failure: %v", err)
   423  			cc.state = TransientFailure
   424  			cc.stateCV.Broadcast()
   425  			if cc.ready != nil {
   426  				close(cc.ready)
   427  				cc.ready = nil
   428  			}
   429  			cc.mu.Unlock()
   430  			sleepTime -= time.Since(connectTime)
   431  			if sleepTime < 0 {
   432  				sleepTime = 0
   433  			}
   434  			// Fail early before falling into sleep.
   435  			if cc.dopts.copts.Timeout > 0 && cc.dopts.copts.Timeout < sleepTime+time.Since(start) {
   436  				cc.mu.Lock()
   437  				cc.errorf("connection timeout")
   438  				cc.mu.Unlock()
   439  				cc.Close()
   440  				return ErrClientConnTimeout
   441  			}
   442  			closeTransport = false
   443  			time.Sleep(sleepTime)
   444  			retries++
   445  			grpclog.Printf("grpc: Conn.resetTransport failed to create client transport: %v; Reconnecting to %q", err, cc.target)
   446  			continue
   447  		}
   448  		cc.mu.Lock()
   449  		cc.printf("ready")
   450  		if cc.state == Shutdown {
   451  			// cc.Close() has been invoked.
   452  			cc.mu.Unlock()
   453  			newTransport.Close()
   454  			return ErrClientConnClosing
   455  		}
   456  		cc.state = Ready
   457  		cc.stateCV.Broadcast()
   458  		cc.transport = newTransport
   459  		if cc.ready != nil {
   460  			close(cc.ready)
   461  			cc.ready = nil
   462  		}
   463  		cc.mu.Unlock()
   464  		return nil
   465  	}
   466  }
   467  
   468  func (cc *Conn) reconnect() bool {
   469  	cc.mu.Lock()
   470  	if cc.state == Shutdown {
   471  		// cc.Close() has been invoked.
   472  		cc.mu.Unlock()
   473  		return false
   474  	}
   475  	cc.state = TransientFailure
   476  	cc.stateCV.Broadcast()
   477  	cc.mu.Unlock()
   478  	if err := cc.resetTransport(true); err != nil {
   479  		// The ClientConn is closing.
   480  		cc.mu.Lock()
   481  		cc.printf("transport exiting: %v", err)
   482  		cc.mu.Unlock()
   483  		grpclog.Printf("grpc: Conn.transportMonitor exits due to: %v", err)
   484  		return false
   485  	}
   486  	return true
   487  }
   488  
   489  // Run in a goroutine to track the error in transport and create the
   490  // new transport if an error happens. It returns when the channel is closing.
   491  func (cc *Conn) transportMonitor() {
   492  	for {
   493  		select {
   494  		// shutdownChan is needed to detect the teardown when
   495  		// the ClientConn is idle (i.e., no RPC in flight).
   496  		case <-cc.shutdownChan:
   497  			return
   498  		case <-cc.resetChan:
   499  			if !cc.reconnect() {
   500  				return
   501  			}
   502  		case <-cc.transport.Error():
   503  			if !cc.reconnect() {
   504  				return
   505  			}
   506  			// Tries to drain reset signal if there is any since it is out-dated.
   507  			select {
   508  			case <-cc.resetChan:
   509  			default:
   510  			}
   511  		}
   512  	}
   513  }
   514  
   515  // Wait blocks until i) the new transport is up or ii) ctx is done or iii) cc is closed.
   516  func (cc *Conn) Wait(ctx context.Context) (transport.ClientTransport, error) {
   517  	for {
   518  		cc.mu.Lock()
   519  		switch {
   520  		case cc.state == Shutdown:
   521  			cc.mu.Unlock()
   522  			return nil, ErrClientConnClosing
   523  		case cc.state == Ready:
   524  			cc.mu.Unlock()
   525  			return cc.transport, nil
   526  		default:
   527  			ready := cc.ready
   528  			if ready == nil {
   529  				ready = make(chan struct{})
   530  				cc.ready = ready
   531  			}
   532  			cc.mu.Unlock()
   533  			select {
   534  			case <-ctx.Done():
   535  				return nil, transport.ContextErr(ctx.Err())
   536  			// Wait until the new transport is ready or failed.
   537  			case <-ready:
   538  			}
   539  		}
   540  	}
   541  }
   542  
   543  // Close starts to tear down the Conn. Returns ErrClientConnClosing if
   544  // it has been closed (mostly due to dial time-out).
   545  // TODO(zhaoq): Make this synchronous to avoid unbounded memory consumption in
   546  // some edge cases (e.g., the caller opens and closes many ClientConn's in a
   547  // tight loop.
   548  func (cc *Conn) Close() error {
   549  	cc.mu.Lock()
   550  	defer cc.mu.Unlock()
   551  	if cc.state == Shutdown {
   552  		return ErrClientConnClosing
   553  	}
   554  	cc.state = Shutdown
   555  	cc.stateCV.Broadcast()
   556  	if cc.events != nil {
   557  		cc.events.Finish()
   558  		cc.events = nil
   559  	}
   560  	if cc.ready != nil {
   561  		close(cc.ready)
   562  		cc.ready = nil
   563  	}
   564  	if cc.transport != nil {
   565  		cc.transport.Close()
   566  	}
   567  	if cc.shutdownChan != nil {
   568  		close(cc.shutdownChan)
   569  	}
   570  	return nil
   571  }