2017-05-27 14:30:11 -05:00
|
|
|
package quic
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
"github.com/lucas-clemente/quic-go/internal/flowcontrol"
|
|
|
|
"github.com/lucas-clemente/quic-go/internal/handshake"
|
|
|
|
"github.com/lucas-clemente/quic-go/internal/protocol"
|
|
|
|
"github.com/lucas-clemente/quic-go/internal/wire"
|
2017-05-27 14:30:11 -05:00
|
|
|
)
|
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
type streamType int
|
2017-05-27 14:30:11 -05:00
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
const (
|
|
|
|
streamTypeOutgoingBidi streamType = iota
|
|
|
|
streamTypeIncomingBidi
|
|
|
|
streamTypeOutgoingUni
|
|
|
|
streamTypeIncomingUni
|
|
|
|
)
|
2017-05-27 14:30:11 -05:00
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
type streamsMap struct {
|
|
|
|
perspective protocol.Perspective
|
2017-05-27 14:30:11 -05:00
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
sender streamSender
|
|
|
|
newFlowController func(protocol.StreamID) flowcontrol.StreamFlowController
|
2017-05-27 14:30:11 -05:00
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
outgoingBidiStreams *outgoingBidiStreamsMap
|
|
|
|
outgoingUniStreams *outgoingUniStreamsMap
|
|
|
|
incomingBidiStreams *incomingBidiStreamsMap
|
|
|
|
incomingUniStreams *incomingUniStreamsMap
|
2017-05-27 14:30:11 -05:00
|
|
|
}
|
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
var _ streamManager = &streamsMap{}
|
|
|
|
|
|
|
|
func newStreamsMap(
|
|
|
|
sender streamSender,
|
|
|
|
newFlowController func(protocol.StreamID) flowcontrol.StreamFlowController,
|
|
|
|
perspective protocol.Perspective,
|
|
|
|
version protocol.VersionNumber,
|
|
|
|
) streamManager {
|
|
|
|
m := &streamsMap{
|
|
|
|
perspective: perspective,
|
|
|
|
newFlowController: newFlowController,
|
|
|
|
sender: sender,
|
|
|
|
}
|
|
|
|
var firstOutgoingBidiStream, firstOutgoingUniStream, firstIncomingBidiStream, firstIncomingUniStream protocol.StreamID
|
|
|
|
if perspective == protocol.PerspectiveServer {
|
|
|
|
firstOutgoingBidiStream = 1
|
|
|
|
firstIncomingBidiStream = 4 // the crypto stream is handled separatedly
|
|
|
|
firstOutgoingUniStream = 3
|
|
|
|
firstIncomingUniStream = 2
|
2017-05-27 14:30:11 -05:00
|
|
|
} else {
|
2018-02-17 00:29:53 -05:00
|
|
|
firstOutgoingBidiStream = 4 // the crypto stream is handled separately
|
|
|
|
firstIncomingBidiStream = 1
|
|
|
|
firstOutgoingUniStream = 2
|
|
|
|
firstIncomingUniStream = 3
|
|
|
|
}
|
|
|
|
newBidiStream := func(id protocol.StreamID) streamI {
|
|
|
|
return newStream(id, m.sender, m.newFlowController(id), version)
|
|
|
|
}
|
|
|
|
newUniSendStream := func(id protocol.StreamID) sendStreamI {
|
|
|
|
return newSendStream(id, m.sender, m.newFlowController(id), version)
|
|
|
|
}
|
|
|
|
newUniReceiveStream := func(id protocol.StreamID) receiveStreamI {
|
|
|
|
return newReceiveStream(id, m.sender, m.newFlowController(id), version)
|
|
|
|
}
|
|
|
|
m.outgoingBidiStreams = newOutgoingBidiStreamsMap(
|
|
|
|
firstOutgoingBidiStream,
|
|
|
|
newBidiStream,
|
|
|
|
sender.queueControlFrame,
|
|
|
|
)
|
|
|
|
// TODO(#523): make these values configurable
|
|
|
|
m.incomingBidiStreams = newIncomingBidiStreamsMap(
|
|
|
|
firstIncomingBidiStream,
|
|
|
|
protocol.MaxBidiStreamID(protocol.MaxIncomingStreams, perspective),
|
|
|
|
protocol.MaxIncomingStreams,
|
|
|
|
sender.queueControlFrame,
|
|
|
|
newBidiStream,
|
|
|
|
)
|
|
|
|
m.outgoingUniStreams = newOutgoingUniStreamsMap(
|
|
|
|
firstOutgoingUniStream,
|
|
|
|
newUniSendStream,
|
|
|
|
sender.queueControlFrame,
|
|
|
|
)
|
|
|
|
// TODO(#523): make these values configurable
|
|
|
|
m.incomingUniStreams = newIncomingUniStreamsMap(
|
|
|
|
firstIncomingUniStream,
|
|
|
|
protocol.MaxUniStreamID(protocol.MaxIncomingStreams, perspective),
|
|
|
|
protocol.MaxIncomingStreams,
|
|
|
|
sender.queueControlFrame,
|
|
|
|
newUniReceiveStream,
|
|
|
|
)
|
|
|
|
return m
|
2017-05-27 14:30:11 -05:00
|
|
|
}
|
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
func (m *streamsMap) getStreamType(id protocol.StreamID) streamType {
|
2017-07-27 17:11:56 -05:00
|
|
|
if m.perspective == protocol.PerspectiveServer {
|
2018-02-17 00:29:53 -05:00
|
|
|
switch id % 4 {
|
|
|
|
case 0:
|
|
|
|
return streamTypeIncomingBidi
|
|
|
|
case 1:
|
|
|
|
return streamTypeOutgoingBidi
|
|
|
|
case 2:
|
|
|
|
return streamTypeIncomingUni
|
|
|
|
case 3:
|
|
|
|
return streamTypeOutgoingUni
|
2017-07-27 17:11:56 -05:00
|
|
|
}
|
2017-05-27 14:30:11 -05:00
|
|
|
} else {
|
2018-02-17 00:29:53 -05:00
|
|
|
switch id % 4 {
|
|
|
|
case 0:
|
|
|
|
return streamTypeOutgoingBidi
|
|
|
|
case 1:
|
|
|
|
return streamTypeIncomingBidi
|
|
|
|
case 2:
|
|
|
|
return streamTypeOutgoingUni
|
|
|
|
case 3:
|
|
|
|
return streamTypeIncomingUni
|
|
|
|
}
|
|
|
|
}
|
|
|
|
panic("")
|
2017-05-27 14:30:11 -05:00
|
|
|
}
|
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
func (m *streamsMap) OpenStream() (Stream, error) {
|
|
|
|
return m.outgoingBidiStreams.OpenStream()
|
2017-05-27 14:30:11 -05:00
|
|
|
}
|
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
func (m *streamsMap) OpenStreamSync() (Stream, error) {
|
|
|
|
return m.outgoingBidiStreams.OpenStreamSync()
|
2017-05-27 14:30:11 -05:00
|
|
|
}
|
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
func (m *streamsMap) OpenUniStream() (SendStream, error) {
|
|
|
|
return m.outgoingUniStreams.OpenStream()
|
2017-05-27 14:30:11 -05:00
|
|
|
}
|
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
func (m *streamsMap) OpenUniStreamSync() (SendStream, error) {
|
|
|
|
return m.outgoingUniStreams.OpenStreamSync()
|
2017-05-27 14:30:11 -05:00
|
|
|
}
|
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
func (m *streamsMap) AcceptStream() (Stream, error) {
|
|
|
|
return m.incomingBidiStreams.AcceptStream()
|
2017-05-27 14:30:11 -05:00
|
|
|
}
|
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
func (m *streamsMap) AcceptUniStream() (ReceiveStream, error) {
|
|
|
|
return m.incomingUniStreams.AcceptStream()
|
2017-05-27 14:30:11 -05:00
|
|
|
}
|
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
func (m *streamsMap) DeleteStream(id protocol.StreamID) error {
|
|
|
|
switch m.getStreamType(id) {
|
|
|
|
case streamTypeIncomingBidi:
|
|
|
|
return m.incomingBidiStreams.DeleteStream(id)
|
|
|
|
case streamTypeOutgoingBidi:
|
|
|
|
return m.outgoingBidiStreams.DeleteStream(id)
|
|
|
|
case streamTypeIncomingUni:
|
|
|
|
return m.incomingUniStreams.DeleteStream(id)
|
|
|
|
case streamTypeOutgoingUni:
|
|
|
|
return m.outgoingUniStreams.DeleteStream(id)
|
|
|
|
default:
|
|
|
|
panic("invalid stream type")
|
2017-05-27 14:30:11 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
func (m *streamsMap) GetOrOpenReceiveStream(id protocol.StreamID) (receiveStreamI, error) {
|
|
|
|
switch m.getStreamType(id) {
|
|
|
|
case streamTypeOutgoingBidi:
|
|
|
|
return m.outgoingBidiStreams.GetStream(id)
|
|
|
|
case streamTypeIncomingBidi:
|
|
|
|
return m.incomingBidiStreams.GetOrOpenStream(id)
|
|
|
|
case streamTypeIncomingUni:
|
|
|
|
return m.incomingUniStreams.GetOrOpenStream(id)
|
|
|
|
case streamTypeOutgoingUni:
|
|
|
|
// an outgoing unidirectional stream is a send stream, not a receive stream
|
|
|
|
return nil, fmt.Errorf("peer attempted to open receive stream %d", id)
|
|
|
|
default:
|
|
|
|
panic("invalid stream type")
|
2017-05-27 14:30:11 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
func (m *streamsMap) GetOrOpenSendStream(id protocol.StreamID) (sendStreamI, error) {
|
|
|
|
switch m.getStreamType(id) {
|
|
|
|
case streamTypeOutgoingBidi:
|
|
|
|
return m.outgoingBidiStreams.GetStream(id)
|
|
|
|
case streamTypeIncomingBidi:
|
|
|
|
return m.incomingBidiStreams.GetOrOpenStream(id)
|
|
|
|
case streamTypeOutgoingUni:
|
|
|
|
return m.outgoingUniStreams.GetStream(id)
|
|
|
|
case streamTypeIncomingUni:
|
|
|
|
// an incoming unidirectional stream is a receive stream, not a send stream
|
|
|
|
return nil, fmt.Errorf("peer attempted to open send stream %d", id)
|
|
|
|
default:
|
|
|
|
panic("invalid stream type")
|
2017-05-27 14:30:11 -05:00
|
|
|
}
|
2018-02-17 00:29:53 -05:00
|
|
|
}
|
2017-05-27 14:30:11 -05:00
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
func (m *streamsMap) HandleMaxStreamIDFrame(f *wire.MaxStreamIDFrame) error {
|
|
|
|
id := f.StreamID
|
|
|
|
switch m.getStreamType(id) {
|
|
|
|
case streamTypeOutgoingBidi:
|
|
|
|
m.outgoingBidiStreams.SetMaxStream(id)
|
|
|
|
return nil
|
|
|
|
case streamTypeOutgoingUni:
|
|
|
|
m.outgoingUniStreams.SetMaxStream(id)
|
|
|
|
return nil
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("received MAX_STREAM_DATA frame for incoming stream %d", id)
|
2017-05-27 14:30:11 -05:00
|
|
|
}
|
2018-02-17 00:29:53 -05:00
|
|
|
}
|
2017-05-27 14:30:11 -05:00
|
|
|
|
2018-02-17 00:29:53 -05:00
|
|
|
func (m *streamsMap) UpdateLimits(p *handshake.TransportParameters) {
|
|
|
|
m.outgoingBidiStreams.SetMaxStream(p.MaxBidiStreamID)
|
|
|
|
m.outgoingUniStreams.SetMaxStream(p.MaxUniStreamID)
|
2017-05-27 14:30:11 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *streamsMap) CloseWithError(err error) {
|
2018-02-17 00:29:53 -05:00
|
|
|
m.outgoingBidiStreams.CloseWithError(err)
|
|
|
|
m.outgoingUniStreams.CloseWithError(err)
|
|
|
|
m.incomingBidiStreams.CloseWithError(err)
|
|
|
|
m.incomingUniStreams.CloseWithError(err)
|
2017-05-27 14:30:11 -05:00
|
|
|
}
|