merge develop into master #21
@ -5,14 +5,19 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Packet struct {
|
||||
type Packet interface {
|
||||
Marshal(generator MacGenerator) []byte
|
||||
Raw() []byte
|
||||
}
|
||||
|
||||
type SimplePacket struct {
|
||||
Data []byte
|
||||
timestamp time.Time
|
||||
}
|
||||
|
||||
// create a packet from the raw data of an IP packet
|
||||
func NewPacket(data []byte) Packet {
|
||||
return Packet{
|
||||
func NewSimplePacket(data []byte) Packet {
|
||||
return SimplePacket{
|
||||
Data: data,
|
||||
timestamp: time.Now(),
|
||||
}
|
||||
@ -25,10 +30,10 @@ func UnmarshalPacket(raw []byte, verifier MacVerifier) (Packet, error) {
|
||||
sum := raw[len(raw)-verifier.CodeLength():]
|
||||
|
||||
if err := verifier.Verify(data, sum); err != nil {
|
||||
return Packet{}, err
|
||||
return SimplePacket{}, err
|
||||
}
|
||||
|
||||
p := Packet{
|
||||
p := SimplePacket{
|
||||
Data: data[:len(data)-8],
|
||||
}
|
||||
|
||||
@ -39,12 +44,12 @@ func UnmarshalPacket(raw []byte, verifier MacVerifier) (Packet, error) {
|
||||
}
|
||||
|
||||
// get the raw data of the IP packet
|
||||
func (p Packet) Raw() []byte {
|
||||
func (p SimplePacket) Raw() []byte {
|
||||
return p.Data
|
||||
}
|
||||
|
||||
// produce the wrapped format of a packet
|
||||
func (p Packet) Marshal(generator MacGenerator) []byte {
|
||||
func (p SimplePacket) Marshal(generator MacGenerator) []byte {
|
||||
// length of data + length of timestamp (8 byte) + length of checksum
|
||||
slice := make([]byte, len(p.Data)+8+generator.CodeLength())
|
||||
|
||||
|
@ -121,13 +121,13 @@ func (f *InitiatedFlow) Produce(v proxy.MacVerifier) (proxy.Packet, error) {
|
||||
|
||||
func (f *Flow) Produce(v proxy.MacVerifier) (proxy.Packet, error) {
|
||||
if !f.isAlive {
|
||||
return proxy.Packet{}, shared.ErrDeadConnection
|
||||
return nil, shared.ErrDeadConnection
|
||||
}
|
||||
|
||||
data, err := f.produceMarshalled()
|
||||
if err != nil {
|
||||
f.isAlive = false
|
||||
return proxy.Packet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return proxy.UnmarshalPacket(data, v)
|
||||
|
@ -61,14 +61,14 @@ func (t *SourceSink) Source() (proxy.Packet, error) {
|
||||
|
||||
read, err := t.tun.Read(buf)
|
||||
if err != nil {
|
||||
return proxy.Packet{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if read == 0 {
|
||||
return proxy.Packet{}, io.EOF
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
return proxy.NewPacket(buf[:read]), nil
|
||||
return proxy.NewSimplePacket(buf[:read]), nil
|
||||
}
|
||||
|
||||
var good, bad float64
|
||||
|
11
udp/congestion.go
Normal file
11
udp/congestion.go
Normal file
@ -0,0 +1,11 @@
|
||||
package udp
|
||||
|
||||
type Congestion interface {
|
||||
Sequence() uint64
|
||||
|
||||
ReceivedAck(uint64)
|
||||
NextAck() uint64
|
||||
|
||||
ReceivedNack(uint64)
|
||||
NextNack() uint64
|
||||
}
|
58
udp/congestion/reno.go
Normal file
58
udp/congestion/reno.go
Normal file
@ -0,0 +1,58 @@
|
||||
package congestion
|
||||
|
||||
import "time"
|
||||
|
||||
type NewReno struct {
|
||||
sequence chan uint64
|
||||
packetTimes map[uint64]time.Time
|
||||
|
||||
nextAck uint64
|
||||
nextNack uint64
|
||||
|
||||
rtt float64
|
||||
}
|
||||
|
||||
func NewNewReno() *NewReno {
|
||||
c := NewReno{
|
||||
sequence: make(chan uint64),
|
||||
packetTimes: make(map[uint64]time.Time),
|
||||
}
|
||||
|
||||
go func() {
|
||||
var s uint64
|
||||
for {
|
||||
if s == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
c.sequence <- s
|
||||
s++
|
||||
}
|
||||
}()
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
// It is assumed that ReceivedAck will only be called by one thread
|
||||
func (c *NewReno) ReceivedAck(uint64) {
|
||||
|
||||
}
|
||||
|
||||
// It is assumed that ReceivedNack will only be called by one thread
|
||||
func (c *NewReno) ReceivedNack(uint64) {
|
||||
|
||||
}
|
||||
|
||||
func (c *NewReno) Sequence() uint64 {
|
||||
s := <-c.sequence
|
||||
c.packetTimes[s] = time.Now()
|
||||
return s
|
||||
}
|
||||
|
||||
func (c *NewReno) NextAck() uint64 {
|
||||
return c.nextAck
|
||||
}
|
||||
|
||||
func (c *NewReno) NextNack() uint64 {
|
||||
return c.nextNack
|
||||
}
|
57
udp/flow.go
Normal file
57
udp/flow.go
Normal file
@ -0,0 +1,57 @@
|
||||
package udp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"mpbl3p/proxy"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type PacketWriter interface {
|
||||
WriteToUDP(b []byte, addr *net.UDPAddr) (int, error)
|
||||
}
|
||||
|
||||
type PacketConn interface {
|
||||
PacketWriter
|
||||
ReadFromUDP(b []byte) (int, *net.UDPAddr, error)
|
||||
}
|
||||
|
||||
type Ack struct {
|
||||
time time.Time
|
||||
packet uint64
|
||||
|
||||
sent bool
|
||||
}
|
||||
|
||||
type Flow struct {
|
||||
writer PacketWriter
|
||||
raddr net.UDPAddr
|
||||
|
||||
isAlive bool
|
||||
congestion Congestion
|
||||
}
|
||||
|
||||
func (f *Flow) IsAlive() bool {
|
||||
return f.isAlive
|
||||
}
|
||||
|
||||
func (f *Flow) Consume(pp proxy.Packet, g proxy.MacGenerator) error {
|
||||
p := Packet{
|
||||
seq: f.congestion.Sequence(),
|
||||
data: pp,
|
||||
}
|
||||
|
||||
p.ack = f.congestion.NextAck()
|
||||
p.nack = f.congestion.NextNack()
|
||||
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (f *Flow) Produce(v proxy.MacVerifier) (proxy.Packet, error) {
|
||||
return proxy.Packet{}, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (f *Flow) handleDatagram(p []byte) {
|
||||
// TODO: Congestion control - read off the ACKs for the send half
|
||||
// TODO: Congestion control - schedule ACKs for this side
|
||||
}
|
77
udp/listener.go
Normal file
77
udp/listener.go
Normal file
@ -0,0 +1,77 @@
|
||||
package udp
|
||||
|
||||
import (
|
||||
"log"
|
||||
"mpbl3p/proxy"
|
||||
"net"
|
||||
)
|
||||
|
||||
type ComparableUdpAddress struct {
|
||||
IP [16]byte
|
||||
Port int
|
||||
Zone string
|
||||
}
|
||||
|
||||
func fromUdpAddress(address net.UDPAddr) ComparableUdpAddress {
|
||||
var ip [16]byte
|
||||
for i, b := range []byte(address.IP) {
|
||||
ip[i] = b
|
||||
}
|
||||
|
||||
return ComparableUdpAddress{
|
||||
IP: ip,
|
||||
Port: address.Port,
|
||||
Zone: address.Zone,
|
||||
}
|
||||
}
|
||||
|
||||
func NewListener(p *proxy.Proxy, local string, v proxy.MacVerifier) error {
|
||||
laddr, err := net.ResolveUDPAddr("udp", local)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pconn, err := net.ListenUDP("udp", laddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = pconn.SetWriteBuffer(0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
receivedConnections := make(map[ComparableUdpAddress]*Flow)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
buf := make([]byte, 1500)
|
||||
|
||||
_, addr, err := pconn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
raddr := fromUdpAddress(*addr)
|
||||
if f, exists := receivedConnections[raddr]; exists {
|
||||
f.handleDatagram(buf)
|
||||
continue
|
||||
}
|
||||
|
||||
f := Flow{
|
||||
writer: pconn,
|
||||
raddr: *addr,
|
||||
isAlive: true,
|
||||
}
|
||||
|
||||
receivedConnections[raddr] = &f
|
||||
|
||||
log.Printf("received new connection: %v\n", f)
|
||||
|
||||
p.AddConsumer(&f)
|
||||
p.AddProducer(&f, v)
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
11
udp/packet.go
Normal file
11
udp/packet.go
Normal file
@ -0,0 +1,11 @@
|
||||
package udp
|
||||
|
||||
import "mpbl3p/proxy"
|
||||
|
||||
type Packet struct {
|
||||
ack uint64
|
||||
nack uint64
|
||||
seq uint64
|
||||
|
||||
data proxy.Packet
|
||||
}
|
64
utils/heap.go
Normal file
64
utils/heap.go
Normal file
@ -0,0 +1,64 @@
|
||||
package utils
|
||||
|
||||
import "errors"
|
||||
|
||||
var ErrorEmptyHeap = errors.New("attempted to extract from empty heap")
|
||||
|
||||
// A MinHeap for Uint64
|
||||
type Uint64Heap struct {
|
||||
data []uint64
|
||||
}
|
||||
|
||||
func (h *Uint64Heap) swap(x, y int) {
|
||||
h.data[x] = h.data[x] ^ h.data[y]
|
||||
h.data[y] = h.data[y] ^ h.data[x]
|
||||
h.data[x] = h.data[x] ^ h.data[y]
|
||||
}
|
||||
|
||||
func (h *Uint64Heap) Insert(new uint64) uint64 {
|
||||
h.data = append(h.data, new)
|
||||
|
||||
child := len(h.data) - 1
|
||||
for child != 0 {
|
||||
parent := (child - 1) / 2
|
||||
if h.data[parent] > h.data[child] {
|
||||
h.swap(parent, child)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
child = parent
|
||||
}
|
||||
|
||||
return h.data[0]
|
||||
}
|
||||
|
||||
func (h *Uint64Heap) Extract() (uint64, error) {
|
||||
if len(h.data) == 0 {
|
||||
return 0, ErrorEmptyHeap
|
||||
}
|
||||
min := h.data[0]
|
||||
|
||||
h.data[0] = h.data[len(h.data)-1]
|
||||
h.data = h.data[:len(h.data)-1]
|
||||
|
||||
parent := 0
|
||||
for {
|
||||
left, right := parent*2+1, parent*2+2
|
||||
|
||||
if (left < len(h.data) && h.data[parent] > h.data[left]) || (right < len(h.data) && h.data[parent] > h.data[right]) {
|
||||
if right < len(h.data) && h.data[left] > h.data[right] {
|
||||
h.swap(parent, right)
|
||||
parent = right
|
||||
} else {
|
||||
h.swap(parent, left)
|
||||
parent = left
|
||||
}
|
||||
} else {
|
||||
return min, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Uint64Heap) Peek() uint64 {
|
||||
return h.data[0]
|
||||
}
|
54
utils/heap_test.go
Normal file
54
utils/heap_test.go
Normal file
@ -0,0 +1,54 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func SlowHeapSort(in []uint64) []uint64 {
|
||||
out := make([]uint64, len(in))
|
||||
|
||||
var heap Uint64Heap
|
||||
|
||||
for _, x := range in {
|
||||
heap.Insert(x)
|
||||
}
|
||||
for i := range out {
|
||||
var err error
|
||||
out[i], err = heap.Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func TestUint64Heap(t *testing.T) {
|
||||
t.Run("EquivalentToMerge", func(t *testing.T) {
|
||||
const ArrayLength = 50
|
||||
|
||||
sortedArray := make([]uint64, ArrayLength)
|
||||
array := make([]uint64, ArrayLength)
|
||||
|
||||
for i := range array {
|
||||
sortedArray[i] = uint64(i)
|
||||
array[i] = uint64(i)
|
||||
}
|
||||
|
||||
rand.Seed(time.Now().Unix())
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
rand.Shuffle(50, func(i, j int) { array[i], array[j] = array[j], array[i] })
|
||||
|
||||
heapSorted := SlowHeapSort(array)
|
||||
|
||||
assert.Equal(t, sortedArray, heapSorted)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package utils
|
||||
|
||||
var NextId = make(chan int)
|
||||
|
||||
func init() {
|
||||
go func() {
|
||||
i := 0
|
||||
for {
|
||||
NextId <- i
|
||||
i += 1
|
||||
}
|
||||
}()
|
||||
}
|
Loading…
Reference in New Issue
Block a user