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