github.com/cloudwego/kitex@v0.9.0/pkg/remote/trans/nphttp2/grpc/http2_client.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   * This file may have been modified by CloudWeGo authors. All CloudWeGo
    18   * Modifications are Copyright 2021 CloudWeGo Authors.
    19   */
    20  
    21  package grpc
    22  
    23  import (
    24  	"context"
    25  	"io"
    26  	"math"
    27  	"net"
    28  	"runtime/debug"
    29  	"strconv"
    30  	"strings"
    31  	"sync"
    32  	"sync/atomic"
    33  	"time"
    34  
    35  	"github.com/cloudwego/netpoll"
    36  	"golang.org/x/net/http2"
    37  	"golang.org/x/net/http2/hpack"
    38  
    39  	"github.com/cloudwego/kitex/pkg/gofunc"
    40  	"github.com/cloudwego/kitex/pkg/klog"
    41  	"github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/codes"
    42  	"github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/grpc/grpcframe"
    43  	"github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/grpc/syscall"
    44  	"github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/metadata"
    45  	"github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/peer"
    46  	"github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/status"
    47  )
    48  
    49  // http2Client implements the ClientTransport interface with HTTP2.
    50  type http2Client struct {
    51  	lastRead   int64 // Keep this field 64-bit aligned. Accessed atomically.
    52  	ctx        context.Context
    53  	cancel     context.CancelFunc
    54  	conn       net.Conn // underlying communication channel
    55  	loopy      *loopyWriter
    56  	remoteAddr net.Addr
    57  	localAddr  net.Addr
    58  	scheme     string
    59  
    60  	readerDone chan struct{} // sync point to enable testing.
    61  	writerDone chan struct{} // sync point to enable testing.
    62  	// goAway is closed to notify the upper layer (i.e., addrConn.transportMonitor)
    63  	// that the server sent GoAway on this transport.
    64  	goAway chan struct{}
    65  
    66  	framer *framer
    67  	// controlBuf delivers all the control related tasks (e.g., window
    68  	// updates, reset streams, and various settings) to the controller.
    69  	// Do not access controlBuf with mu held.
    70  	controlBuf *controlBuffer
    71  	fc         *trInFlow
    72  
    73  	kp               ClientKeepalive
    74  	keepaliveEnabled bool
    75  
    76  	initialWindowSize uint32
    77  
    78  	// configured by peer through SETTINGS_MAX_HEADER_LIST_SIZE
    79  	maxSendHeaderListSize *uint32
    80  
    81  	bdpEst *bdpEstimator
    82  
    83  	maxConcurrentStreams  uint32
    84  	streamQuota           int64
    85  	streamsQuotaAvailable chan struct{}
    86  	waitingStreams        uint32
    87  	nextID                uint32
    88  
    89  	// Do not access controlBuf with mu held.
    90  	mu            sync.Mutex // guard the following variables
    91  	state         transportState
    92  	activeStreams map[uint32]*Stream
    93  	// prevGoAway ID records the Last-Stream-ID in the previous GOAway frame.
    94  	prevGoAwayID uint32
    95  
    96  	goAwayReason GoAwayReason
    97  	// A condition variable used to signal when the keepalive goroutine should
    98  	// go dormant. The condition for dormancy is based on the number of active
    99  	// streams and the `PermitWithoutStream` keepalive client parameter. And
   100  	// since the number of active streams is guarded by the above mutex, we use
   101  	// the same for this condition variable as well.
   102  	kpDormancyCond *sync.Cond
   103  	// A boolean to track whether the keepalive goroutine is dormant or not.
   104  	// This is checked before attempting to signal the above condition
   105  	// variable.
   106  	kpDormant bool
   107  	onGoAway  func(GoAwayReason)
   108  	onClose   func()
   109  
   110  	bufferPool *bufferPool
   111  }
   112  
   113  // newHTTP2Client constructs a connected ClientTransport to addr based on HTTP2
   114  // and starts to receive messages on it. Non-nil error returns if construction
   115  // fails.
   116  func newHTTP2Client(ctx context.Context, conn net.Conn, opts ConnectOptions,
   117  	remoteService string, onGoAway func(GoAwayReason), onClose func(),
   118  ) (_ *http2Client, err error) {
   119  	scheme := "http"
   120  	if opts.TLSConfig != nil {
   121  		scheme = "https"
   122  	}
   123  	ctx, cancel := context.WithCancel(ctx)
   124  	defer func() {
   125  		if err != nil {
   126  			cancel()
   127  		}
   128  	}()
   129  
   130  	kp := opts.KeepaliveParams
   131  	// Validate keepalive parameters.
   132  	if kp.Time == 0 {
   133  		kp.Time = defaultClientKeepaliveTime
   134  	}
   135  	if kp.Timeout == 0 {
   136  		kp.Timeout = defaultClientKeepaliveTimeout
   137  	}
   138  	keepaliveEnabled := false
   139  	if kp.Time != Infinity {
   140  		if err = syscall.SetTCPUserTimeout(conn, kp.Timeout); err != nil {
   141  			return nil, connectionErrorf(false, err, "transport: failed to set TCP_USER_TIMEOUT: %v", err)
   142  		}
   143  		keepaliveEnabled = true
   144  	}
   145  
   146  	dynamicWindow := true
   147  	icwz := initialWindowSize
   148  	if opts.InitialConnWindowSize >= defaultWindowSize {
   149  		icwz = opts.InitialConnWindowSize
   150  		dynamicWindow = false
   151  	}
   152  
   153  	writeBufSize := defaultWriteBufferSize
   154  	readBufSize := defaultReadBufferSize
   155  	if opts.WriteBufferSize > 0 {
   156  		writeBufSize = opts.WriteBufferSize
   157  	}
   158  	if opts.ReadBufferSize > 0 {
   159  		readBufSize = opts.ReadBufferSize
   160  	}
   161  	maxHeaderListSize := defaultClientMaxHeaderListSize
   162  	if opts.MaxHeaderListSize != nil {
   163  		maxHeaderListSize = *opts.MaxHeaderListSize
   164  	}
   165  	t := &http2Client{
   166  		ctx:                   ctx,
   167  		conn:                  conn,
   168  		cancel:                cancel,
   169  		remoteAddr:            conn.RemoteAddr(),
   170  		localAddr:             conn.LocalAddr(),
   171  		scheme:                scheme,
   172  		readerDone:            make(chan struct{}),
   173  		writerDone:            make(chan struct{}),
   174  		goAway:                make(chan struct{}),
   175  		framer:                newFramer(conn, writeBufSize, readBufSize, maxHeaderListSize),
   176  		fc:                    &trInFlow{limit: icwz},
   177  		activeStreams:         make(map[uint32]*Stream),
   178  		kp:                    kp,
   179  		keepaliveEnabled:      keepaliveEnabled,
   180  		initialWindowSize:     initialWindowSize,
   181  		nextID:                1,
   182  		maxConcurrentStreams:  defaultMaxStreamsClient,
   183  		streamQuota:           defaultMaxStreamsClient,
   184  		streamsQuotaAvailable: make(chan struct{}, 1),
   185  		onGoAway:              onGoAway,
   186  		onClose:               onClose,
   187  		bufferPool:            newBufferPool(),
   188  	}
   189  	t.controlBuf = newControlBuffer(t.ctx.Done())
   190  	if opts.InitialWindowSize >= defaultWindowSize {
   191  		t.initialWindowSize = opts.InitialWindowSize
   192  		dynamicWindow = false
   193  	}
   194  	if dynamicWindow {
   195  		t.bdpEst = &bdpEstimator{
   196  			bdp:               initialWindowSize,
   197  			updateFlowControl: t.updateFlowControl,
   198  		}
   199  	}
   200  	t.loopy = newLoopyWriter(clientSide, t.framer, t.controlBuf, t.bdpEst)
   201  
   202  	// Start the reader goroutine for incoming message. Each transport has
   203  	// a dedicated goroutine which reads HTTP2 frame from network. Then it
   204  	// dispatches the frame to the corresponding stream entity.
   205  	if npconn, ok := t.conn.(netpoll.Connection); ok {
   206  		npconn.SetOnRequest(func(ctx context.Context, connection netpoll.Connection) error {
   207  			t.reader()
   208  			return nil
   209  		})
   210  	} else {
   211  		gofunc.RecoverGoFuncWithInfo(ctx, t.reader, gofunc.NewBasicInfo(remoteService, conn.RemoteAddr().String()))
   212  	}
   213  
   214  	if t.keepaliveEnabled {
   215  		t.kpDormancyCond = sync.NewCond(&t.mu)
   216  		gofunc.RecoverGoFuncWithInfo(ctx, t.keepalive, gofunc.NewBasicInfo(remoteService, conn.RemoteAddr().String()))
   217  	}
   218  
   219  	// Send connection preface to server.
   220  	n, err := t.conn.Write(ClientPreface)
   221  	if err != nil {
   222  		t.Close()
   223  		return nil, connectionErrorf(true, err, "transport: failed to write client preface: %v", err)
   224  	}
   225  	if n != ClientPrefaceLen {
   226  		t.Close()
   227  		return nil, connectionErrorf(true, err, "transport: preface mismatch, wrote %d bytes; want %d", n, ClientPrefaceLen)
   228  	}
   229  
   230  	ss := []http2.Setting{
   231  		{
   232  			ID:  http2.SettingInitialWindowSize,
   233  			Val: uint32(t.initialWindowSize),
   234  		},
   235  	}
   236  	err = t.framer.WriteSettings(ss...)
   237  	if err != nil {
   238  		t.Close()
   239  		return nil, connectionErrorf(true, err, "transport: failed to write initial settings frame: %v", err)
   240  	}
   241  
   242  	// Adjust the connection flow control window if needed.
   243  	if delta := uint32(icwz - defaultWindowSize); delta > 0 {
   244  		if err := t.framer.WriteWindowUpdate(0, delta); err != nil {
   245  			t.Close()
   246  			return nil, connectionErrorf(true, err, "transport: failed to write window update: %v", err)
   247  		}
   248  	}
   249  
   250  	if err := t.framer.writer.Flush(); err != nil {
   251  		return nil, err
   252  	}
   253  	gofunc.RecoverGoFuncWithInfo(ctx, func() {
   254  		err := t.loopy.run(conn.RemoteAddr().String())
   255  		if err != nil {
   256  			klog.CtxErrorf(ctx, "KITEX: grpc client loopyWriter.run returning, error=%v", err)
   257  		}
   258  		// If it's a connection error, let reader goroutine handle it
   259  		// since there might be data in the buffers.
   260  		if _, ok := err.(net.Error); !ok {
   261  			t.conn.Close()
   262  		}
   263  		close(t.writerDone)
   264  	}, gofunc.NewBasicInfo(remoteService, conn.RemoteAddr().String()))
   265  
   266  	return t, nil
   267  }
   268  
   269  type preAllocatedStreamFields struct {
   270  	recvBuffer *recvBuffer
   271  	writeQuota *writeQuota
   272  }
   273  
   274  var (
   275  	preallocateChan = make(chan preAllocatedStreamFields, 256)
   276  	preallocateInit sync.Once
   277  )
   278  
   279  func fillStreamFields(s *Stream) {
   280  	preallocateInit.Do(func() {
   281  		go preallocateForStream()
   282  	})
   283  	var fields preAllocatedStreamFields
   284  	select {
   285  	case fields = <-preallocateChan:
   286  	default: // won't block even the producer is not fast enough
   287  		fields = allocateStreamFields()
   288  	}
   289  	s.buf = fields.recvBuffer
   290  	s.wq = fields.writeQuota
   291  	s.wq.done = s.done
   292  }
   293  
   294  func preallocateForStream() {
   295  	defer func() {
   296  		if err := recover(); err != nil {
   297  			klog.Warnf("grpc.preallocateForStream panic, error=%v, stack=%s", err, debug.Stack())
   298  		}
   299  	}()
   300  	for {
   301  		preallocateChan <- allocateStreamFields()
   302  	}
   303  }
   304  
   305  func allocateStreamFields() preAllocatedStreamFields {
   306  	return preAllocatedStreamFields{
   307  		recvBuffer: newRecvBuffer(),
   308  		writeQuota: newWriteQuota(defaultWriteQuota, nil),
   309  	}
   310  }
   311  
   312  func (t *http2Client) newStream(ctx context.Context, callHdr *CallHdr) *Stream {
   313  	s := &Stream{
   314  		ctx:            ctx,
   315  		ct:             t,
   316  		done:           make(chan struct{}),
   317  		method:         callHdr.Method,
   318  		sendCompress:   callHdr.SendCompress,
   319  		headerChan:     make(chan struct{}),
   320  		contentSubtype: callHdr.ContentSubtype,
   321  	}
   322  	fillStreamFields(s)
   323  	s.requestRead = func(n int) {
   324  		t.adjustWindow(s, uint32(n))
   325  	}
   326  	s.trReader = &transportReader{
   327  		reader: &recvBufferReader{
   328  			ctx:     s.ctx,
   329  			ctxDone: s.ctx.Done(),
   330  			recv:    s.buf,
   331  			closeStream: func(err error) {
   332  				t.CloseStream(s, err)
   333  			},
   334  			freeBuffer: t.bufferPool.put,
   335  		},
   336  		windowHandler: func(n int) {
   337  			t.updateWindow(s, uint32(n))
   338  		},
   339  	}
   340  	return s
   341  }
   342  
   343  // TODO: mesh headers
   344  func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr) []hpack.HeaderField {
   345  	hfLen := 7 // :method, :scheme, :path, :authority, content-type, user-agent, te
   346  	headerFields := make([]hpack.HeaderField, 0, hfLen)
   347  	headerFields = append(headerFields, hpack.HeaderField{Name: ":method", Value: "POST"})
   348  	headerFields = append(headerFields, hpack.HeaderField{Name: ":scheme", Value: t.scheme})
   349  	headerFields = append(headerFields, hpack.HeaderField{Name: ":path", Value: callHdr.Method})
   350  	headerFields = append(headerFields, hpack.HeaderField{Name: ":authority", Value: callHdr.Host})
   351  	headerFields = append(headerFields, hpack.HeaderField{Name: "content-type", Value: contentType(callHdr.ContentSubtype)})
   352  	headerFields = append(headerFields, hpack.HeaderField{Name: "user-agent", Value: defaultUserAgent})
   353  	headerFields = append(headerFields, hpack.HeaderField{Name: "te", Value: "trailers"})
   354  	if callHdr.PreviousAttempts > 0 {
   355  		headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-previous-rpc-attempts", Value: strconv.Itoa(callHdr.PreviousAttempts)})
   356  	}
   357  
   358  	if callHdr.SendCompress != "" {
   359  		headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-encoding", Value: callHdr.SendCompress})
   360  		headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-accept-encoding", Value: callHdr.SendCompress})
   361  	}
   362  	if dl, ok := ctx.Deadline(); ok {
   363  		// Send out timeout regardless its value. The server can detect timeout context by itself.
   364  		// TODO(mmukhi): Perhaps this field should be updated when actually writing out to the wire.
   365  		timeout := time.Until(dl)
   366  		headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-timeout", Value: encodeTimeout(timeout)})
   367  	}
   368  	if md, added, ok := metadata.FromOutgoingContextRaw(ctx); ok {
   369  		var k string
   370  		for k, vv := range md {
   371  			// HTTP doesn't allow you to set pseudoheaders after non pseudoheaders were set.
   372  			if isReservedHeader(k) {
   373  				continue
   374  			}
   375  			for _, v := range vv {
   376  				headerFields = append(headerFields, hpack.HeaderField{Name: k, Value: encodeMetadataHeader(k, v)})
   377  			}
   378  		}
   379  		for _, vv := range added {
   380  			for i, v := range vv {
   381  				if i%2 == 0 {
   382  					k = v
   383  					continue
   384  				}
   385  				// HTTP doesn't allow you to set pseudoheaders after non pseudoheaders were set.
   386  				if isReservedHeader(k) {
   387  					continue
   388  				}
   389  				headerFields = append(headerFields, hpack.HeaderField{Name: strings.ToLower(k), Value: encodeMetadataHeader(k, v)})
   390  			}
   391  		}
   392  	}
   393  	return headerFields
   394  }
   395  
   396  func (t *http2Client) setPeer(ctx context.Context) {
   397  	peer, ok := peer.GetPeerFromContext(ctx)
   398  	if ok {
   399  		peer.Addr = t.remoteAddr
   400  	}
   401  }
   402  
   403  // NewStream creates a stream and registers it into the transport as "active"
   404  // streams.
   405  func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Stream, err error) {
   406  	t.setPeer(ctx)
   407  	s := t.newStream(ctx, callHdr)
   408  	cleanup := func(err error) {
   409  		if s.swapState(streamDone) == streamDone {
   410  			// If it was already done, return.
   411  			return
   412  		}
   413  		// The stream was unprocessed by the server.
   414  		atomic.StoreUint32(&s.unprocessed, 1)
   415  		s.write(recvMsg{err: err})
   416  		close(s.done)
   417  		// If headerChan isn't closed, then close it.
   418  		if atomic.CompareAndSwapUint32(&s.headerChanClosed, 0, 1) {
   419  			close(s.headerChan)
   420  		}
   421  	}
   422  	hdr := &headerFrame{
   423  		hf:        t.createHeaderFields(ctx, callHdr),
   424  		endStream: false,
   425  		initStream: func(id uint32) error {
   426  			t.mu.Lock()
   427  			if state := t.state; state != reachable {
   428  				t.mu.Unlock()
   429  				// Do a quick cleanup.
   430  				err := error(errStreamDrain)
   431  				if state == closing {
   432  					err = ErrConnClosing
   433  				}
   434  				cleanup(err)
   435  				return err
   436  			}
   437  			// If the keepalive goroutine has gone dormant, wake it up.
   438  			if t.kpDormant {
   439  				t.kpDormancyCond.Signal()
   440  			}
   441  			t.mu.Unlock()
   442  			return nil
   443  		},
   444  		onOrphaned: cleanup,
   445  		wq:         s.wq,
   446  	}
   447  	firstTry := true
   448  	var ch chan struct{}
   449  	checkForStreamQuota := func(it interface{}) bool {
   450  		if t.streamQuota <= 0 { // Can go negative if server decreases it.
   451  			if firstTry {
   452  				t.waitingStreams++
   453  			}
   454  			ch = t.streamsQuotaAvailable
   455  			return false
   456  		}
   457  		if !firstTry {
   458  			t.waitingStreams--
   459  		}
   460  		t.streamQuota--
   461  		h := it.(*headerFrame)
   462  		h.streamID = t.nextID
   463  		t.nextID += 2
   464  		s.id = h.streamID
   465  		s.fc = &inFlow{limit: uint32(t.initialWindowSize)}
   466  		t.mu.Lock()
   467  		if t.activeStreams == nil { // Can be niled from Close().
   468  			t.mu.Unlock()
   469  			return false // Don't create a stream if the transport is already closed.
   470  		}
   471  		t.activeStreams[s.id] = s
   472  		t.mu.Unlock()
   473  		if t.streamQuota > 0 && t.waitingStreams > 0 {
   474  			select {
   475  			case t.streamsQuotaAvailable <- struct{}{}:
   476  			default:
   477  			}
   478  		}
   479  		return true
   480  	}
   481  	var hdrListSizeErr error
   482  	checkForHeaderListSize := func(it interface{}) bool {
   483  		if t.maxSendHeaderListSize == nil {
   484  			return true
   485  		}
   486  		hdrFrame := it.(*headerFrame)
   487  		var sz int64
   488  		for _, f := range hdrFrame.hf {
   489  			if sz += int64(f.Size()); sz > int64(*t.maxSendHeaderListSize) {
   490  				hdrListSizeErr = status.Errorf(codes.Internal, "header list size to send violates the maximum size (%d bytes) set by server", *t.maxSendHeaderListSize)
   491  				return false
   492  			}
   493  		}
   494  		return true
   495  	}
   496  	for {
   497  		success, err := t.controlBuf.executeAndPut(func(it interface{}) bool {
   498  			return checkForHeaderListSize(it) && checkForStreamQuota(it)
   499  		}, hdr)
   500  		if err != nil {
   501  			return nil, err
   502  		}
   503  		if success {
   504  			break
   505  		}
   506  		if hdrListSizeErr != nil {
   507  			return nil, hdrListSizeErr
   508  		}
   509  		firstTry = false
   510  		select {
   511  		case <-ch:
   512  		case <-s.ctx.Done():
   513  			return nil, ContextErr(s.ctx.Err())
   514  		case <-t.goAway:
   515  			return nil, errStreamDrain
   516  		case <-t.ctx.Done():
   517  			return nil, ErrConnClosing
   518  		}
   519  	}
   520  	return s, nil
   521  }
   522  
   523  // CloseStream clears the footprint of a stream when the stream is not needed any more.
   524  // This must not be executed in reader's goroutine.
   525  func (t *http2Client) CloseStream(s *Stream, err error) {
   526  	var (
   527  		rst     bool
   528  		rstCode http2.ErrCode
   529  	)
   530  	if err != nil {
   531  		rst = true
   532  		rstCode = http2.ErrCodeCancel
   533  	}
   534  	t.closeStream(s, err, rst, rstCode, status.Convert(err), nil, false)
   535  }
   536  
   537  func (t *http2Client) closeStream(s *Stream, err error, rst bool, rstCode http2.ErrCode, st *status.Status, mdata map[string][]string, eosReceived bool) {
   538  	// Set stream status to done.
   539  	if s.swapState(streamDone) == streamDone {
   540  		// If it was already done, return.  If multiple closeStream calls
   541  		// happen simultaneously, wait for the first to finish.
   542  		<-s.done
   543  		return
   544  	}
   545  	// status and trailers can be updated here without any synchronization because the stream goroutine will
   546  	// only read it after it sees an io.EOF error from read or write and we'll write those errors
   547  	// only after updating this.
   548  	s.status = st
   549  	if len(mdata) > 0 {
   550  		s.trailer = mdata
   551  	}
   552  	if err != nil {
   553  		// This will unblock reads eventually.
   554  		s.write(recvMsg{err: err})
   555  	}
   556  	// If headerChan isn't closed, then close it.
   557  	if atomic.CompareAndSwapUint32(&s.headerChanClosed, 0, 1) {
   558  		s.noHeaders = true
   559  		close(s.headerChan)
   560  	}
   561  	cleanup := &cleanupStream{
   562  		streamID: s.id,
   563  		onWrite: func() {
   564  			t.mu.Lock()
   565  			if t.activeStreams != nil {
   566  				delete(t.activeStreams, s.id)
   567  			}
   568  			t.mu.Unlock()
   569  		},
   570  		rst:     rst,
   571  		rstCode: rstCode,
   572  	}
   573  	addBackStreamQuota := func(interface{}) bool {
   574  		t.streamQuota++
   575  		if t.streamQuota > 0 && t.waitingStreams > 0 {
   576  			select {
   577  			case t.streamsQuotaAvailable <- struct{}{}:
   578  			default:
   579  			}
   580  		}
   581  		return true
   582  	}
   583  	t.controlBuf.executeAndPut(addBackStreamQuota, cleanup)
   584  	// This will unblock write.
   585  	close(s.done)
   586  }
   587  
   588  // Close kicks off the shutdown process of the transport. This should be called
   589  // only once on a transport. Once it is called, the transport should not be
   590  // accessed any more.
   591  //
   592  // This method blocks until the addrConn that initiated this transport is
   593  // re-connected. This happens because t.onClose() begins reconnect logic at the
   594  // addrConn level and blocks until the addrConn is successfully connected.
   595  func (t *http2Client) Close() error {
   596  	t.mu.Lock()
   597  	// Make sure we only Close once.
   598  	if t.state == closing {
   599  		t.mu.Unlock()
   600  		return nil
   601  	}
   602  	// Call t.onClose before setting the state to closing to prevent the client
   603  	// from attempting to create new streams ASAP.
   604  	if t.onClose != nil {
   605  		t.onClose()
   606  	}
   607  	t.state = closing
   608  	streams := t.activeStreams
   609  	t.activeStreams = nil
   610  	if t.kpDormant {
   611  		// If the keepalive goroutine is blocked on this condition variable, we
   612  		// should unblock it so that the goroutine eventually exits.
   613  		t.kpDormancyCond.Signal()
   614  	}
   615  	t.mu.Unlock()
   616  	t.controlBuf.finish()
   617  	t.cancel()
   618  	err := t.conn.Close()
   619  	// Notify all active streams.
   620  	for _, s := range streams {
   621  		t.closeStream(s, ErrConnClosing, false, http2.ErrCodeNo, status.New(codes.Unavailable, ErrConnClosing.Desc), nil, false)
   622  	}
   623  	return err
   624  }
   625  
   626  // GracefulClose sets the state to draining, which prevents new streams from
   627  // being created and causes the transport to be closed when the last active
   628  // stream is closed.  If there are no active streams, the transport is closed
   629  // immediately.  This does nothing if the transport is already draining or
   630  // closing.
   631  func (t *http2Client) GracefulClose() {
   632  	t.mu.Lock()
   633  	// Make sure we move to draining only from active.
   634  	if t.state == draining || t.state == closing {
   635  		t.mu.Unlock()
   636  		return
   637  	}
   638  	t.state = draining
   639  	active := len(t.activeStreams)
   640  	t.mu.Unlock()
   641  	if active == 0 {
   642  		t.Close()
   643  		return
   644  	}
   645  	t.controlBuf.put(&incomingGoAway{})
   646  }
   647  
   648  // Write formats the data into HTTP2 data frame(s) and sends it out. The caller
   649  // should proceed only if Write returns nil.
   650  func (t *http2Client) Write(s *Stream, hdr, data []byte, opts *Options) error {
   651  	if opts.Last {
   652  		// If it's the last message, update stream state.
   653  		if !s.compareAndSwapState(streamActive, streamWriteDone) {
   654  			return errStreamDone
   655  		}
   656  	} else if s.getState() != streamActive {
   657  		return errStreamDone
   658  	}
   659  	df := &dataFrame{
   660  		streamID:  s.id,
   661  		endStream: opts.Last,
   662  		h:         hdr,
   663  		d:         data,
   664  	}
   665  	if len(hdr) == 0 && len(data) != 0 {
   666  		df.dcache = data
   667  	}
   668  	if hdr != nil || data != nil { // If it's not an empty data frame, check quota.
   669  		if err := s.wq.get(int32(len(hdr) + len(data))); err != nil {
   670  			return err
   671  		}
   672  	}
   673  	return t.controlBuf.put(df)
   674  }
   675  
   676  func (t *http2Client) getStream(f http2.Frame) *Stream {
   677  	t.mu.Lock()
   678  	s := t.activeStreams[f.Header().StreamID]
   679  	t.mu.Unlock()
   680  	return s
   681  }
   682  
   683  // adjustWindow sends out extra window update over the initial window size
   684  // of stream if the application is requesting data larger in size than
   685  // the window.
   686  func (t *http2Client) adjustWindow(s *Stream, n uint32) {
   687  	if w := s.fc.maybeAdjust(n); w > 0 {
   688  		t.controlBuf.put(&outgoingWindowUpdate{streamID: s.id, increment: w})
   689  	}
   690  }
   691  
   692  // updateFlowControl updates the incoming flow control windows
   693  // for the transport and the stream based on the current bdp
   694  // estimation.
   695  func (t *http2Client) updateFlowControl(n uint32) {
   696  	updateIWS := func(interface{}) bool {
   697  		t.initialWindowSize = n
   698  		t.mu.Lock()
   699  		for _, s := range t.activeStreams {
   700  			s.fc.newLimit(n)
   701  		}
   702  		t.mu.Unlock()
   703  		return true
   704  	}
   705  	t.controlBuf.executeAndPut(updateIWS, &outgoingWindowUpdate{streamID: 0, increment: t.fc.newLimit(n)})
   706  	t.controlBuf.put(&outgoingSettings{
   707  		ss: []http2.Setting{
   708  			{
   709  				ID:  http2.SettingInitialWindowSize,
   710  				Val: n,
   711  			},
   712  		},
   713  	})
   714  }
   715  
   716  // updateWindow adjusts the inbound quota for the stream.
   717  // Window updates will be sent out when the cumulative quota
   718  // exceeds the corresponding threshold.
   719  func (t *http2Client) updateWindow(s *Stream, n uint32) {
   720  	if w := s.fc.onRead(n); w > 0 {
   721  		t.controlBuf.put(&outgoingWindowUpdate{streamID: s.id, increment: w})
   722  	}
   723  }
   724  
   725  func (t *http2Client) handleData(f *grpcframe.DataFrame) {
   726  	size := f.Header().Length
   727  	var sendBDPPing bool
   728  	if t.bdpEst != nil {
   729  		sendBDPPing = t.bdpEst.add(size)
   730  	}
   731  	// Decouple connection's flow control from application's read.
   732  	// An update on connection's flow control should not depend on
   733  	// whether user application has read the data or not. Such a
   734  	// restriction is already imposed on the stream's flow control,
   735  	// and therefore the sender will be blocked anyways.
   736  	// Decoupling the connection flow control will prevent other
   737  	// active(fast) streams from starving in presence of slow or
   738  	// inactive streams.
   739  	//
   740  	if w := t.fc.onData(size); w > 0 {
   741  		t.controlBuf.put(&outgoingWindowUpdate{
   742  			streamID:  0,
   743  			increment: w,
   744  		})
   745  	}
   746  	if sendBDPPing {
   747  		// Avoid excessive ping detection (e.g. in an L7 proxy)
   748  		// by sending a window update prior to the BDP ping.
   749  
   750  		if w := t.fc.reset(); w > 0 {
   751  			t.controlBuf.put(&outgoingWindowUpdate{
   752  				streamID:  0,
   753  				increment: w,
   754  			})
   755  		}
   756  
   757  		t.controlBuf.put(bdpPing)
   758  	}
   759  	// Select the right stream to dispatch.
   760  	s := t.getStream(f)
   761  	if s == nil {
   762  		return
   763  	}
   764  	if size > 0 {
   765  		if err := s.fc.onData(size); err != nil {
   766  			t.closeStream(s, io.EOF, true, http2.ErrCodeFlowControl, status.New(codes.Internal, err.Error()), nil, false)
   767  			return
   768  		}
   769  		if f.Header().Flags.Has(http2.FlagDataPadded) {
   770  			if w := s.fc.onRead(size - uint32(len(f.Data()))); w > 0 {
   771  				t.controlBuf.put(&outgoingWindowUpdate{s.id, w})
   772  			}
   773  		}
   774  		// TODO(bradfitz, zhaoq): A copy is required here because there is no
   775  		// guarantee f.Data() is consumed before the arrival of next frame.
   776  		// Can this copy be eliminated?
   777  		if len(f.Data()) > 0 {
   778  			buffer := t.bufferPool.get()
   779  			buffer.Reset()
   780  			buffer.Write(f.Data())
   781  			s.write(recvMsg{buffer: buffer})
   782  		}
   783  	}
   784  	// The server has closed the stream without sending trailers.  Record that
   785  	// the read direction is closed, and set the status appropriately.
   786  	if f.FrameHeader.Flags.Has(http2.FlagDataEndStream) {
   787  		t.closeStream(s, io.EOF, false, http2.ErrCodeNo, status.New(codes.Internal, "server closed the stream without sending trailers"), nil, true)
   788  	}
   789  }
   790  
   791  func (t *http2Client) handleRSTStream(f *http2.RSTStreamFrame) {
   792  	s := t.getStream(f)
   793  	if s == nil {
   794  		return
   795  	}
   796  	if f.ErrCode == http2.ErrCodeRefusedStream {
   797  		// The stream was unprocessed by the server.
   798  		atomic.StoreUint32(&s.unprocessed, 1)
   799  	}
   800  	statusCode, ok := http2ErrConvTab[f.ErrCode]
   801  	if !ok {
   802  		klog.Warnf("transport: http2Client.handleRSTStream found no mapped gRPC status for the received nhttp2 error %v", f.ErrCode)
   803  		statusCode = codes.Unknown
   804  	}
   805  	if statusCode == codes.Canceled {
   806  		if d, ok := s.ctx.Deadline(); ok && !d.After(time.Now()) {
   807  			// Our deadline was already exceeded, and that was likely the cause
   808  			// of this cancelation.  Alter the status code accordingly.
   809  			statusCode = codes.DeadlineExceeded
   810  		}
   811  	}
   812  	t.closeStream(s, io.EOF, false, http2.ErrCodeNo, status.Newf(statusCode, "stream terminated by RST_STREAM with error code: %v", f.ErrCode), nil, false)
   813  }
   814  
   815  func (t *http2Client) handleSettings(f *grpcframe.SettingsFrame, isFirst bool) {
   816  	if f.IsAck() {
   817  		return
   818  	}
   819  	var maxStreams *uint32
   820  	var ss []http2.Setting
   821  	var updateFuncs []func()
   822  	f.ForeachSetting(func(s http2.Setting) error {
   823  		switch s.ID {
   824  		case http2.SettingMaxConcurrentStreams:
   825  			maxStreams = new(uint32)
   826  			*maxStreams = s.Val
   827  		case http2.SettingMaxHeaderListSize:
   828  			updateFuncs = append(updateFuncs, func() {
   829  				t.maxSendHeaderListSize = new(uint32)
   830  				*t.maxSendHeaderListSize = s.Val
   831  			})
   832  		default:
   833  			ss = append(ss, s)
   834  		}
   835  		return nil
   836  	})
   837  	if isFirst && maxStreams == nil {
   838  		maxStreams = new(uint32)
   839  		*maxStreams = math.MaxUint32
   840  	}
   841  	sf := &incomingSettings{
   842  		ss: ss,
   843  	}
   844  	if maxStreams != nil {
   845  		updateStreamQuota := func() {
   846  			delta := int64(*maxStreams) - int64(t.maxConcurrentStreams)
   847  			t.maxConcurrentStreams = *maxStreams
   848  			t.streamQuota += delta
   849  			if delta > 0 && t.waitingStreams > 0 {
   850  				close(t.streamsQuotaAvailable) // wake all of them up.
   851  				t.streamsQuotaAvailable = make(chan struct{}, 1)
   852  			}
   853  		}
   854  		updateFuncs = append(updateFuncs, updateStreamQuota)
   855  	}
   856  	t.controlBuf.executeAndPut(func(interface{}) bool {
   857  		for _, f := range updateFuncs {
   858  			f()
   859  		}
   860  		return true
   861  	}, sf)
   862  }
   863  
   864  func (t *http2Client) handlePing(f *http2.PingFrame) {
   865  	if f.IsAck() {
   866  		// Maybe it's a BDP ping.
   867  		if t.bdpEst != nil {
   868  			t.bdpEst.calculate(f.Data)
   869  		}
   870  		return
   871  	}
   872  	pingAck := &ping{ack: true}
   873  	copy(pingAck.data[:], f.Data[:])
   874  	t.controlBuf.put(pingAck)
   875  }
   876  
   877  func (t *http2Client) handleGoAway(f *grpcframe.GoAwayFrame) {
   878  	t.mu.Lock()
   879  	if t.state == closing {
   880  		t.mu.Unlock()
   881  		return
   882  	}
   883  	if f.ErrCode == http2.ErrCodeEnhanceYourCalm {
   884  		klog.Infof("Client received GoAway with http2.ErrCodeEnhanceYourCalm.")
   885  	}
   886  	id := f.LastStreamID
   887  	if id > 0 && id%2 != 1 {
   888  		t.mu.Unlock()
   889  		t.Close()
   890  		return
   891  	}
   892  	// A client can receive multiple GoAways from the server (see
   893  	// https://github.com/grpc/grpc-go/issues/1387).  The idea is that the first
   894  	// GoAway will be sent with an ID of MaxInt32 and the second GoAway will be
   895  	// sent after an RTT delay with the ID of the last stream the server will
   896  	// process.
   897  	//
   898  	// Therefore, when we get the first GoAway we don't necessarily close any
   899  	// streams. While in case of second GoAway we close all streams created after
   900  	// the GoAwayId. This way streams that were in-flight while the GoAway from
   901  	// server was being sent don't get killed.
   902  	select {
   903  	case <-t.goAway: // t.goAway has been closed (i.e.,multiple GoAways).
   904  		// If there are multiple GoAways the first one should always have an ID greater than the following ones.
   905  		if id > t.prevGoAwayID {
   906  			t.mu.Unlock()
   907  			t.Close()
   908  			return
   909  		}
   910  	default:
   911  		t.setGoAwayReason(f)
   912  		close(t.goAway)
   913  		defer t.controlBuf.put(&incomingGoAway{}) // Defer as t.mu is currently held.
   914  		// Notify the clientconn about the GOAWAY before we set the state to
   915  		// draining, to allow the client to stop attempting to create streams
   916  		// before disallowing new streams on this connection.
   917  		if t.onGoAway != nil {
   918  			t.onGoAway(t.goAwayReason)
   919  		}
   920  		t.state = draining
   921  	}
   922  	// All streams with IDs greater than the GoAwayId
   923  	// and smaller than the previous GoAway ID should be killed.
   924  	upperLimit := t.prevGoAwayID
   925  	if upperLimit == 0 { // This is the first GoAway Frame.
   926  		upperLimit = math.MaxUint32 // Kill all streams after the GoAway ID.
   927  	}
   928  	for streamID, stream := range t.activeStreams {
   929  		if streamID > id && streamID <= upperLimit {
   930  			// The stream was unprocessed by the server.
   931  			atomic.StoreUint32(&stream.unprocessed, 1)
   932  			t.closeStream(stream, errStreamDrain, false, http2.ErrCodeNo, statusGoAway, nil, false)
   933  		}
   934  	}
   935  	t.prevGoAwayID = id
   936  	active := len(t.activeStreams)
   937  	t.mu.Unlock()
   938  	if active == 0 {
   939  		t.Close()
   940  	}
   941  }
   942  
   943  // setGoAwayReason sets the value of t.goAwayReason based
   944  // on the GoAway frame received.
   945  // It expects a lock on transport's mutext to be held by
   946  // the caller.
   947  func (t *http2Client) setGoAwayReason(f *grpcframe.GoAwayFrame) {
   948  	t.goAwayReason = GoAwayNoReason
   949  	switch f.ErrCode {
   950  	case http2.ErrCodeEnhanceYourCalm:
   951  		if string(f.DebugData()) == "too_many_pings" {
   952  			t.goAwayReason = GoAwayTooManyPings
   953  		}
   954  	}
   955  }
   956  
   957  func (t *http2Client) GetGoAwayReason() GoAwayReason {
   958  	t.mu.Lock()
   959  	defer t.mu.Unlock()
   960  	return t.goAwayReason
   961  }
   962  
   963  func (t *http2Client) handleWindowUpdate(f *http2.WindowUpdateFrame) {
   964  	t.controlBuf.put(&incomingWindowUpdate{
   965  		streamID:  f.Header().StreamID,
   966  		increment: f.Increment,
   967  	})
   968  }
   969  
   970  // operateHeaders takes action on the decoded headers.
   971  func (t *http2Client) operateHeaders(frame *grpcframe.MetaHeadersFrame) {
   972  	s := t.getStream(frame)
   973  	if s == nil {
   974  		return
   975  	}
   976  	endStream := frame.StreamEnded()
   977  	atomic.StoreUint32(&s.bytesReceived, 1)
   978  	initialHeader := atomic.LoadUint32(&s.headerChanClosed) == 0
   979  
   980  	if !initialHeader && !endStream {
   981  		// As specified by gRPC over HTTP2, a HEADERS frame (and associated CONTINUATION frames) can only appear at the start or end of a stream. Therefore, second HEADERS frame must have EOS bit set.
   982  		st := status.New(codes.Internal, "a HEADERS frame cannot appear in the middle of a stream")
   983  		t.closeStream(s, st.Err(), true, http2.ErrCodeProtocol, st, nil, false)
   984  		return
   985  	}
   986  
   987  	state := &decodeState{}
   988  	// Initialize isGRPC value to be !initialHeader, since if a gRPC Response-Headers has already been received, then it means that the peer is speaking gRPC and we are in gRPC mode.
   989  	state.data.isGRPC = !initialHeader
   990  	if err := state.decodeHeader(frame); err != nil {
   991  		t.closeStream(s, err, true, http2.ErrCodeProtocol, status.Convert(err), nil, endStream)
   992  		return
   993  	}
   994  
   995  	// If headerChan hasn't been closed yet
   996  	if atomic.CompareAndSwapUint32(&s.headerChanClosed, 0, 1) {
   997  		s.headerValid = true
   998  		if !endStream {
   999  			// These values can be set without any synchronization because
  1000  			// stream goroutine will read it only after seeing a closed
  1001  			// headerChan which we'll close after setting this.
  1002  			s.recvCompress = state.data.encoding
  1003  			if len(state.data.mdata) > 0 {
  1004  				s.header = state.data.mdata
  1005  			}
  1006  		} else {
  1007  			// HEADERS frame block carries a Trailers-Only.
  1008  			s.noHeaders = true
  1009  		}
  1010  		close(s.headerChan)
  1011  	}
  1012  
  1013  	if !endStream {
  1014  		return
  1015  	}
  1016  
  1017  	// if client received END_STREAM from server while stream was still active, send RST_STREAM
  1018  	rst := s.getState() == streamActive
  1019  	s.SetBizStatusErr(state.bizStatusErr())
  1020  	t.closeStream(s, io.EOF, rst, http2.ErrCodeNo, state.status(), state.data.mdata, true)
  1021  }
  1022  
  1023  // reader runs as a separate goroutine in charge of reading data from network
  1024  // connection.
  1025  //
  1026  // TODO(zhaoq): currently one reader per transport. Investigate whether this is
  1027  // optimal.
  1028  // TODO(zhaoq): Check the validity of the incoming frame sequence.
  1029  func (t *http2Client) reader() {
  1030  	defer close(t.readerDone)
  1031  	// Check the validity of server preface.
  1032  	frame, err := t.framer.ReadFrame()
  1033  	if err != nil {
  1034  		// TODO(emma): comment this log temporarily, because when use short connection, 'resource temporarily unavailable' error will happen
  1035  		// if the log need to be output, connection info should be appended
  1036  		// klog.Errorf("KITEX: grpc readFrame failed, error=%s", err.Error())
  1037  		t.Close() // this kicks off resetTransport, so must be last before return
  1038  		return
  1039  	}
  1040  	t.conn.SetReadDeadline(time.Time{}) // reset deadline once we get the settings frame (we didn't time out, yay!)
  1041  	if t.keepaliveEnabled {
  1042  		atomic.StoreInt64(&t.lastRead, time.Now().UnixNano())
  1043  	}
  1044  	sf, ok := frame.(*grpcframe.SettingsFrame)
  1045  	if !ok {
  1046  		t.Close() // this kicks off resetTransport, so must be last before return
  1047  		return
  1048  	}
  1049  	t.handleSettings(sf, true)
  1050  
  1051  	// loop to keep reading incoming messages on this transport.
  1052  	for {
  1053  		t.controlBuf.throttle()
  1054  		frame, err := t.framer.ReadFrame()
  1055  		if t.keepaliveEnabled {
  1056  			atomic.StoreInt64(&t.lastRead, time.Now().UnixNano())
  1057  		}
  1058  		if err != nil {
  1059  			// Abort an active stream if the http2.Framer returns a
  1060  			// http2.StreamError. This can happen only if the server's response
  1061  			// is malformed http2.
  1062  			if se, ok := err.(http2.StreamError); ok {
  1063  				t.mu.Lock()
  1064  				s := t.activeStreams[se.StreamID]
  1065  				t.mu.Unlock()
  1066  				if s != nil {
  1067  					// use error detail to provide better err message
  1068  					code := http2ErrConvTab[se.Code]
  1069  					err := t.framer.ErrorDetail()
  1070  					var msg string
  1071  					if err != nil {
  1072  						msg = err.Error()
  1073  					}
  1074  					t.closeStream(s, status.New(code, msg).Err(), true, http2.ErrCodeProtocol, status.New(code, msg), nil, false)
  1075  				}
  1076  				continue
  1077  			} else {
  1078  				// Transport error.
  1079  				// TODO(emma): comment this log temporarily, because when use short connection, 'resource temporarily unavailable' error will happen
  1080  				// if the log need to be output, connection info should be appended
  1081  				// klog.Errorf("KITEX: grpc readFrame failed, error=%s", err.Error())
  1082  				t.Close()
  1083  				return
  1084  			}
  1085  		}
  1086  		switch frame := frame.(type) {
  1087  		case *grpcframe.MetaHeadersFrame:
  1088  			t.operateHeaders(frame)
  1089  		case *grpcframe.DataFrame:
  1090  			t.handleData(frame)
  1091  		case *http2.RSTStreamFrame:
  1092  			t.handleRSTStream(frame)
  1093  		case *grpcframe.SettingsFrame:
  1094  			t.handleSettings(frame, false)
  1095  		case *http2.PingFrame:
  1096  			t.handlePing(frame)
  1097  		case *grpcframe.GoAwayFrame:
  1098  			t.handleGoAway(frame)
  1099  		case *http2.WindowUpdateFrame:
  1100  			t.handleWindowUpdate(frame)
  1101  		default:
  1102  			klog.Warnf("transport: http2Client.reader got unhandled frame type %v.", frame)
  1103  		}
  1104  		t.framer.reader.Release()
  1105  	}
  1106  }
  1107  
  1108  func minTime(a, b time.Duration) time.Duration {
  1109  	if a < b {
  1110  		return a
  1111  	}
  1112  	return b
  1113  }
  1114  
  1115  // keepalive running in a separate goroutune makes sure the connection is alive by sending pings.
  1116  func (t *http2Client) keepalive() {
  1117  	p := &ping{data: [8]byte{}}
  1118  	// True iff a ping has been sent, and no data has been received since then.
  1119  	outstandingPing := false
  1120  	// Amount of time remaining before which we should receive an ACK for the
  1121  	// last sent ping.
  1122  	timeoutLeft := time.Duration(0)
  1123  	// Records the last value of t.lastRead before we go block on the timer.
  1124  	// This is required to check for read activity since then.
  1125  	prevNano := time.Now().UnixNano()
  1126  	timer := time.NewTimer(t.kp.Time)
  1127  	for {
  1128  		select {
  1129  		case <-timer.C:
  1130  			lastRead := atomic.LoadInt64(&t.lastRead)
  1131  			if lastRead > prevNano {
  1132  				// There has been read activity since the last time we were here.
  1133  				outstandingPing = false
  1134  				// Next timer should fire at kp.Time seconds from lastRead time.
  1135  				timer.Reset(time.Duration(lastRead) + t.kp.Time - time.Duration(time.Now().UnixNano()))
  1136  				prevNano = lastRead
  1137  				continue
  1138  			}
  1139  			if outstandingPing && timeoutLeft <= 0 {
  1140  				t.Close()
  1141  				return
  1142  			}
  1143  			t.mu.Lock()
  1144  			if t.state == closing {
  1145  				// If the transport is closing, we should exit from the
  1146  				// keepalive goroutine here. If not, we could have a race
  1147  				// between the call to Signal() from Close() and the call to
  1148  				// Wait() here, whereby the keepalive goroutine ends up
  1149  				// blocking on the condition variable which will never be
  1150  				// signalled again.
  1151  				t.mu.Unlock()
  1152  				return
  1153  			}
  1154  			if len(t.activeStreams) < 1 && !t.kp.PermitWithoutStream {
  1155  				// If a ping was sent out previously (because there were active
  1156  				// streams at that point) which wasn't acked and its timeout
  1157  				// hadn't fired, but we got here and are about to go dormant,
  1158  				// we should make sure that we unconditionally send a ping once
  1159  				// we awaken.
  1160  				outstandingPing = false
  1161  				t.kpDormant = true
  1162  				t.kpDormancyCond.Wait()
  1163  			}
  1164  			t.kpDormant = false
  1165  			t.mu.Unlock()
  1166  
  1167  			// We get here either because we were dormant and a new stream was
  1168  			// created which unblocked the Wait() call, or because the
  1169  			// keepalive timer expired. In both cases, we need to send a ping.
  1170  			if !outstandingPing {
  1171  				t.controlBuf.put(p)
  1172  				timeoutLeft = t.kp.Timeout
  1173  				outstandingPing = true
  1174  			}
  1175  			// The amount of time to sleep here is the minimum of kp.Time and
  1176  			// timeoutLeft. This will ensure that we wait only for kp.Time
  1177  			// before sending out the next ping (for cases where the ping is
  1178  			// acked).
  1179  			sleepDuration := minTime(t.kp.Time, timeoutLeft)
  1180  			timeoutLeft -= sleepDuration
  1181  			timer.Reset(sleepDuration)
  1182  		case <-t.ctx.Done():
  1183  			if !timer.Stop() {
  1184  				<-timer.C
  1185  			}
  1186  			return
  1187  		}
  1188  	}
  1189  }
  1190  
  1191  func (t *http2Client) Error() <-chan struct{} {
  1192  	return t.ctx.Done()
  1193  }
  1194  
  1195  func (t *http2Client) GoAway() <-chan struct{} {
  1196  	return t.goAway
  1197  }
  1198  
  1199  func (t *http2Client) RemoteAddr() net.Addr { return t.remoteAddr }
  1200  func (t *http2Client) LocalAddr() net.Addr  { return t.localAddr }
  1201  
  1202  // IsActive return the connection's state, check if it's reachable.
  1203  func (t *http2Client) IsActive() bool {
  1204  	t.mu.Lock()
  1205  	defer t.mu.Unlock()
  1206  	return t.state == reachable
  1207  }