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 }