123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509 |
- /*
- *
- * Copyright 2014, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
- /*
- Package transport defines and implements message oriented communication channel
- to complete various transactions (e.g., an RPC).
- */
- package transport // import "google.golang.org/grpc/transport"
- import (
- "bytes"
- "errors"
- "fmt"
- "io"
- "net"
- "sync"
- "time"
- "golang.org/x/net/context"
- "golang.org/x/net/trace"
- "google.golang.org/grpc/codes"
- "google.golang.org/grpc/credentials"
- "google.golang.org/grpc/metadata"
- )
- // recvMsg represents the received msg from the transport. All transport
- // protocol specific info has been removed.
- type recvMsg struct {
- data []byte
- // nil: received some data
- // io.EOF: stream is completed. data is nil.
- // other non-nil error: transport failure. data is nil.
- err error
- }
- func (*recvMsg) item() {}
- // All items in an out of a recvBuffer should be the same type.
- type item interface {
- item()
- }
- // recvBuffer is an unbounded channel of item.
- type recvBuffer struct {
- c chan item
- mu sync.Mutex
- backlog []item
- }
- func newRecvBuffer() *recvBuffer {
- b := &recvBuffer{
- c: make(chan item, 1),
- }
- return b
- }
- func (b *recvBuffer) put(r item) {
- b.mu.Lock()
- defer b.mu.Unlock()
- if len(b.backlog) == 0 {
- select {
- case b.c <- r:
- return
- default:
- }
- }
- b.backlog = append(b.backlog, r)
- }
- func (b *recvBuffer) load() {
- b.mu.Lock()
- defer b.mu.Unlock()
- if len(b.backlog) > 0 {
- select {
- case b.c <- b.backlog[0]:
- b.backlog = b.backlog[1:]
- default:
- }
- }
- }
- // get returns the channel that receives an item in the buffer.
- //
- // Upon receipt of an item, the caller should call load to send another
- // item onto the channel if there is any.
- func (b *recvBuffer) get() <-chan item {
- return b.c
- }
- // recvBufferReader implements io.Reader interface to read the data from
- // recvBuffer.
- type recvBufferReader struct {
- ctx context.Context
- recv *recvBuffer
- last *bytes.Reader // Stores the remaining data in the previous calls.
- err error
- }
- // Read reads the next len(p) bytes from last. If last is drained, it tries to
- // read additional data from recv. It blocks if there no additional data available
- // in recv. If Read returns any non-nil error, it will continue to return that error.
- func (r *recvBufferReader) Read(p []byte) (n int, err error) {
- if r.err != nil {
- return 0, r.err
- }
- defer func() { r.err = err }()
- if r.last != nil && r.last.Len() > 0 {
- // Read remaining data left in last call.
- return r.last.Read(p)
- }
- select {
- case <-r.ctx.Done():
- return 0, ContextErr(r.ctx.Err())
- case i := <-r.recv.get():
- r.recv.load()
- m := i.(*recvMsg)
- if m.err != nil {
- return 0, m.err
- }
- r.last = bytes.NewReader(m.data)
- return r.last.Read(p)
- }
- }
- type streamState uint8
- const (
- streamActive streamState = iota
- streamWriteDone // EndStream sent
- streamReadDone // EndStream received
- streamDone // sendDone and recvDone or RSTStreamFrame is sent or received.
- )
- // Stream represents an RPC in the transport layer.
- type Stream struct {
- id uint32
- // nil for client side Stream.
- st ServerTransport
- // ctx is the associated context of the stream.
- ctx context.Context
- cancel context.CancelFunc
- // method records the associated RPC method of the stream.
- method string
- recvCompress string
- sendCompress string
- buf *recvBuffer
- dec io.Reader
- fc *inFlow
- recvQuota uint32
- // The accumulated inbound quota pending for window update.
- updateQuota uint32
- // The handler to control the window update procedure for both this
- // particular stream and the associated transport.
- windowHandler func(int)
- sendQuotaPool *quotaPool
- // Close headerChan to indicate the end of reception of header metadata.
- headerChan chan struct{}
- // header caches the received header metadata.
- header metadata.MD
- // The key-value map of trailer metadata.
- trailer metadata.MD
- mu sync.RWMutex // guard the following
- // headerOK becomes true from the first header is about to send.
- headerOk bool
- state streamState
- // true iff headerChan is closed. Used to avoid closing headerChan
- // multiple times.
- headerDone bool
- // the status received from the server.
- statusCode codes.Code
- statusDesc string
- }
- // RecvCompress returns the compression algorithm applied to the inbound
- // message. It is empty string if there is no compression applied.
- func (s *Stream) RecvCompress() string {
- return s.recvCompress
- }
- // SetSendCompress sets the compression algorithm to the stream.
- func (s *Stream) SetSendCompress(str string) {
- s.sendCompress = str
- }
- // Header acquires the key-value pairs of header metadata once it
- // is available. It blocks until i) the metadata is ready or ii) there is no
- // header metadata or iii) the stream is cancelled/expired.
- func (s *Stream) Header() (metadata.MD, error) {
- select {
- case <-s.ctx.Done():
- return nil, ContextErr(s.ctx.Err())
- case <-s.headerChan:
- return s.header.Copy(), nil
- }
- }
- // Trailer returns the cached trailer metedata. Note that if it is not called
- // after the entire stream is done, it could return an empty MD. Client
- // side only.
- func (s *Stream) Trailer() metadata.MD {
- s.mu.RLock()
- defer s.mu.RUnlock()
- return s.trailer.Copy()
- }
- // ServerTransport returns the underlying ServerTransport for the stream.
- // The client side stream always returns nil.
- func (s *Stream) ServerTransport() ServerTransport {
- return s.st
- }
- // Context returns the context of the stream.
- func (s *Stream) Context() context.Context {
- return s.ctx
- }
- // TraceContext recreates the context of s with a trace.Trace.
- func (s *Stream) TraceContext(tr trace.Trace) {
- s.ctx = trace.NewContext(s.ctx, tr)
- }
- // Method returns the method for the stream.
- func (s *Stream) Method() string {
- return s.method
- }
- // StatusCode returns statusCode received from the server.
- func (s *Stream) StatusCode() codes.Code {
- return s.statusCode
- }
- // StatusDesc returns statusDesc received from the server.
- func (s *Stream) StatusDesc() string {
- return s.statusDesc
- }
- // ErrIllegalTrailerSet indicates that the trailer has already been set or it
- // is too late to do so.
- var ErrIllegalTrailerSet = errors.New("transport: trailer has been set")
- // SetTrailer sets the trailer metadata which will be sent with the RPC status
- // by the server. This can only be called at most once. Server side only.
- func (s *Stream) SetTrailer(md metadata.MD) error {
- s.mu.Lock()
- defer s.mu.Unlock()
- if s.trailer != nil {
- return ErrIllegalTrailerSet
- }
- s.trailer = md.Copy()
- return nil
- }
- func (s *Stream) write(m recvMsg) {
- s.buf.put(&m)
- }
- // Read reads all the data available for this Stream from the transport and
- // passes them into the decoder, which converts them into a gRPC message stream.
- // The error is io.EOF when the stream is done or another non-nil error if
- // the stream broke.
- func (s *Stream) Read(p []byte) (n int, err error) {
- n, err = s.dec.Read(p)
- if err != nil {
- return
- }
- s.windowHandler(n)
- return
- }
- // The key to save transport.Stream in the context.
- type streamKey struct{}
- // newContextWithStream creates a new context from ctx and attaches stream
- // to it.
- func newContextWithStream(ctx context.Context, stream *Stream) context.Context {
- return context.WithValue(ctx, streamKey{}, stream)
- }
- // StreamFromContext returns the stream saved in ctx.
- func StreamFromContext(ctx context.Context) (s *Stream, ok bool) {
- s, ok = ctx.Value(streamKey{}).(*Stream)
- return
- }
- // state of transport
- type transportState int
- const (
- reachable transportState = iota
- unreachable
- closing
- )
- // NewServerTransport creates a ServerTransport with conn or non-nil error
- // if it fails.
- func NewServerTransport(protocol string, conn net.Conn, maxStreams uint32, authInfo credentials.AuthInfo) (ServerTransport, error) {
- return newHTTP2Server(conn, maxStreams, authInfo)
- }
- // ConnectOptions covers all relevant options for dialing a server.
- type ConnectOptions struct {
- // UserAgent is the application user agent.
- UserAgent string
- // Dialer specifies how to dial a network address.
- Dialer func(string, time.Duration) (net.Conn, error)
- // AuthOptions stores the credentials required to setup a client connection and/or issue RPCs.
- AuthOptions []credentials.Credentials
- // Timeout specifies the timeout for dialing a client connection.
- Timeout time.Duration
- }
- // NewClientTransport establishes the transport with the required ConnectOptions
- // and returns it to the caller.
- func NewClientTransport(target string, opts *ConnectOptions) (ClientTransport, error) {
- return newHTTP2Client(target, opts)
- }
- // Options provides additional hints and information for message
- // transmission.
- type Options struct {
- // Last indicates whether this write is the last piece for
- // this stream.
- Last bool
- // Delay is a hint to the transport implementation for whether
- // the data could be buffered for a batching write. The
- // Transport implementation may ignore the hint.
- Delay bool
- }
- // CallHdr carries the information of a particular RPC.
- type CallHdr struct {
- // Host specifies the peer's host.
- Host string
- // Method specifies the operation to perform.
- Method string
- // RecvCompress specifies the compression algorithm applied on
- // inbound messages.
- RecvCompress string
- // SendCompress specifies the compression algorithm applied on
- // outbound message.
- SendCompress string
- // Flush indicates whether a new stream command should be sent
- // to the peer without waiting for the first data. This is
- // only a hint. The transport may modify the flush decision
- // for performance purposes.
- Flush bool
- }
- // ClientTransport is the common interface for all gRPC client-side transport
- // implementations.
- type ClientTransport interface {
- // Close tears down this transport. Once it returns, the transport
- // should not be accessed any more. The caller must make sure this
- // is called only once.
- Close() error
- // Write sends the data for the given stream. A nil stream indicates
- // the write is to be performed on the transport as a whole.
- Write(s *Stream, data []byte, opts *Options) error
- // NewStream creates a Stream for an RPC.
- NewStream(ctx context.Context, callHdr *CallHdr) (*Stream, error)
- // CloseStream clears the footprint of a stream when the stream is
- // not needed any more. The err indicates the error incurred when
- // CloseStream is called. Must be called when a stream is finished
- // unless the associated transport is closing.
- CloseStream(stream *Stream, err error)
- // Error returns a channel that is closed when some I/O error
- // happens. Typically the caller should have a goroutine to monitor
- // this in order to take action (e.g., close the current transport
- // and create a new one) in error case. It should not return nil
- // once the transport is initiated.
- Error() <-chan struct{}
- }
- // ServerTransport is the common interface for all gRPC server-side transport
- // implementations.
- //
- // Methods may be called concurrently from multiple goroutines, but
- // Write methods for a given Stream will be called serially.
- type ServerTransport interface {
- // HandleStreams receives incoming streams using the given handler.
- HandleStreams(func(*Stream))
- // WriteHeader sends the header metadata for the given stream.
- // WriteHeader may not be called on all streams.
- WriteHeader(s *Stream, md metadata.MD) error
- // Write sends the data for the given stream.
- // Write may not be called on all streams.
- Write(s *Stream, data []byte, opts *Options) error
- // WriteStatus sends the status of a stream to the client.
- // WriteStatus is the final call made on a stream and always
- // occurs.
- WriteStatus(s *Stream, statusCode codes.Code, statusDesc string) error
- // Close tears down the transport. Once it is called, the transport
- // should not be accessed any more. All the pending streams and their
- // handlers will be terminated asynchronously.
- Close() error
- // RemoteAddr returns the remote network address.
- RemoteAddr() net.Addr
- }
- // StreamErrorf creates an StreamError with the specified error code and description.
- func StreamErrorf(c codes.Code, format string, a ...interface{}) StreamError {
- return StreamError{
- Code: c,
- Desc: fmt.Sprintf(format, a...),
- }
- }
- // ConnectionErrorf creates an ConnectionError with the specified error description.
- func ConnectionErrorf(format string, a ...interface{}) ConnectionError {
- return ConnectionError{
- Desc: fmt.Sprintf(format, a...),
- }
- }
- // ConnectionError is an error that results in the termination of the
- // entire connection and the retry of all the active streams.
- type ConnectionError struct {
- Desc string
- }
- func (e ConnectionError) Error() string {
- return fmt.Sprintf("connection error: desc = %q", e.Desc)
- }
- // Define some common ConnectionErrors.
- var ErrConnClosing = ConnectionError{Desc: "transport is closing"}
- // StreamError is an error that only affects one stream within a connection.
- type StreamError struct {
- Code codes.Code
- Desc string
- }
- func (e StreamError) Error() string {
- return fmt.Sprintf("stream error: code = %d desc = %q", e.Code, e.Desc)
- }
- // ContextErr converts the error from context package into a StreamError.
- func ContextErr(err error) StreamError {
- switch err {
- case context.DeadlineExceeded:
- return StreamErrorf(codes.DeadlineExceeded, "%v", err)
- case context.Canceled:
- return StreamErrorf(codes.Canceled, "%v", err)
- }
- panic(fmt.Sprintf("Unexpected error from context packet: %v", err))
- }
- // wait blocks until it can receive from ctx.Done, closing, or proceed.
- // If it receives from ctx.Done, it returns 0, the StreamError for ctx.Err.
- // If it receives from closing, it returns 0, ErrConnClosing.
- // If it receives from proceed, it returns the received integer, nil.
- func wait(ctx context.Context, closing <-chan struct{}, proceed <-chan int) (int, error) {
- select {
- case <-ctx.Done():
- return 0, ContextErr(ctx.Err())
- case <-closing:
- return 0, ErrConnClosing
- case i := <-proceed:
- return i, nil
- }
- }
|