github.com/ooni/psiphon/tunnel-core@v0.0.0-20230105123940-fe12a24c96ee/psiphon/common/quic/gquic-go/streams_map_incoming_uni.go (about) 1 // This file was automatically generated by genny. 2 // Any changes will be lost if this file is regenerated. 3 // see https://github.com/cheekybits/genny 4 5 package gquic 6 7 import ( 8 "fmt" 9 "sync" 10 11 "github.com/ooni/psiphon/tunnel-core/psiphon/common/quic/gquic-go/internal/protocol" 12 "github.com/ooni/psiphon/tunnel-core/psiphon/common/quic/gquic-go/internal/wire" 13 ) 14 15 type incomingUniStreamsMap struct { 16 mutex sync.RWMutex 17 cond sync.Cond 18 19 streams map[protocol.StreamID]receiveStreamI 20 21 nextStream protocol.StreamID // the next stream that will be returned by AcceptStream() 22 highestStream protocol.StreamID // the highest stream that the peer openend 23 maxStream protocol.StreamID // the highest stream that the peer is allowed to open 24 maxNumStreams int // maximum number of streams 25 26 newStream func(protocol.StreamID) receiveStreamI 27 queueMaxStreamID func(*wire.MaxStreamIDFrame) 28 29 closeErr error 30 } 31 32 func newIncomingUniStreamsMap( 33 nextStream protocol.StreamID, 34 initialMaxStreamID protocol.StreamID, 35 maxNumStreams int, 36 queueControlFrame func(wire.Frame), 37 newStream func(protocol.StreamID) receiveStreamI, 38 ) *incomingUniStreamsMap { 39 m := &incomingUniStreamsMap{ 40 streams: make(map[protocol.StreamID]receiveStreamI), 41 nextStream: nextStream, 42 maxStream: initialMaxStreamID, 43 maxNumStreams: maxNumStreams, 44 newStream: newStream, 45 queueMaxStreamID: func(f *wire.MaxStreamIDFrame) { queueControlFrame(f) }, 46 } 47 m.cond.L = &m.mutex 48 return m 49 } 50 51 func (m *incomingUniStreamsMap) AcceptStream() (receiveStreamI, error) { 52 m.mutex.Lock() 53 defer m.mutex.Unlock() 54 55 var str receiveStreamI 56 for { 57 var ok bool 58 if m.closeErr != nil { 59 return nil, m.closeErr 60 } 61 str, ok = m.streams[m.nextStream] 62 if ok { 63 break 64 } 65 m.cond.Wait() 66 } 67 m.nextStream += 4 68 return str, nil 69 } 70 71 func (m *incomingUniStreamsMap) GetOrOpenStream(id protocol.StreamID) (receiveStreamI, error) { 72 m.mutex.RLock() 73 if id > m.maxStream { 74 m.mutex.RUnlock() 75 return nil, fmt.Errorf("peer tried to open stream %d (current limit: %d)", id, m.maxStream) 76 } 77 // if the id is smaller than the highest we accepted 78 // * this stream exists in the map, and we can return it, or 79 // * this stream was already closed, then we can return the nil 80 if id <= m.highestStream { 81 s := m.streams[id] 82 m.mutex.RUnlock() 83 return s, nil 84 } 85 m.mutex.RUnlock() 86 87 m.mutex.Lock() 88 // no need to check the two error conditions from above again 89 // * maxStream can only increase, so if the id was valid before, it definitely is valid now 90 // * highestStream is only modified by this function 91 var start protocol.StreamID 92 if m.highestStream == 0 { 93 start = m.nextStream 94 } else { 95 start = m.highestStream + 4 96 } 97 for newID := start; newID <= id; newID += 4 { 98 m.streams[newID] = m.newStream(newID) 99 m.cond.Signal() 100 } 101 m.highestStream = id 102 s := m.streams[id] 103 m.mutex.Unlock() 104 return s, nil 105 } 106 107 func (m *incomingUniStreamsMap) DeleteStream(id protocol.StreamID) error { 108 m.mutex.Lock() 109 defer m.mutex.Unlock() 110 111 if _, ok := m.streams[id]; !ok { 112 return fmt.Errorf("Tried to delete unknown stream %d", id) 113 } 114 delete(m.streams, id) 115 // queue a MAX_STREAM_ID frame, giving the peer the option to open a new stream 116 if numNewStreams := m.maxNumStreams - len(m.streams); numNewStreams > 0 { 117 m.maxStream = m.highestStream + protocol.StreamID(numNewStreams*4) 118 m.queueMaxStreamID(&wire.MaxStreamIDFrame{StreamID: m.maxStream}) 119 } 120 return nil 121 } 122 123 func (m *incomingUniStreamsMap) CloseWithError(err error) { 124 m.mutex.Lock() 125 m.closeErr = err 126 for _, str := range m.streams { 127 str.closeForShutdown(err) 128 } 129 m.mutex.Unlock() 130 m.cond.Broadcast() 131 }