1
2
3
4
5 package http3
6
7 import (
8 "context"
9 "io"
10 "sync"
11
12 "golang.org/x/net/quic"
13 )
14
15 type streamHandler interface {
16 handleControlStream(*stream) error
17 handlePushStream(*stream) error
18 handleEncoderStream(*stream) error
19 handleDecoderStream(*stream) error
20 handleRequestStream(*stream) error
21 abort(error)
22 }
23
24 type genericConn struct {
25 mu sync.Mutex
26
27
28
29
30 streamsCreated uint8
31 }
32
33 func (c *genericConn) acceptStreams(qconn *quic.Conn, h streamHandler) {
34 for {
35
36
37 st, err := qconn.AcceptStream(context.Background())
38 if err != nil {
39 return
40 }
41 if st.IsReadOnly() {
42 go c.handleUnidirectionalStream(newStream(st), h)
43 } else {
44 go c.handleRequestStream(newStream(st), h)
45 }
46 }
47 }
48
49 func (c *genericConn) handleUnidirectionalStream(st *stream, h streamHandler) {
50
51 v, err := st.readVarint()
52 if err != nil {
53 h.abort(&connectionError{
54 code: errH3StreamCreationError,
55 message: "error reading unidirectional stream header",
56 })
57 return
58 }
59 stype := streamType(v)
60 if err := c.checkStreamCreation(stype); err != nil {
61 h.abort(err)
62 return
63 }
64 switch stype {
65 case streamTypeControl:
66 err = h.handleControlStream(st)
67 case streamTypePush:
68 err = h.handlePushStream(st)
69 case streamTypeEncoder:
70 err = h.handleEncoderStream(st)
71 case streamTypeDecoder:
72 err = h.handleDecoderStream(st)
73 default:
74
75
76
77 err = &streamError{
78 code: errH3StreamCreationError,
79 message: "unknown stream type",
80 }
81 }
82 if err == io.EOF {
83 err = &connectionError{
84 code: errH3ClosedCriticalStream,
85 message: streamType(stype).String() + " stream closed",
86 }
87 }
88 c.handleStreamError(st, h, err)
89 }
90
91 func (c *genericConn) handleRequestStream(st *stream, h streamHandler) {
92 c.handleStreamError(st, h, h.handleRequestStream(st))
93 }
94
95 func (c *genericConn) handleStreamError(st *stream, h streamHandler, err error) {
96 switch err := err.(type) {
97 case *connectionError:
98 h.abort(err)
99 case nil:
100 st.CloseRead(uint64(errH3NoError))
101 st.CloseWrite()
102 case *streamError:
103 st.CloseRead(uint64(err.code))
104 st.Reset(uint64(err.code))
105 default:
106 st.CloseRead(uint64(errH3InternalError))
107 st.Reset(uint64(errH3InternalError))
108 }
109 }
110
111 func (c *genericConn) checkStreamCreation(stype streamType) error {
112 switch stype {
113 case streamTypeControl, streamTypeEncoder, streamTypeDecoder:
114
115 default:
116 return nil
117 }
118 c.mu.Lock()
119 defer c.mu.Unlock()
120 bit := uint8(1) << stype
121 if c.streamsCreated&bit != 0 {
122 return &connectionError{
123 code: errH3StreamCreationError,
124 message: "multiple " + stype.String() + " streams created",
125 }
126 }
127 c.streamsCreated |= bit
128 return nil
129 }
130
View as plain text