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 }