github.com/blixtra/rkt@v0.8.1-0.20160204105720-ab0d1add1a43/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  	"golang.org/x/net/context"
    43  	"golang.org/x/net/trace"
    44  	"google.golang.org/grpc/codes"
    45  	"google.golang.org/grpc/metadata"
    46  	"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  	var (
   100  		t   transport.ClientTransport
   101  		err error
   102  	)
   103  	t, err = cc.dopts.picker.Pick(ctx)
   104  	if err != nil {
   105  		return nil, toRPCErr(err)
   106  	}
   107  	// TODO(zhaoq): CallOption is omitted. Add support when it is needed.
   108  	callHdr := &transport.CallHdr{
   109  		Host:   cc.authority,
   110  		Method: method,
   111  	}
   112  	cs := &clientStream{
   113  		desc:    desc,
   114  		codec:   cc.dopts.codec,
   115  		tracing: EnableTracing,
   116  	}
   117  	if cs.tracing {
   118  		cs.trInfo.tr = trace.New("grpc.Sent."+methodFamily(method), method)
   119  		cs.trInfo.firstLine.client = true
   120  		if deadline, ok := ctx.Deadline(); ok {
   121  			cs.trInfo.firstLine.deadline = deadline.Sub(time.Now())
   122  		}
   123  		cs.trInfo.tr.LazyLog(&cs.trInfo.firstLine, false)
   124  		ctx = trace.NewContext(ctx, cs.trInfo.tr)
   125  	}
   126  	s, err := t.NewStream(ctx, callHdr)
   127  	if err != nil {
   128  		cs.finish(err)
   129  		return nil, toRPCErr(err)
   130  	}
   131  	cs.t = t
   132  	cs.s = s
   133  	cs.p = &parser{s: s}
   134  	// Listen on ctx.Done() to detect cancellation when there is no pending
   135  	// I/O operations on this stream.
   136  	go func() {
   137  		select {
   138  		case <-t.Error():
   139  			// Incur transport error, simply exit.
   140  		case <-s.Context().Done():
   141  			err := s.Context().Err()
   142  			cs.finish(err)
   143  			cs.closeTransportStream(transport.ContextErr(err))
   144  		}
   145  	}()
   146  	return cs, nil
   147  }
   148  
   149  // clientStream implements a client side Stream.
   150  type clientStream struct {
   151  	t     transport.ClientTransport
   152  	s     *transport.Stream
   153  	p     *parser
   154  	desc  *StreamDesc
   155  	codec Codec
   156  
   157  	tracing bool // set to EnableTracing when the clientStream is created.
   158  
   159  	mu     sync.Mutex
   160  	closed bool
   161  	// trInfo.tr is set when the clientStream is created (if EnableTracing is true),
   162  	// and is set to nil when the clientStream's finish method is called.
   163  	trInfo traceInfo
   164  }
   165  
   166  func (cs *clientStream) Context() context.Context {
   167  	return cs.s.Context()
   168  }
   169  
   170  func (cs *clientStream) Header() (metadata.MD, error) {
   171  	m, err := cs.s.Header()
   172  	if err != nil {
   173  		if _, ok := err.(transport.ConnectionError); !ok {
   174  			cs.closeTransportStream(err)
   175  		}
   176  	}
   177  	return m, err
   178  }
   179  
   180  func (cs *clientStream) Trailer() metadata.MD {
   181  	return cs.s.Trailer()
   182  }
   183  
   184  func (cs *clientStream) SendMsg(m interface{}) (err error) {
   185  	if cs.tracing {
   186  		cs.mu.Lock()
   187  		if cs.trInfo.tr != nil {
   188  			cs.trInfo.tr.LazyLog(&payload{sent: true, msg: m}, true)
   189  		}
   190  		cs.mu.Unlock()
   191  	}
   192  	defer func() {
   193  		if err == nil || err == io.EOF {
   194  			return
   195  		}
   196  		if _, ok := err.(transport.ConnectionError); !ok {
   197  			cs.closeTransportStream(err)
   198  		}
   199  		err = toRPCErr(err)
   200  	}()
   201  	out, err := encode(cs.codec, m, compressionNone)
   202  	if err != nil {
   203  		return transport.StreamErrorf(codes.Internal, "grpc: %v", err)
   204  	}
   205  	return cs.t.Write(cs.s, out, &transport.Options{Last: false})
   206  }
   207  
   208  func (cs *clientStream) RecvMsg(m interface{}) (err error) {
   209  	err = recv(cs.p, cs.codec, m)
   210  	defer func() {
   211  		// err != nil indicates the termination of the stream.
   212  		if err != nil {
   213  			cs.finish(err)
   214  		}
   215  	}()
   216  	if err == nil {
   217  		if cs.tracing {
   218  			cs.mu.Lock()
   219  			if cs.trInfo.tr != nil {
   220  				cs.trInfo.tr.LazyLog(&payload{sent: false, msg: m}, true)
   221  			}
   222  			cs.mu.Unlock()
   223  		}
   224  		if !cs.desc.ClientStreams || cs.desc.ServerStreams {
   225  			return
   226  		}
   227  		// Special handling for client streaming rpc.
   228  		err = recv(cs.p, cs.codec, m)
   229  		cs.closeTransportStream(err)
   230  		if err == nil {
   231  			return toRPCErr(errors.New("grpc: client streaming protocol violation: get <nil>, want <EOF>"))
   232  		}
   233  		if err == io.EOF {
   234  			if cs.s.StatusCode() == codes.OK {
   235  				return nil
   236  			}
   237  			return Errorf(cs.s.StatusCode(), cs.s.StatusDesc())
   238  		}
   239  		return toRPCErr(err)
   240  	}
   241  	if _, ok := err.(transport.ConnectionError); !ok {
   242  		cs.closeTransportStream(err)
   243  	}
   244  	if err == io.EOF {
   245  		if cs.s.StatusCode() == codes.OK {
   246  			// Returns io.EOF to indicate the end of the stream.
   247  			return
   248  		}
   249  		return Errorf(cs.s.StatusCode(), cs.s.StatusDesc())
   250  	}
   251  	return toRPCErr(err)
   252  }
   253  
   254  func (cs *clientStream) CloseSend() (err error) {
   255  	err = cs.t.Write(cs.s, nil, &transport.Options{Last: true})
   256  	if err == nil || err == io.EOF {
   257  		return
   258  	}
   259  	if _, ok := err.(transport.ConnectionError); !ok {
   260  		cs.closeTransportStream(err)
   261  	}
   262  	err = toRPCErr(err)
   263  	return
   264  }
   265  
   266  func (cs *clientStream) closeTransportStream(err error) {
   267  	cs.mu.Lock()
   268  	if cs.closed {
   269  		cs.mu.Unlock()
   270  		return
   271  	}
   272  	cs.closed = true
   273  	cs.mu.Unlock()
   274  	cs.t.CloseStream(cs.s, err)
   275  }
   276  
   277  func (cs *clientStream) finish(err error) {
   278  	if !cs.tracing {
   279  		return
   280  	}
   281  	cs.mu.Lock()
   282  	defer cs.mu.Unlock()
   283  	if cs.trInfo.tr != nil {
   284  		if err == nil || err == io.EOF {
   285  			cs.trInfo.tr.LazyPrintf("RPC: [OK]")
   286  		} else {
   287  			cs.trInfo.tr.LazyPrintf("RPC: [%v]", err)
   288  			cs.trInfo.tr.SetError()
   289  		}
   290  		cs.trInfo.tr.Finish()
   291  		cs.trInfo.tr = nil
   292  	}
   293  }
   294  
   295  // ServerStream defines the interface a server stream has to satisfy.
   296  type ServerStream interface {
   297  	// SendHeader sends the header metadata. It should not be called
   298  	// after SendProto. It fails if called multiple times or if
   299  	// called after SendProto.
   300  	SendHeader(metadata.MD) error
   301  	// SetTrailer sets the trailer metadata which will be sent with the
   302  	// RPC status.
   303  	SetTrailer(metadata.MD)
   304  	Stream
   305  }
   306  
   307  // serverStream implements a server side Stream.
   308  type serverStream struct {
   309  	t          transport.ServerTransport
   310  	s          *transport.Stream
   311  	p          *parser
   312  	codec      Codec
   313  	statusCode codes.Code
   314  	statusDesc string
   315  	trInfo     *traceInfo
   316  
   317  	mu sync.Mutex // protects trInfo.tr after the service handler runs.
   318  }
   319  
   320  func (ss *serverStream) Context() context.Context {
   321  	return ss.s.Context()
   322  }
   323  
   324  func (ss *serverStream) SendHeader(md metadata.MD) error {
   325  	return ss.t.WriteHeader(ss.s, md)
   326  }
   327  
   328  func (ss *serverStream) SetTrailer(md metadata.MD) {
   329  	if md.Len() == 0 {
   330  		return
   331  	}
   332  	ss.s.SetTrailer(md)
   333  	return
   334  }
   335  
   336  func (ss *serverStream) SendMsg(m interface{}) (err error) {
   337  	defer func() {
   338  		if ss.trInfo != nil {
   339  			ss.mu.Lock()
   340  			if ss.trInfo.tr != nil {
   341  				if err == nil {
   342  					ss.trInfo.tr.LazyLog(&payload{sent: true, msg: m}, true)
   343  				} else {
   344  					ss.trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
   345  					ss.trInfo.tr.SetError()
   346  				}
   347  			}
   348  			ss.mu.Unlock()
   349  		}
   350  	}()
   351  	out, err := encode(ss.codec, m, compressionNone)
   352  	if err != nil {
   353  		err = transport.StreamErrorf(codes.Internal, "grpc: %v", err)
   354  		return err
   355  	}
   356  	return ss.t.Write(ss.s, out, &transport.Options{Last: false})
   357  }
   358  
   359  func (ss *serverStream) RecvMsg(m interface{}) (err error) {
   360  	defer func() {
   361  		if ss.trInfo != nil {
   362  			ss.mu.Lock()
   363  			if ss.trInfo.tr != nil {
   364  				if err == nil {
   365  					ss.trInfo.tr.LazyLog(&payload{sent: false, msg: m}, true)
   366  				} else if err != io.EOF {
   367  					ss.trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
   368  					ss.trInfo.tr.SetError()
   369  				}
   370  			}
   371  			ss.mu.Unlock()
   372  		}
   373  	}()
   374  	return recv(ss.p, ss.codec, m)
   375  }