package quic import ( "fmt" "io" "sync" "time" "github.com/lucas-clemente/quic-go/internal/flowcontrol" "github.com/lucas-clemente/quic-go/internal/protocol" "github.com/lucas-clemente/quic-go/internal/wire" ) type receiveStreamI interface { ReceiveStream handleStreamFrame(*wire.StreamFrame) error handleResetStreamFrame(*wire.ResetStreamFrame) error closeForShutdown(error) getWindowUpdate() protocol.ByteCount } type receiveStream struct { mutex sync.Mutex streamID protocol.StreamID sender streamSender frameQueue *frameSorter readOffset protocol.ByteCount currentFrame []byte currentFrameIsLast bool // is the currentFrame the last frame on this stream readPosInFrame int closeForShutdownErr error cancelReadErr error resetRemotelyErr StreamError closedForShutdown bool // set when CloseForShutdown() is called finRead bool // set once we read a frame with a FinBit canceledRead bool // set when CancelRead() is called resetRemotely bool // set when HandleResetStreamFrame() is called readChan chan struct{} deadline time.Time deadlineTimer *time.Timer // initialized by SetReadDeadline() flowController flowcontrol.StreamFlowController version protocol.VersionNumber } var _ ReceiveStream = &receiveStream{} var _ receiveStreamI = &receiveStream{} func newReceiveStream( streamID protocol.StreamID, sender streamSender, flowController flowcontrol.StreamFlowController, version protocol.VersionNumber, ) *receiveStream { return &receiveStream{ streamID: streamID, sender: sender, flowController: flowController, frameQueue: newFrameSorter(), readChan: make(chan struct{}, 1), version: version, } } func (s *receiveStream) StreamID() protocol.StreamID { return s.streamID } // Read implements io.Reader. It is not thread safe! func (s *receiveStream) Read(p []byte) (int, error) { completed, n, err := s.readImpl(p) if completed { s.sender.onStreamCompleted(s.streamID) } return n, err } func (s *receiveStream) readImpl(p []byte) (bool /*stream completed */, int, error) { s.mutex.Lock() defer s.mutex.Unlock() if s.finRead { return false, 0, io.EOF } if s.canceledRead { return false, 0, s.cancelReadErr } if s.resetRemotely { return false, 0, s.resetRemotelyErr } if s.closedForShutdown { return false, 0, s.closeForShutdownErr } bytesRead := 0 for bytesRead < len(p) { if s.currentFrame == nil || s.readPosInFrame >= len(s.currentFrame) { s.dequeueNextFrame() } if s.currentFrame == nil && bytesRead > 0 { return false, bytesRead, s.closeForShutdownErr } for { // Stop waiting on errors if s.closedForShutdown { return false, bytesRead, s.closeForShutdownErr } if s.canceledRead { return false, bytesRead, s.cancelReadErr } if s.resetRemotely { return false, bytesRead, s.resetRemotelyErr } if !s.deadline.IsZero() && !time.Now().Before(s.deadline) { return false, bytesRead, errDeadline } if s.currentFrame != nil || s.currentFrameIsLast { break } s.mutex.Unlock() if s.deadline.IsZero() { <-s.readChan } else { select { case <-s.readChan: case <-s.deadlineTimer.C: } } s.mutex.Lock() if s.currentFrame == nil { s.dequeueNextFrame() } } if bytesRead > len(p) { return false, bytesRead, fmt.Errorf("BUG: bytesRead (%d) > len(p) (%d) in stream.Read", bytesRead, len(p)) } if s.readPosInFrame > len(s.currentFrame) { return false, bytesRead, fmt.Errorf("BUG: readPosInFrame (%d) > frame.DataLen (%d) in stream.Read", s.readPosInFrame, len(s.currentFrame)) } s.mutex.Unlock() m := copy(p[bytesRead:], s.currentFrame[s.readPosInFrame:]) s.readPosInFrame += m bytesRead += m s.readOffset += protocol.ByteCount(m) s.mutex.Lock() // when a RESET_STREAM was received, the was already informed about the final byteOffset for this stream if !s.resetRemotely { s.flowController.AddBytesRead(protocol.ByteCount(m)) } // increase the flow control window, if necessary s.flowController.MaybeQueueWindowUpdate() if s.readPosInFrame >= len(s.currentFrame) && s.currentFrameIsLast { s.finRead = true return true, bytesRead, io.EOF } } return false, bytesRead, nil } func (s *receiveStream) dequeueNextFrame() { s.currentFrame, s.currentFrameIsLast = s.frameQueue.Pop() s.readPosInFrame = 0 } func (s *receiveStream) CancelRead(errorCode protocol.ApplicationErrorCode) error { s.mutex.Lock() defer s.mutex.Unlock() if s.finRead { return nil } if s.canceledRead { return nil } s.canceledRead = true s.cancelReadErr = fmt.Errorf("Read on stream %d canceled with error code %d", s.streamID, errorCode) s.signalRead() s.sender.queueControlFrame(&wire.StopSendingFrame{ StreamID: s.streamID, ErrorCode: errorCode, }) return nil } func (s *receiveStream) handleStreamFrame(frame *wire.StreamFrame) error { maxOffset := frame.Offset + frame.DataLen() if err := s.flowController.UpdateHighestReceived(maxOffset, frame.FinBit); err != nil { return err } s.mutex.Lock() defer s.mutex.Unlock() if err := s.frameQueue.Push(frame.Data, frame.Offset, frame.FinBit); err != nil { return err } s.signalRead() return nil } func (s *receiveStream) handleResetStreamFrame(frame *wire.ResetStreamFrame) error { completed, err := s.handleResetStreamFrameImpl(frame) if completed { s.sender.onStreamCompleted(s.streamID) } return err } func (s *receiveStream) handleResetStreamFrameImpl(frame *wire.ResetStreamFrame) (bool /*completed */, error) { s.mutex.Lock() defer s.mutex.Unlock() if s.closedForShutdown { return false, nil } if err := s.flowController.UpdateHighestReceived(frame.ByteOffset, true); err != nil { return false, err } // ignore duplicate RESET_STREAM frames for this stream (after checking their final offset) if s.resetRemotely { return false, nil } s.resetRemotely = true s.resetRemotelyErr = streamCanceledError{ errorCode: frame.ErrorCode, error: fmt.Errorf("Stream %d was reset with error code %d", s.streamID, frame.ErrorCode), } s.signalRead() return true, nil } func (s *receiveStream) CloseRemote(offset protocol.ByteCount) { s.handleStreamFrame(&wire.StreamFrame{FinBit: true, Offset: offset}) } func (s *receiveStream) SetReadDeadline(t time.Time) error { s.mutex.Lock() defer s.mutex.Unlock() s.deadline = t if s.deadline.IsZero() { // skip if there's no deadline to set s.signalRead() return nil } // Lazily initialize the deadline timer. if s.deadlineTimer == nil { s.deadlineTimer = time.NewTimer(time.Until(t)) return nil } // reset the timer to the new deadline if !s.deadlineTimer.Stop() { <-s.deadlineTimer.C } s.deadlineTimer.Reset(time.Until(t)) return nil } // CloseForShutdown closes a stream abruptly. // It makes Read unblock (and return the error) immediately. // The peer will NOT be informed about this: the stream is closed without sending a FIN or RESET. func (s *receiveStream) closeForShutdown(err error) { s.mutex.Lock() s.closedForShutdown = true s.closeForShutdownErr = err s.mutex.Unlock() s.signalRead() } func (s *receiveStream) getWindowUpdate() protocol.ByteCount { return s.flowController.GetWindowUpdate() } // signalRead performs a non-blocking send on the readChan func (s *receiveStream) signalRead() { select { case s.readChan <- struct{}{}: default: } }