github.com/stackdocker/rkt@v0.10.1-0.20151109095037-1aa827478248/Godeps/_workspace/src/google.golang.org/grpc/stream.go (about)

     1  /*
     2   *
     3   * Copyright 2014, Google Inc.
     4   * All rights reserved.
     5   *
     6   * Redistribution and use in source and binary forms, with or without
     7   * modification, are permitted provided that the following conditions are
     8   * met:
     9   *
    10   *     * Redistributions of source code must retain the above copyright
    11   * notice, this list of conditions and the following disclaimer.
    12   *     * Redistributions in binary form must reproduce the above
    13   * copyright notice, this list of conditions and the following disclaimer
    14   * in the documentation and/or other materials provided with the
    15   * distribution.
    16   *     * Neither the name of Google Inc. nor the names of its
    17   * contributors may be used to endorse or promote products derived from
    18   * this software without specific prior written permission.
    19   *
    20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    21   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    22   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    23   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    24   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    25   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    26   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    28   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    29   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    30   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31   *
    32   */
    33  
    34  package grpc
    35  
    36  import (
    37  	"errors"
    38  	"io"
    39  	"sync"
    40  	"time"
    41  
    42  	"github.com/coreos/rkt/Godeps/_workspace/src/golang.org/x/net/context"
    43  	"github.com/coreos/rkt/Godeps/_workspace/src/golang.org/x/net/trace"
    44  	"github.com/coreos/rkt/Godeps/_workspace/src/google.golang.org/grpc/codes"
    45  	"github.com/coreos/rkt/Godeps/_workspace/src/google.golang.org/grpc/metadata"
    46  	"github.com/coreos/rkt/Godeps/_workspace/src/google.golang.org/grpc/transport"
    47  )
    48  
    49  type streamHandler func(srv interface{}, stream ServerStream) error
    50  
    51  // StreamDesc represents a streaming RPC service's method specification.
    52  type StreamDesc struct {
    53  	StreamName string
    54  	Handler    streamHandler
    55  
    56  	// At least one of these is true.
    57  	ServerStreams bool
    58  	ClientStreams bool
    59  }
    60  
    61  // Stream defines the common interface a client or server stream has to satisfy.
    62  type Stream interface {
    63  	// Context returns the context for this stream.
    64  	Context() context.Context
    65  	// SendMsg blocks until it sends m, the stream is done or the stream
    66  	// breaks.
    67  	// On error, it aborts the stream and returns an RPC status on client
    68  	// side. On server side, it simply returns the error to the caller.
    69  	// SendMsg is called by generated code.
    70  	SendMsg(m interface{}) error
    71  	// RecvMsg blocks until it receives a message or the stream is
    72  	// done. On client side, it returns io.EOF when the stream is done. On
    73  	// any other error, it aborts the streama nd returns an RPC status. On
    74  	// server side, it simply returns the error to the caller.
    75  	RecvMsg(m interface{}) error
    76  }
    77  
    78  // ClientStream defines the interface a client stream has to satify.
    79  type ClientStream interface {
    80  	// Header returns the header metedata received from the server if there
    81  	// is any. It blocks if the metadata is not ready to read.
    82  	Header() (metadata.MD, error)
    83  	// Trailer returns the trailer metadata from the server. It must be called
    84  	// after stream.Recv() returns non-nil error (including io.EOF) for
    85  	// bi-directional streaming and server streaming or stream.CloseAndRecv()
    86  	// returns for client streaming in order to receive trailer metadata if
    87  	// present. Otherwise, it could returns an empty MD even though trailer
    88  	// is present.
    89  	Trailer() metadata.MD
    90  	// CloseSend closes the send direction of the stream. It closes the stream
    91  	// when non-nil error is met.
    92  	CloseSend() error
    93  	Stream
    94  }
    95  
    96  // NewClientStream creates a new Stream for the client side. This is called
    97  // by generated code.
    98  func NewClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (ClientStream, error) {
    99  	// TODO(zhaoq): CallOption is omitted. Add support when it is needed.
   100  	callHdr := &transport.CallHdr{
   101  		Host:   cc.authority,
   102  		Method: method,
   103  	}
   104  	cs := &clientStream{
   105  		desc:    desc,
   106  		codec:   cc.dopts.codec,
   107  		tracing: EnableTracing,
   108  	}
   109  	if cs.tracing {
   110  		cs.traceInfo.tr = trace.New("grpc.Sent."+methodFamily(method), method)
   111  		cs.traceInfo.firstLine.client = true
   112  		if deadline, ok := ctx.Deadline(); ok {
   113  			cs.traceInfo.firstLine.deadline = deadline.Sub(time.Now())
   114  		}
   115  		cs.traceInfo.tr.LazyLog(&cs.traceInfo.firstLine, false)
   116  	}
   117  	t, _, err := cc.wait(ctx, 0)
   118  	if err != nil {
   119  		return nil, toRPCErr(err)
   120  	}
   121  	s, err := t.NewStream(ctx, callHdr)
   122  	if err != nil {
   123  		return nil, toRPCErr(err)
   124  	}
   125  	cs.t = t
   126  	cs.s = s
   127  	cs.p = &parser{s: s}
   128  	return cs, nil
   129  }
   130  
   131  // clientStream implements a client side Stream.
   132  type clientStream struct {
   133  	t     transport.ClientTransport
   134  	s     *transport.Stream
   135  	p     *parser
   136  	desc  *StreamDesc
   137  	codec Codec
   138  
   139  	tracing bool // set to EnableTracing when the clientStream is created.
   140  
   141  	mu sync.Mutex // protects traceInfo
   142  	// traceInfo.tr is set when the clientStream is created (if EnableTracing is true),
   143  	// and is set to nil when the clientStream's finish method is called.
   144  	traceInfo traceInfo
   145  }
   146  
   147  func (cs *clientStream) Context() context.Context {
   148  	return cs.s.Context()
   149  }
   150  
   151  func (cs *clientStream) Header() (metadata.MD, error) {
   152  	m, err := cs.s.Header()
   153  	if err != nil {
   154  		if _, ok := err.(transport.ConnectionError); !ok {
   155  			cs.t.CloseStream(cs.s, err)
   156  		}
   157  	}
   158  	return m, err
   159  }
   160  
   161  func (cs *clientStream) Trailer() metadata.MD {
   162  	return cs.s.Trailer()
   163  }
   164  
   165  func (cs *clientStream) SendMsg(m interface{}) (err error) {
   166  	if cs.tracing {
   167  		cs.mu.Lock()
   168  		if cs.traceInfo.tr != nil {
   169  			cs.traceInfo.tr.LazyLog(&payload{sent: true, msg: m}, true)
   170  		}
   171  		cs.mu.Unlock()
   172  	}
   173  	defer func() {
   174  		if err == nil || err == io.EOF {
   175  			return
   176  		}
   177  		if _, ok := err.(transport.ConnectionError); !ok {
   178  			cs.t.CloseStream(cs.s, err)
   179  		}
   180  		err = toRPCErr(err)
   181  	}()
   182  	out, err := encode(cs.codec, m, compressionNone)
   183  	if err != nil {
   184  		return transport.StreamErrorf(codes.Internal, "grpc: %v", err)
   185  	}
   186  	return cs.t.Write(cs.s, out, &transport.Options{Last: false})
   187  }
   188  
   189  func (cs *clientStream) RecvMsg(m interface{}) (err error) {
   190  	err = recv(cs.p, cs.codec, m)
   191  	defer func() {
   192  		// err != nil indicates the termination of the stream.
   193  		if err != nil {
   194  			cs.finish(err)
   195  		}
   196  	}()
   197  	if err == nil {
   198  		if cs.tracing {
   199  			cs.mu.Lock()
   200  			if cs.traceInfo.tr != nil {
   201  				cs.traceInfo.tr.LazyLog(&payload{sent: false, msg: m}, true)
   202  			}
   203  			cs.mu.Unlock()
   204  		}
   205  		if !cs.desc.ClientStreams || cs.desc.ServerStreams {
   206  			return
   207  		}
   208  		// Special handling for client streaming rpc.
   209  		err = recv(cs.p, cs.codec, m)
   210  		cs.t.CloseStream(cs.s, err)
   211  		if err == nil {
   212  			return toRPCErr(errors.New("grpc: client streaming protocol violation: get <nil>, want <EOF>"))
   213  		}
   214  		if err == io.EOF {
   215  			if cs.s.StatusCode() == codes.OK {
   216  				return nil
   217  			}
   218  			return Errorf(cs.s.StatusCode(), cs.s.StatusDesc())
   219  		}
   220  		return toRPCErr(err)
   221  	}
   222  	if _, ok := err.(transport.ConnectionError); !ok {
   223  		cs.t.CloseStream(cs.s, err)
   224  	}
   225  	if err == io.EOF {
   226  		if cs.s.StatusCode() == codes.OK {
   227  			// Returns io.EOF to indicate the end of the stream.
   228  			return
   229  		}
   230  		return Errorf(cs.s.StatusCode(), cs.s.StatusDesc())
   231  	}
   232  	return toRPCErr(err)
   233  }
   234  
   235  func (cs *clientStream) CloseSend() (err error) {
   236  	err = cs.t.Write(cs.s, nil, &transport.Options{Last: true})
   237  	if err == nil || err == io.EOF {
   238  		return
   239  	}
   240  	if _, ok := err.(transport.ConnectionError); !ok {
   241  		cs.t.CloseStream(cs.s, err)
   242  	}
   243  	err = toRPCErr(err)
   244  	return
   245  }
   246  
   247  func (cs *clientStream) finish(err error) {
   248  	if !cs.tracing {
   249  		return
   250  	}
   251  	cs.mu.Lock()
   252  	defer cs.mu.Unlock()
   253  	if cs.traceInfo.tr != nil {
   254  		if err == nil || err == io.EOF {
   255  			cs.traceInfo.tr.LazyPrintf("RPC: [OK]")
   256  		} else {
   257  			cs.traceInfo.tr.LazyPrintf("RPC: [%v]", err)
   258  			cs.traceInfo.tr.SetError()
   259  		}
   260  		cs.traceInfo.tr.Finish()
   261  		cs.traceInfo.tr = nil
   262  	}
   263  }
   264  
   265  // ServerStream defines the interface a server stream has to satisfy.
   266  type ServerStream interface {
   267  	// SendHeader sends the header metadata. It should not be called
   268  	// after SendProto. It fails if called multiple times or if
   269  	// called after SendProto.
   270  	SendHeader(metadata.MD) error
   271  	// SetTrailer sets the trailer metadata which will be sent with the
   272  	// RPC status.
   273  	SetTrailer(metadata.MD)
   274  	Stream
   275  }
   276  
   277  // serverStream implements a server side Stream.
   278  type serverStream struct {
   279  	t          transport.ServerTransport
   280  	s          *transport.Stream
   281  	p          *parser
   282  	codec      Codec
   283  	statusCode codes.Code
   284  	statusDesc string
   285  
   286  	tracing bool // set to EnableTracing when the serverStream is created.
   287  
   288  	mu sync.Mutex // protects traceInfo
   289  	// traceInfo.tr is set when the serverStream is created (if EnableTracing is true),
   290  	// and is set to nil when the serverStream's finish method is called.
   291  	traceInfo traceInfo
   292  }
   293  
   294  func (ss *serverStream) Context() context.Context {
   295  	return ss.s.Context()
   296  }
   297  
   298  func (ss *serverStream) SendHeader(md metadata.MD) error {
   299  	return ss.t.WriteHeader(ss.s, md)
   300  }
   301  
   302  func (ss *serverStream) SetTrailer(md metadata.MD) {
   303  	if md.Len() == 0 {
   304  		return
   305  	}
   306  	ss.s.SetTrailer(md)
   307  	return
   308  }
   309  
   310  func (ss *serverStream) SendMsg(m interface{}) (err error) {
   311  	defer func() {
   312  		if ss.tracing {
   313  			ss.mu.Lock()
   314  			if err == nil {
   315  				ss.traceInfo.tr.LazyLog(&payload{sent: true, msg: m}, true)
   316  			} else {
   317  				ss.traceInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
   318  				ss.traceInfo.tr.SetError()
   319  			}
   320  
   321  			ss.mu.Unlock()
   322  		}
   323  	}()
   324  	out, err := encode(ss.codec, m, compressionNone)
   325  	if err != nil {
   326  		err = transport.StreamErrorf(codes.Internal, "grpc: %v", err)
   327  		return err
   328  	}
   329  	return ss.t.Write(ss.s, out, &transport.Options{Last: false})
   330  }
   331  
   332  func (ss *serverStream) RecvMsg(m interface{}) (err error) {
   333  	defer func() {
   334  		if ss.tracing {
   335  			ss.mu.Lock()
   336  			if err == nil {
   337  				ss.traceInfo.tr.LazyLog(&payload{sent: false, msg: m}, true)
   338  			} else if err != io.EOF {
   339  				ss.traceInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
   340  				ss.traceInfo.tr.SetError()
   341  			}
   342  			ss.mu.Unlock()
   343  		}
   344  	}()
   345  	return recv(ss.p, ss.codec, m)
   346  }