2017-12-12 02:51:45 +00:00
package quic
import (
"errors"
"fmt"
"sync"
2018-01-20 18:07:01 +00:00
"github.com/lucas-clemente/quic-go/internal/handshake"
2018-01-03 19:19:49 +00:00
"github.com/lucas-clemente/quic-go/internal/protocol"
2018-01-20 18:07:01 +00:00
"github.com/lucas-clemente/quic-go/internal/wire"
2017-12-12 02:51:45 +00:00
"github.com/lucas-clemente/quic-go/qerr"
)
type streamsMap struct {
mutex sync . RWMutex
2018-01-03 19:19:49 +00:00
perspective protocol . Perspective
2017-12-12 02:51:45 +00:00
2018-01-03 19:19:49 +00:00
streams map [ protocol . StreamID ] streamI
2017-12-12 02:51:45 +00:00
2018-01-20 18:07:01 +00:00
nextStreamToOpen protocol . StreamID // StreamID of the next Stream that will be returned by OpenStream()
2017-12-12 02:51:45 +00:00
highestStreamOpenedByPeer protocol . StreamID
nextStreamOrErrCond sync . Cond
openStreamOrErrCond sync . Cond
closeErr error
nextStreamToAccept protocol . StreamID
newStream newStreamLambda
}
2018-01-20 18:07:01 +00:00
var _ streamManager = & streamsMap { }
2018-01-03 19:19:49 +00:00
type newStreamLambda func ( protocol . StreamID ) streamI
2017-12-12 02:51:45 +00:00
2018-01-03 19:19:49 +00:00
var errMapAccess = errors . New ( "streamsMap: Error accessing the streams map" )
2017-12-12 02:51:45 +00:00
2018-01-20 18:07:01 +00:00
func newStreamsMap ( newStream newStreamLambda , pers protocol . Perspective ) streamManager {
2017-12-12 02:51:45 +00:00
sm := streamsMap {
2018-01-20 18:07:01 +00:00
perspective : pers ,
streams : make ( map [ protocol . StreamID ] streamI ) ,
newStream : newStream ,
2017-12-12 02:51:45 +00:00
}
sm . nextStreamOrErrCond . L = & sm . mutex
sm . openStreamOrErrCond . L = & sm . mutex
2018-01-20 18:07:01 +00:00
nextClientInitiatedStream := protocol . StreamID ( 1 )
nextServerInitiatedStream := protocol . StreamID ( 2 )
if pers == protocol . PerspectiveServer {
sm . nextStreamToOpen = nextServerInitiatedStream
sm . nextStreamToAccept = nextClientInitiatedStream
2017-12-12 02:51:45 +00:00
} else {
2018-01-20 18:07:01 +00:00
sm . nextStreamToOpen = nextClientInitiatedStream
sm . nextStreamToAccept = nextServerInitiatedStream
2017-12-12 02:51:45 +00:00
}
return & sm
}
2018-01-03 19:19:49 +00:00
// getStreamPerspective says which side should initiate a stream
func ( m * streamsMap ) streamInitiatedBy ( id protocol . StreamID ) protocol . Perspective {
if id % 2 == 0 {
return protocol . PerspectiveServer
}
return protocol . PerspectiveClient
}
2018-01-20 18:07:01 +00:00
func ( m * streamsMap ) nextStreamID ( id protocol . StreamID ) protocol . StreamID {
if m . perspective == protocol . PerspectiveServer && id == 0 {
return 1
}
return id + 2
}
func ( m * streamsMap ) GetOrOpenReceiveStream ( id protocol . StreamID ) ( receiveStreamI , error ) {
// every bidirectional stream is also a receive stream
return m . GetOrOpenStream ( id )
}
func ( m * streamsMap ) GetOrOpenSendStream ( id protocol . StreamID ) ( sendStreamI , error ) {
// every bidirectional stream is also a send stream
return m . GetOrOpenStream ( id )
}
2017-12-12 02:51:45 +00:00
// GetOrOpenStream either returns an existing stream, a newly opened stream, or nil if a stream with the provided ID is already closed.
// Newly opened streams should only originate from the client. To open a stream from the server, OpenStream should be used.
2018-01-03 19:19:49 +00:00
func ( m * streamsMap ) GetOrOpenStream ( id protocol . StreamID ) ( streamI , error ) {
2017-12-12 02:51:45 +00:00
m . mutex . RLock ( )
s , ok := m . streams [ id ]
m . mutex . RUnlock ( )
if ok {
2018-01-20 18:07:01 +00:00
return s , nil
2017-12-12 02:51:45 +00:00
}
// ... we don't have an existing stream
m . mutex . Lock ( )
defer m . mutex . Unlock ( )
// We need to check whether another invocation has already created a stream (between RUnlock() and Lock()).
s , ok = m . streams [ id ]
if ok {
return s , nil
}
2018-01-03 19:19:49 +00:00
if m . perspective == m . streamInitiatedBy ( id ) {
2018-01-20 18:07:01 +00:00
if id <= m . nextStreamToOpen { // this is a stream opened by us. Must have been closed already
2018-01-03 19:19:49 +00:00
return nil , nil
}
return nil , qerr . Error ( qerr . InvalidStreamID , fmt . Sprintf ( "peer attempted to open stream %d" , id ) )
2017-12-12 02:51:45 +00:00
}
2018-01-03 19:19:49 +00:00
if id <= m . highestStreamOpenedByPeer { // this is a peer-initiated stream that doesn't exist anymore. Must have been closed already
return nil , nil
2017-12-12 02:51:45 +00:00
}
2018-01-20 18:07:01 +00:00
for sid := m . nextStreamID ( m . highestStreamOpenedByPeer ) ; sid <= id ; sid = m . nextStreamID ( sid ) {
2018-01-03 19:19:49 +00:00
if _ , err := m . openRemoteStream ( sid ) ; err != nil {
2017-12-12 02:51:45 +00:00
return nil , err
}
}
m . nextStreamOrErrCond . Broadcast ( )
return m . streams [ id ] , nil
}
2018-01-03 19:19:49 +00:00
func ( m * streamsMap ) openRemoteStream ( id protocol . StreamID ) ( streamI , error ) {
2017-12-12 02:51:45 +00:00
if id + protocol . MaxNewStreamIDDelta < m . highestStreamOpenedByPeer {
return nil , qerr . Error ( qerr . InvalidStreamID , fmt . Sprintf ( "attempted to open stream %d, which is a lot smaller than the highest opened stream, %d" , id , m . highestStreamOpenedByPeer ) )
}
if id > m . highestStreamOpenedByPeer {
m . highestStreamOpenedByPeer = id
}
2018-01-03 19:19:49 +00:00
s := m . newStream ( id )
2017-12-12 02:51:45 +00:00
m . putStream ( s )
return s , nil
}
2018-01-03 19:19:49 +00:00
func ( m * streamsMap ) openStreamImpl ( ) ( streamI , error ) {
2018-01-20 18:07:01 +00:00
s := m . newStream ( m . nextStreamToOpen )
2017-12-12 02:51:45 +00:00
m . putStream ( s )
2018-01-20 18:07:01 +00:00
m . nextStreamToOpen = m . nextStreamID ( m . nextStreamToOpen )
2017-12-12 02:51:45 +00:00
return s , nil
}
// OpenStream opens the next available stream
2018-01-20 18:07:01 +00:00
func ( m * streamsMap ) OpenStream ( ) ( Stream , error ) {
2017-12-12 02:51:45 +00:00
m . mutex . Lock ( )
defer m . mutex . Unlock ( )
2018-01-03 19:19:49 +00:00
if m . closeErr != nil {
return nil , m . closeErr
}
2017-12-12 02:51:45 +00:00
return m . openStreamImpl ( )
}
2018-01-20 18:07:01 +00:00
func ( m * streamsMap ) OpenStreamSync ( ) ( Stream , error ) {
2017-12-12 02:51:45 +00:00
m . mutex . Lock ( )
defer m . mutex . Unlock ( )
for {
if m . closeErr != nil {
return nil , m . closeErr
}
str , err := m . openStreamImpl ( )
if err == nil {
return str , err
}
if err != nil && err != qerr . TooManyOpenStreams {
return nil , err
}
m . openStreamOrErrCond . Wait ( )
}
}
// AcceptStream returns the next stream opened by the peer
// it blocks until a new stream is opened
2018-01-20 18:07:01 +00:00
func ( m * streamsMap ) AcceptStream ( ) ( Stream , error ) {
2017-12-12 02:51:45 +00:00
m . mutex . Lock ( )
defer m . mutex . Unlock ( )
2018-01-03 19:19:49 +00:00
var str streamI
2017-12-12 02:51:45 +00:00
for {
var ok bool
if m . closeErr != nil {
return nil , m . closeErr
}
str , ok = m . streams [ m . nextStreamToAccept ]
if ok {
break
}
m . nextStreamOrErrCond . Wait ( )
}
m . nextStreamToAccept += 2
return str , nil
}
2018-01-20 18:07:01 +00:00
func ( m * streamsMap ) DeleteStream ( id protocol . StreamID ) error {
2017-12-12 02:51:45 +00:00
m . mutex . Lock ( )
defer m . mutex . Unlock ( )
2018-01-20 18:07:01 +00:00
_ , ok := m . streams [ id ]
if ! ok {
return errMapAccess
2017-12-12 02:51:45 +00:00
}
2018-01-20 18:07:01 +00:00
delete ( m . streams , id )
2018-01-03 19:19:49 +00:00
m . openStreamOrErrCond . Signal ( )
2017-12-12 02:51:45 +00:00
return nil
}
2018-01-03 19:19:49 +00:00
func ( m * streamsMap ) putStream ( s streamI ) error {
2017-12-12 02:51:45 +00:00
id := s . StreamID ( )
if _ , ok := m . streams [ id ] ; ok {
return fmt . Errorf ( "a stream with ID %d already exists" , id )
}
m . streams [ id ] = s
return nil
}
func ( m * streamsMap ) CloseWithError ( err error ) {
m . mutex . Lock ( )
2018-01-03 19:19:49 +00:00
defer m . mutex . Unlock ( )
2017-12-12 02:51:45 +00:00
m . closeErr = err
m . nextStreamOrErrCond . Broadcast ( )
m . openStreamOrErrCond . Broadcast ( )
2018-01-20 18:07:01 +00:00
for _ , s := range m . streams {
s . closeForShutdown ( err )
2018-01-03 19:19:49 +00:00
}
}
2018-01-20 18:07:01 +00:00
// TODO(#952): this won't be needed when gQUIC supports stateless handshakes
func ( m * streamsMap ) UpdateLimits ( params * handshake . TransportParameters ) {
2018-01-03 19:19:49 +00:00
m . mutex . Lock ( )
2018-01-20 18:07:01 +00:00
for id , str := range m . streams {
str . handleMaxStreamDataFrame ( & wire . MaxStreamDataFrame {
StreamID : id ,
ByteOffset : params . StreamFlowControlWindow ,
} )
}
m . mutex . Unlock ( )
2018-01-03 19:19:49 +00:00
m . openStreamOrErrCond . Broadcast ( )
2017-12-12 02:51:45 +00:00
}