Juan Batiz-Benet 4d83cc616a vendor things
2014-11-20 00:54:41 -08:00

241 lines
4.5 KiB
Go

package utp
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"sync"
)
type header struct {
typ, ver int
id uint16
t, diff, wnd uint32
seq, ack uint16
}
type extension struct {
typ int
payload []byte
}
type packet struct {
header header
ext []extension
payload []byte
}
type outgoingPacket struct {
typ int
ext []extension
payload []byte
}
func (p *packet) MarshalBinary() ([]byte, error) {
firstExt := ext_none
if len(p.ext) > 0 {
firstExt = p.ext[0].typ
}
buf := new(bytes.Buffer)
var beforeExt = []interface{}{
// | type | ver |
uint8(((byte(p.header.typ) << 4) & 0xF0) | (byte(p.header.ver) & 0xF)),
// | extension |
uint8(firstExt),
}
var afterExt = []interface{}{
// | connection_id |
uint16(p.header.id),
// | timestamp_microseconds |
uint32(p.header.t),
// | timestamp_difference_microseconds |
uint32(p.header.diff),
// | wnd_size |
uint32(p.header.wnd),
// | seq_nr |
uint16(p.header.seq),
// | ack_nr |
uint16(p.header.ack),
}
for _, v := range beforeExt {
err := binary.Write(buf, binary.BigEndian, v)
if err != nil {
return nil, err
}
}
if len(p.ext) > 0 {
for i, e := range p.ext {
next := ext_none
if i < len(p.ext)-1 {
next = p.ext[i+1].typ
}
var ext = []interface{}{
// | extension |
uint8(next),
// | len |
uint8(len(e.payload)),
}
for _, v := range ext {
err := binary.Write(buf, binary.BigEndian, v)
if err != nil {
return nil, err
}
}
_, err := buf.Write(e.payload)
if err != nil {
return nil, err
}
}
}
for _, v := range afterExt {
err := binary.Write(buf, binary.BigEndian, v)
if err != nil {
return nil, err
}
}
_, err := buf.Write(p.payload)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func (p *packet) UnmarshalBinary(data []byte) error {
p.ext = nil
buf := bytes.NewReader(data)
var tv, e uint8
var beforeExt = []interface{}{
// | type | ver |
(*uint8)(&tv),
// | extension |
(*uint8)(&e),
}
for _, v := range beforeExt {
err := binary.Read(buf, binary.BigEndian, v)
if err != nil {
return err
}
}
for e != ext_none {
currentExt := int(e)
var l uint8
var ext = []interface{}{
// | extension |
(*uint8)(&e),
// | len |
(*uint8)(&l),
}
for _, v := range ext {
err := binary.Read(buf, binary.BigEndian, v)
if err != nil {
return err
}
}
payload := make([]byte, l)
size, err := buf.Read(payload[:])
if err != nil {
return err
}
if size != len(payload) {
return io.EOF
}
p.ext = append(p.ext, extension{typ: currentExt, payload: payload})
}
var afterExt = []interface{}{
// | connection_id |
(*uint16)(&p.header.id),
// | timestamp_microseconds |
(*uint32)(&p.header.t),
// | timestamp_difference_microseconds |
(*uint32)(&p.header.diff),
// | wnd_size |
(*uint32)(&p.header.wnd),
// | seq_nr |
(*uint16)(&p.header.seq),
// | ack_nr |
(*uint16)(&p.header.ack),
}
for _, v := range afterExt {
err := binary.Read(buf, binary.BigEndian, v)
if err != nil {
return err
}
}
p.header.typ = int((tv >> 4) & 0xF)
p.header.ver = int(tv & 0xF)
l := buf.Len()
if l > 0 {
p.payload = p.payload[:l]
_, err := buf.Read(p.payload[:])
if err != nil {
return err
}
}
return nil
}
func (p packet) String() string {
var s string = fmt.Sprintf("[%d ", p.header.id)
switch p.header.typ {
case st_data:
s += "ST_DATA"
case st_fin:
s += "ST_FIN"
case st_state:
s += "ST_STATE"
case st_reset:
s += "ST_RESET"
case st_syn:
s += "ST_SYN"
}
s += fmt.Sprintf(" seq:%d ack:%d len:%d", p.header.seq, p.header.ack, len(p.payload))
s += "]"
return s
}
var globalPool packetPool
type packetPool struct {
root *packetPoolNode
mutex sync.Mutex
}
type packetPoolNode struct {
p *packet
next *packetPoolNode
}
func (o *packetPool) get() *packet {
o.mutex.Lock()
defer o.mutex.Unlock()
r := o.root
if r != nil {
o.root = o.root.next
return r.p
} else {
return &packet{
payload: make([]byte, 0, mss),
}
}
}
func (o *packetPool) put(p *packet) {
o.mutex.Lock()
defer o.mutex.Unlock()
o.root = &packetPoolNode{
p: p,
next: o.root,
}
}