Files
smux/frame.go
T
2016-09-03 21:21:58 +08:00

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())
}