mirror of
https://github.com/xtaci/smux.git
synced 2024-04-21 10:51:48 +00:00
99 lines
2.1 KiB
Go
99 lines
2.1 KiB
Go
package smux
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
)
|
|
|
|
const (
|
|
version = 1
|
|
)
|
|
|
|
const ( // cmds
|
|
cmdSYN byte = iota // stream open
|
|
cmdRST // stream close
|
|
cmdPSH // data push
|
|
cmdNOP // no operation
|
|
)
|
|
|
|
const (
|
|
sizeOfVer = 1
|
|
sizeOfCmd = 1
|
|
sizeOfLength = 2
|
|
sizeOfSid = 4
|
|
headerSize = sizeOfVer + sizeOfCmd + sizeOfSid + sizeOfLength
|
|
)
|
|
|
|
// Frame defines a packet from or to be multiplexed into a single connection
|
|
type Frame struct {
|
|
ver byte
|
|
cmd byte
|
|
sid uint32
|
|
data []byte
|
|
}
|
|
|
|
func newFrame(cmd byte, sid uint32) Frame {
|
|
return Frame{ver: version, cmd: cmd, sid: sid}
|
|
}
|
|
|
|
// MarshalBinary a frame to transmit
|
|
// VERSION(1B) | CMD(1B) | LENGTH(2B) | STREAMID(4B) | DATA |
|
|
func (f *Frame) MarshalBinary() ([]byte, error) {
|
|
buf := make([]byte, headerSize+len(f.data))
|
|
buf[0] = version
|
|
buf[1] = f.cmd
|
|
binary.LittleEndian.PutUint16(buf[2:], uint16(len(f.data)))
|
|
binary.LittleEndian.PutUint32(buf[4:], f.sid)
|
|
copy(buf[headerSize:], f.data)
|
|
return buf, nil
|
|
}
|
|
|
|
// UnmarshalBinary a byte slice into a frame
|
|
func (f *Frame) UnmarshalBinary(bts []byte) error {
|
|
f.ver = bts[0]
|
|
f.cmd = bts[1]
|
|
datalength := binary.LittleEndian.Uint16(bts[2:])
|
|
f.sid = binary.LittleEndian.Uint32(bts[4:])
|
|
if datalength > 0 {
|
|
f.data = make([]byte, datalength)
|
|
copy(f.data, bts[headerSize:])
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ZeroCopyUnmarshal a byte slice into a frame,
|
|
// and just reference to the input slice
|
|
func (f *Frame) ZeroCopyUnmarshal(bts []byte) error {
|
|
f.ver = bts[0]
|
|
f.cmd = bts[1]
|
|
datalength := binary.LittleEndian.Uint16(bts[2:])
|
|
f.sid = binary.LittleEndian.Uint32(bts[4:])
|
|
if datalength > 0 {
|
|
f.data = bts[headerSize:]
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type rawHeader []byte
|
|
|
|
func (h rawHeader) Version() byte {
|
|
return h[0]
|
|
}
|
|
|
|
func (h rawHeader) Cmd() byte {
|
|
return h[1]
|
|
}
|
|
|
|
func (h rawHeader) Length() uint16 {
|
|
return binary.LittleEndian.Uint16(h[2:])
|
|
}
|
|
|
|
func (h rawHeader) StreamID() uint32 {
|
|
return binary.LittleEndian.Uint32(h[4:])
|
|
}
|
|
|
|
func (h rawHeader) String() string {
|
|
return fmt.Sprintf("Version:%d Cmd:%d StreamID:%d Length:%d",
|
|
h.Version(), h.Cmd(), h.StreamID(), h.Length())
|
|
}
|