github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/stream.go (about) 1 /* 2 * 3 * Copyright 2014 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 "errors" 24 "io" 25 "math" 26 "strconv" 27 "sync" 28 "time" 29 30 "github.com/hxx258456/ccgo/grpc/balancer" 31 "github.com/hxx258456/ccgo/grpc/codes" 32 "github.com/hxx258456/ccgo/grpc/encoding" 33 "github.com/hxx258456/ccgo/grpc/internal/balancerload" 34 "github.com/hxx258456/ccgo/grpc/internal/binarylog" 35 "github.com/hxx258456/ccgo/grpc/internal/channelz" 36 "github.com/hxx258456/ccgo/grpc/internal/grpcrand" 37 "github.com/hxx258456/ccgo/grpc/internal/grpcutil" 38 iresolver "github.com/hxx258456/ccgo/grpc/internal/resolver" 39 "github.com/hxx258456/ccgo/grpc/internal/serviceconfig" 40 "github.com/hxx258456/ccgo/grpc/internal/transport" 41 "github.com/hxx258456/ccgo/grpc/metadata" 42 "github.com/hxx258456/ccgo/grpc/peer" 43 "github.com/hxx258456/ccgo/grpc/stats" 44 "github.com/hxx258456/ccgo/grpc/status" 45 "github.com/hxx258456/ccgo/net/trace" 46 ) 47 48 // StreamHandler defines the handler called by gRPC server to complete the 49 // execution of a streaming RPC. If a StreamHandler returns an error, it 50 // should be produced by the status package, or else gRPC will use 51 // codes.Unknown as the status code and err.Error() as the status message 52 // of the RPC. 53 type StreamHandler func(srv interface{}, stream ServerStream) error 54 55 // StreamDesc represents a streaming RPC service's method specification. Used 56 // on the server when registering services and on the client when initiating 57 // new streams. 58 type StreamDesc struct { 59 // StreamName and Handler are only used when registering handlers on a 60 // server. 61 StreamName string // the name of the method excluding the service 62 Handler StreamHandler // the handler called for the method 63 64 // ServerStreams and ClientStreams are used for registering handlers on a 65 // server as well as defining RPC behavior when passed to NewClientStream 66 // and ClientConn.NewStream. At least one must be true. 67 ServerStreams bool // indicates the server can perform streaming sends 68 ClientStreams bool // indicates the client can perform streaming sends 69 } 70 71 // Stream defines the common interface a client or server stream has to satisfy. 72 // 73 // Deprecated: See ClientStream and ServerStream documentation instead. 74 type Stream interface { 75 // Deprecated: See ClientStream and ServerStream documentation instead. 76 Context() context.Context 77 // Deprecated: See ClientStream and ServerStream documentation instead. 78 SendMsg(m interface{}) error 79 // Deprecated: See ClientStream and ServerStream documentation instead. 80 RecvMsg(m interface{}) error 81 } 82 83 // ClientStream defines the client-side behavior of a streaming RPC. 84 // 85 // All errors returned from ClientStream methods are compatible with the 86 // status package. 87 type ClientStream interface { 88 // Header returns the header metadata received from the server if there 89 // is any. It blocks if the metadata is not ready to read. 90 Header() (metadata.MD, error) 91 // Trailer returns the trailer metadata from the server, if there is any. 92 // It must only be called after stream.CloseAndRecv has returned, or 93 // stream.Recv has returned a non-nil error (including io.EOF). 94 Trailer() metadata.MD 95 // CloseSend closes the send direction of the stream. It closes the stream 96 // when non-nil error is met. It is also not safe to call CloseSend 97 // concurrently with SendMsg. 98 CloseSend() error 99 // Context returns the context for this stream. 100 // 101 // It should not be called until after Header or RecvMsg has returned. Once 102 // called, subsequent client-side retries are disabled. 103 Context() context.Context 104 // SendMsg is generally called by generated code. On error, SendMsg aborts 105 // the stream. If the error was generated by the client, the status is 106 // returned directly; otherwise, io.EOF is returned and the status of 107 // the stream may be discovered using RecvMsg. 108 // 109 // SendMsg blocks until: 110 // - There is sufficient flow control to schedule m with the transport, or 111 // - The stream is done, or 112 // - The stream breaks. 113 // 114 // SendMsg does not wait until the message is received by the server. An 115 // untimely stream closure may result in lost messages. To ensure delivery, 116 // users should ensure the RPC completed successfully using RecvMsg. 117 // 118 // It is safe to have a goroutine calling SendMsg and another goroutine 119 // calling RecvMsg on the same stream at the same time, but it is not safe 120 // to call SendMsg on the same stream in different goroutines. It is also 121 // not safe to call CloseSend concurrently with SendMsg. 122 SendMsg(m interface{}) error 123 // RecvMsg blocks until it receives a message into m or the stream is 124 // done. It returns io.EOF when the stream completes successfully. On 125 // any other error, the stream is aborted and the error contains the RPC 126 // status. 127 // 128 // It is safe to have a goroutine calling SendMsg and another goroutine 129 // calling RecvMsg on the same stream at the same time, but it is not 130 // safe to call RecvMsg on the same stream in different goroutines. 131 RecvMsg(m interface{}) error 132 } 133 134 // NewStream creates a new Stream for the client side. This is typically 135 // called by generated code. ctx is used for the lifetime of the stream. 136 // 137 // To ensure resources are not leaked due to the stream returned, one of the following 138 // actions must be performed: 139 // 140 // 1. Call Close on the ClientConn. 141 // 2. Cancel the context provided. 142 // 3. Call RecvMsg until a non-nil error is returned. A protobuf-generated 143 // client-streaming RPC, for instance, might use the helper function 144 // CloseAndRecv (note that CloseSend does not Recv, therefore is not 145 // guaranteed to release all resources). 146 // 4. Receive a non-nil, non-io.EOF error from Header or SendMsg. 147 // 148 // If none of the above happen, a goroutine and a context will be leaked, and grpc 149 // will not call the optionally-configured stats handler with a stats.End message. 150 func (cc *ClientConn) NewStream(ctx context.Context, desc *StreamDesc, method string, opts ...CallOption) (ClientStream, error) { 151 // allow interceptor to see all applicable call options, which means those 152 // configured as defaults from dial option as well as per-call options 153 opts = combine(cc.dopts.callOptions, opts) 154 155 if cc.dopts.streamInt != nil { 156 return cc.dopts.streamInt(ctx, desc, cc, method, newClientStream, opts...) 157 } 158 return newClientStream(ctx, desc, cc, method, opts...) 159 } 160 161 // NewClientStream is a wrapper for ClientConn.NewStream. 162 func NewClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (ClientStream, error) { 163 return cc.NewStream(ctx, desc, method, opts...) 164 } 165 166 func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (_ ClientStream, err error) { 167 if channelz.IsOn() { 168 cc.incrCallsStarted() 169 defer func() { 170 if err != nil { 171 cc.incrCallsFailed() 172 } 173 }() 174 } 175 // Provide an opportunity for the first RPC to see the first service config 176 // provided by the resolver. 177 if err := cc.waitForResolvedAddrs(ctx); err != nil { 178 return nil, err 179 } 180 181 var mc serviceconfig.MethodConfig 182 var onCommit func() 183 var newStream = func(ctx context.Context, done func()) (iresolver.ClientStream, error) { 184 return newClientStreamWithParams(ctx, desc, cc, method, mc, onCommit, done, opts...) 185 } 186 187 rpcInfo := iresolver.RPCInfo{Context: ctx, Method: method} 188 rpcConfig, err := cc.safeConfigSelector.SelectConfig(rpcInfo) 189 if err != nil { 190 return nil, toRPCErr(err) 191 } 192 193 if rpcConfig != nil { 194 if rpcConfig.Context != nil { 195 ctx = rpcConfig.Context 196 } 197 mc = rpcConfig.MethodConfig 198 onCommit = rpcConfig.OnCommitted 199 if rpcConfig.Interceptor != nil { 200 rpcInfo.Context = nil 201 ns := newStream 202 newStream = func(ctx context.Context, done func()) (iresolver.ClientStream, error) { 203 cs, err := rpcConfig.Interceptor.NewStream(ctx, rpcInfo, done, ns) 204 if err != nil { 205 return nil, toRPCErr(err) 206 } 207 return cs, nil 208 } 209 } 210 } 211 212 return newStream(ctx, func() {}) 213 } 214 215 func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, mc serviceconfig.MethodConfig, onCommit, doneFunc func(), opts ...CallOption) (_ iresolver.ClientStream, err error) { 216 c := defaultCallInfo() 217 if mc.WaitForReady != nil { 218 c.failFast = !*mc.WaitForReady 219 } 220 221 // Possible context leak: 222 // The cancel function for the child context we create will only be called 223 // when RecvMsg returns a non-nil error, if the ClientConn is closed, or if 224 // an error is generated by SendMsg. 225 // https://github.com/grpc/grpc-go/issues/1818. 226 var cancel context.CancelFunc 227 if mc.Timeout != nil && *mc.Timeout >= 0 { 228 ctx, cancel = context.WithTimeout(ctx, *mc.Timeout) 229 } else { 230 ctx, cancel = context.WithCancel(ctx) 231 } 232 defer func() { 233 if err != nil { 234 cancel() 235 } 236 }() 237 238 for _, o := range opts { 239 if err := o.before(c); err != nil { 240 return nil, toRPCErr(err) 241 } 242 } 243 c.maxSendMessageSize = getMaxSize(mc.MaxReqSize, c.maxSendMessageSize, defaultClientMaxSendMessageSize) 244 c.maxReceiveMessageSize = getMaxSize(mc.MaxRespSize, c.maxReceiveMessageSize, defaultClientMaxReceiveMessageSize) 245 if err := setCallInfoCodec(c); err != nil { 246 return nil, err 247 } 248 249 callHdr := &transport.CallHdr{ 250 Host: cc.authority, 251 Method: method, 252 ContentSubtype: c.contentSubtype, 253 DoneFunc: doneFunc, 254 } 255 256 // Set our outgoing compression according to the UseCompressor CallOption, if 257 // set. In that case, also find the compressor from the encoding package. 258 // Otherwise, use the compressor configured by the WithCompressor DialOption, 259 // if set. 260 var cp Compressor 261 var comp encoding.Compressor 262 if ct := c.compressorType; ct != "" { 263 callHdr.SendCompress = ct 264 if ct != encoding.Identity { 265 comp = encoding.GetCompressor(ct) 266 if comp == nil { 267 return nil, status.Errorf(codes.Internal, "grpc: Compressor is not installed for requested grpc-encoding %q", ct) 268 } 269 } 270 } else if cc.dopts.cp != nil { 271 callHdr.SendCompress = cc.dopts.cp.Type() 272 cp = cc.dopts.cp 273 } 274 if c.creds != nil { 275 callHdr.Creds = c.creds 276 } 277 278 cs := &clientStream{ 279 callHdr: callHdr, 280 ctx: ctx, 281 methodConfig: &mc, 282 opts: opts, 283 callInfo: c, 284 cc: cc, 285 desc: desc, 286 codec: c.codec, 287 cp: cp, 288 comp: comp, 289 cancel: cancel, 290 firstAttempt: true, 291 onCommit: onCommit, 292 } 293 if !cc.dopts.disableRetry { 294 cs.retryThrottler = cc.retryThrottler.Load().(*retryThrottler) 295 } 296 cs.binlog = binarylog.GetMethodLogger(method) 297 298 if err := cs.newAttemptLocked(false /* isTransparent */); err != nil { 299 cs.finish(err) 300 return nil, err 301 } 302 303 op := func(a *csAttempt) error { return a.newStream() } 304 if err := cs.withRetry(op, func() { cs.bufferForRetryLocked(0, op) }); err != nil { 305 cs.finish(err) 306 return nil, err 307 } 308 309 if cs.binlog != nil { 310 md, _ := metadata.FromOutgoingContext(ctx) 311 logEntry := &binarylog.ClientHeader{ 312 OnClientSide: true, 313 Header: md, 314 MethodName: method, 315 Authority: cs.cc.authority, 316 } 317 if deadline, ok := ctx.Deadline(); ok { 318 logEntry.Timeout = time.Until(deadline) 319 if logEntry.Timeout < 0 { 320 logEntry.Timeout = 0 321 } 322 } 323 cs.binlog.Log(logEntry) 324 } 325 326 if desc != unaryStreamDesc { 327 // Listen on cc and stream contexts to cleanup when the user closes the 328 // ClientConn or cancels the stream context. In all other cases, an error 329 // should already be injected into the recv buffer by the transport, which 330 // the client will eventually receive, and then we will cancel the stream's 331 // context in clientStream.finish. 332 go func() { 333 select { 334 case <-cc.ctx.Done(): 335 cs.finish(ErrClientConnClosing) 336 case <-ctx.Done(): 337 cs.finish(toRPCErr(ctx.Err())) 338 } 339 }() 340 } 341 return cs, nil 342 } 343 344 // newAttemptLocked creates a new attempt with a transport. 345 // If it succeeds, then it replaces clientStream's attempt with this new attempt. 346 func (cs *clientStream) newAttemptLocked(isTransparent bool) (retErr error) { 347 ctx := newContextWithRPCInfo(cs.ctx, cs.callInfo.failFast, cs.callInfo.codec, cs.cp, cs.comp) 348 method := cs.callHdr.Method 349 sh := cs.cc.dopts.copts.StatsHandler 350 var beginTime time.Time 351 if sh != nil { 352 ctx = sh.TagRPC(ctx, &stats.RPCTagInfo{FullMethodName: method, FailFast: cs.callInfo.failFast}) 353 beginTime = time.Now() 354 begin := &stats.Begin{ 355 Client: true, 356 BeginTime: beginTime, 357 FailFast: cs.callInfo.failFast, 358 IsClientStream: cs.desc.ClientStreams, 359 IsServerStream: cs.desc.ServerStreams, 360 IsTransparentRetryAttempt: isTransparent, 361 } 362 sh.HandleRPC(ctx, begin) 363 } 364 365 var trInfo *traceInfo 366 if EnableTracing { 367 trInfo = &traceInfo{ 368 tr: trace.New("grpc.Sent."+methodFamily(method), method), 369 firstLine: firstLine{ 370 client: true, 371 }, 372 } 373 if deadline, ok := ctx.Deadline(); ok { 374 trInfo.firstLine.deadline = time.Until(deadline) 375 } 376 trInfo.tr.LazyLog(&trInfo.firstLine, false) 377 ctx = trace.NewContext(ctx, trInfo.tr) 378 } 379 380 newAttempt := &csAttempt{ 381 ctx: ctx, 382 beginTime: beginTime, 383 cs: cs, 384 dc: cs.cc.dopts.dc, 385 statsHandler: sh, 386 trInfo: trInfo, 387 } 388 defer func() { 389 if retErr != nil { 390 // This attempt is not set in the clientStream, so it's finish won't 391 // be called. Call it here for stats and trace in case they are not 392 // nil. 393 newAttempt.finish(retErr) 394 } 395 }() 396 397 if err := ctx.Err(); err != nil { 398 return toRPCErr(err) 399 } 400 401 if cs.cc.parsedTarget.Scheme == "xds" { 402 // Add extra metadata (metadata that will be added by transport) to context 403 // so the balancer can see them. 404 ctx = grpcutil.WithExtraMetadata(ctx, metadata.Pairs( 405 "content-type", grpcutil.ContentType(cs.callHdr.ContentSubtype), 406 )) 407 } 408 t, done, err := cs.cc.getTransport(ctx, cs.callInfo.failFast, cs.callHdr.Method) 409 if err != nil { 410 return err 411 } 412 if trInfo != nil { 413 trInfo.firstLine.SetRemoteAddr(t.RemoteAddr()) 414 } 415 newAttempt.t = t 416 newAttempt.done = done 417 cs.attempt = newAttempt 418 return nil 419 } 420 421 func (a *csAttempt) newStream() error { 422 cs := a.cs 423 cs.callHdr.PreviousAttempts = cs.numRetries 424 s, err := a.t.NewStream(a.ctx, cs.callHdr) 425 if err != nil { 426 // Return without converting to an RPC error so retry code can 427 // inspect. 428 return err 429 } 430 cs.attempt.s = s 431 cs.attempt.p = &parser{r: s} 432 return nil 433 } 434 435 // clientStream implements a client side Stream. 436 type clientStream struct { 437 callHdr *transport.CallHdr 438 opts []CallOption 439 callInfo *callInfo 440 cc *ClientConn 441 desc *StreamDesc 442 443 codec baseCodec 444 cp Compressor 445 comp encoding.Compressor 446 447 cancel context.CancelFunc // cancels all attempts 448 449 sentLast bool // sent an end stream 450 451 methodConfig *MethodConfig 452 453 ctx context.Context // the application's context, wrapped by stats/tracing 454 455 retryThrottler *retryThrottler // The throttler active when the RPC began. 456 457 binlog *binarylog.MethodLogger // Binary logger, can be nil. 458 // serverHeaderBinlogged is a boolean for whether server header has been 459 // logged. Server header will be logged when the first time one of those 460 // happens: stream.Header(), stream.Recv(). 461 // 462 // It's only read and used by Recv() and Header(), so it doesn't need to be 463 // synchronized. 464 serverHeaderBinlogged bool 465 466 mu sync.Mutex 467 firstAttempt bool // if true, transparent retry is valid 468 numRetries int // exclusive of transparent retry attempt(s) 469 numRetriesSincePushback int // retries since pushback; to reset backoff 470 finished bool // TODO: replace with atomic cmpxchg or sync.Once? 471 // attempt is the active client stream attempt. 472 // The only place where it is written is the newAttemptLocked method and this method never writes nil. 473 // So, attempt can be nil only inside newClientStream function when clientStream is first created. 474 // One of the first things done after clientStream's creation, is to call newAttemptLocked which either 475 // assigns a non nil value to the attempt or returns an error. If an error is returned from newAttemptLocked, 476 // then newClientStream calls finish on the clientStream and returns. So, finish method is the only 477 // place where we need to check if the attempt is nil. 478 attempt *csAttempt 479 // TODO(hedging): hedging will have multiple attempts simultaneously. 480 committed bool // active attempt committed for retry? 481 onCommit func() 482 buffer []func(a *csAttempt) error // operations to replay on retry 483 bufferSize int // current size of buffer 484 } 485 486 // csAttempt implements a single transport stream attempt within a 487 // clientStream. 488 type csAttempt struct { 489 ctx context.Context 490 cs *clientStream 491 t transport.ClientTransport 492 s *transport.Stream 493 p *parser 494 done func(balancer.DoneInfo) 495 496 finished bool 497 dc Decompressor 498 decomp encoding.Compressor 499 decompSet bool 500 501 mu sync.Mutex // guards trInfo.tr 502 // trInfo may be nil (if EnableTracing is false). 503 // trInfo.tr is set when created (if EnableTracing is true), 504 // and cleared when the finish method is called. 505 trInfo *traceInfo 506 507 statsHandler stats.Handler 508 beginTime time.Time 509 } 510 511 func (cs *clientStream) commitAttemptLocked() { 512 if !cs.committed && cs.onCommit != nil { 513 cs.onCommit() 514 } 515 cs.committed = true 516 cs.buffer = nil 517 } 518 519 func (cs *clientStream) commitAttempt() { 520 cs.mu.Lock() 521 cs.commitAttemptLocked() 522 cs.mu.Unlock() 523 } 524 525 // shouldRetry returns nil if the RPC should be retried; otherwise it returns 526 // the error that should be returned by the operation. If the RPC should be 527 // retried, the bool indicates whether it is being retried transparently. 528 func (cs *clientStream) shouldRetry(err error) (bool, error) { 529 if cs.attempt.s == nil { 530 // Error from NewClientStream. 531 nse, ok := err.(*transport.NewStreamError) 532 if !ok { 533 // Unexpected, but assume no I/O was performed and the RPC is not 534 // fatal, so retry indefinitely. 535 return true, nil 536 } 537 538 // Unwrap and convert error. 539 err = toRPCErr(nse.Err) 540 541 // Never retry DoNotRetry errors, which indicate the RPC should not be 542 // retried due to max header list size violation, etc. 543 if nse.DoNotRetry { 544 return false, err 545 } 546 547 // In the event of a non-IO operation error from NewStream, we never 548 // attempted to write anything to the wire, so we can retry 549 // indefinitely. 550 if !nse.DoNotTransparentRetry { 551 return true, nil 552 } 553 } 554 if cs.finished || cs.committed { 555 // RPC is finished or committed; cannot retry. 556 return false, err 557 } 558 // Wait for the trailers. 559 unprocessed := false 560 if cs.attempt.s != nil { 561 <-cs.attempt.s.Done() 562 unprocessed = cs.attempt.s.Unprocessed() 563 } 564 if cs.firstAttempt && unprocessed { 565 // First attempt, stream unprocessed: transparently retry. 566 return true, nil 567 } 568 if cs.cc.dopts.disableRetry { 569 return false, err 570 } 571 572 pushback := 0 573 hasPushback := false 574 if cs.attempt.s != nil { 575 if !cs.attempt.s.TrailersOnly() { 576 return false, err 577 } 578 579 // TODO(retry): Move down if the spec changes to not check server pushback 580 // before considering this a failure for throttling. 581 sps := cs.attempt.s.Trailer()["grpc-retry-pushback-ms"] 582 if len(sps) == 1 { 583 var e error 584 if pushback, e = strconv.Atoi(sps[0]); e != nil || pushback < 0 { 585 channelz.Infof(logger, cs.cc.channelzID, "Server retry pushback specified to abort (%q).", sps[0]) 586 cs.retryThrottler.throttle() // This counts as a failure for throttling. 587 return false, err 588 } 589 hasPushback = true 590 } else if len(sps) > 1 { 591 channelz.Warningf(logger, cs.cc.channelzID, "Server retry pushback specified multiple values (%q); not retrying.", sps) 592 cs.retryThrottler.throttle() // This counts as a failure for throttling. 593 return false, err 594 } 595 } 596 597 var code codes.Code 598 if cs.attempt.s != nil { 599 code = cs.attempt.s.Status().Code() 600 } else { 601 code = status.Convert(err).Code() 602 } 603 604 rp := cs.methodConfig.RetryPolicy 605 if rp == nil || !rp.RetryableStatusCodes[code] { 606 return false, err 607 } 608 609 // Note: the ordering here is important; we count this as a failure 610 // only if the code matched a retryable code. 611 if cs.retryThrottler.throttle() { 612 return false, err 613 } 614 if cs.numRetries+1 >= rp.MaxAttempts { 615 return false, err 616 } 617 618 var dur time.Duration 619 if hasPushback { 620 dur = time.Millisecond * time.Duration(pushback) 621 cs.numRetriesSincePushback = 0 622 } else { 623 fact := math.Pow(rp.BackoffMultiplier, float64(cs.numRetriesSincePushback)) 624 cur := float64(rp.InitialBackoff) * fact 625 if max := float64(rp.MaxBackoff); cur > max { 626 cur = max 627 } 628 dur = time.Duration(grpcrand.Int63n(int64(cur))) 629 cs.numRetriesSincePushback++ 630 } 631 632 // TODO(dfawley): we could eagerly fail here if dur puts us past the 633 // deadline, but unsure if it is worth doing. 634 t := time.NewTimer(dur) 635 select { 636 case <-t.C: 637 cs.numRetries++ 638 return false, nil 639 case <-cs.ctx.Done(): 640 t.Stop() 641 return false, status.FromContextError(cs.ctx.Err()).Err() 642 } 643 } 644 645 // Returns nil if a retry was performed and succeeded; error otherwise. 646 func (cs *clientStream) retryLocked(lastErr error) error { 647 for { 648 cs.attempt.finish(toRPCErr(lastErr)) 649 isTransparent, err := cs.shouldRetry(lastErr) 650 if err != nil { 651 cs.commitAttemptLocked() 652 return err 653 } 654 cs.firstAttempt = false 655 if err := cs.newAttemptLocked(isTransparent); err != nil { 656 return err 657 } 658 if lastErr = cs.replayBufferLocked(); lastErr == nil { 659 return nil 660 } 661 } 662 } 663 664 func (cs *clientStream) Context() context.Context { 665 cs.commitAttempt() 666 // No need to lock before using attempt, since we know it is committed and 667 // cannot change. 668 return cs.attempt.s.Context() 669 } 670 671 func (cs *clientStream) withRetry(op func(a *csAttempt) error, onSuccess func()) error { 672 cs.mu.Lock() 673 for { 674 if cs.committed { 675 cs.mu.Unlock() 676 // toRPCErr is used in case the error from the attempt comes from 677 // NewClientStream, which intentionally doesn't return a status 678 // error to allow for further inspection; all other errors should 679 // already be status errors. 680 return toRPCErr(op(cs.attempt)) 681 } 682 a := cs.attempt 683 cs.mu.Unlock() 684 err := op(a) 685 cs.mu.Lock() 686 if a != cs.attempt { 687 // We started another attempt already. 688 continue 689 } 690 if err == io.EOF { 691 <-a.s.Done() 692 } 693 if err == nil || (err == io.EOF && a.s.Status().Code() == codes.OK) { 694 onSuccess() 695 cs.mu.Unlock() 696 return err 697 } 698 if err := cs.retryLocked(err); err != nil { 699 cs.mu.Unlock() 700 return err 701 } 702 } 703 } 704 705 func (cs *clientStream) Header() (metadata.MD, error) { 706 var m metadata.MD 707 err := cs.withRetry(func(a *csAttempt) error { 708 var err error 709 m, err = a.s.Header() 710 return toRPCErr(err) 711 }, cs.commitAttemptLocked) 712 if err != nil { 713 cs.finish(err) 714 return nil, err 715 } 716 if cs.binlog != nil && !cs.serverHeaderBinlogged { 717 // Only log if binary log is on and header has not been logged. 718 logEntry := &binarylog.ServerHeader{ 719 OnClientSide: true, 720 Header: m, 721 PeerAddr: nil, 722 } 723 if peer, ok := peer.FromContext(cs.Context()); ok { 724 logEntry.PeerAddr = peer.Addr 725 } 726 cs.binlog.Log(logEntry) 727 cs.serverHeaderBinlogged = true 728 } 729 return m, err 730 } 731 732 func (cs *clientStream) Trailer() metadata.MD { 733 // On RPC failure, we never need to retry, because usage requires that 734 // RecvMsg() returned a non-nil error before calling this function is valid. 735 // We would have retried earlier if necessary. 736 // 737 // Commit the attempt anyway, just in case users are not following those 738 // directions -- it will prevent races and should not meaningfully impact 739 // performance. 740 cs.commitAttempt() 741 if cs.attempt.s == nil { 742 return nil 743 } 744 return cs.attempt.s.Trailer() 745 } 746 747 func (cs *clientStream) replayBufferLocked() error { 748 a := cs.attempt 749 for _, f := range cs.buffer { 750 if err := f(a); err != nil { 751 return err 752 } 753 } 754 return nil 755 } 756 757 func (cs *clientStream) bufferForRetryLocked(sz int, op func(a *csAttempt) error) { 758 // Note: we still will buffer if retry is disabled (for transparent retries). 759 if cs.committed { 760 return 761 } 762 cs.bufferSize += sz 763 if cs.bufferSize > cs.callInfo.maxRetryRPCBufferSize { 764 cs.commitAttemptLocked() 765 return 766 } 767 cs.buffer = append(cs.buffer, op) 768 } 769 770 func (cs *clientStream) SendMsg(m interface{}) (err error) { 771 defer func() { 772 if err != nil && err != io.EOF { 773 // Call finish on the client stream for errors generated by this SendMsg 774 // call, as these indicate problems created by this client. (Transport 775 // errors are converted to an io.EOF error in csAttempt.sendMsg; the real 776 // error will be returned from RecvMsg eventually in that case, or be 777 // retried.) 778 cs.finish(err) 779 } 780 }() 781 if cs.sentLast { 782 return status.Errorf(codes.Internal, "SendMsg called after CloseSend") 783 } 784 if !cs.desc.ClientStreams { 785 cs.sentLast = true 786 } 787 788 // load hdr, payload, data 789 hdr, payload, data, err := prepareMsg(m, cs.codec, cs.cp, cs.comp) 790 if err != nil { 791 return err 792 } 793 794 // TODO(dfawley): should we be checking len(data) instead? 795 if len(payload) > *cs.callInfo.maxSendMessageSize { 796 return status.Errorf(codes.ResourceExhausted, "trying to send message larger than max (%d vs. %d)", len(payload), *cs.callInfo.maxSendMessageSize) 797 } 798 msgBytes := data // Store the pointer before setting to nil. For binary logging. 799 op := func(a *csAttempt) error { 800 err := a.sendMsg(m, hdr, payload, data) 801 // nil out the message and uncomp when replaying; they are only needed for 802 // stats which is disabled for subsequent attempts. 803 m, data = nil, nil 804 return err 805 } 806 err = cs.withRetry(op, func() { cs.bufferForRetryLocked(len(hdr)+len(payload), op) }) 807 if cs.binlog != nil && err == nil { 808 cs.binlog.Log(&binarylog.ClientMessage{ 809 OnClientSide: true, 810 Message: msgBytes, 811 }) 812 } 813 return 814 } 815 816 func (cs *clientStream) RecvMsg(m interface{}) error { 817 if cs.binlog != nil && !cs.serverHeaderBinlogged { 818 // Call Header() to binary log header if it's not already logged. 819 cs.Header() 820 } 821 var recvInfo *payloadInfo 822 if cs.binlog != nil { 823 recvInfo = &payloadInfo{} 824 } 825 err := cs.withRetry(func(a *csAttempt) error { 826 return a.recvMsg(m, recvInfo) 827 }, cs.commitAttemptLocked) 828 if cs.binlog != nil && err == nil { 829 cs.binlog.Log(&binarylog.ServerMessage{ 830 OnClientSide: true, 831 Message: recvInfo.uncompressedBytes, 832 }) 833 } 834 if err != nil || !cs.desc.ServerStreams { 835 // err != nil or non-server-streaming indicates end of stream. 836 cs.finish(err) 837 838 if cs.binlog != nil { 839 // finish will not log Trailer. Log Trailer here. 840 logEntry := &binarylog.ServerTrailer{ 841 OnClientSide: true, 842 Trailer: cs.Trailer(), 843 Err: err, 844 } 845 if logEntry.Err == io.EOF { 846 logEntry.Err = nil 847 } 848 if peer, ok := peer.FromContext(cs.Context()); ok { 849 logEntry.PeerAddr = peer.Addr 850 } 851 cs.binlog.Log(logEntry) 852 } 853 } 854 return err 855 } 856 857 func (cs *clientStream) CloseSend() error { 858 if cs.sentLast { 859 // TODO: return an error and finish the stream instead, due to API misuse? 860 return nil 861 } 862 cs.sentLast = true 863 op := func(a *csAttempt) error { 864 a.t.Write(a.s, nil, nil, &transport.Options{Last: true}) 865 // Always return nil; io.EOF is the only error that might make sense 866 // instead, but there is no need to signal the client to call RecvMsg 867 // as the only use left for the stream after CloseSend is to call 868 // RecvMsg. This also matches historical behavior. 869 return nil 870 } 871 cs.withRetry(op, func() { cs.bufferForRetryLocked(0, op) }) 872 if cs.binlog != nil { 873 cs.binlog.Log(&binarylog.ClientHalfClose{ 874 OnClientSide: true, 875 }) 876 } 877 // We never returned an error here for reasons. 878 return nil 879 } 880 881 func (cs *clientStream) finish(err error) { 882 if err == io.EOF { 883 // Ending a stream with EOF indicates a success. 884 err = nil 885 } 886 cs.mu.Lock() 887 if cs.finished { 888 cs.mu.Unlock() 889 return 890 } 891 cs.finished = true 892 cs.commitAttemptLocked() 893 if cs.attempt != nil { 894 cs.attempt.finish(err) 895 // after functions all rely upon having a stream. 896 if cs.attempt.s != nil { 897 for _, o := range cs.opts { 898 o.after(cs.callInfo, cs.attempt) 899 } 900 } 901 } 902 cs.mu.Unlock() 903 // For binary logging. only log cancel in finish (could be caused by RPC ctx 904 // canceled or ClientConn closed). Trailer will be logged in RecvMsg. 905 // 906 // Only one of cancel or trailer needs to be logged. In the cases where 907 // users don't call RecvMsg, users must have already canceled the RPC. 908 if cs.binlog != nil && status.Code(err) == codes.Canceled { 909 cs.binlog.Log(&binarylog.Cancel{ 910 OnClientSide: true, 911 }) 912 } 913 if err == nil { 914 cs.retryThrottler.successfulRPC() 915 } 916 if channelz.IsOn() { 917 if err != nil { 918 cs.cc.incrCallsFailed() 919 } else { 920 cs.cc.incrCallsSucceeded() 921 } 922 } 923 cs.cancel() 924 } 925 926 func (a *csAttempt) sendMsg(m interface{}, hdr, payld, data []byte) error { 927 cs := a.cs 928 if a.trInfo != nil { 929 a.mu.Lock() 930 if a.trInfo.tr != nil { 931 a.trInfo.tr.LazyLog(&payload{sent: true, msg: m}, true) 932 } 933 a.mu.Unlock() 934 } 935 if err := a.t.Write(a.s, hdr, payld, &transport.Options{Last: !cs.desc.ClientStreams}); err != nil { 936 if !cs.desc.ClientStreams { 937 // For non-client-streaming RPCs, we return nil instead of EOF on error 938 // because the generated code requires it. finish is not called; RecvMsg() 939 // will call it with the stream's status independently. 940 return nil 941 } 942 return io.EOF 943 } 944 if a.statsHandler != nil { 945 a.statsHandler.HandleRPC(a.ctx, outPayload(true, m, data, payld, time.Now())) 946 } 947 if channelz.IsOn() { 948 a.t.IncrMsgSent() 949 } 950 return nil 951 } 952 953 func (a *csAttempt) recvMsg(m interface{}, payInfo *payloadInfo) (err error) { 954 cs := a.cs 955 if a.statsHandler != nil && payInfo == nil { 956 payInfo = &payloadInfo{} 957 } 958 959 if !a.decompSet { 960 // Block until we receive headers containing received message encoding. 961 if ct := a.s.RecvCompress(); ct != "" && ct != encoding.Identity { 962 if a.dc == nil || a.dc.Type() != ct { 963 // No configured decompressor, or it does not match the incoming 964 // message encoding; attempt to find a registered compressor that does. 965 a.dc = nil 966 a.decomp = encoding.GetCompressor(ct) 967 } 968 } else { 969 // No compression is used; disable our decompressor. 970 a.dc = nil 971 } 972 // Only initialize this state once per stream. 973 a.decompSet = true 974 } 975 err = recv(a.p, cs.codec, a.s, a.dc, m, *cs.callInfo.maxReceiveMessageSize, payInfo, a.decomp) 976 if err != nil { 977 if err == io.EOF { 978 if statusErr := a.s.Status().Err(); statusErr != nil { 979 return statusErr 980 } 981 return io.EOF // indicates successful end of stream. 982 } 983 return toRPCErr(err) 984 } 985 if a.trInfo != nil { 986 a.mu.Lock() 987 if a.trInfo.tr != nil { 988 a.trInfo.tr.LazyLog(&payload{sent: false, msg: m}, true) 989 } 990 a.mu.Unlock() 991 } 992 if a.statsHandler != nil { 993 a.statsHandler.HandleRPC(a.ctx, &stats.InPayload{ 994 Client: true, 995 RecvTime: time.Now(), 996 Payload: m, 997 // TODO truncate large payload. 998 Data: payInfo.uncompressedBytes, 999 WireLength: payInfo.wireLength + headerLen, 1000 Length: len(payInfo.uncompressedBytes), 1001 }) 1002 } 1003 if channelz.IsOn() { 1004 a.t.IncrMsgRecv() 1005 } 1006 if cs.desc.ServerStreams { 1007 // Subsequent messages should be received by subsequent RecvMsg calls. 1008 return nil 1009 } 1010 // Special handling for non-server-stream rpcs. 1011 // This recv expects EOF or errors, so we don't collect inPayload. 1012 err = recv(a.p, cs.codec, a.s, a.dc, m, *cs.callInfo.maxReceiveMessageSize, nil, a.decomp) 1013 if err == nil { 1014 return toRPCErr(errors.New("grpc: client streaming protocol violation: get <nil>, want <EOF>")) 1015 } 1016 if err == io.EOF { 1017 return a.s.Status().Err() // non-server streaming Recv returns nil on success 1018 } 1019 return toRPCErr(err) 1020 } 1021 1022 func (a *csAttempt) finish(err error) { 1023 a.mu.Lock() 1024 if a.finished { 1025 a.mu.Unlock() 1026 return 1027 } 1028 a.finished = true 1029 if err == io.EOF { 1030 // Ending a stream with EOF indicates a success. 1031 err = nil 1032 } 1033 var tr metadata.MD 1034 if a.s != nil { 1035 a.t.CloseStream(a.s, err) 1036 tr = a.s.Trailer() 1037 } 1038 1039 if a.done != nil { 1040 br := false 1041 if a.s != nil { 1042 br = a.s.BytesReceived() 1043 } 1044 a.done(balancer.DoneInfo{ 1045 Err: err, 1046 Trailer: tr, 1047 BytesSent: a.s != nil, 1048 BytesReceived: br, 1049 ServerLoad: balancerload.Parse(tr), 1050 }) 1051 } 1052 if a.statsHandler != nil { 1053 end := &stats.End{ 1054 Client: true, 1055 BeginTime: a.beginTime, 1056 EndTime: time.Now(), 1057 Trailer: tr, 1058 Error: err, 1059 } 1060 a.statsHandler.HandleRPC(a.ctx, end) 1061 } 1062 if a.trInfo != nil && a.trInfo.tr != nil { 1063 if err == nil { 1064 a.trInfo.tr.LazyPrintf("RPC: [OK]") 1065 } else { 1066 a.trInfo.tr.LazyPrintf("RPC: [%v]", err) 1067 a.trInfo.tr.SetError() 1068 } 1069 a.trInfo.tr.Finish() 1070 a.trInfo.tr = nil 1071 } 1072 a.mu.Unlock() 1073 } 1074 1075 // newClientStream creates a ClientStream with the specified transport, on the 1076 // given addrConn. 1077 // 1078 // It's expected that the given transport is either the same one in addrConn, or 1079 // is already closed. To avoid race, transport is specified separately, instead 1080 // of using ac.transpot. 1081 // 1082 // Main difference between this and ClientConn.NewStream: 1083 // - no retry 1084 // - no service config (or wait for service config) 1085 // - no tracing or stats 1086 func newNonRetryClientStream(ctx context.Context, desc *StreamDesc, method string, t transport.ClientTransport, ac *addrConn, opts ...CallOption) (_ ClientStream, err error) { 1087 if t == nil { 1088 // TODO: return RPC error here? 1089 return nil, errors.New("transport provided is nil") 1090 } 1091 // defaultCallInfo contains unnecessary info(i.e. failfast, maxRetryRPCBufferSize), so we just initialize an empty struct. 1092 c := &callInfo{} 1093 1094 // Possible context leak: 1095 // The cancel function for the child context we create will only be called 1096 // when RecvMsg returns a non-nil error, if the ClientConn is closed, or if 1097 // an error is generated by SendMsg. 1098 // https://github.com/grpc/grpc-go/issues/1818. 1099 ctx, cancel := context.WithCancel(ctx) 1100 defer func() { 1101 if err != nil { 1102 cancel() 1103 } 1104 }() 1105 1106 for _, o := range opts { 1107 if err := o.before(c); err != nil { 1108 return nil, toRPCErr(err) 1109 } 1110 } 1111 c.maxReceiveMessageSize = getMaxSize(nil, c.maxReceiveMessageSize, defaultClientMaxReceiveMessageSize) 1112 c.maxSendMessageSize = getMaxSize(nil, c.maxSendMessageSize, defaultServerMaxSendMessageSize) 1113 if err := setCallInfoCodec(c); err != nil { 1114 return nil, err 1115 } 1116 1117 callHdr := &transport.CallHdr{ 1118 Host: ac.cc.authority, 1119 Method: method, 1120 ContentSubtype: c.contentSubtype, 1121 } 1122 1123 // Set our outgoing compression according to the UseCompressor CallOption, if 1124 // set. In that case, also find the compressor from the encoding package. 1125 // Otherwise, use the compressor configured by the WithCompressor DialOption, 1126 // if set. 1127 var cp Compressor 1128 var comp encoding.Compressor 1129 if ct := c.compressorType; ct != "" { 1130 callHdr.SendCompress = ct 1131 if ct != encoding.Identity { 1132 comp = encoding.GetCompressor(ct) 1133 if comp == nil { 1134 return nil, status.Errorf(codes.Internal, "grpc: Compressor is not installed for requested grpc-encoding %q", ct) 1135 } 1136 } 1137 } else if ac.cc.dopts.cp != nil { 1138 callHdr.SendCompress = ac.cc.dopts.cp.Type() 1139 cp = ac.cc.dopts.cp 1140 } 1141 if c.creds != nil { 1142 callHdr.Creds = c.creds 1143 } 1144 1145 // Use a special addrConnStream to avoid retry. 1146 as := &addrConnStream{ 1147 callHdr: callHdr, 1148 ac: ac, 1149 ctx: ctx, 1150 cancel: cancel, 1151 opts: opts, 1152 callInfo: c, 1153 desc: desc, 1154 codec: c.codec, 1155 cp: cp, 1156 comp: comp, 1157 t: t, 1158 } 1159 1160 s, err := as.t.NewStream(as.ctx, as.callHdr) 1161 if err != nil { 1162 err = toRPCErr(err) 1163 return nil, err 1164 } 1165 as.s = s 1166 as.p = &parser{r: s} 1167 ac.incrCallsStarted() 1168 if desc != unaryStreamDesc { 1169 // Listen on cc and stream contexts to cleanup when the user closes the 1170 // ClientConn or cancels the stream context. In all other cases, an error 1171 // should already be injected into the recv buffer by the transport, which 1172 // the client will eventually receive, and then we will cancel the stream's 1173 // context in clientStream.finish. 1174 go func() { 1175 select { 1176 case <-ac.ctx.Done(): 1177 as.finish(status.Error(codes.Canceled, "grpc: the SubConn is closing")) 1178 case <-ctx.Done(): 1179 as.finish(toRPCErr(ctx.Err())) 1180 } 1181 }() 1182 } 1183 return as, nil 1184 } 1185 1186 type addrConnStream struct { 1187 s *transport.Stream 1188 ac *addrConn 1189 callHdr *transport.CallHdr 1190 cancel context.CancelFunc 1191 opts []CallOption 1192 callInfo *callInfo 1193 t transport.ClientTransport 1194 ctx context.Context 1195 sentLast bool 1196 desc *StreamDesc 1197 codec baseCodec 1198 cp Compressor 1199 comp encoding.Compressor 1200 decompSet bool 1201 dc Decompressor 1202 decomp encoding.Compressor 1203 p *parser 1204 mu sync.Mutex 1205 finished bool 1206 } 1207 1208 func (as *addrConnStream) Header() (metadata.MD, error) { 1209 m, err := as.s.Header() 1210 if err != nil { 1211 as.finish(toRPCErr(err)) 1212 } 1213 return m, err 1214 } 1215 1216 func (as *addrConnStream) Trailer() metadata.MD { 1217 return as.s.Trailer() 1218 } 1219 1220 func (as *addrConnStream) CloseSend() error { 1221 if as.sentLast { 1222 // TODO: return an error and finish the stream instead, due to API misuse? 1223 return nil 1224 } 1225 as.sentLast = true 1226 1227 as.t.Write(as.s, nil, nil, &transport.Options{Last: true}) 1228 // Always return nil; io.EOF is the only error that might make sense 1229 // instead, but there is no need to signal the client to call RecvMsg 1230 // as the only use left for the stream after CloseSend is to call 1231 // RecvMsg. This also matches historical behavior. 1232 return nil 1233 } 1234 1235 func (as *addrConnStream) Context() context.Context { 1236 return as.s.Context() 1237 } 1238 1239 func (as *addrConnStream) SendMsg(m interface{}) (err error) { 1240 defer func() { 1241 if err != nil && err != io.EOF { 1242 // Call finish on the client stream for errors generated by this SendMsg 1243 // call, as these indicate problems created by this client. (Transport 1244 // errors are converted to an io.EOF error in csAttempt.sendMsg; the real 1245 // error will be returned from RecvMsg eventually in that case, or be 1246 // retried.) 1247 as.finish(err) 1248 } 1249 }() 1250 if as.sentLast { 1251 return status.Errorf(codes.Internal, "SendMsg called after CloseSend") 1252 } 1253 if !as.desc.ClientStreams { 1254 as.sentLast = true 1255 } 1256 1257 // load hdr, payload, data 1258 hdr, payld, _, err := prepareMsg(m, as.codec, as.cp, as.comp) 1259 if err != nil { 1260 return err 1261 } 1262 1263 // TODO(dfawley): should we be checking len(data) instead? 1264 if len(payld) > *as.callInfo.maxSendMessageSize { 1265 return status.Errorf(codes.ResourceExhausted, "trying to send message larger than max (%d vs. %d)", len(payld), *as.callInfo.maxSendMessageSize) 1266 } 1267 1268 if err := as.t.Write(as.s, hdr, payld, &transport.Options{Last: !as.desc.ClientStreams}); err != nil { 1269 if !as.desc.ClientStreams { 1270 // For non-client-streaming RPCs, we return nil instead of EOF on error 1271 // because the generated code requires it. finish is not called; RecvMsg() 1272 // will call it with the stream's status independently. 1273 return nil 1274 } 1275 return io.EOF 1276 } 1277 1278 if channelz.IsOn() { 1279 as.t.IncrMsgSent() 1280 } 1281 return nil 1282 } 1283 1284 func (as *addrConnStream) RecvMsg(m interface{}) (err error) { 1285 defer func() { 1286 if err != nil || !as.desc.ServerStreams { 1287 // err != nil or non-server-streaming indicates end of stream. 1288 as.finish(err) 1289 } 1290 }() 1291 1292 if !as.decompSet { 1293 // Block until we receive headers containing received message encoding. 1294 if ct := as.s.RecvCompress(); ct != "" && ct != encoding.Identity { 1295 if as.dc == nil || as.dc.Type() != ct { 1296 // No configured decompressor, or it does not match the incoming 1297 // message encoding; attempt to find a registered compressor that does. 1298 as.dc = nil 1299 as.decomp = encoding.GetCompressor(ct) 1300 } 1301 } else { 1302 // No compression is used; disable our decompressor. 1303 as.dc = nil 1304 } 1305 // Only initialize this state once per stream. 1306 as.decompSet = true 1307 } 1308 err = recv(as.p, as.codec, as.s, as.dc, m, *as.callInfo.maxReceiveMessageSize, nil, as.decomp) 1309 if err != nil { 1310 if err == io.EOF { 1311 if statusErr := as.s.Status().Err(); statusErr != nil { 1312 return statusErr 1313 } 1314 return io.EOF // indicates successful end of stream. 1315 } 1316 return toRPCErr(err) 1317 } 1318 1319 if channelz.IsOn() { 1320 as.t.IncrMsgRecv() 1321 } 1322 if as.desc.ServerStreams { 1323 // Subsequent messages should be received by subsequent RecvMsg calls. 1324 return nil 1325 } 1326 1327 // Special handling for non-server-stream rpcs. 1328 // This recv expects EOF or errors, so we don't collect inPayload. 1329 err = recv(as.p, as.codec, as.s, as.dc, m, *as.callInfo.maxReceiveMessageSize, nil, as.decomp) 1330 if err == nil { 1331 return toRPCErr(errors.New("grpc: client streaming protocol violation: get <nil>, want <EOF>")) 1332 } 1333 if err == io.EOF { 1334 return as.s.Status().Err() // non-server streaming Recv returns nil on success 1335 } 1336 return toRPCErr(err) 1337 } 1338 1339 func (as *addrConnStream) finish(err error) { 1340 as.mu.Lock() 1341 if as.finished { 1342 as.mu.Unlock() 1343 return 1344 } 1345 as.finished = true 1346 if err == io.EOF { 1347 // Ending a stream with EOF indicates a success. 1348 err = nil 1349 } 1350 if as.s != nil { 1351 as.t.CloseStream(as.s, err) 1352 } 1353 1354 if err != nil { 1355 as.ac.incrCallsFailed() 1356 } else { 1357 as.ac.incrCallsSucceeded() 1358 } 1359 as.cancel() 1360 as.mu.Unlock() 1361 } 1362 1363 // ServerStream defines the server-side behavior of a streaming RPC. 1364 // 1365 // All errors returned from ServerStream methods are compatible with the 1366 // status package. 1367 type ServerStream interface { 1368 // SetHeader sets the header metadata. It may be called multiple times. 1369 // When call multiple times, all the provided metadata will be merged. 1370 // All the metadata will be sent out when one of the following happens: 1371 // - ServerStream.SendHeader() is called; 1372 // - The first response is sent out; 1373 // - An RPC status is sent out (error or success). 1374 SetHeader(metadata.MD) error 1375 // SendHeader sends the header metadata. 1376 // The provided md and headers set by SetHeader() will be sent. 1377 // It fails if called multiple times. 1378 SendHeader(metadata.MD) error 1379 // SetTrailer sets the trailer metadata which will be sent with the RPC status. 1380 // When called more than once, all the provided metadata will be merged. 1381 SetTrailer(metadata.MD) 1382 // Context returns the context for this stream. 1383 Context() context.Context 1384 // SendMsg sends a message. On error, SendMsg aborts the stream and the 1385 // error is returned directly. 1386 // 1387 // SendMsg blocks until: 1388 // - There is sufficient flow control to schedule m with the transport, or 1389 // - The stream is done, or 1390 // - The stream breaks. 1391 // 1392 // SendMsg does not wait until the message is received by the client. An 1393 // untimely stream closure may result in lost messages. 1394 // 1395 // It is safe to have a goroutine calling SendMsg and another goroutine 1396 // calling RecvMsg on the same stream at the same time, but it is not safe 1397 // to call SendMsg on the same stream in different goroutines. 1398 SendMsg(m interface{}) error 1399 // RecvMsg blocks until it receives a message into m or the stream is 1400 // done. It returns io.EOF when the client has performed a CloseSend. On 1401 // any non-EOF error, the stream is aborted and the error contains the 1402 // RPC status. 1403 // 1404 // It is safe to have a goroutine calling SendMsg and another goroutine 1405 // calling RecvMsg on the same stream at the same time, but it is not 1406 // safe to call RecvMsg on the same stream in different goroutines. 1407 RecvMsg(m interface{}) error 1408 } 1409 1410 // serverStream implements a server side Stream. 1411 type serverStream struct { 1412 ctx context.Context 1413 t transport.ServerTransport 1414 s *transport.Stream 1415 p *parser 1416 codec baseCodec 1417 1418 cp Compressor 1419 dc Decompressor 1420 comp encoding.Compressor 1421 decomp encoding.Compressor 1422 1423 maxReceiveMessageSize int 1424 maxSendMessageSize int 1425 trInfo *traceInfo 1426 1427 statsHandler stats.Handler 1428 1429 binlog *binarylog.MethodLogger 1430 // serverHeaderBinlogged indicates whether server header has been logged. It 1431 // will happen when one of the following two happens: stream.SendHeader(), 1432 // stream.Send(). 1433 // 1434 // It's only checked in send and sendHeader, doesn't need to be 1435 // synchronized. 1436 serverHeaderBinlogged bool 1437 1438 mu sync.Mutex // protects trInfo.tr after the service handler runs. 1439 } 1440 1441 func (ss *serverStream) Context() context.Context { 1442 return ss.ctx 1443 } 1444 1445 func (ss *serverStream) SetHeader(md metadata.MD) error { 1446 if md.Len() == 0 { 1447 return nil 1448 } 1449 return ss.s.SetHeader(md) 1450 } 1451 1452 func (ss *serverStream) SendHeader(md metadata.MD) error { 1453 err := ss.t.WriteHeader(ss.s, md) 1454 if ss.binlog != nil && !ss.serverHeaderBinlogged { 1455 h, _ := ss.s.Header() 1456 ss.binlog.Log(&binarylog.ServerHeader{ 1457 Header: h, 1458 }) 1459 ss.serverHeaderBinlogged = true 1460 } 1461 return err 1462 } 1463 1464 func (ss *serverStream) SetTrailer(md metadata.MD) { 1465 if md.Len() == 0 { 1466 return 1467 } 1468 ss.s.SetTrailer(md) 1469 } 1470 1471 func (ss *serverStream) SendMsg(m interface{}) (err error) { 1472 defer func() { 1473 if ss.trInfo != nil { 1474 ss.mu.Lock() 1475 if ss.trInfo.tr != nil { 1476 if err == nil { 1477 ss.trInfo.tr.LazyLog(&payload{sent: true, msg: m}, true) 1478 } else { 1479 ss.trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true) 1480 ss.trInfo.tr.SetError() 1481 } 1482 } 1483 ss.mu.Unlock() 1484 } 1485 if err != nil && err != io.EOF { 1486 st, _ := status.FromError(toRPCErr(err)) 1487 ss.t.WriteStatus(ss.s, st) 1488 // Non-user specified status was sent out. This should be an error 1489 // case (as a server side Cancel maybe). 1490 // 1491 // This is not handled specifically now. User will return a final 1492 // status from the service handler, we will log that error instead. 1493 // This behavior is similar to an interceptor. 1494 } 1495 if channelz.IsOn() && err == nil { 1496 ss.t.IncrMsgSent() 1497 } 1498 }() 1499 1500 // load hdr, payload, data 1501 hdr, payload, data, err := prepareMsg(m, ss.codec, ss.cp, ss.comp) 1502 if err != nil { 1503 return err 1504 } 1505 1506 // TODO(dfawley): should we be checking len(data) instead? 1507 if len(payload) > ss.maxSendMessageSize { 1508 return status.Errorf(codes.ResourceExhausted, "trying to send message larger than max (%d vs. %d)", len(payload), ss.maxSendMessageSize) 1509 } 1510 if err := ss.t.Write(ss.s, hdr, payload, &transport.Options{Last: false}); err != nil { 1511 return toRPCErr(err) 1512 } 1513 if ss.binlog != nil { 1514 if !ss.serverHeaderBinlogged { 1515 h, _ := ss.s.Header() 1516 ss.binlog.Log(&binarylog.ServerHeader{ 1517 Header: h, 1518 }) 1519 ss.serverHeaderBinlogged = true 1520 } 1521 ss.binlog.Log(&binarylog.ServerMessage{ 1522 Message: data, 1523 }) 1524 } 1525 if ss.statsHandler != nil { 1526 ss.statsHandler.HandleRPC(ss.s.Context(), outPayload(false, m, data, payload, time.Now())) 1527 } 1528 return nil 1529 } 1530 1531 func (ss *serverStream) RecvMsg(m interface{}) (err error) { 1532 defer func() { 1533 if ss.trInfo != nil { 1534 ss.mu.Lock() 1535 if ss.trInfo.tr != nil { 1536 if err == nil { 1537 ss.trInfo.tr.LazyLog(&payload{sent: false, msg: m}, true) 1538 } else if err != io.EOF { 1539 ss.trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true) 1540 ss.trInfo.tr.SetError() 1541 } 1542 } 1543 ss.mu.Unlock() 1544 } 1545 if err != nil && err != io.EOF { 1546 st, _ := status.FromError(toRPCErr(err)) 1547 ss.t.WriteStatus(ss.s, st) 1548 // Non-user specified status was sent out. This should be an error 1549 // case (as a server side Cancel maybe). 1550 // 1551 // This is not handled specifically now. User will return a final 1552 // status from the service handler, we will log that error instead. 1553 // This behavior is similar to an interceptor. 1554 } 1555 if channelz.IsOn() && err == nil { 1556 ss.t.IncrMsgRecv() 1557 } 1558 }() 1559 var payInfo *payloadInfo 1560 if ss.statsHandler != nil || ss.binlog != nil { 1561 payInfo = &payloadInfo{} 1562 } 1563 if err := recv(ss.p, ss.codec, ss.s, ss.dc, m, ss.maxReceiveMessageSize, payInfo, ss.decomp); err != nil { 1564 if err == io.EOF { 1565 if ss.binlog != nil { 1566 ss.binlog.Log(&binarylog.ClientHalfClose{}) 1567 } 1568 return err 1569 } 1570 if err == io.ErrUnexpectedEOF { 1571 err = status.Errorf(codes.Internal, io.ErrUnexpectedEOF.Error()) 1572 } 1573 return toRPCErr(err) 1574 } 1575 if ss.statsHandler != nil { 1576 ss.statsHandler.HandleRPC(ss.s.Context(), &stats.InPayload{ 1577 RecvTime: time.Now(), 1578 Payload: m, 1579 // TODO truncate large payload. 1580 Data: payInfo.uncompressedBytes, 1581 WireLength: payInfo.wireLength + headerLen, 1582 Length: len(payInfo.uncompressedBytes), 1583 }) 1584 } 1585 if ss.binlog != nil { 1586 ss.binlog.Log(&binarylog.ClientMessage{ 1587 Message: payInfo.uncompressedBytes, 1588 }) 1589 } 1590 return nil 1591 } 1592 1593 // MethodFromServerStream returns the method string for the input stream. 1594 // The returned string is in the format of "/service/method". 1595 func MethodFromServerStream(stream ServerStream) (string, bool) { 1596 return Method(stream.Context()) 1597 } 1598 1599 // prepareMsg returns the hdr, payload and data 1600 // using the compressors passed or using the 1601 // passed preparedmsg 1602 func prepareMsg(m interface{}, codec baseCodec, cp Compressor, comp encoding.Compressor) (hdr, payload, data []byte, err error) { 1603 if preparedMsg, ok := m.(*PreparedMsg); ok { 1604 return preparedMsg.hdr, preparedMsg.payload, preparedMsg.encodedData, nil 1605 } 1606 // The input interface is not a prepared msg. 1607 // Marshal and Compress the data at this point 1608 data, err = encode(codec, m) 1609 if err != nil { 1610 return nil, nil, nil, err 1611 } 1612 compData, err := compress(data, cp, comp) 1613 if err != nil { 1614 return nil, nil, nil, err 1615 } 1616 hdr, payload = msgHeader(data, compData) 1617 return hdr, payload, data, nil 1618 }