]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | package yamux |
2 | ||
3 | import ( | |
4 | "encoding/binary" | |
5 | "fmt" | |
6 | ) | |
7 | ||
8 | var ( | |
9 | // ErrInvalidVersion means we received a frame with an | |
10 | // invalid version | |
11 | ErrInvalidVersion = fmt.Errorf("invalid protocol version") | |
12 | ||
13 | // ErrInvalidMsgType means we received a frame with an | |
14 | // invalid message type | |
15 | ErrInvalidMsgType = fmt.Errorf("invalid msg type") | |
16 | ||
17 | // ErrSessionShutdown is used if there is a shutdown during | |
18 | // an operation | |
19 | ErrSessionShutdown = fmt.Errorf("session shutdown") | |
20 | ||
21 | // ErrStreamsExhausted is returned if we have no more | |
22 | // stream ids to issue | |
23 | ErrStreamsExhausted = fmt.Errorf("streams exhausted") | |
24 | ||
25 | // ErrDuplicateStream is used if a duplicate stream is | |
26 | // opened inbound | |
27 | ErrDuplicateStream = fmt.Errorf("duplicate stream initiated") | |
28 | ||
29 | // ErrReceiveWindowExceeded indicates the window was exceeded | |
30 | ErrRecvWindowExceeded = fmt.Errorf("recv window exceeded") | |
31 | ||
32 | // ErrTimeout is used when we reach an IO deadline | |
33 | ErrTimeout = fmt.Errorf("i/o deadline reached") | |
34 | ||
35 | // ErrStreamClosed is returned when using a closed stream | |
36 | ErrStreamClosed = fmt.Errorf("stream closed") | |
37 | ||
38 | // ErrUnexpectedFlag is set when we get an unexpected flag | |
39 | ErrUnexpectedFlag = fmt.Errorf("unexpected flag") | |
40 | ||
41 | // ErrRemoteGoAway is used when we get a go away from the other side | |
42 | ErrRemoteGoAway = fmt.Errorf("remote end is not accepting connections") | |
43 | ||
44 | // ErrConnectionReset is sent if a stream is reset. This can happen | |
45 | // if the backlog is exceeded, or if there was a remote GoAway. | |
46 | ErrConnectionReset = fmt.Errorf("connection reset") | |
47 | ||
48 | // ErrConnectionWriteTimeout indicates that we hit the "safety valve" | |
49 | // timeout writing to the underlying stream connection. | |
50 | ErrConnectionWriteTimeout = fmt.Errorf("connection write timeout") | |
51 | ||
52 | // ErrKeepAliveTimeout is sent if a missed keepalive caused the stream close | |
53 | ErrKeepAliveTimeout = fmt.Errorf("keepalive timeout") | |
54 | ) | |
55 | ||
56 | const ( | |
57 | // protoVersion is the only version we support | |
58 | protoVersion uint8 = 0 | |
59 | ) | |
60 | ||
61 | const ( | |
62 | // Data is used for data frames. They are followed | |
63 | // by length bytes worth of payload. | |
64 | typeData uint8 = iota | |
65 | ||
66 | // WindowUpdate is used to change the window of | |
67 | // a given stream. The length indicates the delta | |
68 | // update to the window. | |
69 | typeWindowUpdate | |
70 | ||
71 | // Ping is sent as a keep-alive or to measure | |
72 | // the RTT. The StreamID and Length value are echoed | |
73 | // back in the response. | |
74 | typePing | |
75 | ||
76 | // GoAway is sent to terminate a session. The StreamID | |
77 | // should be 0 and the length is an error code. | |
78 | typeGoAway | |
79 | ) | |
80 | ||
81 | const ( | |
82 | // SYN is sent to signal a new stream. May | |
83 | // be sent with a data payload | |
84 | flagSYN uint16 = 1 << iota | |
85 | ||
86 | // ACK is sent to acknowledge a new stream. May | |
87 | // be sent with a data payload | |
88 | flagACK | |
89 | ||
90 | // FIN is sent to half-close the given stream. | |
91 | // May be sent with a data payload. | |
92 | flagFIN | |
93 | ||
94 | // RST is used to hard close a given stream. | |
95 | flagRST | |
96 | ) | |
97 | ||
98 | const ( | |
99 | // initialStreamWindow is the initial stream window size | |
100 | initialStreamWindow uint32 = 256 * 1024 | |
101 | ) | |
102 | ||
103 | const ( | |
104 | // goAwayNormal is sent on a normal termination | |
105 | goAwayNormal uint32 = iota | |
106 | ||
107 | // goAwayProtoErr sent on a protocol error | |
108 | goAwayProtoErr | |
109 | ||
110 | // goAwayInternalErr sent on an internal error | |
111 | goAwayInternalErr | |
112 | ) | |
113 | ||
114 | const ( | |
115 | sizeOfVersion = 1 | |
116 | sizeOfType = 1 | |
117 | sizeOfFlags = 2 | |
118 | sizeOfStreamID = 4 | |
119 | sizeOfLength = 4 | |
120 | headerSize = sizeOfVersion + sizeOfType + sizeOfFlags + | |
121 | sizeOfStreamID + sizeOfLength | |
122 | ) | |
123 | ||
124 | type header []byte | |
125 | ||
126 | func (h header) Version() uint8 { | |
127 | return h[0] | |
128 | } | |
129 | ||
130 | func (h header) MsgType() uint8 { | |
131 | return h[1] | |
132 | } | |
133 | ||
134 | func (h header) Flags() uint16 { | |
135 | return binary.BigEndian.Uint16(h[2:4]) | |
136 | } | |
137 | ||
138 | func (h header) StreamID() uint32 { | |
139 | return binary.BigEndian.Uint32(h[4:8]) | |
140 | } | |
141 | ||
142 | func (h header) Length() uint32 { | |
143 | return binary.BigEndian.Uint32(h[8:12]) | |
144 | } | |
145 | ||
146 | func (h header) String() string { | |
147 | return fmt.Sprintf("Vsn:%d Type:%d Flags:%d StreamID:%d Length:%d", | |
148 | h.Version(), h.MsgType(), h.Flags(), h.StreamID(), h.Length()) | |
149 | } | |
150 | ||
151 | func (h header) encode(msgType uint8, flags uint16, streamID uint32, length uint32) { | |
152 | h[0] = protoVersion | |
153 | h[1] = msgType | |
154 | binary.BigEndian.PutUint16(h[2:4], flags) | |
155 | binary.BigEndian.PutUint32(h[4:8], streamID) | |
156 | binary.BigEndian.PutUint32(h[8:12], length) | |
157 | } |