1package yamux 2 3import ( 4 "encoding/binary" 5 "fmt" 6) 7 8var ( 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 56const ( 57 // protoVersion is the only version we support 58 protoVersion uint8 = 0 59) 60 61const ( 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 81const ( 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 98const ( 99 // initialStreamWindow is the initial stream window size 100 initialStreamWindow uint32 = 256 * 1024 101) 102 103const ( 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 114const ( 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 124type header []byte 125 126func (h header) Version() uint8 { 127 return h[0] 128} 129 130func (h header) MsgType() uint8 { 131 return h[1] 132} 133 134func (h header) Flags() uint16 { 135 return binary.BigEndian.Uint16(h[2:4]) 136} 137 138func (h header) StreamID() uint32 { 139 return binary.BigEndian.Uint32(h[4:8]) 140} 141 142func (h header) Length() uint32 { 143 return binary.BigEndian.Uint32(h[8:12]) 144} 145 146func (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 151func (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} 158