mirror of
https://github.com/v2fly/v2ray-core.git
synced 2024-11-06 10:20:44 -05:00
303 lines
7.4 KiB
Go
303 lines
7.4 KiB
Go
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) HasMoreData() bool {
|
|
s.mutex.Lock()
|
|
defer s.mutex.Unlock()
|
|
|
|
return s.currentFrame != nil
|
|
}
|
|
|
|
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:
|
|
}
|
|
}
|