mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-25 23:01:38 +00:00
Merge pull request #1 from neilalexander/master
Add support for tun ifname on Linux, run gofmt
This commit is contained in:
commit
b76fcbb402
@ -20,58 +20,67 @@ import . "yggdrasil"
|
|||||||
var doSig = flag.Bool("sig", false, "generate new signing keys instead")
|
var doSig = flag.Bool("sig", false, "generate new signing keys instead")
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
switch {
|
switch {
|
||||||
case *doSig: doSigKeys()
|
case *doSig:
|
||||||
default: doBoxKeys()
|
doSigKeys()
|
||||||
}
|
default:
|
||||||
|
doBoxKeys()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isBetter(oldID, newID []byte) bool {
|
func isBetter(oldID, newID []byte) bool {
|
||||||
for idx := range oldID {
|
for idx := range oldID {
|
||||||
if newID[idx] > oldID[idx] { return true }
|
if newID[idx] > oldID[idx] {
|
||||||
if newID[idx] < oldID[idx] { return false }
|
return true
|
||||||
}
|
}
|
||||||
return false
|
if newID[idx] < oldID[idx] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func doBoxKeys() {
|
func doBoxKeys() {
|
||||||
c := Core{}
|
c := Core{}
|
||||||
pub, _ := c.DEBUG_newBoxKeys()
|
pub, _ := c.DEBUG_newBoxKeys()
|
||||||
bestID := c.DEBUG_getNodeID(pub)
|
bestID := c.DEBUG_getNodeID(pub)
|
||||||
for idx := range bestID {
|
for idx := range bestID {
|
||||||
bestID[idx] = 0
|
bestID[idx] = 0
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
pub, priv := c.DEBUG_newBoxKeys()
|
pub, priv := c.DEBUG_newBoxKeys()
|
||||||
id := c.DEBUG_getNodeID(pub)
|
id := c.DEBUG_getNodeID(pub)
|
||||||
if !isBetter(bestID[:], id[:]) { continue }
|
if !isBetter(bestID[:], id[:]) {
|
||||||
bestID = id
|
continue
|
||||||
ip := c.DEBUG_addrForNodeID(id)
|
}
|
||||||
fmt.Println("--------------------------------------------------------------------------------")
|
bestID = id
|
||||||
fmt.Println("boxPriv:", hex.EncodeToString(priv[:]))
|
ip := c.DEBUG_addrForNodeID(id)
|
||||||
fmt.Println("boxPub:", hex.EncodeToString(pub[:]))
|
fmt.Println("--------------------------------------------------------------------------------")
|
||||||
fmt.Println("NodeID:", hex.EncodeToString(id[:]))
|
fmt.Println("boxPriv:", hex.EncodeToString(priv[:]))
|
||||||
fmt.Println("IP:", ip)
|
fmt.Println("boxPub:", hex.EncodeToString(pub[:]))
|
||||||
}
|
fmt.Println("NodeID:", hex.EncodeToString(id[:]))
|
||||||
|
fmt.Println("IP:", ip)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func doSigKeys() {
|
func doSigKeys() {
|
||||||
c := Core{}
|
c := Core{}
|
||||||
pub, _ := c.DEBUG_newSigKeys()
|
pub, _ := c.DEBUG_newSigKeys()
|
||||||
bestID := c.DEBUG_getTreeID(pub)
|
bestID := c.DEBUG_getTreeID(pub)
|
||||||
for idx := range bestID {
|
for idx := range bestID {
|
||||||
bestID[idx] = 0
|
bestID[idx] = 0
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
pub, priv := c.DEBUG_newSigKeys()
|
pub, priv := c.DEBUG_newSigKeys()
|
||||||
id := c.DEBUG_getTreeID(pub)
|
id := c.DEBUG_getTreeID(pub)
|
||||||
if !isBetter(bestID[:], id[:]) { continue }
|
if !isBetter(bestID[:], id[:]) {
|
||||||
bestID = id
|
continue
|
||||||
fmt.Println("--------------------------------------------------------------------------------")
|
}
|
||||||
fmt.Println("sigPriv:", hex.EncodeToString(priv[:]))
|
bestID = id
|
||||||
fmt.Println("sigPub:", hex.EncodeToString(pub[:]))
|
fmt.Println("--------------------------------------------------------------------------------")
|
||||||
fmt.Println("TreeID:", hex.EncodeToString(id[:]))
|
fmt.Println("sigPriv:", hex.EncodeToString(priv[:]))
|
||||||
}
|
fmt.Println("sigPub:", hex.EncodeToString(pub[:]))
|
||||||
|
fmt.Println("TreeID:", hex.EncodeToString(id[:]))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,153 +15,157 @@ import "router"
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
nodeID router.NodeID
|
nodeID router.NodeID
|
||||||
table router.Table
|
table router.Table
|
||||||
links []*Node
|
links []*Node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) init(nodeID router.NodeID) {
|
func (n *Node) init(nodeID router.NodeID) {
|
||||||
n.nodeID = nodeID
|
n.nodeID = nodeID
|
||||||
n.table.Init(nodeID)
|
n.table.Init(nodeID)
|
||||||
n.links = append(n.links, n)
|
n.links = append(n.links, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func linkNodes(m, n *Node) {
|
func linkNodes(m, n *Node) {
|
||||||
for _, o := range m.links {
|
for _, o := range m.links {
|
||||||
if o.nodeID == n.nodeID {
|
if o.nodeID == n.nodeID {
|
||||||
// Don't allow duplicates
|
// Don't allow duplicates
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.links = append(m.links, n)
|
m.links = append(m.links, n)
|
||||||
n.links = append(n.links, m)
|
n.links = append(n.links, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeStoreSquareGrid(sideLength int) map[router.NodeID]*Node {
|
func makeStoreSquareGrid(sideLength int) map[router.NodeID]*Node {
|
||||||
store := make(map[router.NodeID]*Node)
|
store := make(map[router.NodeID]*Node)
|
||||||
nNodes := sideLength*sideLength
|
nNodes := sideLength * sideLength
|
||||||
nodeIDs := make([]router.NodeID, 0, nNodes)
|
nodeIDs := make([]router.NodeID, 0, nNodes)
|
||||||
// TODO shuffle nodeIDs
|
// TODO shuffle nodeIDs
|
||||||
for nodeID := 1 ; nodeID <= nNodes ; nodeID++ {
|
for nodeID := 1; nodeID <= nNodes; nodeID++ {
|
||||||
nodeIDs = append(nodeIDs, router.NodeID(nodeID))
|
nodeIDs = append(nodeIDs, router.NodeID(nodeID))
|
||||||
}
|
}
|
||||||
for _, nodeID := range nodeIDs {
|
for _, nodeID := range nodeIDs {
|
||||||
node := &Node{}
|
node := &Node{}
|
||||||
node.init(nodeID)
|
node.init(nodeID)
|
||||||
store[nodeID] = node
|
store[nodeID] = node
|
||||||
}
|
}
|
||||||
for idx := 0 ; idx < nNodes ; idx++ {
|
for idx := 0; idx < nNodes; idx++ {
|
||||||
if (idx % sideLength) != 0 {
|
if (idx % sideLength) != 0 {
|
||||||
linkNodes(store[nodeIDs[idx]], store[nodeIDs[idx-1]])
|
linkNodes(store[nodeIDs[idx]], store[nodeIDs[idx-1]])
|
||||||
}
|
}
|
||||||
if idx >= sideLength {
|
if idx >= sideLength {
|
||||||
linkNodes(store[nodeIDs[idx]], store[nodeIDs[idx-sideLength]])
|
linkNodes(store[nodeIDs[idx]], store[nodeIDs[idx-sideLength]])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return store
|
return store
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadGraph(path string) map[router.NodeID]*Node {
|
func loadGraph(path string) map[router.NodeID]*Node {
|
||||||
f, err := os.Open(path)
|
f, err := os.Open(path)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
defer f.Close()
|
panic(err)
|
||||||
store := make(map[router.NodeID]*Node)
|
}
|
||||||
s := bufio.NewScanner(f)
|
defer f.Close()
|
||||||
for s.Scan() {
|
store := make(map[router.NodeID]*Node)
|
||||||
line := s.Text()
|
s := bufio.NewScanner(f)
|
||||||
nodeIDstrs := strings.Split(line, " ")
|
for s.Scan() {
|
||||||
nodeIDi0, _ := strconv.Atoi(nodeIDstrs[0])
|
line := s.Text()
|
||||||
nodeIDi1, _ := strconv.Atoi(nodeIDstrs[1])
|
nodeIDstrs := strings.Split(line, " ")
|
||||||
nodeID0 := router.NodeID(nodeIDi0)
|
nodeIDi0, _ := strconv.Atoi(nodeIDstrs[0])
|
||||||
nodeID1 := router.NodeID(nodeIDi1)
|
nodeIDi1, _ := strconv.Atoi(nodeIDstrs[1])
|
||||||
if store[nodeID0] == nil {
|
nodeID0 := router.NodeID(nodeIDi0)
|
||||||
node := &Node{}
|
nodeID1 := router.NodeID(nodeIDi1)
|
||||||
node.init(nodeID0)
|
if store[nodeID0] == nil {
|
||||||
store[nodeID0] = node
|
node := &Node{}
|
||||||
}
|
node.init(nodeID0)
|
||||||
if store[nodeID1] == nil {
|
store[nodeID0] = node
|
||||||
node := &Node{}
|
}
|
||||||
node.init(nodeID1)
|
if store[nodeID1] == nil {
|
||||||
store[nodeID1] = node
|
node := &Node{}
|
||||||
}
|
node.init(nodeID1)
|
||||||
linkNodes(store[nodeID0], store[nodeID1])
|
store[nodeID1] = node
|
||||||
}
|
}
|
||||||
return store
|
linkNodes(store[nodeID0], store[nodeID1])
|
||||||
|
}
|
||||||
|
return store
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
func idleUntilConverged(store map[router.NodeID]*Node) {
|
func idleUntilConverged(store map[router.NodeID]*Node) {
|
||||||
timeOfLastChange := 0
|
timeOfLastChange := 0
|
||||||
step := 0
|
step := 0
|
||||||
// Idle untl the network has converged
|
// Idle untl the network has converged
|
||||||
for step - timeOfLastChange < 4*router.TIMEOUT {
|
for step-timeOfLastChange < 4*router.TIMEOUT {
|
||||||
step++
|
step++
|
||||||
fmt.Println("Step:", step, "--", "last change:", timeOfLastChange)
|
fmt.Println("Step:", step, "--", "last change:", timeOfLastChange)
|
||||||
for _, node := range store {
|
for _, node := range store {
|
||||||
node.table.Tick()
|
node.table.Tick()
|
||||||
for idx, link := range node.links[1:] {
|
for idx, link := range node.links[1:] {
|
||||||
msg := node.table.CreateMessage(router.Iface(idx))
|
msg := node.table.CreateMessage(router.Iface(idx))
|
||||||
for idx, fromNode := range link.links {
|
for idx, fromNode := range link.links {
|
||||||
if fromNode == node {
|
if fromNode == node {
|
||||||
//fmt.Println("Sending from node", node.nodeID, "to", link.nodeID)
|
//fmt.Println("Sending from node", node.nodeID, "to", link.nodeID)
|
||||||
link.table.HandleMessage(msg, router.Iface(idx))
|
link.table.HandleMessage(msg, router.Iface(idx))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//for _, node := range store {
|
//for _, node := range store {
|
||||||
// if node.table.DEBUG_isDirty() { timeOfLastChange = step }
|
// if node.table.DEBUG_isDirty() { timeOfLastChange = step }
|
||||||
//}
|
//}
|
||||||
//time.Sleep(10*time.Millisecond)
|
//time.Sleep(10*time.Millisecond)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPaths(store map[router.NodeID]*Node) {
|
func testPaths(store map[router.NodeID]*Node) {
|
||||||
nNodes := len(store)
|
nNodes := len(store)
|
||||||
nodeIDs := make([]router.NodeID, 0, nNodes)
|
nodeIDs := make([]router.NodeID, 0, nNodes)
|
||||||
for nodeID := range store {
|
for nodeID := range store {
|
||||||
nodeIDs = append(nodeIDs, nodeID)
|
nodeIDs = append(nodeIDs, nodeID)
|
||||||
}
|
}
|
||||||
lookups := 0
|
lookups := 0
|
||||||
count := 0
|
count := 0
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
for _, source := range store {
|
for _, source := range store {
|
||||||
count++
|
count++
|
||||||
fmt.Printf("Testing paths from node %d / %d (%d)\n", count, nNodes, source.nodeID)
|
fmt.Printf("Testing paths from node %d / %d (%d)\n", count, nNodes, source.nodeID)
|
||||||
for _, dest := range store {
|
for _, dest := range store {
|
||||||
//if source == dest { continue }
|
//if source == dest { continue }
|
||||||
destLoc := dest.table.GetLocator()
|
destLoc := dest.table.GetLocator()
|
||||||
temp := 0
|
temp := 0
|
||||||
for here := source ; here != dest ; {
|
for here := source; here != dest; {
|
||||||
temp++
|
temp++
|
||||||
if temp > 16 { panic("Loop?") }
|
if temp > 16 {
|
||||||
next := here.links[here.table.Lookup(destLoc)]
|
panic("Loop?")
|
||||||
if next == here {
|
}
|
||||||
//for idx, link := range here.links {
|
next := here.links[here.table.Lookup(destLoc)]
|
||||||
// fmt.Println("DUMP:", idx, link.nodeID)
|
if next == here {
|
||||||
//}
|
//for idx, link := range here.links {
|
||||||
panic(fmt.Sprintln("Routing Loop:",
|
// fmt.Println("DUMP:", idx, link.nodeID)
|
||||||
source.nodeID,
|
//}
|
||||||
here.nodeID,
|
panic(fmt.Sprintln("Routing Loop:",
|
||||||
dest.nodeID))
|
source.nodeID,
|
||||||
}
|
here.nodeID,
|
||||||
//fmt.Println("DEBUG:", source.nodeID, here.nodeID, dest.nodeID)
|
dest.nodeID))
|
||||||
here = next
|
}
|
||||||
lookups++
|
//fmt.Println("DEBUG:", source.nodeID, here.nodeID, dest.nodeID)
|
||||||
}
|
here = next
|
||||||
}
|
lookups++
|
||||||
}
|
}
|
||||||
timed := time.Since(start)
|
}
|
||||||
fmt.Printf("%f lookups per second\n", float64(lookups)/timed.Seconds())
|
}
|
||||||
|
timed := time.Since(start)
|
||||||
|
fmt.Printf("%f lookups per second\n", float64(lookups)/timed.Seconds())
|
||||||
}
|
}
|
||||||
|
|
||||||
func dumpStore(store map[router.NodeID]*Node) {
|
func dumpStore(store map[router.NodeID]*Node) {
|
||||||
for _, node := range store {
|
for _, node := range store {
|
||||||
fmt.Println("DUMPSTORE:", node.nodeID, node.table.GetLocator())
|
fmt.Println("DUMPSTORE:", node.nodeID, node.table.GetLocator())
|
||||||
node.table.DEBUG_dumpTable()
|
node.table.DEBUG_dumpTable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -169,25 +173,25 @@ func dumpStore(store map[router.NodeID]*Node) {
|
|||||||
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if *cpuprofile != "" {
|
if *cpuprofile != "" {
|
||||||
f, err := os.Create(*cpuprofile)
|
f, err := os.Create(*cpuprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
||||||
}
|
}
|
||||||
if err := pprof.StartCPUProfile(f); err != nil {
|
if err := pprof.StartCPUProfile(f); err != nil {
|
||||||
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
||||||
}
|
}
|
||||||
defer pprof.StopCPUProfile()
|
defer pprof.StopCPUProfile()
|
||||||
}
|
}
|
||||||
fmt.Println("Test")
|
fmt.Println("Test")
|
||||||
store := makeStoreSquareGrid(4)
|
store := makeStoreSquareGrid(4)
|
||||||
idleUntilConverged(store)
|
idleUntilConverged(store)
|
||||||
dumpStore(store)
|
dumpStore(store)
|
||||||
testPaths(store)
|
testPaths(store)
|
||||||
//panic("DYING")
|
//panic("DYING")
|
||||||
store = loadGraph("hype-2016-09-19.list")
|
store = loadGraph("hype-2016-09-19.list")
|
||||||
idleUntilConverged(store)
|
idleUntilConverged(store)
|
||||||
dumpStore(store)
|
dumpStore(store)
|
||||||
testPaths(store)
|
testPaths(store)
|
||||||
}
|
}
|
||||||
|
@ -15,347 +15,366 @@ import . "yggdrasil"
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
index int
|
index int
|
||||||
core Core
|
core Core
|
||||||
send chan<- []byte
|
send chan<- []byte
|
||||||
recv <-chan []byte
|
recv <-chan []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) init(index int) {
|
func (n *Node) init(index int) {
|
||||||
n.index = index
|
n.index = index
|
||||||
n.core.Init()
|
n.core.Init()
|
||||||
n.send = n.core.DEBUG_getSend()
|
n.send = n.core.DEBUG_getSend()
|
||||||
n.recv = n.core.DEBUG_getRecv()
|
n.recv = n.core.DEBUG_getRecv()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) printTraffic() {
|
func (n *Node) printTraffic() {
|
||||||
for {
|
for {
|
||||||
packet := <-n.recv
|
packet := <-n.recv
|
||||||
fmt.Println(n.index, packet)
|
fmt.Println(n.index, packet)
|
||||||
//panic("Got a packet")
|
//panic("Got a packet")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) startPeers() {
|
func (n *Node) startPeers() {
|
||||||
//for _, p := range n.core.Peers.Ports {
|
//for _, p := range n.core.Peers.Ports {
|
||||||
// go p.MainLoop()
|
// go p.MainLoop()
|
||||||
//}
|
//}
|
||||||
//go n.printTraffic()
|
//go n.printTraffic()
|
||||||
//n.core.Peers.DEBUG_startPeers()
|
//n.core.Peers.DEBUG_startPeers()
|
||||||
}
|
}
|
||||||
|
|
||||||
func linkNodes(m, n *Node) {
|
func linkNodes(m, n *Node) {
|
||||||
// Don't allow duplicates
|
// Don't allow duplicates
|
||||||
if m.core.DEBUG_getPeers().DEBUG_hasPeer(n.core.DEBUG_getSigPub()) { return }
|
if m.core.DEBUG_getPeers().DEBUG_hasPeer(n.core.DEBUG_getSigPub()) {
|
||||||
// Create peers
|
return
|
||||||
// Buffering reduces packet loss in the sim
|
}
|
||||||
// This slightly speeds up testing (fewer delays before retrying a ping)
|
// Create peers
|
||||||
p := m.core.DEBUG_getPeers().DEBUG_newPeer(n.core.DEBUG_getBoxPub(),
|
// Buffering reduces packet loss in the sim
|
||||||
n.core.DEBUG_getSigPub())
|
// This slightly speeds up testing (fewer delays before retrying a ping)
|
||||||
q := n.core.DEBUG_getPeers().DEBUG_newPeer(m.core.DEBUG_getBoxPub(),
|
p := m.core.DEBUG_getPeers().DEBUG_newPeer(n.core.DEBUG_getBoxPub(),
|
||||||
m.core.DEBUG_getSigPub())
|
n.core.DEBUG_getSigPub())
|
||||||
DEBUG_simLinkPeers(p, q)
|
q := n.core.DEBUG_getPeers().DEBUG_newPeer(m.core.DEBUG_getBoxPub(),
|
||||||
return
|
m.core.DEBUG_getSigPub())
|
||||||
|
DEBUG_simLinkPeers(p, q)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeStoreSquareGrid(sideLength int) map[int]*Node {
|
func makeStoreSquareGrid(sideLength int) map[int]*Node {
|
||||||
store := make(map[int]*Node)
|
store := make(map[int]*Node)
|
||||||
nNodes := sideLength*sideLength
|
nNodes := sideLength * sideLength
|
||||||
idxs := make([]int, 0, nNodes)
|
idxs := make([]int, 0, nNodes)
|
||||||
// TODO shuffle nodeIDs
|
// TODO shuffle nodeIDs
|
||||||
for idx := 1 ; idx <= nNodes ; idx++ {
|
for idx := 1; idx <= nNodes; idx++ {
|
||||||
idxs = append(idxs, idx)
|
idxs = append(idxs, idx)
|
||||||
}
|
}
|
||||||
for _, idx := range idxs {
|
for _, idx := range idxs {
|
||||||
node := &Node{}
|
node := &Node{}
|
||||||
node.init(idx)
|
node.init(idx)
|
||||||
store[idx] = node
|
store[idx] = node
|
||||||
}
|
}
|
||||||
for idx := 0 ; idx < nNodes ; idx++ {
|
for idx := 0; idx < nNodes; idx++ {
|
||||||
if (idx % sideLength) != 0 {
|
if (idx % sideLength) != 0 {
|
||||||
linkNodes(store[idxs[idx]], store[idxs[idx-1]])
|
linkNodes(store[idxs[idx]], store[idxs[idx-1]])
|
||||||
}
|
}
|
||||||
if idx >= sideLength {
|
if idx >= sideLength {
|
||||||
linkNodes(store[idxs[idx]], store[idxs[idx-sideLength]])
|
linkNodes(store[idxs[idx]], store[idxs[idx-sideLength]])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//for _, node := range store { node.initPorts() }
|
//for _, node := range store { node.initPorts() }
|
||||||
return store
|
return store
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeStoreStar(nNodes int) map[int]*Node {
|
func makeStoreStar(nNodes int) map[int]*Node {
|
||||||
store := make(map[int]*Node)
|
store := make(map[int]*Node)
|
||||||
center := &Node{}
|
center := &Node{}
|
||||||
center.init(0)
|
center.init(0)
|
||||||
store[0] = center
|
store[0] = center
|
||||||
for idx := 1 ; idx < nNodes ; idx++ {
|
for idx := 1; idx < nNodes; idx++ {
|
||||||
node := &Node{}
|
node := &Node{}
|
||||||
node.init(idx)
|
node.init(idx)
|
||||||
store[idx] = node
|
store[idx] = node
|
||||||
linkNodes(center, node)
|
linkNodes(center, node)
|
||||||
}
|
}
|
||||||
return store
|
return store
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadGraph(path string) map[int]*Node {
|
func loadGraph(path string) map[int]*Node {
|
||||||
f, err := os.Open(path)
|
f, err := os.Open(path)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
defer f.Close()
|
panic(err)
|
||||||
store := make(map[int]*Node)
|
}
|
||||||
s := bufio.NewScanner(f)
|
defer f.Close()
|
||||||
for s.Scan() {
|
store := make(map[int]*Node)
|
||||||
line := s.Text()
|
s := bufio.NewScanner(f)
|
||||||
nodeIdxstrs := strings.Split(line, " ")
|
for s.Scan() {
|
||||||
nodeIdx0, _ := strconv.Atoi(nodeIdxstrs[0])
|
line := s.Text()
|
||||||
nodeIdx1, _ := strconv.Atoi(nodeIdxstrs[1])
|
nodeIdxstrs := strings.Split(line, " ")
|
||||||
if store[nodeIdx0] == nil {
|
nodeIdx0, _ := strconv.Atoi(nodeIdxstrs[0])
|
||||||
node := &Node{}
|
nodeIdx1, _ := strconv.Atoi(nodeIdxstrs[1])
|
||||||
node.init(nodeIdx0)
|
if store[nodeIdx0] == nil {
|
||||||
store[nodeIdx0] = node
|
node := &Node{}
|
||||||
}
|
node.init(nodeIdx0)
|
||||||
if store[nodeIdx1] == nil {
|
store[nodeIdx0] = node
|
||||||
node := &Node{}
|
}
|
||||||
node.init(nodeIdx1)
|
if store[nodeIdx1] == nil {
|
||||||
store[nodeIdx1] = node
|
node := &Node{}
|
||||||
}
|
node.init(nodeIdx1)
|
||||||
linkNodes(store[nodeIdx0], store[nodeIdx1])
|
store[nodeIdx1] = node
|
||||||
}
|
}
|
||||||
//for _, node := range store { node.initPorts() }
|
linkNodes(store[nodeIdx0], store[nodeIdx1])
|
||||||
return store
|
}
|
||||||
|
//for _, node := range store { node.initPorts() }
|
||||||
|
return store
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
func startNetwork(store map[[32]byte]*Node) {
|
func startNetwork(store map[[32]byte]*Node) {
|
||||||
for _, node := range store {
|
for _, node := range store {
|
||||||
node.startPeers()
|
node.startPeers()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getKeyedStore(store map[int]*Node) map[[32]byte]*Node {
|
func getKeyedStore(store map[int]*Node) map[[32]byte]*Node {
|
||||||
newStore := make(map[[32]byte]*Node)
|
newStore := make(map[[32]byte]*Node)
|
||||||
for _, node := range store {
|
for _, node := range store {
|
||||||
newStore[node.core.DEBUG_getSigPub()] = node
|
newStore[node.core.DEBUG_getSigPub()] = node
|
||||||
}
|
}
|
||||||
return newStore
|
return newStore
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPaths(store map[[32]byte]*Node) bool {
|
func testPaths(store map[[32]byte]*Node) bool {
|
||||||
nNodes := len(store)
|
nNodes := len(store)
|
||||||
count := 0
|
count := 0
|
||||||
for _, source := range store {
|
for _, source := range store {
|
||||||
count++
|
count++
|
||||||
fmt.Printf("Testing paths from node %d / %d (%d)\n", count, nNodes, source.index)
|
fmt.Printf("Testing paths from node %d / %d (%d)\n", count, nNodes, source.index)
|
||||||
for _, dest := range store {
|
for _, dest := range store {
|
||||||
//if source == dest { continue }
|
//if source == dest { continue }
|
||||||
destLoc := dest.core.DEBUG_getLocator()
|
destLoc := dest.core.DEBUG_getLocator()
|
||||||
coords := destLoc.DEBUG_getCoords()
|
coords := destLoc.DEBUG_getCoords()
|
||||||
temp := 0
|
temp := 0
|
||||||
ttl := ^uint64(0)
|
ttl := ^uint64(0)
|
||||||
oldTTL := ttl
|
oldTTL := ttl
|
||||||
for here := source ; here != dest ; {
|
for here := source; here != dest; {
|
||||||
if ttl == 0 {
|
if ttl == 0 {
|
||||||
fmt.Println("Drop:", source.index, here.index, dest.index, oldTTL)
|
fmt.Println("Drop:", source.index, here.index, dest.index, oldTTL)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
temp++
|
temp++
|
||||||
if temp > 4096 { panic("Loop?") }
|
if temp > 4096 {
|
||||||
oldTTL = ttl
|
panic("Loop?")
|
||||||
nextPort, newTTL := here.core.DEBUG_switchLookup(coords, ttl)
|
}
|
||||||
ttl = newTTL
|
oldTTL = ttl
|
||||||
// First check if "here" is accepting packets from the previous node
|
nextPort, newTTL := here.core.DEBUG_switchLookup(coords, ttl)
|
||||||
// TODO explain how this works
|
ttl = newTTL
|
||||||
ports := here.core.DEBUG_getPeers().DEBUG_getPorts()
|
// First check if "here" is accepting packets from the previous node
|
||||||
nextPeer := ports[nextPort]
|
// TODO explain how this works
|
||||||
if nextPeer == nil {
|
ports := here.core.DEBUG_getPeers().DEBUG_getPorts()
|
||||||
fmt.Println("Peer associated with next port is nil")
|
nextPeer := ports[nextPort]
|
||||||
return false
|
if nextPeer == nil {
|
||||||
}
|
fmt.Println("Peer associated with next port is nil")
|
||||||
next := store[nextPeer.DEBUG_getSigKey()]
|
return false
|
||||||
/*
|
}
|
||||||
if next == here {
|
next := store[nextPeer.DEBUG_getSigKey()]
|
||||||
//for idx, link := range here.links {
|
/*
|
||||||
// fmt.Println("DUMP:", idx, link.nodeID)
|
if next == here {
|
||||||
//}
|
//for idx, link := range here.links {
|
||||||
if nextPort != 0 { panic("This should not be") }
|
// fmt.Println("DUMP:", idx, link.nodeID)
|
||||||
fmt.Println("Failed to route:", source.index, here.index, dest.index, oldTTL, ttl)
|
//}
|
||||||
//here.table.DEBUG_dumpTable()
|
if nextPort != 0 { panic("This should not be") }
|
||||||
//fmt.Println("Ports:", here.nodeID, here.ports)
|
fmt.Println("Failed to route:", source.index, here.index, dest.index, oldTTL, ttl)
|
||||||
return false
|
//here.table.DEBUG_dumpTable()
|
||||||
panic(fmt.Sprintln("Routing Loop:",
|
//fmt.Println("Ports:", here.nodeID, here.ports)
|
||||||
source.index,
|
return false
|
||||||
here.index,
|
panic(fmt.Sprintln("Routing Loop:",
|
||||||
dest.index))
|
source.index,
|
||||||
}
|
here.index,
|
||||||
*/
|
dest.index))
|
||||||
if temp > 4090 {
|
}
|
||||||
fmt.Println("DEBUG:",
|
*/
|
||||||
source.index, source.core.DEBUG_getLocator(),
|
if temp > 4090 {
|
||||||
here.index, here.core.DEBUG_getLocator(),
|
fmt.Println("DEBUG:",
|
||||||
dest.index, dest.core.DEBUG_getLocator())
|
source.index, source.core.DEBUG_getLocator(),
|
||||||
here.core.DEBUG_getSwitchTable().DEBUG_dumpTable()
|
here.index, here.core.DEBUG_getLocator(),
|
||||||
}
|
dest.index, dest.core.DEBUG_getLocator())
|
||||||
if (here != source) {
|
here.core.DEBUG_getSwitchTable().DEBUG_dumpTable()
|
||||||
// This is sufficient to check for routing loops or blackholes
|
}
|
||||||
//break
|
if here != source {
|
||||||
}
|
// This is sufficient to check for routing loops or blackholes
|
||||||
here = next
|
//break
|
||||||
}
|
}
|
||||||
}
|
here = next
|
||||||
}
|
}
|
||||||
return true
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func stressTest(store map[[32]byte]*Node) {
|
func stressTest(store map[[32]byte]*Node) {
|
||||||
fmt.Println("Stress testing network...")
|
fmt.Println("Stress testing network...")
|
||||||
nNodes := len(store)
|
nNodes := len(store)
|
||||||
dests := make([][]byte, 0, nNodes)
|
dests := make([][]byte, 0, nNodes)
|
||||||
for _, dest := range store {
|
for _, dest := range store {
|
||||||
loc := dest.core.DEBUG_getLocator()
|
loc := dest.core.DEBUG_getLocator()
|
||||||
coords := loc.DEBUG_getCoords()
|
coords := loc.DEBUG_getCoords()
|
||||||
dests = append(dests, coords)
|
dests = append(dests, coords)
|
||||||
}
|
}
|
||||||
lookups := 0
|
lookups := 0
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
for _, source := range store {
|
for _, source := range store {
|
||||||
for _, coords := range dests {
|
for _, coords := range dests {
|
||||||
source.core.DEBUG_switchLookup(coords, ^uint64(0))
|
source.core.DEBUG_switchLookup(coords, ^uint64(0))
|
||||||
lookups++
|
lookups++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timed := time.Since(start)
|
timed := time.Since(start)
|
||||||
fmt.Printf("%d lookups in %s (%f lookups per second)\n",
|
fmt.Printf("%d lookups in %s (%f lookups per second)\n",
|
||||||
lookups,
|
lookups,
|
||||||
timed,
|
timed,
|
||||||
float64(lookups)/timed.Seconds())
|
float64(lookups)/timed.Seconds())
|
||||||
}
|
}
|
||||||
|
|
||||||
func pingNodes(store map[[32]byte]*Node) {
|
func pingNodes(store map[[32]byte]*Node) {
|
||||||
fmt.Println("Sending pings...")
|
fmt.Println("Sending pings...")
|
||||||
nNodes := len(store)
|
nNodes := len(store)
|
||||||
count := 0
|
count := 0
|
||||||
equiv := func (a []byte, b []byte) bool {
|
equiv := func(a []byte, b []byte) bool {
|
||||||
if len(a) != len(b) { return false }
|
if len(a) != len(b) {
|
||||||
for idx := 0 ; idx < len(a) ; idx++ {
|
return false
|
||||||
if a[idx] != b[idx] { return false }
|
}
|
||||||
}
|
for idx := 0; idx < len(a); idx++ {
|
||||||
return true
|
if a[idx] != b[idx] {
|
||||||
}
|
return false
|
||||||
for _, source := range store {
|
}
|
||||||
count++
|
}
|
||||||
//if count > 16 { break }
|
return true
|
||||||
fmt.Printf("Sending packets from node %d/%d (%d)\n", count, nNodes, source.index)
|
}
|
||||||
sourceKey := source.core.DEBUG_getBoxPub()
|
for _, source := range store {
|
||||||
payload := sourceKey[:]
|
count++
|
||||||
sourceAddr := source.core.DEBUG_getAddr()[:]
|
//if count > 16 { break }
|
||||||
sendTo := func (bs []byte, destAddr []byte) {
|
fmt.Printf("Sending packets from node %d/%d (%d)\n", count, nNodes, source.index)
|
||||||
packet := make([]byte, 40+len(bs))
|
sourceKey := source.core.DEBUG_getBoxPub()
|
||||||
copy(packet[8:24], sourceAddr)
|
payload := sourceKey[:]
|
||||||
copy(packet[24:40], destAddr)
|
sourceAddr := source.core.DEBUG_getAddr()[:]
|
||||||
copy(packet[40:], bs)
|
sendTo := func(bs []byte, destAddr []byte) {
|
||||||
source.send<-packet
|
packet := make([]byte, 40+len(bs))
|
||||||
}
|
copy(packet[8:24], sourceAddr)
|
||||||
destCount := 0
|
copy(packet[24:40], destAddr)
|
||||||
for _, dest := range store {
|
copy(packet[40:], bs)
|
||||||
destCount += 1
|
source.send <- packet
|
||||||
fmt.Printf("%d Nodes, %d Send, %d Recv\n", nNodes, count, destCount)
|
}
|
||||||
if dest == source {
|
destCount := 0
|
||||||
fmt.Println("Skipping self")
|
for _, dest := range store {
|
||||||
continue
|
destCount += 1
|
||||||
}
|
fmt.Printf("%d Nodes, %d Send, %d Recv\n", nNodes, count, destCount)
|
||||||
destAddr := dest.core.DEBUG_getAddr()[:]
|
if dest == source {
|
||||||
ticker := time.NewTicker(150*time.Millisecond)
|
fmt.Println("Skipping self")
|
||||||
ch := make(chan bool, 1)
|
continue
|
||||||
ch<-true
|
}
|
||||||
doTicker := func () {
|
destAddr := dest.core.DEBUG_getAddr()[:]
|
||||||
for _ = range ticker.C {
|
ticker := time.NewTicker(150 * time.Millisecond)
|
||||||
select {
|
ch := make(chan bool, 1)
|
||||||
case ch<-true:
|
ch <- true
|
||||||
default:
|
doTicker := func() {
|
||||||
}
|
for range ticker.C {
|
||||||
}
|
select {
|
||||||
}
|
case ch <- true:
|
||||||
go doTicker()
|
default:
|
||||||
for loop := true ; loop ; {
|
}
|
||||||
select {
|
}
|
||||||
case packet := <-dest.recv: {
|
}
|
||||||
if equiv(payload, packet[len(packet)-len(payload):]) {
|
go doTicker()
|
||||||
loop = false
|
for loop := true; loop; {
|
||||||
}
|
select {
|
||||||
}
|
case packet := <-dest.recv:
|
||||||
case <-ch: sendTo(payload, destAddr)
|
{
|
||||||
}
|
if equiv(payload, packet[len(packet)-len(payload):]) {
|
||||||
}
|
loop = false
|
||||||
ticker.Stop()
|
}
|
||||||
}
|
}
|
||||||
//break // Only try sending pings from 1 node
|
case <-ch:
|
||||||
// This is because, for some reason, stopTun() doesn't always close it
|
sendTo(payload, destAddr)
|
||||||
// And if two tuns are up, bad things happen (sends via wrong interface)
|
}
|
||||||
}
|
}
|
||||||
fmt.Println("Finished pinging nodes")
|
ticker.Stop()
|
||||||
|
}
|
||||||
|
//break // Only try sending pings from 1 node
|
||||||
|
// This is because, for some reason, stopTun() doesn't always close it
|
||||||
|
// And if two tuns are up, bad things happen (sends via wrong interface)
|
||||||
|
}
|
||||||
|
fmt.Println("Finished pinging nodes")
|
||||||
}
|
}
|
||||||
|
|
||||||
func pingBench(store map[[32]byte]*Node) {
|
func pingBench(store map[[32]byte]*Node) {
|
||||||
fmt.Println("Benchmarking pings...")
|
fmt.Println("Benchmarking pings...")
|
||||||
nPings := 0
|
nPings := 0
|
||||||
payload := make([]byte, 1280+40) // MTU + ipv6 header
|
payload := make([]byte, 1280+40) // MTU + ipv6 header
|
||||||
var timed time.Duration
|
var timed time.Duration
|
||||||
//nNodes := len(store)
|
//nNodes := len(store)
|
||||||
count := 0
|
count := 0
|
||||||
for _, source := range store {
|
for _, source := range store {
|
||||||
count++
|
count++
|
||||||
//fmt.Printf("Sending packets from node %d/%d (%d)\n", count, nNodes, source.index)
|
//fmt.Printf("Sending packets from node %d/%d (%d)\n", count, nNodes, source.index)
|
||||||
getPing := func (key [32]byte, decodedCoords []byte) []byte {
|
getPing := func(key [32]byte, decodedCoords []byte) []byte {
|
||||||
// TODO write some function to do this the right way, put... somewhere...
|
// TODO write some function to do this the right way, put... somewhere...
|
||||||
coords := DEBUG_wire_encode_coords(decodedCoords)
|
coords := DEBUG_wire_encode_coords(decodedCoords)
|
||||||
packet := make([]byte, 0, len(key)+len(coords)+len(payload))
|
packet := make([]byte, 0, len(key)+len(coords)+len(payload))
|
||||||
packet = append(packet, key[:]...)
|
packet = append(packet, key[:]...)
|
||||||
packet = append(packet, coords...)
|
packet = append(packet, coords...)
|
||||||
packet = append(packet, payload[:]...)
|
packet = append(packet, payload[:]...)
|
||||||
return packet
|
return packet
|
||||||
}
|
}
|
||||||
for _, dest := range store {
|
for _, dest := range store {
|
||||||
key := dest.core.DEBUG_getBoxPub()
|
key := dest.core.DEBUG_getBoxPub()
|
||||||
loc := dest.core.DEBUG_getLocator()
|
loc := dest.core.DEBUG_getLocator()
|
||||||
coords := loc.DEBUG_getCoords()
|
coords := loc.DEBUG_getCoords()
|
||||||
ping := getPing(key, coords)
|
ping := getPing(key, coords)
|
||||||
// TODO make sure the session is open first
|
// TODO make sure the session is open first
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
for i := 0 ; i < 1000000 ; i++{ source.send<-ping ; nPings++ }
|
for i := 0; i < 1000000; i++ {
|
||||||
timed += time.Since(start)
|
source.send <- ping
|
||||||
break
|
nPings++
|
||||||
}
|
}
|
||||||
break
|
timed += time.Since(start)
|
||||||
}
|
break
|
||||||
fmt.Printf("Sent %d pings in %s (%f per second)\n",
|
}
|
||||||
nPings,
|
break
|
||||||
timed,
|
}
|
||||||
float64(nPings)/timed.Seconds())
|
fmt.Printf("Sent %d pings in %s (%f per second)\n",
|
||||||
|
nPings,
|
||||||
|
timed,
|
||||||
|
float64(nPings)/timed.Seconds())
|
||||||
}
|
}
|
||||||
|
|
||||||
func dumpStore(store map[NodeID]*Node) {
|
func dumpStore(store map[NodeID]*Node) {
|
||||||
for _, node := range store {
|
for _, node := range store {
|
||||||
fmt.Println("DUMPSTORE:", node.index, node.core.DEBUG_getLocator())
|
fmt.Println("DUMPSTORE:", node.index, node.core.DEBUG_getLocator())
|
||||||
node.core.DEBUG_getSwitchTable().DEBUG_dumpTable()
|
node.core.DEBUG_getSwitchTable().DEBUG_dumpTable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func dumpDHTSize(store map[[32]byte]*Node) {
|
func dumpDHTSize(store map[[32]byte]*Node) {
|
||||||
var min, max, sum int
|
var min, max, sum int
|
||||||
for _, node := range store {
|
for _, node := range store {
|
||||||
num := node.core.DEBUG_getDHTSize()
|
num := node.core.DEBUG_getDHTSize()
|
||||||
min = num
|
min = num
|
||||||
max = num
|
max = num
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
for _, node := range store {
|
for _, node := range store {
|
||||||
num := node.core.DEBUG_getDHTSize()
|
num := node.core.DEBUG_getDHTSize()
|
||||||
if num < min { min = num }
|
if num < min {
|
||||||
if num > max { max = num }
|
min = num
|
||||||
sum += num
|
}
|
||||||
}
|
if num > max {
|
||||||
avg := float64(sum)/float64(len(store))
|
max = num
|
||||||
fmt.Printf("DHT min %d / avg %f / max %d\n", min, avg, max)
|
}
|
||||||
|
sum += num
|
||||||
|
}
|
||||||
|
avg := float64(sum) / float64(len(store))
|
||||||
|
fmt.Printf("DHT min %d / avg %f / max %d\n", min, avg, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -364,47 +383,48 @@ var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
|||||||
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if *cpuprofile != "" {
|
if *cpuprofile != "" {
|
||||||
f, err := os.Create(*cpuprofile)
|
f, err := os.Create(*cpuprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
||||||
}
|
}
|
||||||
if err := pprof.StartCPUProfile(f); err != nil {
|
if err := pprof.StartCPUProfile(f); err != nil {
|
||||||
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
||||||
}
|
}
|
||||||
defer pprof.StopCPUProfile()
|
defer pprof.StopCPUProfile()
|
||||||
}
|
}
|
||||||
if *memprofile != "" {
|
if *memprofile != "" {
|
||||||
f, err := os.Create(*memprofile)
|
f, err := os.Create(*memprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create memory profile: ", err))
|
panic(fmt.Sprintf("could not create memory profile: ", err))
|
||||||
}
|
}
|
||||||
defer func () { pprof.WriteHeapProfile(f) ; f.Close() }()
|
defer func() { pprof.WriteHeapProfile(f); f.Close() }()
|
||||||
}
|
}
|
||||||
fmt.Println("Test")
|
fmt.Println("Test")
|
||||||
Util_testAddrIDMask()
|
Util_testAddrIDMask()
|
||||||
idxstore := makeStoreSquareGrid(4)
|
idxstore := makeStoreSquareGrid(4)
|
||||||
//idxstore := makeStoreStar(256)
|
//idxstore := makeStoreStar(256)
|
||||||
//idxstore := loadGraph("misc/sim/hype-2016-09-19.list")
|
//idxstore := loadGraph("misc/sim/hype-2016-09-19.list")
|
||||||
//idxstore := loadGraph("misc/sim/fc00-2017-08-12.txt")
|
//idxstore := loadGraph("misc/sim/fc00-2017-08-12.txt")
|
||||||
//idxstore := loadGraph("skitter")
|
//idxstore := loadGraph("skitter")
|
||||||
kstore := getKeyedStore(idxstore)
|
kstore := getKeyedStore(idxstore)
|
||||||
/*
|
/*
|
||||||
for _, n := range kstore {
|
for _, n := range kstore {
|
||||||
log := n.core.DEBUG_getLogger()
|
log := n.core.DEBUG_getLogger()
|
||||||
log.SetOutput(os.Stderr)
|
log.SetOutput(os.Stderr)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
startNetwork(kstore)
|
startNetwork(kstore)
|
||||||
//time.Sleep(10*time.Second)
|
//time.Sleep(10*time.Second)
|
||||||
// Note that testPaths only works if pressure is turend off
|
// Note that testPaths only works if pressure is turend off
|
||||||
// Otherwise congestion can lead to routing loops?
|
// Otherwise congestion can lead to routing loops?
|
||||||
for finished := false; !finished ; { finished = testPaths(kstore) }
|
for finished := false; !finished; {
|
||||||
pingNodes(kstore)
|
finished = testPaths(kstore)
|
||||||
//pingBench(kstore) // Only after disabling debug output
|
}
|
||||||
//stressTest(kstore)
|
pingNodes(kstore)
|
||||||
//time.Sleep(120*time.Second)
|
//pingBench(kstore) // Only after disabling debug output
|
||||||
dumpDHTSize(kstore) // note that this uses racey functions to read things...
|
//stressTest(kstore)
|
||||||
|
//time.Sleep(120*time.Second)
|
||||||
|
dumpDHTSize(kstore) // note that this uses racey functions to read things...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,16 +7,16 @@ import "runtime"
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
var ops uint64 = 0
|
var ops uint64 = 0
|
||||||
for i := 0 ; i < 4 ; i++ {
|
for i := 0; i < 4; i++ {
|
||||||
go func () {
|
go func() {
|
||||||
for {
|
for {
|
||||||
atomic.AddUint64(&ops, 1)
|
atomic.AddUint64(&ops, 1)
|
||||||
runtime.Gosched()
|
runtime.Gosched()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
time.Sleep(1*time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
opsFinal := atomic.LoadUint64(&ops)
|
opsFinal := atomic.LoadUint64(&ops)
|
||||||
fmt.Println("ops:", opsFinal)
|
fmt.Println("ops:", opsFinal)
|
||||||
}
|
}
|
||||||
|
@ -4,39 +4,50 @@ import "fmt"
|
|||||||
import "net"
|
import "net"
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
func main () {
|
func main() {
|
||||||
addr, err := net.ResolveTCPAddr("tcp", "[::1]:9001")
|
addr, err := net.ResolveTCPAddr("tcp", "[::1]:9001")
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
listener, err := net.ListenTCP("tcp", addr)
|
panic(err)
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
defer listener.Close()
|
listener, err := net.ListenTCP("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer listener.Close()
|
||||||
|
|
||||||
packetSize := 65535
|
packetSize := 65535
|
||||||
numPackets := 65535
|
numPackets := 65535
|
||||||
|
|
||||||
go func () {
|
go func() {
|
||||||
send, err := net.DialTCP("tcp", nil, addr)
|
send, err := net.DialTCP("tcp", nil, addr)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
defer send.Close()
|
panic(err)
|
||||||
msg := make([]byte, packetSize)
|
}
|
||||||
for idx := 0 ; idx < numPackets ; idx++ { send.Write(msg) }
|
defer send.Close()
|
||||||
}()
|
msg := make([]byte, packetSize)
|
||||||
|
for idx := 0; idx < numPackets; idx++ {
|
||||||
|
send.Write(msg)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
//msg := make([]byte, 1280)
|
//msg := make([]byte, 1280)
|
||||||
sock, err := listener.AcceptTCP()
|
sock, err := listener.AcceptTCP()
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
defer sock.Close()
|
panic(err)
|
||||||
read := 0
|
}
|
||||||
buf := make([]byte, packetSize)
|
defer sock.Close()
|
||||||
for {
|
read := 0
|
||||||
n, err := sock.Read(buf)
|
buf := make([]byte, packetSize)
|
||||||
read += n
|
for {
|
||||||
if err != nil { break }
|
n, err := sock.Read(buf)
|
||||||
}
|
read += n
|
||||||
timed := time.Since(start)
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timed := time.Since(start)
|
||||||
|
|
||||||
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
||||||
fmt.Printf("%f bits/sec\n", 8*float64(read)/timed.Seconds())
|
fmt.Printf("%f bits/sec\n", 8*float64(read)/timed.Seconds())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,32 +5,32 @@ import "fmt"
|
|||||||
import "sync"
|
import "sync"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println("Testing speed of recv+send loop")
|
fmt.Println("Testing speed of recv+send loop")
|
||||||
const count = 10000000
|
const count = 10000000
|
||||||
c := make(chan []byte, 1)
|
c := make(chan []byte, 1)
|
||||||
c<-[]byte{}
|
c <- []byte{}
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
worker := func () {
|
worker := func() {
|
||||||
for idx := 0 ; idx < count ; idx++ {
|
for idx := 0; idx < count; idx++ {
|
||||||
p := <-c
|
p := <-c
|
||||||
select {
|
select {
|
||||||
case c<-p:
|
case c <- p:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}
|
}
|
||||||
nIter := 0
|
nIter := 0
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
for idx := 0 ; idx < 1 ; idx++ {
|
for idx := 0; idx < 1; idx++ {
|
||||||
go worker()
|
go worker()
|
||||||
nIter += count
|
nIter += count
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
stop := time.Now()
|
stop := time.Now()
|
||||||
timed := stop.Sub(start)
|
timed := stop.Sub(start)
|
||||||
fmt.Printf("%d iterations in %s\n", nIter, timed)
|
fmt.Printf("%d iterations in %s\n", nIter, timed)
|
||||||
fmt.Printf("%f iterations per second\n", float64(nIter)/timed.Seconds())
|
fmt.Printf("%f iterations per second\n", float64(nIter)/timed.Seconds())
|
||||||
fmt.Printf("%s per iteration\n", timed/time.Duration(nIter))
|
fmt.Printf("%s per iteration\n", timed/time.Duration(nIter))
|
||||||
}
|
}
|
||||||
|
@ -6,47 +6,51 @@ import "time"
|
|||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
type testStruct struct {
|
type testStruct struct {
|
||||||
First uint64
|
First uint64
|
||||||
Second float64
|
Second float64
|
||||||
Third []byte
|
Third []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func testFunc(tickerDuration time.Duration) {
|
func testFunc(tickerDuration time.Duration) {
|
||||||
chn := make(chan []byte)
|
chn := make(chan []byte)
|
||||||
ticker := time.NewTicker(tickerDuration)
|
ticker := time.NewTicker(tickerDuration)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
send := testStruct{First: 1, Second: 2, Third: []byte{3, 4, 5}}
|
send := testStruct{First: 1, Second: 2, Third: []byte{3, 4, 5}}
|
||||||
buf := bytes.NewBuffer(nil)
|
buf := bytes.NewBuffer(nil)
|
||||||
enc := gob.NewEncoder(buf)
|
enc := gob.NewEncoder(buf)
|
||||||
dec := gob.NewDecoder(buf)
|
dec := gob.NewDecoder(buf)
|
||||||
sendCall := func () {
|
sendCall := func() {
|
||||||
err := enc.EncodeValue(&send)
|
err := enc.EncodeValue(&send)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
bs := make([]byte, buf.Len())
|
panic(err)
|
||||||
buf.Read(bs)
|
}
|
||||||
fmt.Println("send:", bs)
|
bs := make([]byte, buf.Len())
|
||||||
go func() { chn<-bs }()
|
buf.Read(bs)
|
||||||
}
|
fmt.Println("send:", bs)
|
||||||
recvCall := func (bs []byte) {
|
go func() { chn <- bs }()
|
||||||
buf.Write(bs)
|
}
|
||||||
recv := testStruct{}
|
recvCall := func(bs []byte) {
|
||||||
err := dec.DecodeValue(&recv)
|
buf.Write(bs)
|
||||||
fmt.Println("recv:", bs)
|
recv := testStruct{}
|
||||||
if err != nil { panic(err) }
|
err := dec.DecodeValue(&recv)
|
||||||
}
|
fmt.Println("recv:", bs)
|
||||||
for {
|
if err != nil {
|
||||||
select {
|
panic(err)
|
||||||
case bs := <-chn : recvCall(bs)
|
}
|
||||||
case <-ticker.C : sendCall()
|
}
|
||||||
}
|
for {
|
||||||
}
|
select {
|
||||||
|
case bs := <-chn:
|
||||||
|
recvCall(bs)
|
||||||
|
case <-ticker.C:
|
||||||
|
sendCall()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
go testFunc(100*time.Millisecond) // Does not crash
|
go testFunc(100 * time.Millisecond) // Does not crash
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
go testFunc(time.Nanosecond) // Does crash
|
go testFunc(time.Nanosecond) // Does crash
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,19 +4,19 @@ import "sync"
|
|||||||
import "time"
|
import "time"
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
func main () {
|
func main() {
|
||||||
const reqs = 1000000
|
const reqs = 1000000
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
for idx := 0 ; idx < reqs ; idx++ {
|
for idx := 0; idx < reqs; idx++ {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func () { wg.Done() } ()
|
go func() { wg.Done() }()
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
stop := time.Now()
|
stop := time.Now()
|
||||||
timed := stop.Sub(start)
|
timed := stop.Sub(start)
|
||||||
fmt.Printf("%d goroutines in %s (%f per second)\n",
|
fmt.Printf("%d goroutines in %s (%f per second)\n",
|
||||||
reqs,
|
reqs,
|
||||||
timed,
|
timed,
|
||||||
reqs/timed.Seconds())
|
reqs/timed.Seconds())
|
||||||
}
|
}
|
||||||
|
@ -8,42 +8,50 @@ import "time"
|
|||||||
|
|
||||||
func basic_test() {
|
func basic_test() {
|
||||||
|
|
||||||
// TODO need a way to look up who our link-local neighbors are for each iface!
|
// TODO need a way to look up who our link-local neighbors are for each iface!
|
||||||
//addr, err := net.ResolveUDPAddr("udp", "[ff02::1%veth0]:9001")
|
//addr, err := net.ResolveUDPAddr("udp", "[ff02::1%veth0]:9001")
|
||||||
addr, err := net.ResolveUDPAddr("udp", "[ff02::1]:9001")
|
addr, err := net.ResolveUDPAddr("udp", "[ff02::1]:9001")
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
sock, err := net.ListenMulticastUDP("udp", nil, addr)
|
panic(err)
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
defer sock.Close()
|
sock, err := net.ListenMulticastUDP("udp", nil, addr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer sock.Close()
|
||||||
|
|
||||||
go func () {
|
go func() {
|
||||||
saddr, err := net.ResolveUDPAddr("udp", "[::]:0")
|
saddr, err := net.ResolveUDPAddr("udp", "[::]:0")
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
send, err := net.ListenUDP("udp", saddr)
|
panic(err)
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
defer send.Close()
|
send, err := net.ListenUDP("udp", saddr)
|
||||||
msg := make([]byte, 1280)
|
if err != nil {
|
||||||
for {
|
panic(err)
|
||||||
//fmt.Println("Sending...")
|
}
|
||||||
send.WriteTo(msg, addr)
|
defer send.Close()
|
||||||
}
|
msg := make([]byte, 1280)
|
||||||
}()
|
for {
|
||||||
|
//fmt.Println("Sending...")
|
||||||
|
send.WriteTo(msg, addr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
numPackets := 1000
|
numPackets := 1000
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
msg := make([]byte, 2000)
|
msg := make([]byte, 2000)
|
||||||
for i := 0 ; i < numPackets ; i++ {
|
for i := 0; i < numPackets; i++ {
|
||||||
//fmt.Println("Reading:", i)
|
//fmt.Println("Reading:", i)
|
||||||
sock.ReadFromUDP(msg)
|
sock.ReadFromUDP(msg)
|
||||||
}
|
}
|
||||||
timed := time.Since(start)
|
timed := time.Since(start)
|
||||||
|
|
||||||
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main () {
|
func main() {
|
||||||
|
|
||||||
basic_test()
|
basic_test()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,75 +4,89 @@ import "fmt"
|
|||||||
import "net"
|
import "net"
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
|
|
||||||
// TODO look into netmap + libpcap to bypass the kernel as much as possible
|
// TODO look into netmap + libpcap to bypass the kernel as much as possible
|
||||||
|
|
||||||
func basic_test() {
|
func basic_test() {
|
||||||
|
|
||||||
// TODO need a way to look up who our link-local neighbors are for each iface!
|
// TODO need a way to look up who our link-local neighbors are for each iface!
|
||||||
|
|
||||||
var ip *net.IP
|
var ip *net.IP
|
||||||
ifaces, err := net.Interfaces()
|
ifaces, err := net.Interfaces()
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
var zone string
|
panic(err)
|
||||||
for _, iface := range ifaces {
|
}
|
||||||
addrs, err := iface.Addrs()
|
var zone string
|
||||||
if err != nil { panic(err) }
|
for _, iface := range ifaces {
|
||||||
for _, addr := range addrs {
|
addrs, err := iface.Addrs()
|
||||||
addrIP, _, _ := net.ParseCIDR(addr.String())
|
if err != nil {
|
||||||
if addrIP.To4() != nil { continue } // IPv6 only
|
panic(err)
|
||||||
if !addrIP.IsLinkLocalUnicast() { continue }
|
}
|
||||||
zone = iface.Name
|
for _, addr := range addrs {
|
||||||
ip = &addrIP
|
addrIP, _, _ := net.ParseCIDR(addr.String())
|
||||||
}
|
if addrIP.To4() != nil {
|
||||||
addrs, err = iface.MulticastAddrs()
|
continue
|
||||||
if err != nil { panic(err) }
|
} // IPv6 only
|
||||||
for _, addr := range addrs {
|
if !addrIP.IsLinkLocalUnicast() {
|
||||||
fmt.Println(addr.String())
|
continue
|
||||||
}
|
}
|
||||||
}
|
zone = iface.Name
|
||||||
if ip == nil { panic("No link-local IPv6 found") }
|
ip = &addrIP
|
||||||
fmt.Println("Using address:", *ip)
|
}
|
||||||
|
addrs, err = iface.MulticastAddrs()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
fmt.Println(addr.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ip == nil {
|
||||||
|
panic("No link-local IPv6 found")
|
||||||
|
}
|
||||||
|
fmt.Println("Using address:", *ip)
|
||||||
|
|
||||||
addr := net.UDPAddr{IP: *ip, Port: 9001, Zone: zone}
|
addr := net.UDPAddr{IP: *ip, Port: 9001, Zone: zone}
|
||||||
|
|
||||||
saddr := net.UDPAddr{IP: *ip, Port: 9002, Zone: zone}
|
saddr := net.UDPAddr{IP: *ip, Port: 9002, Zone: zone}
|
||||||
send, err := net.ListenUDP("udp", &saddr)
|
send, err := net.ListenUDP("udp", &saddr)
|
||||||
defer send.Close()
|
defer send.Close()
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
sock, err := net.ListenUDP("udp", &addr)
|
panic(err)
|
||||||
defer sock.Close()
|
}
|
||||||
if err != nil { panic(err) }
|
sock, err := net.ListenUDP("udp", &addr)
|
||||||
|
defer sock.Close()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
const buffSize = 1048576*100
|
const buffSize = 1048576 * 100
|
||||||
|
|
||||||
send.SetWriteBuffer(buffSize)
|
send.SetWriteBuffer(buffSize)
|
||||||
sock.SetReadBuffer(buffSize)
|
sock.SetReadBuffer(buffSize)
|
||||||
sock.SetWriteBuffer(buffSize)
|
sock.SetWriteBuffer(buffSize)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
msg := make([]byte, 1280)
|
||||||
|
for {
|
||||||
|
send.WriteTo(msg, &addr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
go func () {
|
numPackets := 100000
|
||||||
msg := make([]byte, 1280)
|
start := time.Now()
|
||||||
for {
|
msg := make([]byte, 2000)
|
||||||
send.WriteTo(msg, &addr)
|
for i := 0; i < numPackets; i++ {
|
||||||
}
|
_, addr, _ := sock.ReadFrom(msg)
|
||||||
}()
|
sock.WriteTo(msg, addr)
|
||||||
|
}
|
||||||
|
timed := time.Since(start)
|
||||||
|
|
||||||
numPackets := 100000
|
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
||||||
start := time.Now()
|
|
||||||
msg := make([]byte, 2000)
|
|
||||||
for i := 0 ; i < numPackets ; i++ {
|
|
||||||
_, addr, _ := sock.ReadFrom(msg)
|
|
||||||
sock.WriteTo(msg, addr)
|
|
||||||
}
|
|
||||||
timed := time.Since(start)
|
|
||||||
|
|
||||||
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main () {
|
func main() {
|
||||||
|
|
||||||
basic_test()
|
basic_test()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,83 +1,89 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
//import "net"
|
//import "net"
|
||||||
import "time"
|
import "time"
|
||||||
import "runtime"
|
import "runtime"
|
||||||
import "sync/atomic"
|
import "sync/atomic"
|
||||||
|
|
||||||
func poolbench() {
|
func poolbench() {
|
||||||
nWorkers := runtime.GOMAXPROCS(0)
|
nWorkers := runtime.GOMAXPROCS(0)
|
||||||
work := make(chan func(), 1)
|
work := make(chan func(), 1)
|
||||||
workers := make(chan chan<- func(), nWorkers)
|
workers := make(chan chan<- func(), nWorkers)
|
||||||
makeWorker := func() chan<- func() {
|
makeWorker := func() chan<- func() {
|
||||||
ch := make(chan func())
|
ch := make(chan func())
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
f := <-ch
|
f := <-ch
|
||||||
f()
|
f()
|
||||||
select {
|
select {
|
||||||
case workers<-(ch):
|
case workers <- (ch):
|
||||||
default: return
|
default:
|
||||||
}
|
return
|
||||||
}
|
}
|
||||||
}()
|
}
|
||||||
return ch
|
}()
|
||||||
}
|
return ch
|
||||||
getWorker := func() chan<- func() {
|
}
|
||||||
select {
|
getWorker := func() chan<- func() {
|
||||||
case ch := <-workers: return ch
|
select {
|
||||||
default: return makeWorker()
|
case ch := <-workers:
|
||||||
}
|
return ch
|
||||||
}
|
default:
|
||||||
dispatcher := func() {
|
return makeWorker()
|
||||||
for {
|
}
|
||||||
w := <-work
|
}
|
||||||
ch := getWorker()
|
dispatcher := func() {
|
||||||
ch<-w
|
for {
|
||||||
}
|
w := <-work
|
||||||
}
|
ch := getWorker()
|
||||||
go dispatcher()
|
ch <- w
|
||||||
var count uint64
|
}
|
||||||
const nCounts = 1000000
|
}
|
||||||
for idx := 0 ; idx < nCounts ; idx++ {
|
go dispatcher()
|
||||||
f := func() { atomic.AddUint64(&count, 1) }
|
var count uint64
|
||||||
work <- f
|
const nCounts = 1000000
|
||||||
}
|
for idx := 0; idx < nCounts; idx++ {
|
||||||
for atomic.LoadUint64(&count) < nCounts {}
|
f := func() { atomic.AddUint64(&count, 1) }
|
||||||
|
work <- f
|
||||||
|
}
|
||||||
|
for atomic.LoadUint64(&count) < nCounts {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func normalbench() {
|
func normalbench() {
|
||||||
var count uint64
|
var count uint64
|
||||||
const nCounts = 1000000
|
const nCounts = 1000000
|
||||||
ch := make(chan struct{}, 1)
|
ch := make(chan struct{}, 1)
|
||||||
ch<-struct{}{}
|
ch <- struct{}{}
|
||||||
for idx := 0 ; idx < nCounts ; idx++ {
|
for idx := 0; idx < nCounts; idx++ {
|
||||||
f := func() { atomic.AddUint64(&count, 1) }
|
f := func() { atomic.AddUint64(&count, 1) }
|
||||||
f()
|
f()
|
||||||
<-ch
|
<-ch
|
||||||
ch<-struct{}{}
|
ch <- struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func gobench() {
|
func gobench() {
|
||||||
var count uint64
|
var count uint64
|
||||||
const nCounts = 1000000
|
const nCounts = 1000000
|
||||||
for idx := 0 ; idx < nCounts ; idx++ {
|
for idx := 0; idx < nCounts; idx++ {
|
||||||
f := func() { atomic.AddUint64(&count, 1) }
|
f := func() { atomic.AddUint64(&count, 1) }
|
||||||
go f()
|
go f()
|
||||||
}
|
}
|
||||||
for atomic.LoadUint64(&count) < nCounts {}
|
for atomic.LoadUint64(&count) < nCounts {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
poolbench()
|
poolbench()
|
||||||
fmt.Println(time.Since(start))
|
fmt.Println(time.Since(start))
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
normalbench()
|
normalbench()
|
||||||
fmt.Println(time.Since(start))
|
fmt.Println(time.Since(start))
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
gobench()
|
gobench()
|
||||||
fmt.Println(time.Since(start))
|
fmt.Println(time.Since(start))
|
||||||
}
|
}
|
||||||
|
@ -1,64 +1,76 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"bytes"
|
||||||
"time"
|
"crypto/rand"
|
||||||
"bytes"
|
"crypto/rsa"
|
||||||
"sync"
|
"crypto/tls"
|
||||||
"crypto/rand"
|
"crypto/x509"
|
||||||
"crypto/rsa"
|
"encoding/pem"
|
||||||
"crypto/tls"
|
"fmt"
|
||||||
"crypto/x509"
|
quic "github.com/lucas-clemente/quic-go"
|
||||||
"encoding/pem"
|
"math/big"
|
||||||
"math/big"
|
"sync"
|
||||||
quic "github.com/lucas-clemente/quic-go"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const addr = "[::1]:9001"
|
const addr = "[::1]:9001"
|
||||||
|
|
||||||
func main () {
|
func main() {
|
||||||
go run_server()
|
go run_server()
|
||||||
run_client()
|
run_client()
|
||||||
}
|
}
|
||||||
|
|
||||||
func run_server() {
|
func run_server() {
|
||||||
listener, err := quic.ListenAddr(addr, generateTLSConfig(), nil)
|
listener, err := quic.ListenAddr(addr, generateTLSConfig(), nil)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
ses, err := listener.Accept()
|
panic(err)
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
for {
|
ses, err := listener.Accept()
|
||||||
stream, err := ses.AcceptStream()
|
if err != nil {
|
||||||
if err != nil { panic(err) }
|
panic(err)
|
||||||
go func() {
|
}
|
||||||
defer stream.Close()
|
for {
|
||||||
bs := bytes.Buffer{}
|
stream, err := ses.AcceptStream()
|
||||||
_, err := bs.ReadFrom(stream)
|
if err != nil {
|
||||||
if err != nil { panic(err) } //<-- TooManyOpenStreams
|
panic(err)
|
||||||
}()
|
}
|
||||||
}
|
go func() {
|
||||||
|
defer stream.Close()
|
||||||
|
bs := bytes.Buffer{}
|
||||||
|
_, err := bs.ReadFrom(stream)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
} //<-- TooManyOpenStreams
|
||||||
|
}()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func run_client() {
|
func run_client() {
|
||||||
msgSize := 1048576
|
msgSize := 1048576
|
||||||
msgCount := 128
|
msgCount := 128
|
||||||
ses, err := quic.DialAddr(addr, &tls.Config{InsecureSkipVerify: true}, nil)
|
ses, err := quic.DialAddr(addr, &tls.Config{InsecureSkipVerify: true}, nil)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
bs := make([]byte, msgSize)
|
panic(err)
|
||||||
wg := sync.WaitGroup{}
|
}
|
||||||
start := time.Now()
|
bs := make([]byte, msgSize)
|
||||||
for idx := 0 ; idx < msgCount ; idx++ {
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(1)
|
start := time.Now()
|
||||||
go func() {
|
for idx := 0; idx < msgCount; idx++ {
|
||||||
defer wg.Done()
|
wg.Add(1)
|
||||||
stream, err := ses.OpenStreamSync()
|
go func() {
|
||||||
if err != nil { panic(err) }
|
defer wg.Done()
|
||||||
defer stream.Close()
|
stream, err := ses.OpenStreamSync()
|
||||||
stream.Write(bs)
|
if err != nil {
|
||||||
}() // "go" this later
|
panic(err)
|
||||||
}
|
}
|
||||||
wg.Wait()
|
defer stream.Close()
|
||||||
timed := time.Since(start)
|
stream.Write(bs)
|
||||||
fmt.Println("Client finished", timed, fmt.Sprintf("%f Bits/sec", 8*float64(msgSize*msgCount)/timed.Seconds()))
|
}() // "go" this later
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
timed := time.Since(start)
|
||||||
|
fmt.Println("Client finished", timed, fmt.Sprintf("%f Bits/sec", 8*float64(msgSize*msgCount)/timed.Seconds()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup a bare-bones TLS config for the server
|
// Setup a bare-bones TLS config for the server
|
||||||
@ -81,4 +93,3 @@ func generateTLSConfig() *tls.Config {
|
|||||||
}
|
}
|
||||||
return &tls.Config{Certificates: []tls.Certificate{tlsCert}}
|
return &tls.Config{Certificates: []tls.Certificate{tlsCert}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,59 +11,64 @@ import "runtime/pprof"
|
|||||||
|
|
||||||
func basic_test() {
|
func basic_test() {
|
||||||
|
|
||||||
// TODO need a way to look up who our link-local neighbors are for each iface!
|
// TODO need a way to look up who our link-local neighbors are for each iface!
|
||||||
|
|
||||||
addr, err := net.ResolveUDPAddr("udp", "[::1]:9001")
|
addr, err := net.ResolveUDPAddr("udp", "[::1]:9001")
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
sock, err := net.ListenUDP("udp", addr)
|
panic(err)
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
defer sock.Close()
|
sock, err := net.ListenUDP("udp", addr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer sock.Close()
|
||||||
|
|
||||||
go func () {
|
go func() {
|
||||||
send, err := net.DialUDP("udp", nil, addr)
|
send, err := net.DialUDP("udp", nil, addr)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
defer send.Close()
|
panic(err)
|
||||||
msg := make([]byte, 1280)
|
}
|
||||||
for {
|
defer send.Close()
|
||||||
send.Write(msg)
|
msg := make([]byte, 1280)
|
||||||
}
|
for {
|
||||||
}()
|
send.Write(msg)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
numPackets := 1000000
|
numPackets := 1000000
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
msg := make([]byte, 2000)
|
msg := make([]byte, 2000)
|
||||||
for i := 0 ; i < numPackets ; i++ {
|
for i := 0; i < numPackets; i++ {
|
||||||
sock.ReadFrom(msg)
|
sock.ReadFrom(msg)
|
||||||
}
|
}
|
||||||
timed := time.Since(start)
|
timed := time.Since(start)
|
||||||
|
|
||||||
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
||||||
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
||||||
|
|
||||||
func main () {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if *cpuprofile != "" {
|
if *cpuprofile != "" {
|
||||||
f, err := os.Create(*cpuprofile)
|
f, err := os.Create(*cpuprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
||||||
}
|
}
|
||||||
if err := pprof.StartCPUProfile(f); err != nil {
|
if err := pprof.StartCPUProfile(f); err != nil {
|
||||||
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
||||||
}
|
}
|
||||||
defer pprof.StopCPUProfile()
|
defer pprof.StopCPUProfile()
|
||||||
}
|
}
|
||||||
if *memprofile != "" {
|
if *memprofile != "" {
|
||||||
f, err := os.Create(*memprofile)
|
f, err := os.Create(*memprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create memory profile: ", err))
|
panic(fmt.Sprintf("could not create memory profile: ", err))
|
||||||
}
|
}
|
||||||
defer func () { pprof.WriteHeapProfile(f) ; f.Close() }()
|
defer func() { pprof.WriteHeapProfile(f); f.Close() }()
|
||||||
}
|
}
|
||||||
basic_test()
|
basic_test()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,67 +11,74 @@ import "runtime/pprof"
|
|||||||
|
|
||||||
func basic_test() {
|
func basic_test() {
|
||||||
|
|
||||||
// TODO need a way to look up who our link-local neighbors are for each iface!
|
// TODO need a way to look up who our link-local neighbors are for each iface!
|
||||||
|
|
||||||
addr, err := net.ResolveUDPAddr("udp", "[::1]:9001")
|
addr, err := net.ResolveUDPAddr("udp", "[::1]:9001")
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
sock, err := net.ListenUDP("udp", addr)
|
panic(err)
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
defer sock.Close()
|
sock, err := net.ListenUDP("udp", addr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer sock.Close()
|
||||||
|
|
||||||
go func () {
|
go func() {
|
||||||
send, err := net.DialUDP("udp", nil, addr)
|
send, err := net.DialUDP("udp", nil, addr)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
defer send.Close()
|
panic(err)
|
||||||
msg := make([]byte, 1280)
|
}
|
||||||
bss := make(net.Buffers, 0, 1024)
|
defer send.Close()
|
||||||
for {
|
msg := make([]byte, 1280)
|
||||||
for len(bss) < 1024 {
|
bss := make(net.Buffers, 0, 1024)
|
||||||
bss = append(bss, msg)
|
for {
|
||||||
}
|
for len(bss) < 1024 {
|
||||||
bss.WriteTo(send)
|
bss = append(bss, msg)
|
||||||
//bss = bss[:0]
|
}
|
||||||
//send.Write(msg)
|
bss.WriteTo(send)
|
||||||
}
|
//bss = bss[:0]
|
||||||
}()
|
//send.Write(msg)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
numPackets := 1000
|
numPackets := 1000
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
msg := make([]byte, 2000)
|
msg := make([]byte, 2000)
|
||||||
for i := 0 ; i < numPackets ; i++ {
|
for i := 0; i < numPackets; i++ {
|
||||||
n, err := sock.Read(msg)
|
n, err := sock.Read(msg)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
fmt.Println(n)
|
panic(err)
|
||||||
}
|
}
|
||||||
timed := time.Since(start)
|
fmt.Println(n)
|
||||||
|
}
|
||||||
|
timed := time.Since(start)
|
||||||
|
|
||||||
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
||||||
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
||||||
|
|
||||||
func main () {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if *cpuprofile != "" {
|
if *cpuprofile != "" {
|
||||||
f, err := os.Create(*cpuprofile)
|
f, err := os.Create(*cpuprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
||||||
}
|
}
|
||||||
if err := pprof.StartCPUProfile(f); err != nil {
|
if err := pprof.StartCPUProfile(f); err != nil {
|
||||||
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
||||||
}
|
}
|
||||||
defer pprof.StopCPUProfile()
|
defer pprof.StopCPUProfile()
|
||||||
}
|
}
|
||||||
if *memprofile != "" {
|
if *memprofile != "" {
|
||||||
f, err := os.Create(*memprofile)
|
f, err := os.Create(*memprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create memory profile: ", err))
|
panic(fmt.Sprintf("could not create memory profile: ", err))
|
||||||
}
|
}
|
||||||
defer func () { pprof.WriteHeapProfile(f) ; f.Close() }()
|
defer func() { pprof.WriteHeapProfile(f); f.Close() }()
|
||||||
}
|
}
|
||||||
basic_test()
|
basic_test()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,89 +11,106 @@ import "time"
|
|||||||
|
|
||||||
func basic_test() {
|
func basic_test() {
|
||||||
|
|
||||||
// TODO need a way to look up who our link-local neighbors are for each iface!
|
// TODO need a way to look up who our link-local neighbors are for each iface!
|
||||||
|
|
||||||
var ip *net.IP
|
var ip *net.IP
|
||||||
ifaces, err := net.Interfaces()
|
ifaces, err := net.Interfaces()
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
var zone string
|
panic(err)
|
||||||
for _, iface := range ifaces {
|
}
|
||||||
addrs, err := iface.Addrs()
|
var zone string
|
||||||
if err != nil { panic(err) }
|
for _, iface := range ifaces {
|
||||||
for _, addr := range addrs {
|
addrs, err := iface.Addrs()
|
||||||
addrIP, _, _ := net.ParseCIDR(addr.String())
|
if err != nil {
|
||||||
if addrIP.To4() != nil { continue } // IPv6 only
|
panic(err)
|
||||||
if !addrIP.IsLinkLocalUnicast() { continue }
|
}
|
||||||
fmt.Println(iface.Name, addrIP)
|
for _, addr := range addrs {
|
||||||
zone = iface.Name
|
addrIP, _, _ := net.ParseCIDR(addr.String())
|
||||||
ip = &addrIP
|
if addrIP.To4() != nil {
|
||||||
}
|
continue
|
||||||
if ip != nil { break }
|
} // IPv6 only
|
||||||
/*
|
if !addrIP.IsLinkLocalUnicast() {
|
||||||
addrs, err = iface.MulticastAddrs()
|
continue
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
for _, addr := range addrs {
|
fmt.Println(iface.Name, addrIP)
|
||||||
fmt.Println(addr.String())
|
zone = iface.Name
|
||||||
}
|
ip = &addrIP
|
||||||
*/
|
}
|
||||||
}
|
if ip != nil {
|
||||||
if ip == nil { panic("No link-local IPv6 found") }
|
break
|
||||||
fmt.Println("Using address:", *ip)
|
}
|
||||||
addr := net.UDPAddr{IP: *ip, Port: 9001, Zone: zone}
|
/*
|
||||||
|
addrs, err = iface.MulticastAddrs()
|
||||||
|
if err != nil { panic(err) }
|
||||||
|
for _, addr := range addrs {
|
||||||
|
fmt.Println(addr.String())
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
if ip == nil {
|
||||||
|
panic("No link-local IPv6 found")
|
||||||
|
}
|
||||||
|
fmt.Println("Using address:", *ip)
|
||||||
|
addr := net.UDPAddr{IP: *ip, Port: 9001, Zone: zone}
|
||||||
|
|
||||||
laddr, err := net.ResolveUDPAddr("udp", "[::]:9001")
|
laddr, err := net.ResolveUDPAddr("udp", "[::]:9001")
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
sock, err := net.ListenUDP("udp", laddr)
|
panic(err)
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
defer sock.Close()
|
sock, err := net.ListenUDP("udp", laddr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer sock.Close()
|
||||||
|
|
||||||
go func () {
|
go func() {
|
||||||
send, err := net.DialUDP("udp", nil, &addr)
|
send, err := net.DialUDP("udp", nil, &addr)
|
||||||
//send, err := net.ListenUDP("udp", nil)
|
//send, err := net.ListenUDP("udp", nil)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
defer send.Close()
|
panic(err)
|
||||||
msg := make([]byte, 1280)
|
}
|
||||||
for {
|
defer send.Close()
|
||||||
send.Write(msg)
|
msg := make([]byte, 1280)
|
||||||
//send.WriteToUDP(msg, &addr)
|
for {
|
||||||
}
|
send.Write(msg)
|
||||||
}()
|
//send.WriteToUDP(msg, &addr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
numPackets := 1000000
|
numPackets := 1000000
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
msg := make([]byte, 2000)
|
msg := make([]byte, 2000)
|
||||||
for i := 0 ; i < numPackets ; i++ {
|
for i := 0; i < numPackets; i++ {
|
||||||
sock.ReadFromUDP(msg)
|
sock.ReadFromUDP(msg)
|
||||||
}
|
}
|
||||||
timed := time.Since(start)
|
timed := time.Since(start)
|
||||||
|
|
||||||
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
||||||
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
||||||
|
|
||||||
func main () {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if *cpuprofile != "" {
|
if *cpuprofile != "" {
|
||||||
f, err := os.Create(*cpuprofile)
|
f, err := os.Create(*cpuprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
||||||
}
|
}
|
||||||
if err := pprof.StartCPUProfile(f); err != nil {
|
if err := pprof.StartCPUProfile(f); err != nil {
|
||||||
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
||||||
}
|
}
|
||||||
defer pprof.StopCPUProfile()
|
defer pprof.StopCPUProfile()
|
||||||
}
|
}
|
||||||
if *memprofile != "" {
|
if *memprofile != "" {
|
||||||
f, err := os.Create(*memprofile)
|
f, err := os.Create(*memprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create memory profile: ", err))
|
panic(fmt.Sprintf("could not create memory profile: ", err))
|
||||||
}
|
}
|
||||||
defer func () { pprof.WriteHeapProfile(f) ; f.Close() }()
|
defer func() { pprof.WriteHeapProfile(f); f.Close() }()
|
||||||
}
|
}
|
||||||
basic_test()
|
basic_test()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,82 +13,91 @@ const buffSize = 32
|
|||||||
|
|
||||||
func basic_test() {
|
func basic_test() {
|
||||||
|
|
||||||
// TODO need a way to look up who our link-local neighbors are for each iface!
|
// TODO need a way to look up who our link-local neighbors are for each iface!
|
||||||
|
|
||||||
addr, err := net.ResolveTCPAddr("tcp", "[::1]:9001")
|
addr, err := net.ResolveTCPAddr("tcp", "[::1]:9001")
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
listener, err := net.ListenTCP("tcp", addr)
|
panic(err)
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
defer listener.Close()
|
listener, err := net.ListenTCP("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer listener.Close()
|
||||||
|
|
||||||
go func () {
|
go func() {
|
||||||
send, err := net.DialTCP("tcp", nil, addr)
|
send, err := net.DialTCP("tcp", nil, addr)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
defer send.Close()
|
panic(err)
|
||||||
msg := make([]byte, 1280)
|
}
|
||||||
bss := make(net.Buffers, 0, 1024)
|
defer send.Close()
|
||||||
for {
|
msg := make([]byte, 1280)
|
||||||
for len(bss) < 1 { //buffSize {
|
bss := make(net.Buffers, 0, 1024)
|
||||||
bss = append(bss, msg)
|
for {
|
||||||
}
|
for len(bss) < 1 { //buffSize {
|
||||||
bss := net.Buffers{[]byte{0,1,2,3}, []byte{0,1}, msg}
|
bss = append(bss, msg)
|
||||||
bss.WriteTo(send)
|
}
|
||||||
//send.Write(msg)
|
bss := net.Buffers{[]byte{0, 1, 2, 3}, []byte{0, 1}, msg}
|
||||||
}
|
bss.WriteTo(send)
|
||||||
}()
|
//send.Write(msg)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
numPackets := 1000000
|
numPackets := 1000000
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
//msg := make([]byte, 1280)
|
//msg := make([]byte, 1280)
|
||||||
sock, err := listener.AcceptTCP()
|
sock, err := listener.AcceptTCP()
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
defer sock.Close()
|
panic(err)
|
||||||
for i := 0 ; i < numPackets ; i++ {
|
}
|
||||||
msg := make([]byte, 1280*buffSize)
|
defer sock.Close()
|
||||||
n, err := sock.Read(msg)
|
for i := 0; i < numPackets; i++ {
|
||||||
if err != nil { panic(err) }
|
msg := make([]byte, 1280*buffSize)
|
||||||
msg = msg[:n]
|
n, err := sock.Read(msg)
|
||||||
for len(msg) > 1286 {
|
if err != nil {
|
||||||
// handle message
|
panic(err)
|
||||||
i++
|
}
|
||||||
msg = msg[1286:]
|
msg = msg[:n]
|
||||||
}
|
for len(msg) > 1286 {
|
||||||
// handle remaining fragment of message
|
// handle message
|
||||||
//fmt.Println(n)
|
i++
|
||||||
}
|
msg = msg[1286:]
|
||||||
timed := time.Since(start)
|
}
|
||||||
|
// handle remaining fragment of message
|
||||||
|
//fmt.Println(n)
|
||||||
|
}
|
||||||
|
timed := time.Since(start)
|
||||||
|
|
||||||
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
||||||
|
|
||||||
_ = func (in (chan<- int)) {
|
_ = func(in chan<- int) {
|
||||||
close(in)
|
close(in)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
||||||
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
||||||
|
|
||||||
func main () {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if *cpuprofile != "" {
|
if *cpuprofile != "" {
|
||||||
f, err := os.Create(*cpuprofile)
|
f, err := os.Create(*cpuprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
||||||
}
|
}
|
||||||
if err := pprof.StartCPUProfile(f); err != nil {
|
if err := pprof.StartCPUProfile(f); err != nil {
|
||||||
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
||||||
}
|
}
|
||||||
defer pprof.StopCPUProfile()
|
defer pprof.StopCPUProfile()
|
||||||
}
|
}
|
||||||
if *memprofile != "" {
|
if *memprofile != "" {
|
||||||
f, err := os.Create(*memprofile)
|
f, err := os.Create(*memprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create memory profile: ", err))
|
panic(fmt.Sprintf("could not create memory profile: ", err))
|
||||||
}
|
}
|
||||||
defer func () { pprof.WriteHeapProfile(f) ; f.Close() }()
|
defer func() { pprof.WriteHeapProfile(f); f.Close() }()
|
||||||
}
|
}
|
||||||
basic_test()
|
basic_test()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,62 +11,67 @@ import "runtime/pprof"
|
|||||||
|
|
||||||
func basic_test() {
|
func basic_test() {
|
||||||
|
|
||||||
// TODO need a way to look up who our link-local neighbors are for each iface!
|
// TODO need a way to look up who our link-local neighbors are for each iface!
|
||||||
|
|
||||||
addr, err := net.ResolveUDPAddr("udp", "[::1]:0")
|
addr, err := net.ResolveUDPAddr("udp", "[::1]:0")
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
sock, err := net.ListenUDP("udp", addr)
|
panic(err)
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
defer sock.Close()
|
sock, err := net.ListenUDP("udp", addr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer sock.Close()
|
||||||
|
|
||||||
go func () {
|
go func() {
|
||||||
raddr := sock.LocalAddr().(*net.UDPAddr)
|
raddr := sock.LocalAddr().(*net.UDPAddr)
|
||||||
send, err := net.DialUDP("udp", nil, raddr)
|
send, err := net.DialUDP("udp", nil, raddr)
|
||||||
//send, err := net.ListenUDP("udp", addr)
|
//send, err := net.ListenUDP("udp", addr)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
defer send.Close()
|
panic(err)
|
||||||
msg := make([]byte, 1280)
|
}
|
||||||
for {
|
defer send.Close()
|
||||||
send.Write(msg)
|
msg := make([]byte, 1280)
|
||||||
//send.WriteToUDP(msg, raddr)
|
for {
|
||||||
}
|
send.Write(msg)
|
||||||
}()
|
//send.WriteToUDP(msg, raddr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
numPackets := 1000000
|
numPackets := 1000000
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
msg := make([]byte, 2000)
|
msg := make([]byte, 2000)
|
||||||
for i := 0 ; i < numPackets ; i++ {
|
for i := 0; i < numPackets; i++ {
|
||||||
sock.ReadFromUDP(msg)
|
sock.ReadFromUDP(msg)
|
||||||
}
|
}
|
||||||
timed := time.Since(start)
|
timed := time.Since(start)
|
||||||
|
|
||||||
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
||||||
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
||||||
|
|
||||||
func main () {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if *cpuprofile != "" {
|
if *cpuprofile != "" {
|
||||||
f, err := os.Create(*cpuprofile)
|
f, err := os.Create(*cpuprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
||||||
}
|
}
|
||||||
if err := pprof.StartCPUProfile(f); err != nil {
|
if err := pprof.StartCPUProfile(f); err != nil {
|
||||||
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
||||||
}
|
}
|
||||||
defer pprof.StopCPUProfile()
|
defer pprof.StopCPUProfile()
|
||||||
}
|
}
|
||||||
if *memprofile != "" {
|
if *memprofile != "" {
|
||||||
f, err := os.Create(*memprofile)
|
f, err := os.Create(*memprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create memory profile: ", err))
|
panic(fmt.Sprintf("could not create memory profile: ", err))
|
||||||
}
|
}
|
||||||
defer func () { pprof.WriteHeapProfile(f) ; f.Close() }()
|
defer func() { pprof.WriteHeapProfile(f); f.Close() }()
|
||||||
}
|
}
|
||||||
basic_test()
|
basic_test()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,62 +11,69 @@ import "runtime/pprof"
|
|||||||
|
|
||||||
func basic_test() {
|
func basic_test() {
|
||||||
|
|
||||||
// TODO need a way to look up who our link-local neighbors are for each iface!
|
// TODO need a way to look up who our link-local neighbors are for each iface!
|
||||||
|
|
||||||
saddr, err := net.ResolveUDPAddr("udp", "[::1]:9001")
|
saddr, err := net.ResolveUDPAddr("udp", "[::1]:9001")
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
raddr, err := net.ResolveUDPAddr("udp", "[::1]:9002")
|
panic(err)
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
|
raddr, err := net.ResolveUDPAddr("udp", "[::1]:9002")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
send, err := net.DialUDP("udp", saddr, raddr)
|
send, err := net.DialUDP("udp", saddr, raddr)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
defer send.Close()
|
panic(err)
|
||||||
|
}
|
||||||
|
defer send.Close()
|
||||||
|
|
||||||
recv, err := net.DialUDP("udp", raddr, saddr)
|
recv, err := net.DialUDP("udp", raddr, saddr)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
defer recv.Close()
|
panic(err)
|
||||||
|
}
|
||||||
|
defer recv.Close()
|
||||||
|
|
||||||
go func () {
|
go func() {
|
||||||
msg := make([]byte, 1280)
|
msg := make([]byte, 1280)
|
||||||
for {
|
for {
|
||||||
send.Write(msg)
|
send.Write(msg)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
numPackets := 1000000
|
numPackets := 1000000
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
msg := make([]byte, 2000)
|
msg := make([]byte, 2000)
|
||||||
for i := 0 ; i < numPackets ; i++ {
|
for i := 0; i < numPackets; i++ {
|
||||||
recv.Read(msg)
|
recv.Read(msg)
|
||||||
}
|
}
|
||||||
timed := time.Since(start)
|
timed := time.Since(start)
|
||||||
|
|
||||||
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
||||||
}
|
}
|
||||||
|
|
||||||
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
||||||
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
||||||
|
|
||||||
func main () {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if *cpuprofile != "" {
|
if *cpuprofile != "" {
|
||||||
f, err := os.Create(*cpuprofile)
|
f, err := os.Create(*cpuprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
||||||
}
|
}
|
||||||
if err := pprof.StartCPUProfile(f); err != nil {
|
if err := pprof.StartCPUProfile(f); err != nil {
|
||||||
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
||||||
}
|
}
|
||||||
defer pprof.StopCPUProfile()
|
defer pprof.StopCPUProfile()
|
||||||
}
|
}
|
||||||
if *memprofile != "" {
|
if *memprofile != "" {
|
||||||
f, err := os.Create(*memprofile)
|
f, err := os.Create(*memprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create memory profile: ", err))
|
panic(fmt.Sprintf("could not create memory profile: ", err))
|
||||||
}
|
}
|
||||||
defer func () { pprof.WriteHeapProfile(f) ; f.Close() }()
|
defer func() { pprof.WriteHeapProfile(f); f.Close() }()
|
||||||
}
|
}
|
||||||
basic_test()
|
basic_test()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,78 +11,82 @@ import "runtime/pprof"
|
|||||||
|
|
||||||
func basic_test() {
|
func basic_test() {
|
||||||
|
|
||||||
// TODO need a way to look up who our link-local neighbors are for each iface!
|
// TODO need a way to look up who our link-local neighbors are for each iface!
|
||||||
|
|
||||||
sock, err := net.ListenUDP("udp", nil)
|
sock, err := net.ListenUDP("udp", nil)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
defer sock.Close()
|
panic(err)
|
||||||
|
}
|
||||||
|
defer sock.Close()
|
||||||
|
|
||||||
ch := make(chan []byte, 1)
|
ch := make(chan []byte, 1)
|
||||||
|
|
||||||
writer := func () {
|
writer := func() {
|
||||||
raddr := sock.LocalAddr().(*net.UDPAddr)
|
raddr := sock.LocalAddr().(*net.UDPAddr)
|
||||||
//send, err := net.ListenUDP("udp", nil)
|
//send, err := net.ListenUDP("udp", nil)
|
||||||
//if err != nil { panic(err) }
|
//if err != nil { panic(err) }
|
||||||
//defer send.Close()
|
//defer send.Close()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ch:
|
case <-ch:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
msg := make([]byte, 1280)
|
msg := make([]byte, 1280)
|
||||||
sock.WriteToUDP(msg, raddr)
|
sock.WriteToUDP(msg, raddr)
|
||||||
//send.WriteToUDP(msg, raddr)
|
//send.WriteToUDP(msg, raddr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
go writer()
|
go writer()
|
||||||
//go writer()
|
//go writer()
|
||||||
//go writer()
|
//go writer()
|
||||||
//go writer()
|
//go writer()
|
||||||
|
|
||||||
numPackets := 65536
|
numPackets := 65536
|
||||||
size := 0
|
size := 0
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
success := 0
|
success := 0
|
||||||
for i := 0 ; i < numPackets ; i++ {
|
for i := 0; i < numPackets; i++ {
|
||||||
msg := make([]byte, 2048)
|
msg := make([]byte, 2048)
|
||||||
n, _, err := sock.ReadFromUDP(msg)
|
n, _, err := sock.ReadFromUDP(msg)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
size += n
|
panic(err)
|
||||||
select {
|
}
|
||||||
case ch <- msg: success += 1
|
size += n
|
||||||
default:
|
select {
|
||||||
}
|
case ch <- msg:
|
||||||
}
|
success += 1
|
||||||
timed := time.Since(start)
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timed := time.Since(start)
|
||||||
|
|
||||||
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
||||||
fmt.Printf("%f bits per second\n", 8*float64(size)/timed.Seconds())
|
fmt.Printf("%f bits per second\n", 8*float64(size)/timed.Seconds())
|
||||||
fmt.Println("Success:", success, "/", numPackets)
|
fmt.Println("Success:", success, "/", numPackets)
|
||||||
}
|
}
|
||||||
|
|
||||||
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
||||||
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
||||||
|
|
||||||
func main () {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if *cpuprofile != "" {
|
if *cpuprofile != "" {
|
||||||
f, err := os.Create(*cpuprofile)
|
f, err := os.Create(*cpuprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
||||||
}
|
}
|
||||||
if err := pprof.StartCPUProfile(f); err != nil {
|
if err := pprof.StartCPUProfile(f); err != nil {
|
||||||
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
||||||
}
|
}
|
||||||
defer pprof.StopCPUProfile()
|
defer pprof.StopCPUProfile()
|
||||||
}
|
}
|
||||||
if *memprofile != "" {
|
if *memprofile != "" {
|
||||||
f, err := os.Create(*memprofile)
|
f, err := os.Create(*memprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create memory profile: ", err))
|
panic(fmt.Sprintf("could not create memory profile: ", err))
|
||||||
}
|
}
|
||||||
defer func () { pprof.WriteHeapProfile(f) ; f.Close() }()
|
defer func() { pprof.WriteHeapProfile(f); f.Close() }()
|
||||||
}
|
}
|
||||||
basic_test()
|
basic_test()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,105 +13,112 @@ import "golang.org/x/net/ipv6"
|
|||||||
|
|
||||||
func basic_test() {
|
func basic_test() {
|
||||||
|
|
||||||
// TODO need a way to look up who our link-local neighbors are for each iface!
|
// TODO need a way to look up who our link-local neighbors are for each iface!
|
||||||
|
|
||||||
udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
sock, err := net.ListenUDP("udp", udpAddr)
|
panic(err)
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
defer sock.Close()
|
sock, err := net.ListenUDP("udp", udpAddr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer sock.Close()
|
||||||
|
|
||||||
writer := func () {
|
writer := func() {
|
||||||
raddr := sock.LocalAddr().(*net.UDPAddr)
|
raddr := sock.LocalAddr().(*net.UDPAddr)
|
||||||
send, err := net.ListenUDP("udp", nil)
|
send, err := net.ListenUDP("udp", nil)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
defer send.Close()
|
panic(err)
|
||||||
conn := ipv6.NewPacketConn(send)
|
}
|
||||||
defer conn.Close()
|
defer send.Close()
|
||||||
var msgs []ipv6.Message
|
conn := ipv6.NewPacketConn(send)
|
||||||
for idx := 0 ; idx < 1024 ; idx++ {
|
defer conn.Close()
|
||||||
msg := ipv6.Message{Addr: raddr, Buffers: [][]byte{make([]byte, 1280)}}
|
var msgs []ipv6.Message
|
||||||
msgs = append(msgs, msg)
|
for idx := 0; idx < 1024; idx++ {
|
||||||
}
|
msg := ipv6.Message{Addr: raddr, Buffers: [][]byte{make([]byte, 1280)}}
|
||||||
for {
|
msgs = append(msgs, msg)
|
||||||
/*
|
}
|
||||||
var msgs []ipv6.Message
|
for {
|
||||||
for idx := 0 ; idx < 1024 ; idx++ {
|
/*
|
||||||
msg := ipv6.Message{Addr: raddr, Buffers: [][]byte{make([]byte, 1280)}}
|
var msgs []ipv6.Message
|
||||||
msgs = append(msgs, msg)
|
for idx := 0 ; idx < 1024 ; idx++ {
|
||||||
}
|
msg := ipv6.Message{Addr: raddr, Buffers: [][]byte{make([]byte, 1280)}}
|
||||||
*/
|
msgs = append(msgs, msg)
|
||||||
conn.WriteBatch(msgs, 0)
|
}
|
||||||
}
|
*/
|
||||||
|
conn.WriteBatch(msgs, 0)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
go writer()
|
go writer()
|
||||||
//go writer()
|
//go writer()
|
||||||
//go writer()
|
//go writer()
|
||||||
//go writer()
|
//go writer()
|
||||||
|
|
||||||
numPackets := 65536
|
numPackets := 65536
|
||||||
size := 0
|
size := 0
|
||||||
count := 0
|
count := 0
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
/*
|
/*
|
||||||
conn := ipv6.NewPacketConn(sock)
|
conn := ipv6.NewPacketConn(sock)
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
for ; count < numPackets ; count++ {
|
for ; count < numPackets ; count++ {
|
||||||
msgs := make([]ipv6.Message, 1024)
|
msgs := make([]ipv6.Message, 1024)
|
||||||
for _, msg := range msgs {
|
for _, msg := range msgs {
|
||||||
msg.Buffers = append(msg.Buffers, make([]byte, 2048))
|
msg.Buffers = append(msg.Buffers, make([]byte, 2048))
|
||||||
}
|
}
|
||||||
n, err := conn.ReadBatch(msgs, 0)
|
n, err := conn.ReadBatch(msgs, 0)
|
||||||
if err != nil { panic(err) }
|
if err != nil { panic(err) }
|
||||||
fmt.Println("DEBUG: n", n)
|
fmt.Println("DEBUG: n", n)
|
||||||
for _, msg := range msgs[:n] {
|
for _, msg := range msgs[:n] {
|
||||||
fmt.Println("DEBUG: msg", msg)
|
fmt.Println("DEBUG: msg", msg)
|
||||||
size += msg.N
|
size += msg.N
|
||||||
//for _, bs := range msg.Buffers {
|
//for _, bs := range msg.Buffers {
|
||||||
// size += len(bs)
|
// size += len(bs)
|
||||||
//}
|
//}
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//*/
|
//*/
|
||||||
//*
|
//*
|
||||||
for ; count < numPackets ; count++ {
|
for ; count < numPackets; count++ {
|
||||||
msg := make([]byte, 2048)
|
msg := make([]byte, 2048)
|
||||||
n, _, err := sock.ReadFromUDP(msg)
|
n, _, err := sock.ReadFromUDP(msg)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
size += n
|
panic(err)
|
||||||
}
|
}
|
||||||
//*/
|
size += n
|
||||||
timed := time.Since(start)
|
}
|
||||||
|
//*/
|
||||||
|
timed := time.Since(start)
|
||||||
|
|
||||||
fmt.Printf("%f packets per second\n", float64(count)/timed.Seconds())
|
fmt.Printf("%f packets per second\n", float64(count)/timed.Seconds())
|
||||||
fmt.Printf("%f bits/second\n", float64(8*size)/timed.Seconds())
|
fmt.Printf("%f bits/second\n", float64(8*size)/timed.Seconds())
|
||||||
}
|
}
|
||||||
|
|
||||||
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
||||||
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
||||||
|
|
||||||
func main () {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if *cpuprofile != "" {
|
if *cpuprofile != "" {
|
||||||
f, err := os.Create(*cpuprofile)
|
f, err := os.Create(*cpuprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
||||||
}
|
}
|
||||||
if err := pprof.StartCPUProfile(f); err != nil {
|
if err := pprof.StartCPUProfile(f); err != nil {
|
||||||
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
||||||
}
|
}
|
||||||
defer pprof.StopCPUProfile()
|
defer pprof.StopCPUProfile()
|
||||||
}
|
}
|
||||||
if *memprofile != "" {
|
if *memprofile != "" {
|
||||||
f, err := os.Create(*memprofile)
|
f, err := os.Create(*memprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create memory profile: ", err))
|
panic(fmt.Sprintf("could not create memory profile: ", err))
|
||||||
}
|
}
|
||||||
defer func () { pprof.WriteHeapProfile(f) ; f.Close() }()
|
defer func() { pprof.WriteHeapProfile(f); f.Close() }()
|
||||||
}
|
}
|
||||||
basic_test()
|
basic_test()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,84 +13,93 @@ const buffSize = 32
|
|||||||
|
|
||||||
func basic_test() {
|
func basic_test() {
|
||||||
|
|
||||||
// TODO need a way to look up who our link-local neighbors are for each iface!
|
// TODO need a way to look up who our link-local neighbors are for each iface!
|
||||||
|
|
||||||
addr, err := net.ResolveTCPAddr("tcp", "[::1]:9001")
|
addr, err := net.ResolveTCPAddr("tcp", "[::1]:9001")
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
listener, err := net.ListenTCP("tcp", addr)
|
panic(err)
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
defer listener.Close()
|
listener, err := net.ListenTCP("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer listener.Close()
|
||||||
|
|
||||||
go func () {
|
go func() {
|
||||||
send, err := net.DialTCP("tcp", nil, addr)
|
send, err := net.DialTCP("tcp", nil, addr)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
defer send.Close()
|
panic(err)
|
||||||
msg := make([]byte, 1280)
|
}
|
||||||
bss := make(net.Buffers, 0, 1024)
|
defer send.Close()
|
||||||
count := 0
|
msg := make([]byte, 1280)
|
||||||
for {
|
bss := make(net.Buffers, 0, 1024)
|
||||||
time.Sleep(100*time.Millisecond)
|
count := 0
|
||||||
for len(bss) < count {
|
for {
|
||||||
bss = append(bss, msg)
|
time.Sleep(100 * time.Millisecond)
|
||||||
}
|
for len(bss) < count {
|
||||||
bss.WriteTo(send)
|
bss = append(bss, msg)
|
||||||
count++
|
}
|
||||||
//send.Write(msg)
|
bss.WriteTo(send)
|
||||||
}
|
count++
|
||||||
}()
|
//send.Write(msg)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
numPackets := 1000000
|
numPackets := 1000000
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
//msg := make([]byte, 1280)
|
//msg := make([]byte, 1280)
|
||||||
sock, err := listener.AcceptTCP()
|
sock, err := listener.AcceptTCP()
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
defer sock.Close()
|
panic(err)
|
||||||
for {
|
}
|
||||||
msg := make([]byte, 1280*buffSize)
|
defer sock.Close()
|
||||||
n, err := sock.Read(msg)
|
for {
|
||||||
if err != nil { panic(err) }
|
msg := make([]byte, 1280*buffSize)
|
||||||
msg = msg[:n]
|
n, err := sock.Read(msg)
|
||||||
fmt.Println("Read:", n)
|
if err != nil {
|
||||||
for len(msg) > 1280 {
|
panic(err)
|
||||||
// handle message
|
}
|
||||||
msg = msg[1280:]
|
msg = msg[:n]
|
||||||
}
|
fmt.Println("Read:", n)
|
||||||
// handle remaining fragment of message
|
for len(msg) > 1280 {
|
||||||
//fmt.Println(n)
|
// handle message
|
||||||
}
|
msg = msg[1280:]
|
||||||
timed := time.Since(start)
|
}
|
||||||
|
// handle remaining fragment of message
|
||||||
|
//fmt.Println(n)
|
||||||
|
}
|
||||||
|
timed := time.Since(start)
|
||||||
|
|
||||||
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
fmt.Printf("%f packets per second\n", float64(numPackets)/timed.Seconds())
|
||||||
|
|
||||||
_ = func (in (chan<- int)) {
|
_ = func(in chan<- int) {
|
||||||
close(in)
|
close(in)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
|
||||||
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
var memprofile = flag.String("memprofile", "", "write memory profile to this file")
|
||||||
|
|
||||||
func main () {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if *cpuprofile != "" {
|
if *cpuprofile != "" {
|
||||||
f, err := os.Create(*cpuprofile)
|
f, err := os.Create(*cpuprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
panic(fmt.Sprintf("could not create CPU profile: ", err))
|
||||||
}
|
}
|
||||||
if err := pprof.StartCPUProfile(f); err != nil {
|
if err := pprof.StartCPUProfile(f); err != nil {
|
||||||
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
panic(fmt.Sprintf("could not start CPU profile: ", err))
|
||||||
}
|
}
|
||||||
defer pprof.StopCPUProfile()
|
defer pprof.StopCPUProfile()
|
||||||
}
|
}
|
||||||
if *memprofile != "" {
|
if *memprofile != "" {
|
||||||
f, err := os.Create(*memprofile)
|
f, err := os.Create(*memprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("could not create memory profile: ", err))
|
panic(fmt.Sprintf("could not create memory profile: ", err))
|
||||||
}
|
}
|
||||||
defer func () { pprof.WriteHeapProfile(f) ; f.Close() }()
|
defer func() { pprof.WriteHeapProfile(f); f.Close() }()
|
||||||
}
|
}
|
||||||
basic_test()
|
basic_test()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/songgao/water"
|
"github.com/songgao/water"
|
||||||
)
|
)
|
||||||
@ -17,54 +17,56 @@ func setup_dev() *water.Interface {
|
|||||||
DeviceType: water.TUN,
|
DeviceType: water.TUN,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return ifce
|
return ifce
|
||||||
}
|
}
|
||||||
|
|
||||||
func setup_dev1() *water.Interface {
|
func setup_dev1() *water.Interface {
|
||||||
ifce := setup_dev()
|
ifce := setup_dev()
|
||||||
cmd := exec.Command("ip", "-f", "inet6",
|
cmd := exec.Command("ip", "-f", "inet6",
|
||||||
"addr", "add", "fc00::2/8",
|
"addr", "add", "fc00::2/8",
|
||||||
"dev", ifce.Name())
|
"dev", ifce.Name())
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
panic("Failed to assign address")
|
panic("Failed to assign address")
|
||||||
}
|
}
|
||||||
cmd = exec.Command("ip", "link", "set",
|
cmd = exec.Command("ip", "link", "set",
|
||||||
"dev", ifce.Name(),
|
"dev", ifce.Name(),
|
||||||
"mtu", fmt.Sprintf("%d", mtu),
|
"mtu", fmt.Sprintf("%d", mtu),
|
||||||
"up")
|
"up")
|
||||||
out, err = cmd.CombinedOutput()
|
out, err = cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
panic("Failed to bring up interface")
|
panic("Failed to bring up interface")
|
||||||
}
|
}
|
||||||
return ifce
|
return ifce
|
||||||
}
|
}
|
||||||
|
|
||||||
func connect(ifce *water.Interface) {
|
func connect(ifce *water.Interface) {
|
||||||
conn, err := net.DialTimeout("tcp", "192.168.2.2:9001", time.Second)
|
conn, err := net.DialTimeout("tcp", "192.168.2.2:9001", time.Second)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
sock := conn.(*net.TCPConn)
|
panic(err)
|
||||||
// TODO go a worker to move packets to/from the tun
|
}
|
||||||
|
sock := conn.(*net.TCPConn)
|
||||||
|
// TODO go a worker to move packets to/from the tun
|
||||||
}
|
}
|
||||||
|
|
||||||
func bench() {
|
func bench() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ifce := setup_dev1()
|
ifce := setup_dev1()
|
||||||
connect(ifce)
|
connect(ifce)
|
||||||
bench()
|
bench()
|
||||||
fmt.Println("Done?")
|
fmt.Println("Done?")
|
||||||
return
|
return
|
||||||
ifce, err := water.New(water.Config{
|
ifce, err := water.New(water.Config{
|
||||||
DeviceType: water.TUN,
|
DeviceType: water.TUN,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Interface Name: %s\n", ifce.Name())
|
log.Printf("Interface Name: %s\n", ifce.Name())
|
||||||
@ -73,10 +75,9 @@ func main() {
|
|||||||
for {
|
for {
|
||||||
n, err := ifce.Read(packet)
|
n, err := ifce.Read(packet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
log.Printf("Packet Received: % x\n", packet[:n])
|
log.Printf("Packet Received: % x\n", packet[:n])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
|
||||||
"github.com/songgao/water"
|
"github.com/songgao/water"
|
||||||
)
|
)
|
||||||
@ -17,84 +17,84 @@ func setup_dev() *water.Interface {
|
|||||||
DeviceType: water.TUN,
|
DeviceType: water.TUN,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return ifce
|
return ifce
|
||||||
}
|
}
|
||||||
|
|
||||||
func setup_dev1() *water.Interface {
|
func setup_dev1() *water.Interface {
|
||||||
ifce := setup_dev()
|
ifce := setup_dev()
|
||||||
cmd := exec.Command("ip", "-f", "inet6",
|
cmd := exec.Command("ip", "-f", "inet6",
|
||||||
"addr", "add", "fc00::1/8",
|
"addr", "add", "fc00::1/8",
|
||||||
"dev", ifce.Name())
|
"dev", ifce.Name())
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
fmt.Println(string(err))
|
fmt.Println(string(err))
|
||||||
panic("Failed to assign address")
|
panic("Failed to assign address")
|
||||||
}
|
}
|
||||||
cmd = exec.Command("ip", "link", "set",
|
cmd = exec.Command("ip", "link", "set",
|
||||||
"dev", tun.name,
|
"dev", tun.name,
|
||||||
"mtu", fmt.Sprintf("%d", mtu),
|
"mtu", fmt.Sprintf("%d", mtu),
|
||||||
"up")
|
"up")
|
||||||
out, err = cmd.CombinedOutput()
|
out, err = cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
panic("Failed to bring up interface")
|
panic("Failed to bring up interface")
|
||||||
}
|
}
|
||||||
return ifce
|
return ifce
|
||||||
}
|
}
|
||||||
|
|
||||||
func addNS(name string) {
|
func addNS(name string) {
|
||||||
cmd := exec.COmmand("ip", "netns", "add", name)
|
cmd := exec.COmmand("ip", "netns", "add", name)
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
panic("Failed to setup netns")
|
panic("Failed to setup netns")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func delNS(name string) {
|
func delNS(name string) {
|
||||||
cmd := exec.COmmand("ip", "netns", "delete", name)
|
cmd := exec.COmmand("ip", "netns", "delete", name)
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
panic("Failed to setup netns")
|
panic("Failed to setup netns")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func doInNetNS(comm ...string) *exec.Cmd {
|
func doInNetNS(comm ...string) *exec.Cmd {
|
||||||
return exec.Command("ip", "netns", "exec", netnsName, comm...)
|
return exec.Command("ip", "netns", "exec", netnsName, comm...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setup_dev2() *water.Interface {
|
func setup_dev2() *water.Interface {
|
||||||
ifce := setup_dev()
|
ifce := setup_dev()
|
||||||
addNS(netnsName)
|
addNS(netnsName)
|
||||||
cmd := exec.Command("ip", "link", "set", ifce.Name(), "netns", netnsName)
|
cmd := exec.Command("ip", "link", "set", ifce.Name(), "netns", netnsName)
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
panic("Failed to move tun to netns")
|
panic("Failed to move tun to netns")
|
||||||
}
|
}
|
||||||
cmd = doInNetNS("ip", "-f", "inet6",
|
cmd = doInNetNS("ip", "-f", "inet6",
|
||||||
"addr", "add", "fc00::2/8",
|
"addr", "add", "fc00::2/8",
|
||||||
"dev", ifce.Name())
|
"dev", ifce.Name())
|
||||||
out, err = cmd.CombinedOutput()
|
out, err = cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
panic("Failed to assign address")
|
panic("Failed to assign address")
|
||||||
}
|
}
|
||||||
cmd = doInNetNS("ip", "link", "set",
|
cmd = doInNetNS("ip", "link", "set",
|
||||||
"dev", tun.name,
|
"dev", tun.name,
|
||||||
"mtu", fmt.Sprintf("%d", mtu),
|
"mtu", fmt.Sprintf("%d", mtu),
|
||||||
"up")
|
"up")
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
fmt.Println(string(err))
|
fmt.Println(string(err))
|
||||||
panic("Failed to bring up interface")
|
panic("Failed to bring up interface")
|
||||||
}
|
}
|
||||||
return ifce
|
return ifce
|
||||||
}
|
}
|
||||||
|
|
||||||
func connect() {
|
func connect() {
|
||||||
@ -109,7 +109,7 @@ func main() {
|
|||||||
DeviceType: water.TUN,
|
DeviceType: water.TUN,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Interface Name: %s\n", ifce.Name())
|
log.Printf("Interface Name: %s\n", ifce.Name())
|
||||||
@ -118,10 +118,9 @@ func main() {
|
|||||||
for {
|
for {
|
||||||
n, err := ifce.Read(packet)
|
n, err := ifce.Read(packet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
log.Printf("Packet Received: % x\n", packet[:n])
|
log.Printf("Packet Received: % x\n", packet[:n])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
|
||||||
"github.com/songgao/water"
|
"github.com/songgao/water"
|
||||||
)
|
)
|
||||||
@ -17,87 +17,86 @@ func setup_dev() *water.Interface {
|
|||||||
DeviceType: water.TUN,
|
DeviceType: water.TUN,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return ifce
|
return ifce
|
||||||
}
|
}
|
||||||
|
|
||||||
func setup_dev1() *water.Interface {
|
func setup_dev1() *water.Interface {
|
||||||
ifce := setup_dev()
|
ifce := setup_dev()
|
||||||
cmd := exec.Command("ip", "-f", "inet6",
|
cmd := exec.Command("ip", "-f", "inet6",
|
||||||
"addr", "add", "fc00::1/8",
|
"addr", "add", "fc00::1/8",
|
||||||
"dev", ifce.Name())
|
"dev", ifce.Name())
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
fmt.Println(string(err))
|
fmt.Println(string(err))
|
||||||
panic("Failed to assign address")
|
panic("Failed to assign address")
|
||||||
}
|
}
|
||||||
cmd = exec.Command("ip", "link", "set",
|
cmd = exec.Command("ip", "link", "set",
|
||||||
"dev", tun.name,
|
"dev", tun.name,
|
||||||
"mtu", fmt.Sprintf("%d", mtu),
|
"mtu", fmt.Sprintf("%d", mtu),
|
||||||
"up")
|
"up")
|
||||||
out, err = cmd.CombinedOutput()
|
out, err = cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
panic("Failed to bring up interface")
|
panic("Failed to bring up interface")
|
||||||
}
|
}
|
||||||
return ifce
|
return ifce
|
||||||
}
|
}
|
||||||
|
|
||||||
func addNS(name string) {
|
func addNS(name string) {
|
||||||
cmd := exec.COmmand("ip", "netns", "add", name)
|
cmd := exec.COmmand("ip", "netns", "add", name)
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
panic("Failed to setup netns")
|
panic("Failed to setup netns")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func delNS(name string) {
|
func delNS(name string) {
|
||||||
cmd := exec.COmmand("ip", "netns", "delete", name)
|
cmd := exec.COmmand("ip", "netns", "delete", name)
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
panic("Failed to setup netns")
|
panic("Failed to setup netns")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func doInNetNS(comm ...string) *exec.Cmd {
|
func doInNetNS(comm ...string) *exec.Cmd {
|
||||||
return exec.Command("ip", "netns", "exec", netnsName, comm...)
|
return exec.Command("ip", "netns", "exec", netnsName, comm...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setup_dev2() *water.Interface {
|
func setup_dev2() *water.Interface {
|
||||||
ifce := setup_dev()
|
ifce := setup_dev()
|
||||||
addNS(netnsName)
|
addNS(netnsName)
|
||||||
cmd := exec.Command("ip", "link", "set", ifce.Name(), "netns", netnsName)
|
cmd := exec.Command("ip", "link", "set", ifce.Name(), "netns", netnsName)
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
panic("Failed to move tun to netns")
|
panic("Failed to move tun to netns")
|
||||||
}
|
}
|
||||||
cmd =
|
cmd = exec.Command(
|
||||||
cmd = exec.Command(
|
"ip", "-f", "inet6",
|
||||||
"ip", "-f", "inet6",
|
"addr", "add", "fc00::2/8",
|
||||||
"addr", "add", "fc00::2/8",
|
"dev", ifce.Name())
|
||||||
"dev", ifce.Name())
|
out, err := cmd.CombinedOutput()
|
||||||
out, err := cmd.CombinedOutput()
|
if err != nil {
|
||||||
if err != nil {
|
fmt.Println(string(out))
|
||||||
fmt.Println(string(out))
|
panic("Failed to assign address")
|
||||||
panic("Failed to assign address")
|
}
|
||||||
}
|
cmd = exec.Command(
|
||||||
cmd = exec.Command(
|
"ip", "link", "set",
|
||||||
"ip", "link", "set",
|
"dev", tun.name,
|
||||||
"dev", tun.name,
|
"mtu", fmt.Sprintf("%d", mtu),
|
||||||
"mtu", fmt.Sprintf("%d", mtu),
|
"up")
|
||||||
"up")
|
out, err := cmd.CombinedOutput()
|
||||||
out, err := cmd.CombinedOutput()
|
if err != nil {
|
||||||
if err != nil {
|
fmt.Println(string(out))
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(err))
|
||||||
fmt.Println(string(err))
|
panic("Failed to bring up interface")
|
||||||
panic("Failed to bring up interface")
|
}
|
||||||
}
|
return ifce
|
||||||
return ifce
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func connect() {
|
func connect() {
|
||||||
@ -112,7 +111,7 @@ func main() {
|
|||||||
DeviceType: water.TUN,
|
DeviceType: water.TUN,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Interface Name: %s\n", ifce.Name())
|
log.Printf("Interface Name: %s\n", ifce.Name())
|
||||||
@ -121,10 +120,9 @@ func main() {
|
|||||||
for {
|
for {
|
||||||
n, err := ifce.Read(packet)
|
n, err := ifce.Read(packet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
log.Printf("Packet Received: % x\n", packet[:n])
|
log.Printf("Packet Received: % x\n", packet[:n])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,14 +27,18 @@ func main() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
address := net.ParseIP("fc00::1")
|
address := net.ParseIP("fc00::1")
|
||||||
tuntap, err := tun.OpenTun(address)
|
tuntap, err := tun.OpenTun(address)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
defer tuntap.Close()
|
defer tuntap.Close()
|
||||||
// read data from tun into rCh channel.
|
// read data from tun into rCh channel.
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
if err := tuntap.Read(rCh); err != nil { panic(err) }
|
if err := tuntap.Read(rCh); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
@ -6,34 +6,35 @@ import "fmt"
|
|||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
for idx := 0 ; idx < 64 ; idx++ {
|
for idx := 0; idx < 64; idx++ {
|
||||||
num := uint64(1) << uint(idx)
|
num := uint64(1) << uint(idx)
|
||||||
encoded := make([]byte, 10)
|
encoded := make([]byte, 10)
|
||||||
length := wire.Encode_uint64(num, encoded)
|
length := wire.Encode_uint64(num, encoded)
|
||||||
decoded, _ := wire.Decode_uint64(encoded[:length])
|
decoded, _ := wire.Decode_uint64(encoded[:length])
|
||||||
if decoded != num { panic(fmt.Sprintf("%d != %d", decoded, num)) }
|
if decoded != num {
|
||||||
}
|
panic(fmt.Sprintf("%d != %d", decoded, num))
|
||||||
const count = 1000000
|
}
|
||||||
start := time.Now()
|
}
|
||||||
encoded := make([]byte, 10)
|
const count = 1000000
|
||||||
//num := ^uint64(0) // Longest possible value for full uint64 range
|
start := time.Now()
|
||||||
num := ^uint64(0) >> 1 // Largest positive int64 (real use case)
|
encoded := make([]byte, 10)
|
||||||
//num := uint64(0) // Shortest possible value, most will be of this length
|
//num := ^uint64(0) // Longest possible value for full uint64 range
|
||||||
length := wire.Encode_uint64(num, encoded)
|
num := ^uint64(0) >> 1 // Largest positive int64 (real use case)
|
||||||
for idx := 0 ; idx < count ; idx++ {
|
//num := uint64(0) // Shortest possible value, most will be of this length
|
||||||
wire.Encode_uint64(num, encoded)
|
length := wire.Encode_uint64(num, encoded)
|
||||||
}
|
for idx := 0; idx < count; idx++ {
|
||||||
timed := time.Since(start)
|
wire.Encode_uint64(num, encoded)
|
||||||
fmt.Println("Ops:", count/timed.Seconds())
|
}
|
||||||
fmt.Println("Time:", timed.Nanoseconds()/count)
|
timed := time.Since(start)
|
||||||
|
fmt.Println("Ops:", count/timed.Seconds())
|
||||||
|
fmt.Println("Time:", timed.Nanoseconds()/count)
|
||||||
|
|
||||||
encoded = encoded[:length]
|
encoded = encoded[:length]
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
for idx := 0 ; idx < count ; idx++ {
|
for idx := 0; idx < count; idx++ {
|
||||||
wire.Decode_uint64(encoded)
|
wire.Decode_uint64(encoded)
|
||||||
}
|
}
|
||||||
timed = time.Since(start)
|
timed = time.Since(start)
|
||||||
fmt.Println("Ops:", count/timed.Seconds())
|
fmt.Println("Ops:", count/timed.Seconds())
|
||||||
fmt.Println("Time:", timed.Nanoseconds()/count)
|
fmt.Println("Time:", timed.Nanoseconds()/count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,108 +1,120 @@
|
|||||||
package yggdrasil
|
package yggdrasil
|
||||||
|
|
||||||
type address [16]byte // IPv6 address within the network
|
type address [16]byte // IPv6 address within the network
|
||||||
type subnet [8]byte // It's a /64
|
type subnet [8]byte // It's a /64
|
||||||
|
|
||||||
var address_prefix = [...]byte{0xfd} // For node addresses + local subnets
|
var address_prefix = [...]byte{0xfd} // For node addresses + local subnets
|
||||||
|
|
||||||
func (a *address) isValid() bool {
|
func (a *address) isValid() bool {
|
||||||
for idx := range address_prefix {
|
for idx := range address_prefix {
|
||||||
if (*a)[idx] != address_prefix[idx] { return false }
|
if (*a)[idx] != address_prefix[idx] {
|
||||||
}
|
return false
|
||||||
return (*a)[len(address_prefix)] & 0x80 == 0
|
}
|
||||||
|
}
|
||||||
|
return (*a)[len(address_prefix)]&0x80 == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *subnet) isValid() bool {
|
func (s *subnet) isValid() bool {
|
||||||
for idx := range address_prefix {
|
for idx := range address_prefix {
|
||||||
if (*s)[idx] != address_prefix[idx] { return false }
|
if (*s)[idx] != address_prefix[idx] {
|
||||||
}
|
return false
|
||||||
return (*s)[len(address_prefix)] & 0x80 != 0
|
}
|
||||||
|
}
|
||||||
|
return (*s)[len(address_prefix)]&0x80 != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func address_addrForNodeID(nid *NodeID) *address {
|
func address_addrForNodeID(nid *NodeID) *address {
|
||||||
// 128 bit address
|
// 128 bit address
|
||||||
// Begins with prefix
|
// Begins with prefix
|
||||||
// Next bit is a 0
|
// Next bit is a 0
|
||||||
// Next 7 bits, interpreted as a uint, are # of leading 1s in the NodeID
|
// Next 7 bits, interpreted as a uint, are # of leading 1s in the NodeID
|
||||||
// Leading 1s and first leading 0 of the NodeID are truncated off
|
// Leading 1s and first leading 0 of the NodeID are truncated off
|
||||||
// The rest is appended to the IPv6 address (truncated to 128 bits total)
|
// The rest is appended to the IPv6 address (truncated to 128 bits total)
|
||||||
var addr address
|
var addr address
|
||||||
var temp []byte
|
var temp []byte
|
||||||
done := false
|
done := false
|
||||||
ones := byte(0)
|
ones := byte(0)
|
||||||
bits := byte(0)
|
bits := byte(0)
|
||||||
nBits := 0
|
nBits := 0
|
||||||
for idx := 0 ; idx < 8*len(nid) ; idx++ {
|
for idx := 0; idx < 8*len(nid); idx++ {
|
||||||
bit := (nid[idx/8] & (0x80 >> byte(idx % 8))) >> byte(7 - (idx % 8))
|
bit := (nid[idx/8] & (0x80 >> byte(idx%8))) >> byte(7-(idx%8))
|
||||||
if !done && bit != 0 {
|
if !done && bit != 0 {
|
||||||
ones++
|
ones++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !done && bit == 0 {
|
if !done && bit == 0 {
|
||||||
done = true
|
done = true
|
||||||
continue // FIXME this assumes that ones <= 127
|
continue // FIXME this assumes that ones <= 127
|
||||||
}
|
}
|
||||||
bits = (bits << 1) | bit
|
bits = (bits << 1) | bit
|
||||||
nBits++
|
nBits++
|
||||||
if nBits == 8 {
|
if nBits == 8 {
|
||||||
nBits = 0
|
nBits = 0
|
||||||
temp = append(temp, bits)
|
temp = append(temp, bits)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
copy(addr[:], address_prefix[:])
|
copy(addr[:], address_prefix[:])
|
||||||
addr[len(address_prefix)] = ones & 0x7f
|
addr[len(address_prefix)] = ones & 0x7f
|
||||||
copy(addr[len(address_prefix)+1:], temp)
|
copy(addr[len(address_prefix)+1:], temp)
|
||||||
return &addr
|
return &addr
|
||||||
}
|
}
|
||||||
|
|
||||||
func address_subnetForNodeID(nid *NodeID) *subnet {
|
func address_subnetForNodeID(nid *NodeID) *subnet {
|
||||||
// Exactly as the address version, with two exceptions:
|
// Exactly as the address version, with two exceptions:
|
||||||
// 1) The first bit after the fixed prefix is a 1 instead of a 0
|
// 1) The first bit after the fixed prefix is a 1 instead of a 0
|
||||||
// 2) It's truncated to a subnet prefix length instead of 128 bits
|
// 2) It's truncated to a subnet prefix length instead of 128 bits
|
||||||
addr := *address_addrForNodeID(nid)
|
addr := *address_addrForNodeID(nid)
|
||||||
var snet subnet
|
var snet subnet
|
||||||
copy(snet[:], addr[:])
|
copy(snet[:], addr[:])
|
||||||
snet[len(address_prefix)] |= 0x80
|
snet[len(address_prefix)] |= 0x80
|
||||||
return &snet
|
return &snet
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *address) getNodeIDandMask() (*NodeID, *NodeID) {
|
func (a *address) getNodeIDandMask() (*NodeID, *NodeID) {
|
||||||
// Mask is a bitmask to mark the bits visible from the address
|
// Mask is a bitmask to mark the bits visible from the address
|
||||||
// This means truncated leading 1s, first leading 0, and visible part of addr
|
// This means truncated leading 1s, first leading 0, and visible part of addr
|
||||||
var nid NodeID
|
var nid NodeID
|
||||||
var mask NodeID
|
var mask NodeID
|
||||||
ones := int(a[len(address_prefix)] & 0x7f)
|
ones := int(a[len(address_prefix)] & 0x7f)
|
||||||
for idx := 0 ; idx < ones ; idx++ { nid[idx/8] |= 0x80 >> byte(idx % 8) }
|
for idx := 0; idx < ones; idx++ {
|
||||||
nidOffset := ones+1
|
nid[idx/8] |= 0x80 >> byte(idx%8)
|
||||||
addrOffset := 8*len(address_prefix)+8
|
}
|
||||||
for idx := addrOffset ; idx < 8*len(a) ; idx++ {
|
nidOffset := ones + 1
|
||||||
bits := a[idx/8] & (0x80 >> byte(idx % 8))
|
addrOffset := 8*len(address_prefix) + 8
|
||||||
bits <<= byte(idx % 8)
|
for idx := addrOffset; idx < 8*len(a); idx++ {
|
||||||
nidIdx := nidOffset + (idx - addrOffset)
|
bits := a[idx/8] & (0x80 >> byte(idx%8))
|
||||||
bits >>= byte(nidIdx % 8)
|
bits <<= byte(idx % 8)
|
||||||
nid[nidIdx/8] |= bits
|
nidIdx := nidOffset + (idx - addrOffset)
|
||||||
}
|
bits >>= byte(nidIdx % 8)
|
||||||
maxMask := 8*(len(a) - len(address_prefix) - 1) + ones + 1
|
nid[nidIdx/8] |= bits
|
||||||
for idx := 0 ; idx < maxMask ; idx++ { mask[idx/8] |= 0x80 >> byte(idx % 8) }
|
}
|
||||||
return &nid, &mask
|
maxMask := 8*(len(a)-len(address_prefix)-1) + ones + 1
|
||||||
|
for idx := 0; idx < maxMask; idx++ {
|
||||||
|
mask[idx/8] |= 0x80 >> byte(idx%8)
|
||||||
|
}
|
||||||
|
return &nid, &mask
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *subnet) getNodeIDandMask() (*NodeID, *NodeID) {
|
func (s *subnet) getNodeIDandMask() (*NodeID, *NodeID) {
|
||||||
// As witht he address version, but visible parts of the subnet prefix instead
|
// As witht he address version, but visible parts of the subnet prefix instead
|
||||||
var nid NodeID
|
var nid NodeID
|
||||||
var mask NodeID
|
var mask NodeID
|
||||||
ones := int(s[len(address_prefix)] & 0x7f)
|
ones := int(s[len(address_prefix)] & 0x7f)
|
||||||
for idx := 0 ; idx < ones ; idx++ { nid[idx/8] |= 0x80 >> byte(idx % 8) }
|
for idx := 0; idx < ones; idx++ {
|
||||||
nidOffset := ones+1
|
nid[idx/8] |= 0x80 >> byte(idx%8)
|
||||||
addrOffset := 8*len(address_prefix)+8
|
}
|
||||||
for idx := addrOffset ; idx < 8*len(s) ; idx++ {
|
nidOffset := ones + 1
|
||||||
bits := s[idx/8] & (0x80 >> byte(idx % 8))
|
addrOffset := 8*len(address_prefix) + 8
|
||||||
bits <<= byte(idx % 8)
|
for idx := addrOffset; idx < 8*len(s); idx++ {
|
||||||
nidIdx := nidOffset + (idx - addrOffset)
|
bits := s[idx/8] & (0x80 >> byte(idx%8))
|
||||||
bits >>= byte(nidIdx % 8)
|
bits <<= byte(idx % 8)
|
||||||
nid[nidIdx/8] |= bits
|
nidIdx := nidOffset + (idx - addrOffset)
|
||||||
}
|
bits >>= byte(nidIdx % 8)
|
||||||
maxMask := 8*(len(s) - len(address_prefix) - 1) + ones + 1
|
nid[nidIdx/8] |= bits
|
||||||
for idx := 0 ; idx < maxMask ; idx++ { mask[idx/8] |= 0x80 >> byte(idx % 8) }
|
}
|
||||||
return &nid, &mask
|
maxMask := 8*(len(s)-len(address_prefix)-1) + ones + 1
|
||||||
|
for idx := 0; idx < maxMask; idx++ {
|
||||||
|
mask[idx/8] |= 0x80 >> byte(idx%8)
|
||||||
|
}
|
||||||
|
return &nid, &mask
|
||||||
}
|
}
|
||||||
|
@ -4,61 +4,60 @@ import "io/ioutil"
|
|||||||
import "log"
|
import "log"
|
||||||
|
|
||||||
type Core struct {
|
type Core struct {
|
||||||
// This is the main data structure that holds everything else for a node
|
// This is the main data structure that holds everything else for a node
|
||||||
// TODO? move keys out of core and into something more appropriate
|
// TODO? move keys out of core and into something more appropriate
|
||||||
// e.g. box keys live in sessions
|
// e.g. box keys live in sessions
|
||||||
// sig keys live in peers or sigs (or wherever signing/validating logic is)
|
// sig keys live in peers or sigs (or wherever signing/validating logic is)
|
||||||
boxPub boxPubKey
|
boxPub boxPubKey
|
||||||
boxPriv boxPrivKey
|
boxPriv boxPrivKey
|
||||||
sigPub sigPubKey
|
sigPub sigPubKey
|
||||||
sigPriv sigPrivKey
|
sigPriv sigPrivKey
|
||||||
switchTable switchTable
|
switchTable switchTable
|
||||||
peers peers
|
peers peers
|
||||||
sigs sigManager
|
sigs sigManager
|
||||||
sessions sessions
|
sessions sessions
|
||||||
router router
|
router router
|
||||||
dht dht
|
dht dht
|
||||||
tun tunDevice
|
tun tunDevice
|
||||||
searches searches
|
searches searches
|
||||||
tcp *tcpInterface
|
tcp *tcpInterface
|
||||||
udp *udpInterface
|
udp *udpInterface
|
||||||
log *log.Logger
|
log *log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) Init() {
|
func (c *Core) Init() {
|
||||||
// Only called by the simulator, to set up nodes with random keys
|
// Only called by the simulator, to set up nodes with random keys
|
||||||
bpub, bpriv := newBoxKeys()
|
bpub, bpriv := newBoxKeys()
|
||||||
spub, spriv := newSigKeys()
|
spub, spriv := newSigKeys()
|
||||||
c.init(bpub, bpriv, spub, spriv)
|
c.init(bpub, bpriv, spub, spriv)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) init(bpub *boxPubKey,
|
func (c *Core) init(bpub *boxPubKey,
|
||||||
bpriv *boxPrivKey,
|
bpriv *boxPrivKey,
|
||||||
spub *sigPubKey,
|
spub *sigPubKey,
|
||||||
spriv *sigPrivKey) {
|
spriv *sigPrivKey) {
|
||||||
// TODO separate init and start functions
|
// TODO separate init and start functions
|
||||||
// Init sets up structs
|
// Init sets up structs
|
||||||
// Start launches goroutines that depend on structs being set up
|
// Start launches goroutines that depend on structs being set up
|
||||||
// This is pretty much required to avoid race conditions
|
// This is pretty much required to avoid race conditions
|
||||||
util_initByteStore()
|
util_initByteStore()
|
||||||
c.log = log.New(ioutil.Discard, "", 0)
|
c.log = log.New(ioutil.Discard, "", 0)
|
||||||
c.boxPub, c.boxPriv = *bpub, *bpriv
|
c.boxPub, c.boxPriv = *bpub, *bpriv
|
||||||
c.sigPub, c.sigPriv = *spub, *spriv
|
c.sigPub, c.sigPriv = *spub, *spriv
|
||||||
c.sigs.init()
|
c.sigs.init()
|
||||||
c.searches.init(c)
|
c.searches.init(c)
|
||||||
c.dht.init(c)
|
c.dht.init(c)
|
||||||
c.sessions.init(c)
|
c.sessions.init(c)
|
||||||
c.peers.init(c)
|
c.peers.init(c)
|
||||||
c.router.init(c)
|
c.router.init(c)
|
||||||
c.switchTable.init(c, c.sigPub) // TODO move before peers? before router?
|
c.switchTable.init(c, c.sigPub) // TODO move before peers? before router?
|
||||||
c.tun.init(c)
|
c.tun.init(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) GetNodeID() *NodeID {
|
func (c *Core) GetNodeID() *NodeID {
|
||||||
return getNodeID(&c.boxPub)
|
return getNodeID(&c.boxPub)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) GetTreeID() *TreeID {
|
func (c *Core) GetTreeID() *TreeID {
|
||||||
return getTreeID(&c.sigPub)
|
return getTreeID(&c.sigPub)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,20 +28,22 @@ type TreeID [TreeIDLen]byte
|
|||||||
type handle [handleLen]byte
|
type handle [handleLen]byte
|
||||||
|
|
||||||
func getNodeID(pub *boxPubKey) *NodeID {
|
func getNodeID(pub *boxPubKey) *NodeID {
|
||||||
h := sha512.Sum512(pub[:])
|
h := sha512.Sum512(pub[:])
|
||||||
return (*NodeID)(&h)
|
return (*NodeID)(&h)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTreeID(pub *sigPubKey) *TreeID {
|
func getTreeID(pub *sigPubKey) *TreeID {
|
||||||
h := sha512.Sum512(pub[:])
|
h := sha512.Sum512(pub[:])
|
||||||
return (*TreeID)(&h)
|
return (*TreeID)(&h)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newHandle() *handle {
|
func newHandle() *handle {
|
||||||
var h handle
|
var h handle
|
||||||
_, err := rand.Read(h[:])
|
_, err := rand.Read(h[:])
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
return &h
|
panic(err)
|
||||||
|
}
|
||||||
|
return &h
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -57,26 +59,28 @@ type sigPrivKey [sigPrivKeyLen]byte
|
|||||||
type sigBytes [sigLen]byte
|
type sigBytes [sigLen]byte
|
||||||
|
|
||||||
func newSigKeys() (*sigPubKey, *sigPrivKey) {
|
func newSigKeys() (*sigPubKey, *sigPrivKey) {
|
||||||
var pub sigPubKey
|
var pub sigPubKey
|
||||||
var priv sigPrivKey
|
var priv sigPrivKey
|
||||||
pubSlice, privSlice, err := ed25519.GenerateKey(rand.Reader)
|
pubSlice, privSlice, err := ed25519.GenerateKey(rand.Reader)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
copy(pub[:], pubSlice)
|
panic(err)
|
||||||
copy(priv[:], privSlice)
|
}
|
||||||
return &pub, &priv
|
copy(pub[:], pubSlice)
|
||||||
|
copy(priv[:], privSlice)
|
||||||
|
return &pub, &priv
|
||||||
}
|
}
|
||||||
|
|
||||||
func sign(priv *sigPrivKey, msg []byte) *sigBytes {
|
func sign(priv *sigPrivKey, msg []byte) *sigBytes {
|
||||||
var sig sigBytes
|
var sig sigBytes
|
||||||
sigSlice := ed25519.Sign(priv[:], msg)
|
sigSlice := ed25519.Sign(priv[:], msg)
|
||||||
copy(sig[:], sigSlice)
|
copy(sig[:], sigSlice)
|
||||||
return &sig
|
return &sig
|
||||||
}
|
}
|
||||||
|
|
||||||
func verify(pub *sigPubKey, msg []byte, sig *sigBytes) bool {
|
func verify(pub *sigPubKey, msg []byte, sig *sigBytes) bool {
|
||||||
// Should sig be an array instead of a slice?...
|
// Should sig be an array instead of a slice?...
|
||||||
// It's fixed size, but
|
// It's fixed size, but
|
||||||
return ed25519.Verify(pub[:], msg, sig[:])
|
return ed25519.Verify(pub[:], msg, sig[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -94,61 +98,68 @@ type boxSharedKey [boxSharedKeyLen]byte
|
|||||||
type boxNonce [boxNonceLen]byte
|
type boxNonce [boxNonceLen]byte
|
||||||
|
|
||||||
func newBoxKeys() (*boxPubKey, *boxPrivKey) {
|
func newBoxKeys() (*boxPubKey, *boxPrivKey) {
|
||||||
pubBytes, privBytes, err := box.GenerateKey(rand.Reader)
|
pubBytes, privBytes, err := box.GenerateKey(rand.Reader)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
pub := (*boxPubKey)(pubBytes)
|
panic(err)
|
||||||
priv := (*boxPrivKey)(privBytes)
|
}
|
||||||
return pub, priv
|
pub := (*boxPubKey)(pubBytes)
|
||||||
|
priv := (*boxPrivKey)(privBytes)
|
||||||
|
return pub, priv
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSharedKey(myPrivKey *boxPrivKey,
|
func getSharedKey(myPrivKey *boxPrivKey,
|
||||||
othersPubKey *boxPubKey) *boxSharedKey {
|
othersPubKey *boxPubKey) *boxSharedKey {
|
||||||
var shared [boxSharedKeyLen]byte
|
var shared [boxSharedKeyLen]byte
|
||||||
priv := (*[boxPrivKeyLen]byte)(myPrivKey)
|
priv := (*[boxPrivKeyLen]byte)(myPrivKey)
|
||||||
pub := (*[boxPubKeyLen]byte)(othersPubKey)
|
pub := (*[boxPubKeyLen]byte)(othersPubKey)
|
||||||
box.Precompute(&shared, pub, priv)
|
box.Precompute(&shared, pub, priv)
|
||||||
return (*boxSharedKey)(&shared)
|
return (*boxSharedKey)(&shared)
|
||||||
}
|
}
|
||||||
|
|
||||||
func boxOpen(shared *boxSharedKey,
|
func boxOpen(shared *boxSharedKey,
|
||||||
boxed []byte,
|
boxed []byte,
|
||||||
nonce *boxNonce) ([]byte, bool) {
|
nonce *boxNonce) ([]byte, bool) {
|
||||||
out := util_getBytes()
|
out := util_getBytes()
|
||||||
//return append(out, boxed...), true // XXX HACK to test without encryption
|
//return append(out, boxed...), true // XXX HACK to test without encryption
|
||||||
s := (*[boxSharedKeyLen]byte)(shared)
|
s := (*[boxSharedKeyLen]byte)(shared)
|
||||||
n := (*[boxNonceLen]byte)(nonce)
|
n := (*[boxNonceLen]byte)(nonce)
|
||||||
unboxed, success := box.OpenAfterPrecomputation(out, boxed, n, s)
|
unboxed, success := box.OpenAfterPrecomputation(out, boxed, n, s)
|
||||||
return unboxed, success
|
return unboxed, success
|
||||||
}
|
}
|
||||||
|
|
||||||
func boxSeal(shared *boxSharedKey, unboxed []byte, nonce *boxNonce) ([]byte, *boxNonce) {
|
func boxSeal(shared *boxSharedKey, unboxed []byte, nonce *boxNonce) ([]byte, *boxNonce) {
|
||||||
if nonce == nil { nonce = newBoxNonce() }
|
if nonce == nil {
|
||||||
nonce.update()
|
nonce = newBoxNonce()
|
||||||
out := util_getBytes()
|
}
|
||||||
//return append(out, unboxed...), nonce // XXX HACK to test without encryption
|
nonce.update()
|
||||||
s := (*[boxSharedKeyLen]byte)(shared)
|
out := util_getBytes()
|
||||||
n := (*[boxNonceLen]byte)(nonce)
|
//return append(out, unboxed...), nonce // XXX HACK to test without encryption
|
||||||
boxed := box.SealAfterPrecomputation(out, unboxed, n, s)
|
s := (*[boxSharedKeyLen]byte)(shared)
|
||||||
return boxed, nonce
|
n := (*[boxNonceLen]byte)(nonce)
|
||||||
|
boxed := box.SealAfterPrecomputation(out, unboxed, n, s)
|
||||||
|
return boxed, nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBoxNonce() *boxNonce {
|
func newBoxNonce() *boxNonce {
|
||||||
var nonce boxNonce
|
var nonce boxNonce
|
||||||
_, err := rand.Read(nonce[:])
|
_, err := rand.Read(nonce[:])
|
||||||
for ; err == nil && nonce[0] == 0xff ; _, err = rand.Read(nonce[:]){
|
for ; err == nil && nonce[0] == 0xff; _, err = rand.Read(nonce[:]) {
|
||||||
// Make sure nonce isn't too high
|
// Make sure nonce isn't too high
|
||||||
// This is just to make rollover unlikely to happen
|
// This is just to make rollover unlikely to happen
|
||||||
// Rollover is fine, but it may kill the session and force it to reopen
|
// Rollover is fine, but it may kill the session and force it to reopen
|
||||||
}
|
}
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
return &nonce
|
panic(err)
|
||||||
|
}
|
||||||
|
return &nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *boxNonce) update() {
|
func (n *boxNonce) update() {
|
||||||
oldNonce := *n
|
oldNonce := *n
|
||||||
n[len(n)-1] += 2
|
n[len(n)-1] += 2
|
||||||
for i := len(n)-2 ; i >= 0 ; i-- {
|
for i := len(n) - 2; i >= 0; i-- {
|
||||||
if n[i+1] < oldNonce[i+1] { n[i] += 1 }
|
if n[i+1] < oldNonce[i+1] {
|
||||||
}
|
n[i] += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,32 +15,32 @@ import "log"
|
|||||||
// Core
|
// Core
|
||||||
|
|
||||||
func (c *Core) DEBUG_getSigPub() sigPubKey {
|
func (c *Core) DEBUG_getSigPub() sigPubKey {
|
||||||
return (sigPubKey)(c.sigPub)
|
return (sigPubKey)(c.sigPub)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DEBUG_getBoxPub() boxPubKey {
|
func (c *Core) DEBUG_getBoxPub() boxPubKey {
|
||||||
return (boxPubKey)(c.boxPub)
|
return (boxPubKey)(c.boxPub)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DEBUG_getSend() (chan<- []byte) {
|
func (c *Core) DEBUG_getSend() chan<- []byte {
|
||||||
return c.tun.send
|
return c.tun.send
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DEBUG_getRecv() (<-chan []byte) {
|
func (c *Core) DEBUG_getRecv() <-chan []byte {
|
||||||
return c.tun.recv
|
return c.tun.recv
|
||||||
}
|
}
|
||||||
|
|
||||||
// Peer
|
// Peer
|
||||||
|
|
||||||
func (c *Core) DEBUG_getPeers() *peers {
|
func (c *Core) DEBUG_getPeers() *peers {
|
||||||
return &c.peers
|
return &c.peers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *peers) DEBUG_newPeer(box boxPubKey,
|
func (ps *peers) DEBUG_newPeer(box boxPubKey,
|
||||||
sig sigPubKey) *peer {
|
sig sigPubKey) *peer {
|
||||||
//in <-chan []byte,
|
//in <-chan []byte,
|
||||||
//out chan<- []byte) *peer {
|
//out chan<- []byte) *peer {
|
||||||
return ps.newPeer(&box, &sig)//, in, out)
|
return ps.newPeer(&box, &sig) //, in, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -55,47 +55,51 @@ func (ps *peers) DEBUG_startPeers() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
func (ps *peers) DEBUG_hasPeer(key sigPubKey) bool {
|
func (ps *peers) DEBUG_hasPeer(key sigPubKey) bool {
|
||||||
ports := ps.ports.Load().(map[switchPort]*peer)
|
ports := ps.ports.Load().(map[switchPort]*peer)
|
||||||
for _, p := range ports {
|
for _, p := range ports {
|
||||||
if p == nil { continue }
|
if p == nil {
|
||||||
if p.sig == key { return true }
|
continue
|
||||||
}
|
}
|
||||||
return false
|
if p.sig == key {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *peers) DEBUG_getPorts() map[switchPort]*peer {
|
func (ps *peers) DEBUG_getPorts() map[switchPort]*peer {
|
||||||
ports := ps.ports.Load().(map[switchPort]*peer)
|
ports := ps.ports.Load().(map[switchPort]*peer)
|
||||||
newPeers := make(map[switchPort]*peer)
|
newPeers := make(map[switchPort]*peer)
|
||||||
for port, p := range ports{
|
for port, p := range ports {
|
||||||
newPeers[port] = p
|
newPeers[port] = p
|
||||||
}
|
}
|
||||||
return newPeers
|
return newPeers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) DEBUG_getSigKey() sigPubKey {
|
func (p *peer) DEBUG_getSigKey() sigPubKey {
|
||||||
return p.sig
|
return p.sig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) DEEBUG_getPort() switchPort {
|
func (p *peer) DEEBUG_getPort() switchPort {
|
||||||
return p.port
|
return p.port
|
||||||
}
|
}
|
||||||
|
|
||||||
// Router
|
// Router
|
||||||
|
|
||||||
func (c *Core) DEBUG_getSwitchTable() *switchTable {
|
func (c *Core) DEBUG_getSwitchTable() *switchTable {
|
||||||
return &c.switchTable
|
return &c.switchTable
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DEBUG_getLocator() switchLocator {
|
func (c *Core) DEBUG_getLocator() switchLocator {
|
||||||
return c.switchTable.getLocator()
|
return c.switchTable.getLocator()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *switchLocator) DEBUG_getCoords() []byte {
|
func (l *switchLocator) DEBUG_getCoords() []byte {
|
||||||
return l.getCoords()
|
return l.getCoords()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DEBUG_switchLookup(dest []byte, ttl uint64) (switchPort, uint64) {
|
func (c *Core) DEBUG_switchLookup(dest []byte, ttl uint64) (switchPort, uint64) {
|
||||||
return c.switchTable.lookup(dest, ttl)
|
return c.switchTable.lookup(dest, ttl)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -109,45 +113,49 @@ func (t *switchTable) DEBUG_isDirty() bool {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
func (t *switchTable) DEBUG_dumpTable() {
|
func (t *switchTable) DEBUG_dumpTable() {
|
||||||
//data := t.data.Load().(*tabledata)
|
//data := t.data.Load().(*tabledata)
|
||||||
t.mutex.RLock()
|
t.mutex.RLock()
|
||||||
defer t.mutex.RUnlock()
|
defer t.mutex.RUnlock()
|
||||||
data := t.data
|
data := t.data
|
||||||
for _, peer := range data.peers {
|
for _, peer := range data.peers {
|
||||||
//fmt.Println("DUMPTABLE:", t.treeID, peer.treeID, peer.port,
|
//fmt.Println("DUMPTABLE:", t.treeID, peer.treeID, peer.port,
|
||||||
// peer.locator.Root, peer.coords,
|
// peer.locator.Root, peer.coords,
|
||||||
// peer.reverse.Root, peer.reverse.Coords, peer.forward)
|
// peer.reverse.Root, peer.reverse.Coords, peer.forward)
|
||||||
fmt.Println("DUMPTABLE:", t.key, peer.key, peer.locator.coords, peer.port/*, peer.forward*/)
|
fmt.Println("DUMPTABLE:", t.key, peer.key, peer.locator.coords, peer.port /*, peer.forward*/)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *switchTable) DEBUG_getReversePort(port switchPort) switchPort {
|
func (t *switchTable) DEBUG_getReversePort(port switchPort) switchPort {
|
||||||
// Returns Port(0) if it cannot get the reverse peer for any reason
|
// Returns Port(0) if it cannot get the reverse peer for any reason
|
||||||
//data := t.data.Load().(*tabledata)
|
//data := t.data.Load().(*tabledata)
|
||||||
t.mutex.RLock()
|
t.mutex.RLock()
|
||||||
defer t.mutex.RUnlock()
|
defer t.mutex.RUnlock()
|
||||||
data := t.data
|
data := t.data
|
||||||
if port >= switchPort(len(data.peers)) { return switchPort(0) }
|
if port >= switchPort(len(data.peers)) {
|
||||||
pinfo := data.peers[port]
|
return switchPort(0)
|
||||||
if len(pinfo.locator.coords) < 1 { return switchPort(0) }
|
}
|
||||||
return pinfo.locator.coords[len(pinfo.locator.coords)-1]
|
pinfo := data.peers[port]
|
||||||
|
if len(pinfo.locator.coords) < 1 {
|
||||||
|
return switchPort(0)
|
||||||
|
}
|
||||||
|
return pinfo.locator.coords[len(pinfo.locator.coords)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wire
|
// Wire
|
||||||
|
|
||||||
func DEBUG_wire_encode_coords(coords []byte) []byte {
|
func DEBUG_wire_encode_coords(coords []byte) []byte {
|
||||||
return wire_encode_coords(coords)
|
return wire_encode_coords(coords)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DHT, via core
|
// DHT, via core
|
||||||
|
|
||||||
func (c *Core) DEBUG_getDHTSize() int {
|
func (c *Core) DEBUG_getDHTSize() int {
|
||||||
total := 0
|
total := 0
|
||||||
for bidx := 0 ; bidx < c.dht.nBuckets() ; bidx++ {
|
for bidx := 0; bidx < c.dht.nBuckets(); bidx++ {
|
||||||
b := c.dht.getBucket(bidx)
|
b := c.dht.getBucket(bidx)
|
||||||
total += len(b.infos)
|
total += len(b.infos)
|
||||||
}
|
}
|
||||||
return total
|
return total
|
||||||
}
|
}
|
||||||
|
|
||||||
// udpInterface
|
// udpInterface
|
||||||
@ -193,99 +201,104 @@ func (c *Core) DEBUG_startLoopbackUDPInterface() {
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
func (c *Core) DEBUG_getAddr() *address {
|
func (c *Core) DEBUG_getAddr() *address {
|
||||||
return address_addrForNodeID(&c.dht.nodeID)
|
return address_addrForNodeID(&c.dht.nodeID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DEBUG_startTun() {
|
func (c *Core) DEBUG_startTun(ifname string) {
|
||||||
c.DEBUG_startTunWithMTU(1280)
|
c.DEBUG_startTunWithMTU(ifname, 1280)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DEBUG_startTunWithMTU(mtu int) {
|
func (c *Core) DEBUG_startTunWithMTU(ifname string, mtu int) {
|
||||||
addr := c.DEBUG_getAddr()
|
addr := c.DEBUG_getAddr()
|
||||||
straddr := fmt.Sprintf("%s/%v", net.IP(addr[:]).String(), 8*len(address_prefix))
|
straddr := fmt.Sprintf("%s/%v", net.IP(addr[:]).String(), 8*len(address_prefix))
|
||||||
err := c.tun.setup(straddr, mtu)
|
err := c.tun.setup(ifname, straddr, mtu)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
go c.tun.read()
|
panic(err)
|
||||||
go c.tun.write()
|
}
|
||||||
|
go c.tun.read()
|
||||||
|
go c.tun.write()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DEBUG_stopTun() {
|
func (c *Core) DEBUG_stopTun() {
|
||||||
c.tun.close()
|
c.tun.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
func (c *Core) DEBUG_newBoxKeys() (*boxPubKey, *boxPrivKey) {
|
func (c *Core) DEBUG_newBoxKeys() (*boxPubKey, *boxPrivKey) {
|
||||||
return newBoxKeys()
|
return newBoxKeys()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DEBUG_newSigKeys() (*sigPubKey, *sigPrivKey) {
|
func (c *Core) DEBUG_newSigKeys() (*sigPubKey, *sigPrivKey) {
|
||||||
return newSigKeys()
|
return newSigKeys()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DEBUG_getNodeID(pub *boxPubKey) *NodeID {
|
func (c *Core) DEBUG_getNodeID(pub *boxPubKey) *NodeID {
|
||||||
return getNodeID(pub)
|
return getNodeID(pub)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DEBUG_getTreeID(pub *sigPubKey) *TreeID {
|
func (c *Core) DEBUG_getTreeID(pub *sigPubKey) *TreeID {
|
||||||
return getTreeID(pub)
|
return getTreeID(pub)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DEBUG_addrForNodeID(nodeID *NodeID) string {
|
func (c *Core) DEBUG_addrForNodeID(nodeID *NodeID) string {
|
||||||
return net.IP(address_addrForNodeID(nodeID)[:]).String()
|
return net.IP(address_addrForNodeID(nodeID)[:]).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DEBUG_init(bpub []byte,
|
func (c *Core) DEBUG_init(bpub []byte,
|
||||||
bpriv []byte,
|
bpriv []byte,
|
||||||
spub []byte,
|
spub []byte,
|
||||||
spriv []byte) {
|
spriv []byte) {
|
||||||
var boxPub boxPubKey
|
var boxPub boxPubKey
|
||||||
var boxPriv boxPrivKey
|
var boxPriv boxPrivKey
|
||||||
var sigPub sigPubKey
|
var sigPub sigPubKey
|
||||||
var sigPriv sigPrivKey
|
var sigPriv sigPrivKey
|
||||||
copy(boxPub[:], bpub)
|
copy(boxPub[:], bpub)
|
||||||
copy(boxPriv[:], bpriv)
|
copy(boxPriv[:], bpriv)
|
||||||
copy(sigPub[:], spub)
|
copy(sigPub[:], spub)
|
||||||
copy(sigPriv[:], spriv)
|
copy(sigPriv[:], spriv)
|
||||||
c.init(&boxPub, &boxPriv, &sigPub, &sigPriv)
|
c.init(&boxPub, &boxPriv, &sigPub, &sigPriv)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
func (c *Core) DEBUG_setupAndStartGlobalUDPInterface(addrport string) {
|
func (c *Core) DEBUG_setupAndStartGlobalUDPInterface(addrport string) {
|
||||||
iface := udpInterface{}
|
iface := udpInterface{}
|
||||||
iface.init(c, addrport)
|
iface.init(c, addrport)
|
||||||
c.udp = &iface
|
c.udp = &iface
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DEBUG_getGlobalUDPAddr() net.Addr {
|
func (c *Core) DEBUG_getGlobalUDPAddr() net.Addr {
|
||||||
return c.udp.sock.LocalAddr()
|
return c.udp.sock.LocalAddr()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DEBUG_maybeSendUDPKeys(saddr string) {
|
func (c *Core) DEBUG_maybeSendUDPKeys(saddr string) {
|
||||||
addr := connAddr(saddr)
|
addr := connAddr(saddr)
|
||||||
c.udp.mutex.RLock()
|
c.udp.mutex.RLock()
|
||||||
_, isIn := c.udp.conns[connAddr(addr)]
|
_, isIn := c.udp.conns[connAddr(addr)]
|
||||||
c.udp.mutex.RUnlock()
|
c.udp.mutex.RUnlock()
|
||||||
if !isIn { c.udp.sendKeys(addr) }
|
if !isIn {
|
||||||
|
c.udp.sendKeys(addr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
//*
|
//*
|
||||||
func (c *Core) DEBUG_setupAndStartGlobalTCPInterface(addrport string) {
|
func (c *Core) DEBUG_setupAndStartGlobalTCPInterface(addrport string) {
|
||||||
iface := tcpInterface{}
|
iface := tcpInterface{}
|
||||||
iface.init(c, addrport)
|
iface.init(c, addrport)
|
||||||
c.tcp = &iface
|
c.tcp = &iface
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DEBUG_getGlobalTCPAddr() *net.TCPAddr {
|
func (c *Core) DEBUG_getGlobalTCPAddr() *net.TCPAddr {
|
||||||
return c.tcp.serv.Addr().(*net.TCPAddr)
|
return c.tcp.serv.Addr().(*net.TCPAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) DEBUG_addTCPConn(saddr string) {
|
func (c *Core) DEBUG_addTCPConn(saddr string) {
|
||||||
c.tcp.call(saddr)
|
c.tcp.call(saddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
//*/
|
//*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -318,22 +331,21 @@ func (c *Core) DEBUG_addKCPConn(saddr string) {
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
func (c *Core) DEBUG_setLogger(log *log.Logger) {
|
func (c *Core) DEBUG_setLogger(log *log.Logger) {
|
||||||
c.log = log
|
c.log = log
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
func DEBUG_simLinkPeers(p, q *peer) {
|
func DEBUG_simLinkPeers(p, q *peer) {
|
||||||
// Sets q.out() to point to p and starts p.linkLoop()
|
// Sets q.out() to point to p and starts p.linkLoop()
|
||||||
plinkIn := make(chan []byte, 1)
|
plinkIn := make(chan []byte, 1)
|
||||||
qlinkIn := make(chan []byte, 1)
|
qlinkIn := make(chan []byte, 1)
|
||||||
p.out = func(bs []byte) {
|
p.out = func(bs []byte) {
|
||||||
go q.handlePacket(bs, qlinkIn)
|
go q.handlePacket(bs, qlinkIn)
|
||||||
}
|
}
|
||||||
q.out = func(bs []byte) {
|
q.out = func(bs []byte) {
|
||||||
go p.handlePacket(bs, plinkIn)
|
go p.handlePacket(bs, plinkIn)
|
||||||
}
|
}
|
||||||
go p.linkLoop(plinkIn)
|
go p.linkLoop(plinkIn)
|
||||||
go q.linkLoop(qlinkIn)
|
go q.linkLoop(qlinkIn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,360 +24,420 @@ Slight changes *do* make it blackhole hard, bootstrapping isn't an easy problem
|
|||||||
|
|
||||||
import "sort"
|
import "sort"
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
//import "fmt"
|
//import "fmt"
|
||||||
|
|
||||||
// Maximum size for buckets and lookups
|
// Maximum size for buckets and lookups
|
||||||
// Exception for buckets if the next one is non-full
|
// Exception for buckets if the next one is non-full
|
||||||
const dht_bucket_size = 2 // This should be at least 2
|
const dht_bucket_size = 2 // This should be at least 2
|
||||||
const dht_lookup_size = 2 // This should be at least 1, below 2 is impractical
|
const dht_lookup_size = 2 // This should be at least 1, below 2 is impractical
|
||||||
const dht_bucket_number = 8*NodeIDLen // This shouldn't be changed
|
const dht_bucket_number = 8 * NodeIDLen // This shouldn't be changed
|
||||||
|
|
||||||
type dhtInfo struct {
|
type dhtInfo struct {
|
||||||
// TODO save their nodeID so we don't need to rehash if we need it again
|
// TODO save their nodeID so we don't need to rehash if we need it again
|
||||||
nodeID_hidden *NodeID
|
nodeID_hidden *NodeID
|
||||||
key boxPubKey
|
key boxPubKey
|
||||||
coords []byte
|
coords []byte
|
||||||
send time.Time // When we last sent a message
|
send time.Time // When we last sent a message
|
||||||
recv time.Time // When we last received a message
|
recv time.Time // When we last received a message
|
||||||
pings int // Decide when to drop
|
pings int // Decide when to drop
|
||||||
}
|
}
|
||||||
|
|
||||||
func (info *dhtInfo) getNodeID() *NodeID {
|
func (info *dhtInfo) getNodeID() *NodeID {
|
||||||
if info.nodeID_hidden == nil {
|
if info.nodeID_hidden == nil {
|
||||||
info.nodeID_hidden = getNodeID(&info.key)
|
info.nodeID_hidden = getNodeID(&info.key)
|
||||||
}
|
}
|
||||||
return info.nodeID_hidden
|
return info.nodeID_hidden
|
||||||
}
|
}
|
||||||
|
|
||||||
type bucket struct {
|
type bucket struct {
|
||||||
infos []*dhtInfo
|
infos []*dhtInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type dhtReq struct {
|
type dhtReq struct {
|
||||||
key boxPubKey // Key of whoever asked
|
key boxPubKey // Key of whoever asked
|
||||||
coords []byte // Coords of whoever asked
|
coords []byte // Coords of whoever asked
|
||||||
dest NodeID // NodeID they're asking about
|
dest NodeID // NodeID they're asking about
|
||||||
}
|
}
|
||||||
|
|
||||||
type dhtRes struct {
|
type dhtRes struct {
|
||||||
key boxPubKey // key to respond to
|
key boxPubKey // key to respond to
|
||||||
coords []byte // coords to respond to
|
coords []byte // coords to respond to
|
||||||
dest NodeID
|
dest NodeID
|
||||||
infos []*dhtInfo // response
|
infos []*dhtInfo // response
|
||||||
}
|
}
|
||||||
|
|
||||||
type dht struct {
|
type dht struct {
|
||||||
core *Core
|
core *Core
|
||||||
nodeID NodeID
|
nodeID NodeID
|
||||||
buckets_hidden [dht_bucket_number]bucket // Extra is for the self-bucket
|
buckets_hidden [dht_bucket_number]bucket // Extra is for the self-bucket
|
||||||
peers chan *dhtInfo // other goroutines put incoming dht updates here
|
peers chan *dhtInfo // other goroutines put incoming dht updates here
|
||||||
reqs map[boxPubKey]map[NodeID]time.Time
|
reqs map[boxPubKey]map[NodeID]time.Time
|
||||||
offset int
|
offset int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *dht) init(c *Core) {
|
func (t *dht) init(c *Core) {
|
||||||
t.core = c
|
t.core = c
|
||||||
t.nodeID = *t.core.GetNodeID()
|
t.nodeID = *t.core.GetNodeID()
|
||||||
t.peers = make(chan *dhtInfo, 1)
|
t.peers = make(chan *dhtInfo, 1)
|
||||||
t.reqs = make(map[boxPubKey]map[NodeID]time.Time)
|
t.reqs = make(map[boxPubKey]map[NodeID]time.Time)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *dht) handleReq(req *dhtReq) {
|
func (t *dht) handleReq(req *dhtReq) {
|
||||||
// Send them what they asked for
|
// Send them what they asked for
|
||||||
loc := t.core.switchTable.getLocator()
|
loc := t.core.switchTable.getLocator()
|
||||||
coords := loc.getCoords()
|
coords := loc.getCoords()
|
||||||
res := dhtRes{
|
res := dhtRes{
|
||||||
key: t.core.boxPub,
|
key: t.core.boxPub,
|
||||||
coords: coords,
|
coords: coords,
|
||||||
dest: req.dest,
|
dest: req.dest,
|
||||||
infos: t.lookup(&req.dest),
|
infos: t.lookup(&req.dest),
|
||||||
}
|
}
|
||||||
t.sendRes(&res, req)
|
t.sendRes(&res, req)
|
||||||
// Also (possibly) add them to our DHT
|
// Also (possibly) add them to our DHT
|
||||||
info := dhtInfo{
|
info := dhtInfo{
|
||||||
key: req.key,
|
key: req.key,
|
||||||
coords: req.coords,
|
coords: req.coords,
|
||||||
}
|
}
|
||||||
t.insertIfNew(&info) // This seems DoSable (we just trust their coords...)
|
t.insertIfNew(&info) // This seems DoSable (we just trust their coords...)
|
||||||
//if req.dest != t.nodeID { t.ping(&info, info.getNodeID()) } // Or spam...
|
//if req.dest != t.nodeID { t.ping(&info, info.getNodeID()) } // Or spam...
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *dht) handleRes(res *dhtRes) {
|
func (t *dht) handleRes(res *dhtRes) {
|
||||||
reqs, isIn := t.reqs[res.key]
|
reqs, isIn := t.reqs[res.key]
|
||||||
if !isIn { return }
|
if !isIn {
|
||||||
_, isIn = reqs[res.dest]
|
return
|
||||||
if !isIn { return }
|
}
|
||||||
rinfo := dhtInfo{
|
_, isIn = reqs[res.dest]
|
||||||
key: res.key,
|
if !isIn {
|
||||||
coords: res.coords,
|
return
|
||||||
send: time.Now(), // Technically wrong but should be OK... FIXME or not
|
}
|
||||||
recv: time.Now(),
|
rinfo := dhtInfo{
|
||||||
}
|
key: res.key,
|
||||||
// If they're already in the table, then keep the correct send time
|
coords: res.coords,
|
||||||
bidx, isOK := t.getBucketIndex(rinfo.getNodeID())
|
send: time.Now(), // Technically wrong but should be OK... FIXME or not
|
||||||
if !isOK { return }
|
recv: time.Now(),
|
||||||
b := t.getBucket(bidx)
|
}
|
||||||
for _, oldinfo := range b.infos {
|
// If they're already in the table, then keep the correct send time
|
||||||
if oldinfo.key == rinfo.key {rinfo.send = oldinfo.send }
|
bidx, isOK := t.getBucketIndex(rinfo.getNodeID())
|
||||||
}
|
if !isOK {
|
||||||
// Insert into table
|
return
|
||||||
t.insert(&rinfo)
|
}
|
||||||
if res.dest == *rinfo.getNodeID() { return } // No infinite recursions
|
b := t.getBucket(bidx)
|
||||||
// ping the nodes we were told about
|
for _, oldinfo := range b.infos {
|
||||||
if len(res.infos) > dht_lookup_size {
|
if oldinfo.key == rinfo.key {
|
||||||
// Ignore any "extra" lookup results
|
rinfo.send = oldinfo.send
|
||||||
res.infos = res.infos[:dht_lookup_size]
|
}
|
||||||
}
|
}
|
||||||
for _, info := range res.infos {
|
// Insert into table
|
||||||
bidx, isOK := t.getBucketIndex(info.getNodeID())
|
t.insert(&rinfo)
|
||||||
if !isOK { continue }
|
if res.dest == *rinfo.getNodeID() {
|
||||||
b := t.getBucket(bidx)
|
return
|
||||||
if b.contains(info) { continue } // wait for maintenance cycle to get them
|
} // No infinite recursions
|
||||||
t.ping(info, info.getNodeID())
|
// ping the nodes we were told about
|
||||||
}
|
if len(res.infos) > dht_lookup_size {
|
||||||
|
// Ignore any "extra" lookup results
|
||||||
|
res.infos = res.infos[:dht_lookup_size]
|
||||||
|
}
|
||||||
|
for _, info := range res.infos {
|
||||||
|
bidx, isOK := t.getBucketIndex(info.getNodeID())
|
||||||
|
if !isOK {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
b := t.getBucket(bidx)
|
||||||
|
if b.contains(info) {
|
||||||
|
continue
|
||||||
|
} // wait for maintenance cycle to get them
|
||||||
|
t.ping(info, info.getNodeID())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *dht) lookup(nodeID *NodeID) []*dhtInfo {
|
func (t *dht) lookup(nodeID *NodeID) []*dhtInfo {
|
||||||
// FIXME this allocates a bunch, sorts, and keeps the part it likes
|
// FIXME this allocates a bunch, sorts, and keeps the part it likes
|
||||||
// It would be better to only track the part it likes to begin with
|
// It would be better to only track the part it likes to begin with
|
||||||
addInfos := func (res []*dhtInfo, infos []*dhtInfo) ([]*dhtInfo) {
|
addInfos := func(res []*dhtInfo, infos []*dhtInfo) []*dhtInfo {
|
||||||
for _, info := range infos {
|
for _, info := range infos {
|
||||||
if info == nil { panic ("Should never happen!") }
|
if info == nil {
|
||||||
if true || dht_firstCloserThanThird(info.getNodeID(), nodeID, &t.nodeID) {
|
panic("Should never happen!")
|
||||||
res = append(res, info)
|
}
|
||||||
}
|
if true || dht_firstCloserThanThird(info.getNodeID(), nodeID, &t.nodeID) {
|
||||||
}
|
res = append(res, info)
|
||||||
return res
|
}
|
||||||
}
|
}
|
||||||
var res []*dhtInfo
|
return res
|
||||||
for bidx := 0 ; bidx < t.nBuckets() ; bidx++ {
|
}
|
||||||
b := t.getBucket(bidx)
|
var res []*dhtInfo
|
||||||
res = addInfos(res, b.infos)
|
for bidx := 0; bidx < t.nBuckets(); bidx++ {
|
||||||
}
|
b := t.getBucket(bidx)
|
||||||
doSort := func(infos []*dhtInfo) {
|
res = addInfos(res, b.infos)
|
||||||
less := func (i, j int) bool {
|
}
|
||||||
return dht_firstCloserThanThird(infos[i].getNodeID(),
|
doSort := func(infos []*dhtInfo) {
|
||||||
nodeID,
|
less := func(i, j int) bool {
|
||||||
infos[j].getNodeID())
|
return dht_firstCloserThanThird(infos[i].getNodeID(),
|
||||||
}
|
nodeID,
|
||||||
sort.SliceStable(infos, less)
|
infos[j].getNodeID())
|
||||||
}
|
}
|
||||||
doSort(res)
|
sort.SliceStable(infos, less)
|
||||||
if len(res) > dht_lookup_size { res = res[:dht_lookup_size] }
|
}
|
||||||
return res
|
doSort(res)
|
||||||
|
if len(res) > dht_lookup_size {
|
||||||
|
res = res[:dht_lookup_size]
|
||||||
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *dht) getBucket(bidx int) *bucket {
|
func (t *dht) getBucket(bidx int) *bucket {
|
||||||
return &t.buckets_hidden[bidx]
|
return &t.buckets_hidden[bidx]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *dht) nBuckets() int {
|
func (t *dht) nBuckets() int {
|
||||||
return len(t.buckets_hidden)
|
return len(t.buckets_hidden)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *dht) insertIfNew(info *dhtInfo) {
|
func (t *dht) insertIfNew(info *dhtInfo) {
|
||||||
//fmt.Println("DEBUG: dht insertIfNew:", info.getNodeID(), info.coords)
|
//fmt.Println("DEBUG: dht insertIfNew:", info.getNodeID(), info.coords)
|
||||||
// Insert a peer if and only if the bucket doesn't already contain it
|
// Insert a peer if and only if the bucket doesn't already contain it
|
||||||
nodeID := info.getNodeID()
|
nodeID := info.getNodeID()
|
||||||
bidx, isOK := t.getBucketIndex(nodeID)
|
bidx, isOK := t.getBucketIndex(nodeID)
|
||||||
if !isOK { return }
|
if !isOK {
|
||||||
b := t.getBucket(bidx)
|
return
|
||||||
if !b.contains(info) {
|
}
|
||||||
// We've never heard this node before
|
b := t.getBucket(bidx)
|
||||||
// TODO is there a better time than "now" to set send/recv to?
|
if !b.contains(info) {
|
||||||
// (Is there another "natural" choice that bootstraps faster?)
|
// We've never heard this node before
|
||||||
info.send = time.Now()
|
// TODO is there a better time than "now" to set send/recv to?
|
||||||
info.recv = info.send
|
// (Is there another "natural" choice that bootstraps faster?)
|
||||||
t.insert(info)
|
info.send = time.Now()
|
||||||
}
|
info.recv = info.send
|
||||||
|
t.insert(info)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *dht) insert(info *dhtInfo) {
|
func (t *dht) insert(info *dhtInfo) {
|
||||||
//fmt.Println("DEBUG: dht insert:", info.getNodeID(), info.coords)
|
//fmt.Println("DEBUG: dht insert:", info.getNodeID(), info.coords)
|
||||||
// First update the time on this info
|
// First update the time on this info
|
||||||
info.recv = time.Now()
|
info.recv = time.Now()
|
||||||
// Get the bucket for this node
|
// Get the bucket for this node
|
||||||
nodeID := info.getNodeID()
|
nodeID := info.getNodeID()
|
||||||
bidx, isOK := t.getBucketIndex(nodeID)
|
bidx, isOK := t.getBucketIndex(nodeID)
|
||||||
if !isOK { return }
|
if !isOK {
|
||||||
b := t.getBucket(bidx)
|
return
|
||||||
// First drop any existing entry from the bucket
|
}
|
||||||
b.drop(&info.key)
|
b := t.getBucket(bidx)
|
||||||
// Now add to the *end* of the bucket
|
// First drop any existing entry from the bucket
|
||||||
b.infos = append(b.infos, info)
|
b.drop(&info.key)
|
||||||
// Check if the next bucket is non-full and return early if it is
|
// Now add to the *end* of the bucket
|
||||||
if bidx+1 == t.nBuckets() { return }
|
b.infos = append(b.infos, info)
|
||||||
bnext := t.getBucket(bidx+1)
|
// Check if the next bucket is non-full and return early if it is
|
||||||
if len(bnext.infos) < dht_bucket_size { return }
|
if bidx+1 == t.nBuckets() {
|
||||||
// Shrink from the *front* to requied size
|
return
|
||||||
for len(b.infos) > dht_bucket_size { b.infos = b.infos[1:] }
|
}
|
||||||
|
bnext := t.getBucket(bidx + 1)
|
||||||
|
if len(bnext.infos) < dht_bucket_size {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Shrink from the *front* to requied size
|
||||||
|
for len(b.infos) > dht_bucket_size {
|
||||||
|
b.infos = b.infos[1:]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *dht) getBucketIndex(nodeID *NodeID) (int, bool) {
|
func (t *dht) getBucketIndex(nodeID *NodeID) (int, bool) {
|
||||||
for bidx := 0 ; bidx < t.nBuckets() ; bidx++ {
|
for bidx := 0; bidx < t.nBuckets(); bidx++ {
|
||||||
them := nodeID[bidx/8] & (0x80 >> byte(bidx % 8))
|
them := nodeID[bidx/8] & (0x80 >> byte(bidx%8))
|
||||||
me := t.nodeID[bidx/8] & (0x80 >> byte(bidx % 8))
|
me := t.nodeID[bidx/8] & (0x80 >> byte(bidx%8))
|
||||||
if them != me { return bidx, true }
|
if them != me {
|
||||||
}
|
return bidx, true
|
||||||
return t.nBuckets(), false
|
}
|
||||||
|
}
|
||||||
|
return t.nBuckets(), false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bucket) contains(ninfo *dhtInfo) bool {
|
func (b *bucket) contains(ninfo *dhtInfo) bool {
|
||||||
// Compares if key and coords match
|
// Compares if key and coords match
|
||||||
for _, info := range b.infos {
|
for _, info := range b.infos {
|
||||||
if info == nil { panic("Should never happen") }
|
if info == nil {
|
||||||
if info.key == ninfo.key {
|
panic("Should never happen")
|
||||||
if len(info.coords) != len(ninfo.coords) { return false }
|
}
|
||||||
for idx := 0 ; idx < len(info.coords) ; idx++ {
|
if info.key == ninfo.key {
|
||||||
if info.coords[idx] != ninfo.coords[idx] { return false }
|
if len(info.coords) != len(ninfo.coords) {
|
||||||
}
|
return false
|
||||||
return true
|
}
|
||||||
}
|
for idx := 0; idx < len(info.coords); idx++ {
|
||||||
}
|
if info.coords[idx] != ninfo.coords[idx] {
|
||||||
return false
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bucket) drop(key *boxPubKey) {
|
func (b *bucket) drop(key *boxPubKey) {
|
||||||
clean := func (infos []*dhtInfo) []*dhtInfo {
|
clean := func(infos []*dhtInfo) []*dhtInfo {
|
||||||
cleaned := infos[:0]
|
cleaned := infos[:0]
|
||||||
for _, info := range infos {
|
for _, info := range infos {
|
||||||
if info.key == *key { continue }
|
if info.key == *key {
|
||||||
cleaned = append(cleaned, info)
|
continue
|
||||||
}
|
}
|
||||||
return cleaned
|
cleaned = append(cleaned, info)
|
||||||
}
|
}
|
||||||
b.infos = clean(b.infos)
|
return cleaned
|
||||||
|
}
|
||||||
|
b.infos = clean(b.infos)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *dht) sendReq(req *dhtReq, dest *dhtInfo) {
|
func (t *dht) sendReq(req *dhtReq, dest *dhtInfo) {
|
||||||
// Send a dhtReq to the node in dhtInfo
|
// Send a dhtReq to the node in dhtInfo
|
||||||
bs := req.encode()
|
bs := req.encode()
|
||||||
shared := t.core.sessions.getSharedKey(&t.core.boxPriv, &dest.key)
|
shared := t.core.sessions.getSharedKey(&t.core.boxPriv, &dest.key)
|
||||||
payload, nonce := boxSeal(shared, bs, nil)
|
payload, nonce := boxSeal(shared, bs, nil)
|
||||||
p := wire_protoTrafficPacket{
|
p := wire_protoTrafficPacket{
|
||||||
ttl: ^uint64(0),
|
ttl: ^uint64(0),
|
||||||
coords: dest.coords,
|
coords: dest.coords,
|
||||||
toKey: dest.key,
|
toKey: dest.key,
|
||||||
fromKey: t.core.boxPub,
|
fromKey: t.core.boxPub,
|
||||||
nonce: *nonce,
|
nonce: *nonce,
|
||||||
payload:payload,
|
payload: payload,
|
||||||
}
|
}
|
||||||
packet := p.encode()
|
packet := p.encode()
|
||||||
t.core.router.out(packet)
|
t.core.router.out(packet)
|
||||||
reqsToDest, isIn := t.reqs[dest.key]
|
reqsToDest, isIn := t.reqs[dest.key]
|
||||||
if !isIn {
|
if !isIn {
|
||||||
t.reqs[dest.key] = make(map[NodeID]time.Time)
|
t.reqs[dest.key] = make(map[NodeID]time.Time)
|
||||||
reqsToDest, isIn = t.reqs[dest.key]
|
reqsToDest, isIn = t.reqs[dest.key]
|
||||||
if !isIn { panic("This should never happen") }
|
if !isIn {
|
||||||
}
|
panic("This should never happen")
|
||||||
reqsToDest[req.dest] = time.Now()
|
}
|
||||||
|
}
|
||||||
|
reqsToDest[req.dest] = time.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *dht) sendRes(res *dhtRes, req *dhtReq) {
|
func (t *dht) sendRes(res *dhtRes, req *dhtReq) {
|
||||||
// Send a reply for a dhtReq
|
// Send a reply for a dhtReq
|
||||||
bs := res.encode()
|
bs := res.encode()
|
||||||
shared := t.core.sessions.getSharedKey(&t.core.boxPriv, &req.key)
|
shared := t.core.sessions.getSharedKey(&t.core.boxPriv, &req.key)
|
||||||
payload, nonce := boxSeal(shared, bs, nil)
|
payload, nonce := boxSeal(shared, bs, nil)
|
||||||
p := wire_protoTrafficPacket{
|
p := wire_protoTrafficPacket{
|
||||||
ttl: ^uint64(0),
|
ttl: ^uint64(0),
|
||||||
coords: req.coords,
|
coords: req.coords,
|
||||||
toKey: req.key,
|
toKey: req.key,
|
||||||
fromKey: t.core.boxPub,
|
fromKey: t.core.boxPub,
|
||||||
nonce: *nonce,
|
nonce: *nonce,
|
||||||
payload: payload,
|
payload: payload,
|
||||||
}
|
}
|
||||||
packet := p.encode()
|
packet := p.encode()
|
||||||
t.core.router.out(packet)
|
t.core.router.out(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bucket) isEmpty() bool {
|
func (b *bucket) isEmpty() bool {
|
||||||
return len(b.infos) == 0
|
return len(b.infos) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bucket) nextToPing() *dhtInfo {
|
func (b *bucket) nextToPing() *dhtInfo {
|
||||||
// Check the nodes in the bucket
|
// Check the nodes in the bucket
|
||||||
// Return whichever one responded least recently
|
// Return whichever one responded least recently
|
||||||
// Delay of 6 seconds between pinging the same node
|
// Delay of 6 seconds between pinging the same node
|
||||||
// Gives them time to respond
|
// Gives them time to respond
|
||||||
// And time between traffic loss from short term congestion in the network
|
// And time between traffic loss from short term congestion in the network
|
||||||
var toPing *dhtInfo
|
var toPing *dhtInfo
|
||||||
for _, next := range b.infos {
|
for _, next := range b.infos {
|
||||||
if time.Since(next.send) < 6*time.Second { continue }
|
if time.Since(next.send) < 6*time.Second {
|
||||||
if toPing == nil || next.recv.Before(toPing.recv) { toPing = next }
|
continue
|
||||||
}
|
}
|
||||||
return toPing
|
if toPing == nil || next.recv.Before(toPing.recv) {
|
||||||
|
toPing = next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return toPing
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *dht) getTarget(bidx int) *NodeID {
|
func (t *dht) getTarget(bidx int) *NodeID {
|
||||||
targetID := t.nodeID
|
targetID := t.nodeID
|
||||||
targetID[bidx/8] ^= 0x80 >> byte(bidx % 8)
|
targetID[bidx/8] ^= 0x80 >> byte(bidx%8)
|
||||||
return &targetID
|
return &targetID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *dht) ping(info *dhtInfo, target *NodeID) {
|
func (t *dht) ping(info *dhtInfo, target *NodeID) {
|
||||||
if info.pings > 2 {
|
if info.pings > 2 {
|
||||||
bidx, isOK := t.getBucketIndex(info.getNodeID())
|
bidx, isOK := t.getBucketIndex(info.getNodeID())
|
||||||
if !isOK { panic("This should never happen") }
|
if !isOK {
|
||||||
b := t.getBucket(bidx)
|
panic("This should never happen")
|
||||||
b.drop(&info.key)
|
}
|
||||||
return
|
b := t.getBucket(bidx)
|
||||||
}
|
b.drop(&info.key)
|
||||||
if target == nil { target = &t.nodeID }
|
return
|
||||||
loc := t.core.switchTable.getLocator()
|
}
|
||||||
coords := loc.getCoords()
|
if target == nil {
|
||||||
req := dhtReq{
|
target = &t.nodeID
|
||||||
key: t.core.boxPub,
|
}
|
||||||
coords: coords,
|
loc := t.core.switchTable.getLocator()
|
||||||
dest: *target,
|
coords := loc.getCoords()
|
||||||
}
|
req := dhtReq{
|
||||||
info.pings++
|
key: t.core.boxPub,
|
||||||
info.send = time.Now()
|
coords: coords,
|
||||||
t.sendReq(&req, info)
|
dest: *target,
|
||||||
|
}
|
||||||
|
info.pings++
|
||||||
|
info.send = time.Now()
|
||||||
|
t.sendReq(&req, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *dht) doMaintenance() {
|
func (t *dht) doMaintenance() {
|
||||||
// First clean up reqs
|
// First clean up reqs
|
||||||
for key, reqs := range t.reqs {
|
for key, reqs := range t.reqs {
|
||||||
for target, timeout := range reqs {
|
for target, timeout := range reqs {
|
||||||
if time.Since(timeout) > time.Minute { delete(reqs, target) }
|
if time.Since(timeout) > time.Minute {
|
||||||
}
|
delete(reqs, target)
|
||||||
if len(reqs) == 0 { delete(t.reqs, key) }
|
}
|
||||||
}
|
}
|
||||||
// Ping the least recently contacted node
|
if len(reqs) == 0 {
|
||||||
// This is to make sure we eventually notice when someone times out
|
delete(t.reqs, key)
|
||||||
var oldest *dhtInfo
|
}
|
||||||
last := 0
|
}
|
||||||
for bidx := 0 ; bidx < t.nBuckets() ; bidx++ {
|
// Ping the least recently contacted node
|
||||||
b := t.getBucket(bidx)
|
// This is to make sure we eventually notice when someone times out
|
||||||
if !b.isEmpty() {
|
var oldest *dhtInfo
|
||||||
last = bidx
|
last := 0
|
||||||
toPing := b.nextToPing()
|
for bidx := 0; bidx < t.nBuckets(); bidx++ {
|
||||||
if toPing == nil { continue } // We've recently pinged everyone in b
|
b := t.getBucket(bidx)
|
||||||
if oldest == nil || toPing.recv.Before(oldest.recv) {
|
if !b.isEmpty() {
|
||||||
oldest = toPing
|
last = bidx
|
||||||
}
|
toPing := b.nextToPing()
|
||||||
}
|
if toPing == nil {
|
||||||
}
|
continue
|
||||||
if oldest != nil { t.ping(oldest, nil) } // if the DHT isn't empty
|
} // We've recently pinged everyone in b
|
||||||
// Refresh buckets
|
if oldest == nil || toPing.recv.Before(oldest.recv) {
|
||||||
if t.offset > last { t.offset = 0 }
|
oldest = toPing
|
||||||
target := t.getTarget(t.offset)
|
}
|
||||||
for _, info := range t.lookup(target) {
|
}
|
||||||
t.ping(info, target)
|
}
|
||||||
break
|
if oldest != nil {
|
||||||
}
|
t.ping(oldest, nil)
|
||||||
t.offset++
|
} // if the DHT isn't empty
|
||||||
|
// Refresh buckets
|
||||||
|
if t.offset > last {
|
||||||
|
t.offset = 0
|
||||||
|
}
|
||||||
|
target := t.getTarget(t.offset)
|
||||||
|
for _, info := range t.lookup(target) {
|
||||||
|
t.ping(info, target)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
t.offset++
|
||||||
}
|
}
|
||||||
|
|
||||||
func dht_firstCloserThanThird(first *NodeID,
|
func dht_firstCloserThanThird(first *NodeID,
|
||||||
second *NodeID,
|
second *NodeID,
|
||||||
third *NodeID) bool {
|
third *NodeID) bool {
|
||||||
for idx := 0 ; idx < NodeIDLen ; idx++ {
|
for idx := 0; idx < NodeIDLen; idx++ {
|
||||||
f := first[idx] ^ second[idx]
|
f := first[idx] ^ second[idx]
|
||||||
t := third[idx] ^ second[idx]
|
t := third[idx] ^ second[idx]
|
||||||
if f == t { continue }
|
if f == t {
|
||||||
return f < t
|
continue
|
||||||
}
|
}
|
||||||
return false
|
return f < t
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,335 +11,424 @@ import "time"
|
|||||||
import "sync"
|
import "sync"
|
||||||
import "sync/atomic"
|
import "sync/atomic"
|
||||||
import "math"
|
import "math"
|
||||||
|
|
||||||
//import "fmt"
|
//import "fmt"
|
||||||
|
|
||||||
type peers struct {
|
type peers struct {
|
||||||
core *Core
|
core *Core
|
||||||
mutex sync.Mutex // Synchronize writes to atomic
|
mutex sync.Mutex // Synchronize writes to atomic
|
||||||
ports atomic.Value //map[Port]*peer, use CoW semantics
|
ports atomic.Value //map[Port]*peer, use CoW semantics
|
||||||
//ports map[Port]*peer
|
//ports map[Port]*peer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *peers) init(c *Core) {
|
func (ps *peers) init(c *Core) {
|
||||||
ps.mutex.Lock()
|
ps.mutex.Lock()
|
||||||
defer ps.mutex.Unlock()
|
defer ps.mutex.Unlock()
|
||||||
ps.putPorts(make(map[switchPort]*peer))
|
ps.putPorts(make(map[switchPort]*peer))
|
||||||
ps.core = c
|
ps.core = c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *peers) getPorts() map[switchPort]*peer {
|
func (ps *peers) getPorts() map[switchPort]*peer {
|
||||||
return ps.ports.Load().(map[switchPort]*peer)
|
return ps.ports.Load().(map[switchPort]*peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *peers) putPorts(ports map[switchPort]*peer) {
|
func (ps *peers) putPorts(ports map[switchPort]*peer) {
|
||||||
ps.ports.Store(ports)
|
ps.ports.Store(ports)
|
||||||
}
|
}
|
||||||
|
|
||||||
type peer struct {
|
type peer struct {
|
||||||
// Rolling approximation of bandwidth, in bps, used by switch, updated by tcp
|
// Rolling approximation of bandwidth, in bps, used by switch, updated by tcp
|
||||||
// use get/update methods only! (atomic accessors as float64)
|
// use get/update methods only! (atomic accessors as float64)
|
||||||
bandwidth uint64
|
bandwidth uint64
|
||||||
// BUG: sync/atomic, 32 bit platforms need the above to be the first element
|
// BUG: sync/atomic, 32 bit platforms need the above to be the first element
|
||||||
box boxPubKey
|
box boxPubKey
|
||||||
sig sigPubKey
|
sig sigPubKey
|
||||||
shared boxSharedKey
|
shared boxSharedKey
|
||||||
//in <-chan []byte
|
//in <-chan []byte
|
||||||
//out chan<- []byte
|
//out chan<- []byte
|
||||||
//in func([]byte)
|
//in func([]byte)
|
||||||
out func([]byte)
|
out func([]byte)
|
||||||
core *Core
|
core *Core
|
||||||
port switchPort
|
port switchPort
|
||||||
msgAnc *msgAnnounce
|
msgAnc *msgAnnounce
|
||||||
msgHops []*msgHop
|
msgHops []*msgHop
|
||||||
myMsg *switchMessage
|
myMsg *switchMessage
|
||||||
mySigs []sigInfo
|
mySigs []sigInfo
|
||||||
// This is used to limit how often we perform expensive operations
|
// This is used to limit how often we perform expensive operations
|
||||||
// Specifically, processing switch messages, signing, and verifying sigs
|
// Specifically, processing switch messages, signing, and verifying sigs
|
||||||
// Resets at the start of each tick
|
// Resets at the start of each tick
|
||||||
throttle uint8
|
throttle uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
const peer_Throttle = 1
|
const peer_Throttle = 1
|
||||||
|
|
||||||
func (p *peer) getBandwidth() float64 {
|
func (p *peer) getBandwidth() float64 {
|
||||||
bits := atomic.LoadUint64(&p.bandwidth)
|
bits := atomic.LoadUint64(&p.bandwidth)
|
||||||
return math.Float64frombits(bits)
|
return math.Float64frombits(bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) updateBandwidth(bytes int, duration time.Duration) {
|
func (p *peer) updateBandwidth(bytes int, duration time.Duration) {
|
||||||
if p == nil { return }
|
if p == nil {
|
||||||
for ok := false ; !ok ; {
|
return
|
||||||
oldBits := atomic.LoadUint64(&p.bandwidth)
|
}
|
||||||
oldBandwidth := math.Float64frombits(oldBits)
|
for ok := false; !ok; {
|
||||||
bandwidth := oldBandwidth * 7 / 8 + float64(bytes)/duration.Seconds()
|
oldBits := atomic.LoadUint64(&p.bandwidth)
|
||||||
bits := math.Float64bits(bandwidth)
|
oldBandwidth := math.Float64frombits(oldBits)
|
||||||
ok = atomic.CompareAndSwapUint64(&p.bandwidth, oldBits, bits)
|
bandwidth := oldBandwidth*7/8 + float64(bytes)/duration.Seconds()
|
||||||
}
|
bits := math.Float64bits(bandwidth)
|
||||||
|
ok = atomic.CompareAndSwapUint64(&p.bandwidth, oldBits, bits)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *peers) newPeer(box *boxPubKey,
|
func (ps *peers) newPeer(box *boxPubKey,
|
||||||
sig *sigPubKey) *peer {
|
sig *sigPubKey) *peer {
|
||||||
//in <-chan []byte,
|
//in <-chan []byte,
|
||||||
//out chan<- []byte) *peer {
|
//out chan<- []byte) *peer {
|
||||||
p := peer{box: *box,
|
p := peer{box: *box,
|
||||||
sig: *sig,
|
sig: *sig,
|
||||||
shared: *getSharedKey(&ps.core.boxPriv, box),
|
shared: *getSharedKey(&ps.core.boxPriv, box),
|
||||||
//in: in,
|
//in: in,
|
||||||
//out: out,
|
//out: out,
|
||||||
core: ps.core}
|
core: ps.core}
|
||||||
ps.mutex.Lock()
|
ps.mutex.Lock()
|
||||||
defer ps.mutex.Unlock()
|
defer ps.mutex.Unlock()
|
||||||
oldPorts := ps.getPorts()
|
oldPorts := ps.getPorts()
|
||||||
newPorts := make(map[switchPort]*peer)
|
newPorts := make(map[switchPort]*peer)
|
||||||
for k,v := range oldPorts{ newPorts[k] = v }
|
for k, v := range oldPorts {
|
||||||
for idx := switchPort(0) ; true ; idx++ {
|
newPorts[k] = v
|
||||||
if _, isIn := newPorts[idx]; !isIn {
|
}
|
||||||
p.port = switchPort(idx)
|
for idx := switchPort(0); true; idx++ {
|
||||||
newPorts[p.port] = &p
|
if _, isIn := newPorts[idx]; !isIn {
|
||||||
break
|
p.port = switchPort(idx)
|
||||||
}
|
newPorts[p.port] = &p
|
||||||
}
|
break
|
||||||
ps.putPorts(newPorts)
|
}
|
||||||
return &p
|
}
|
||||||
|
ps.putPorts(newPorts)
|
||||||
|
return &p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) linkLoop(in <-chan []byte) {
|
func (p *peer) linkLoop(in <-chan []byte) {
|
||||||
ticker := time.NewTicker(time.Second)
|
ticker := time.NewTicker(time.Second)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case packet, ok := <-in:
|
case packet, ok := <-in:
|
||||||
if !ok { return }
|
if !ok {
|
||||||
p.handleLinkTraffic(packet)
|
return
|
||||||
case <-ticker.C: {
|
}
|
||||||
p.throttle = 0
|
p.handleLinkTraffic(packet)
|
||||||
if p.port == 0 { continue } // Don't send announces on selfInterface
|
case <-ticker.C:
|
||||||
// Maybe we shouldn't time out, and instead wait for a kill signal?
|
{
|
||||||
p.myMsg, p.mySigs = p.core.switchTable.createMessage(p.port)
|
p.throttle = 0
|
||||||
p.sendSwitchAnnounce()
|
if p.port == 0 {
|
||||||
}
|
continue
|
||||||
}
|
} // Don't send announces on selfInterface
|
||||||
}
|
// Maybe we shouldn't time out, and instead wait for a kill signal?
|
||||||
|
p.myMsg, p.mySigs = p.core.switchTable.createMessage(p.port)
|
||||||
|
p.sendSwitchAnnounce()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) handlePacket(packet []byte, linkIn (chan<- []byte)) {
|
func (p *peer) handlePacket(packet []byte, linkIn chan<- []byte) {
|
||||||
pType, pTypeLen := wire_decode_uint64(packet)
|
pType, pTypeLen := wire_decode_uint64(packet)
|
||||||
if pTypeLen==0 { return }
|
if pTypeLen == 0 {
|
||||||
switch (pType) {
|
return
|
||||||
case wire_Traffic: p.handleTraffic(packet, pTypeLen)
|
}
|
||||||
case wire_ProtocolTraffic: p.handleTraffic(packet, pTypeLen)
|
switch pType {
|
||||||
case wire_LinkProtocolTraffic: {
|
case wire_Traffic:
|
||||||
select {
|
p.handleTraffic(packet, pTypeLen)
|
||||||
case linkIn<-packet:
|
case wire_ProtocolTraffic:
|
||||||
default:
|
p.handleTraffic(packet, pTypeLen)
|
||||||
}
|
case wire_LinkProtocolTraffic:
|
||||||
}
|
{
|
||||||
default: /*panic(pType) ;*/ return
|
select {
|
||||||
}
|
case linkIn <- packet:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default: /*panic(pType) ;*/
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) handleTraffic(packet []byte, pTypeLen int) {
|
func (p *peer) handleTraffic(packet []byte, pTypeLen int) {
|
||||||
ttl, ttlLen := wire_decode_uint64(packet[pTypeLen:])
|
ttl, ttlLen := wire_decode_uint64(packet[pTypeLen:])
|
||||||
ttlBegin := pTypeLen
|
ttlBegin := pTypeLen
|
||||||
ttlEnd := pTypeLen+ttlLen
|
ttlEnd := pTypeLen + ttlLen
|
||||||
coords, coordLen := wire_decode_coords(packet[ttlEnd:])
|
coords, coordLen := wire_decode_coords(packet[ttlEnd:])
|
||||||
coordEnd := ttlEnd+coordLen
|
coordEnd := ttlEnd + coordLen
|
||||||
if coordEnd == len(packet) { return } // No payload
|
if coordEnd == len(packet) {
|
||||||
toPort, newTTL := p.core.switchTable.lookup(coords, ttl)
|
return
|
||||||
if toPort == p.port { return } // FIXME? shouldn't happen, does it? would loop
|
} // No payload
|
||||||
to := p.core.peers.getPorts()[toPort]
|
toPort, newTTL := p.core.switchTable.lookup(coords, ttl)
|
||||||
if to == nil { return }
|
if toPort == p.port {
|
||||||
newTTLSlice := wire_encode_uint64(newTTL)
|
return
|
||||||
// This mutates the packet in-place if the length of the TTL changes!
|
} // FIXME? shouldn't happen, does it? would loop
|
||||||
shift := ttlLen - len(newTTLSlice)
|
to := p.core.peers.getPorts()[toPort]
|
||||||
copy(packet[ttlBegin+shift:], newTTLSlice)
|
if to == nil {
|
||||||
copy(packet[shift:], packet[:pTypeLen])
|
return
|
||||||
packet = packet[shift:]
|
}
|
||||||
to.sendPacket(packet)
|
newTTLSlice := wire_encode_uint64(newTTL)
|
||||||
|
// This mutates the packet in-place if the length of the TTL changes!
|
||||||
|
shift := ttlLen - len(newTTLSlice)
|
||||||
|
copy(packet[ttlBegin+shift:], newTTLSlice)
|
||||||
|
copy(packet[shift:], packet[:pTypeLen])
|
||||||
|
packet = packet[shift:]
|
||||||
|
to.sendPacket(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) sendPacket(packet []byte) {
|
func (p *peer) sendPacket(packet []byte) {
|
||||||
// Is there ever a case where something more complicated is needed?
|
// Is there ever a case where something more complicated is needed?
|
||||||
// What if p.out blocks?
|
// What if p.out blocks?
|
||||||
p.out(packet)
|
p.out(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) sendLinkPacket(packet []byte) {
|
func (p *peer) sendLinkPacket(packet []byte) {
|
||||||
bs, nonce := boxSeal(&p.shared, packet, nil)
|
bs, nonce := boxSeal(&p.shared, packet, nil)
|
||||||
linkPacket := wire_linkProtoTrafficPacket{
|
linkPacket := wire_linkProtoTrafficPacket{
|
||||||
toKey: p.box,
|
toKey: p.box,
|
||||||
fromKey: p.core.boxPub,
|
fromKey: p.core.boxPub,
|
||||||
nonce: *nonce,
|
nonce: *nonce,
|
||||||
payload: bs,
|
payload: bs,
|
||||||
}
|
}
|
||||||
packet = linkPacket.encode()
|
packet = linkPacket.encode()
|
||||||
p.sendPacket(packet)
|
p.sendPacket(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) handleLinkTraffic(bs []byte) {
|
func (p *peer) handleLinkTraffic(bs []byte) {
|
||||||
packet := wire_linkProtoTrafficPacket{}
|
packet := wire_linkProtoTrafficPacket{}
|
||||||
// TODO throttle on returns?
|
// TODO throttle on returns?
|
||||||
if !packet.decode(bs) { return }
|
if !packet.decode(bs) {
|
||||||
if packet.toKey != p.core.boxPub { return }
|
return
|
||||||
if packet.fromKey != p.box { return }
|
}
|
||||||
payload, isOK := boxOpen(&p.shared, packet.payload, &packet.nonce)
|
if packet.toKey != p.core.boxPub {
|
||||||
if !isOK { return }
|
return
|
||||||
pType, pTypeLen := wire_decode_uint64(payload)
|
}
|
||||||
if pTypeLen == 0 { return }
|
if packet.fromKey != p.box {
|
||||||
switch pType {
|
return
|
||||||
case wire_SwitchAnnounce: p.handleSwitchAnnounce(payload)
|
}
|
||||||
case wire_SwitchHopRequest: p.handleSwitchHopRequest(payload)
|
payload, isOK := boxOpen(&p.shared, packet.payload, &packet.nonce)
|
||||||
case wire_SwitchHop: p.handleSwitchHop(payload)
|
if !isOK {
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
pType, pTypeLen := wire_decode_uint64(payload)
|
||||||
|
if pTypeLen == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch pType {
|
||||||
|
case wire_SwitchAnnounce:
|
||||||
|
p.handleSwitchAnnounce(payload)
|
||||||
|
case wire_SwitchHopRequest:
|
||||||
|
p.handleSwitchHopRequest(payload)
|
||||||
|
case wire_SwitchHop:
|
||||||
|
p.handleSwitchHop(payload)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) handleSwitchAnnounce(packet []byte) {
|
func (p *peer) handleSwitchAnnounce(packet []byte) {
|
||||||
//p.core.log.Println("DEBUG: handleSwitchAnnounce")
|
//p.core.log.Println("DEBUG: handleSwitchAnnounce")
|
||||||
anc := msgAnnounce{}
|
anc := msgAnnounce{}
|
||||||
//err := wire_decode_struct(packet, &anc)
|
//err := wire_decode_struct(packet, &anc)
|
||||||
//if err != nil { return }
|
//if err != nil { return }
|
||||||
if !anc.decode(packet) { return }
|
if !anc.decode(packet) {
|
||||||
//if p.msgAnc != nil && anc.Seq != p.msgAnc.Seq { p.msgHops = nil }
|
return
|
||||||
if p.msgAnc == nil ||
|
}
|
||||||
anc.root != p.msgAnc.root ||
|
//if p.msgAnc != nil && anc.Seq != p.msgAnc.Seq { p.msgHops = nil }
|
||||||
anc.tstamp != p.msgAnc.tstamp ||
|
if p.msgAnc == nil ||
|
||||||
anc.seq != p.msgAnc.seq { p.msgHops = nil }
|
anc.root != p.msgAnc.root ||
|
||||||
p.msgAnc = &anc
|
anc.tstamp != p.msgAnc.tstamp ||
|
||||||
p.processSwitchMessage()
|
anc.seq != p.msgAnc.seq {
|
||||||
|
p.msgHops = nil
|
||||||
|
}
|
||||||
|
p.msgAnc = &anc
|
||||||
|
p.processSwitchMessage()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) requestHop(hop uint64) {
|
func (p *peer) requestHop(hop uint64) {
|
||||||
//p.core.log.Println("DEBUG requestHop")
|
//p.core.log.Println("DEBUG requestHop")
|
||||||
req := msgHopReq{}
|
req := msgHopReq{}
|
||||||
req.root = p.msgAnc.root
|
req.root = p.msgAnc.root
|
||||||
req.tstamp = p.msgAnc.tstamp
|
req.tstamp = p.msgAnc.tstamp
|
||||||
req.seq = p.msgAnc.seq
|
req.seq = p.msgAnc.seq
|
||||||
req.hop = hop
|
req.hop = hop
|
||||||
packet := req.encode()
|
packet := req.encode()
|
||||||
p.sendLinkPacket(packet)
|
p.sendLinkPacket(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) handleSwitchHopRequest(packet []byte) {
|
func (p *peer) handleSwitchHopRequest(packet []byte) {
|
||||||
//p.core.log.Println("DEBUG: handleSwitchHopRequest")
|
//p.core.log.Println("DEBUG: handleSwitchHopRequest")
|
||||||
if p.throttle > peer_Throttle { return }
|
if p.throttle > peer_Throttle {
|
||||||
if p.myMsg == nil { return }
|
return
|
||||||
req := msgHopReq{}
|
}
|
||||||
if !req.decode(packet) { return }
|
if p.myMsg == nil {
|
||||||
if req.root != p.myMsg.locator.root { return }
|
return
|
||||||
if req.tstamp != p.myMsg.locator.tstamp { return }
|
}
|
||||||
if req.seq != p.myMsg.seq { return }
|
req := msgHopReq{}
|
||||||
if uint64(len(p.myMsg.locator.coords)) <= req.hop { return }
|
if !req.decode(packet) {
|
||||||
res := msgHop{}
|
return
|
||||||
res.root = p.myMsg.locator.root
|
}
|
||||||
res.tstamp = p.myMsg.locator.tstamp
|
if req.root != p.myMsg.locator.root {
|
||||||
res.seq = p.myMsg.seq
|
return
|
||||||
res.hop = req.hop
|
}
|
||||||
res.port = p.myMsg.locator.coords[res.hop]
|
if req.tstamp != p.myMsg.locator.tstamp {
|
||||||
sinfo := p.getSig(res.hop)
|
return
|
||||||
//p.core.log.Println("DEBUG sig:", sinfo)
|
}
|
||||||
res.next = sinfo.next
|
if req.seq != p.myMsg.seq {
|
||||||
res.sig = sinfo.sig
|
return
|
||||||
packet = res.encode()
|
}
|
||||||
p.sendLinkPacket(packet)
|
if uint64(len(p.myMsg.locator.coords)) <= req.hop {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res := msgHop{}
|
||||||
|
res.root = p.myMsg.locator.root
|
||||||
|
res.tstamp = p.myMsg.locator.tstamp
|
||||||
|
res.seq = p.myMsg.seq
|
||||||
|
res.hop = req.hop
|
||||||
|
res.port = p.myMsg.locator.coords[res.hop]
|
||||||
|
sinfo := p.getSig(res.hop)
|
||||||
|
//p.core.log.Println("DEBUG sig:", sinfo)
|
||||||
|
res.next = sinfo.next
|
||||||
|
res.sig = sinfo.sig
|
||||||
|
packet = res.encode()
|
||||||
|
p.sendLinkPacket(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) handleSwitchHop(packet []byte) {
|
func (p *peer) handleSwitchHop(packet []byte) {
|
||||||
//p.core.log.Println("DEBUG: handleSwitchHop")
|
//p.core.log.Println("DEBUG: handleSwitchHop")
|
||||||
if p.throttle > peer_Throttle { return }
|
if p.throttle > peer_Throttle {
|
||||||
if p.msgAnc == nil { return }
|
return
|
||||||
res := msgHop{}
|
}
|
||||||
if !res.decode(packet) { return }
|
if p.msgAnc == nil {
|
||||||
if res.root != p.msgAnc.root { return }
|
return
|
||||||
if res.tstamp != p.msgAnc.tstamp { return }
|
}
|
||||||
if res.seq != p.msgAnc.seq { return }
|
res := msgHop{}
|
||||||
if res.hop != uint64(len(p.msgHops)) { return } // always process in order
|
if !res.decode(packet) {
|
||||||
loc := switchLocator{coords: make([]switchPort, 0, len(p.msgHops)+1)}
|
return
|
||||||
loc.root = res.root
|
}
|
||||||
loc.tstamp = res.tstamp
|
if res.root != p.msgAnc.root {
|
||||||
for _, hop := range p.msgHops { loc.coords = append(loc.coords, hop.port) }
|
return
|
||||||
loc.coords = append(loc.coords, res.port)
|
}
|
||||||
thisHopKey := &res.root
|
if res.tstamp != p.msgAnc.tstamp {
|
||||||
if res.hop != 0 { thisHopKey = &p.msgHops[res.hop-1].next }
|
return
|
||||||
bs := getBytesForSig(&res.next, &loc)
|
}
|
||||||
if p.core.sigs.check(thisHopKey, &res.sig, bs) {
|
if res.seq != p.msgAnc.seq {
|
||||||
p.msgHops = append(p.msgHops, &res)
|
return
|
||||||
p.processSwitchMessage()
|
}
|
||||||
} else {
|
if res.hop != uint64(len(p.msgHops)) {
|
||||||
p.throttle++
|
return
|
||||||
}
|
} // always process in order
|
||||||
|
loc := switchLocator{coords: make([]switchPort, 0, len(p.msgHops)+1)}
|
||||||
|
loc.root = res.root
|
||||||
|
loc.tstamp = res.tstamp
|
||||||
|
for _, hop := range p.msgHops {
|
||||||
|
loc.coords = append(loc.coords, hop.port)
|
||||||
|
}
|
||||||
|
loc.coords = append(loc.coords, res.port)
|
||||||
|
thisHopKey := &res.root
|
||||||
|
if res.hop != 0 {
|
||||||
|
thisHopKey = &p.msgHops[res.hop-1].next
|
||||||
|
}
|
||||||
|
bs := getBytesForSig(&res.next, &loc)
|
||||||
|
if p.core.sigs.check(thisHopKey, &res.sig, bs) {
|
||||||
|
p.msgHops = append(p.msgHops, &res)
|
||||||
|
p.processSwitchMessage()
|
||||||
|
} else {
|
||||||
|
p.throttle++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) processSwitchMessage() {
|
func (p *peer) processSwitchMessage() {
|
||||||
//p.core.log.Println("DEBUG: processSwitchMessage")
|
//p.core.log.Println("DEBUG: processSwitchMessage")
|
||||||
if p.throttle > peer_Throttle { return }
|
if p.throttle > peer_Throttle {
|
||||||
if p.msgAnc == nil { return }
|
return
|
||||||
if uint64(len(p.msgHops)) < p.msgAnc.len {
|
}
|
||||||
p.requestHop(uint64(len(p.msgHops)))
|
if p.msgAnc == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p.throttle++
|
if uint64(len(p.msgHops)) < p.msgAnc.len {
|
||||||
if p.msgAnc.len != uint64(len(p.msgHops)) { return }
|
p.requestHop(uint64(len(p.msgHops)))
|
||||||
msg := switchMessage{}
|
return
|
||||||
coords := make([]switchPort, 0, len(p.msgHops))
|
}
|
||||||
sigs := make([]sigInfo, 0, len(p.msgHops))
|
p.throttle++
|
||||||
for idx, hop := range p.msgHops {
|
if p.msgAnc.len != uint64(len(p.msgHops)) {
|
||||||
// Consistency checks, should be redundant (already checked these...)
|
return
|
||||||
if hop.root != p.msgAnc.root { return }
|
}
|
||||||
if hop.tstamp != p.msgAnc.tstamp { return }
|
msg := switchMessage{}
|
||||||
if hop.seq != p.msgAnc.seq { return }
|
coords := make([]switchPort, 0, len(p.msgHops))
|
||||||
if hop.hop != uint64(idx) { return }
|
sigs := make([]sigInfo, 0, len(p.msgHops))
|
||||||
coords = append(coords, hop.port)
|
for idx, hop := range p.msgHops {
|
||||||
sigs = append(sigs, sigInfo{next: hop.next, sig: hop.sig})
|
// Consistency checks, should be redundant (already checked these...)
|
||||||
}
|
if hop.root != p.msgAnc.root {
|
||||||
msg.from = p.sig
|
return
|
||||||
msg.locator.root = p.msgAnc.root
|
}
|
||||||
msg.locator.tstamp = p.msgAnc.tstamp
|
if hop.tstamp != p.msgAnc.tstamp {
|
||||||
msg.locator.coords = coords
|
return
|
||||||
msg.seq = p.msgAnc.seq
|
}
|
||||||
//msg.RSeq = p.msgAnc.RSeq
|
if hop.seq != p.msgAnc.seq {
|
||||||
//msg.Degree = p.msgAnc.Deg
|
return
|
||||||
p.core.switchTable.handleMessage(&msg, p.port, sigs)
|
}
|
||||||
if len(coords) == 0 { return }
|
if hop.hop != uint64(idx) {
|
||||||
// Reuse locator, set the coords to the peer's coords, to use in dht
|
return
|
||||||
msg.locator.coords = coords[:len(coords)-1]
|
}
|
||||||
// Pass a mesage to the dht informing it that this peer (still) exists
|
coords = append(coords, hop.port)
|
||||||
dinfo := dhtInfo{
|
sigs = append(sigs, sigInfo{next: hop.next, sig: hop.sig})
|
||||||
key: p.box,
|
}
|
||||||
coords: msg.locator.getCoords(),
|
msg.from = p.sig
|
||||||
}
|
msg.locator.root = p.msgAnc.root
|
||||||
p.core.dht.peers<-&dinfo
|
msg.locator.tstamp = p.msgAnc.tstamp
|
||||||
|
msg.locator.coords = coords
|
||||||
|
msg.seq = p.msgAnc.seq
|
||||||
|
//msg.RSeq = p.msgAnc.RSeq
|
||||||
|
//msg.Degree = p.msgAnc.Deg
|
||||||
|
p.core.switchTable.handleMessage(&msg, p.port, sigs)
|
||||||
|
if len(coords) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Reuse locator, set the coords to the peer's coords, to use in dht
|
||||||
|
msg.locator.coords = coords[:len(coords)-1]
|
||||||
|
// Pass a mesage to the dht informing it that this peer (still) exists
|
||||||
|
dinfo := dhtInfo{
|
||||||
|
key: p.box,
|
||||||
|
coords: msg.locator.getCoords(),
|
||||||
|
}
|
||||||
|
p.core.dht.peers <- &dinfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) sendSwitchAnnounce() {
|
func (p *peer) sendSwitchAnnounce() {
|
||||||
anc := msgAnnounce{}
|
anc := msgAnnounce{}
|
||||||
anc.root = p.myMsg.locator.root
|
anc.root = p.myMsg.locator.root
|
||||||
anc.tstamp = p.myMsg.locator.tstamp
|
anc.tstamp = p.myMsg.locator.tstamp
|
||||||
anc.seq = p.myMsg.seq
|
anc.seq = p.myMsg.seq
|
||||||
anc.len = uint64(len(p.myMsg.locator.coords))
|
anc.len = uint64(len(p.myMsg.locator.coords))
|
||||||
//anc.Deg = p.myMsg.Degree
|
//anc.Deg = p.myMsg.Degree
|
||||||
//anc.RSeq = p.myMsg.RSeq
|
//anc.RSeq = p.myMsg.RSeq
|
||||||
packet := anc.encode()
|
packet := anc.encode()
|
||||||
p.sendLinkPacket(packet)
|
p.sendLinkPacket(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) getSig(hop uint64) sigInfo {
|
func (p *peer) getSig(hop uint64) sigInfo {
|
||||||
//p.core.log.Println("DEBUG getSig:", len(p.mySigs), hop)
|
//p.core.log.Println("DEBUG getSig:", len(p.mySigs), hop)
|
||||||
if hop < uint64(len(p.mySigs)) { return p.mySigs[hop] }
|
if hop < uint64(len(p.mySigs)) {
|
||||||
bs := getBytesForSig(&p.sig, &p.myMsg.locator)
|
return p.mySigs[hop]
|
||||||
sig := sigInfo{}
|
}
|
||||||
sig.next = p.sig
|
bs := getBytesForSig(&p.sig, &p.myMsg.locator)
|
||||||
sig.sig = *sign(&p.core.sigPriv, bs)
|
sig := sigInfo{}
|
||||||
p.mySigs = append(p.mySigs, sig)
|
sig.next = p.sig
|
||||||
//p.core.log.Println("DEBUG sig bs:", bs)
|
sig.sig = *sign(&p.core.sigPriv, bs)
|
||||||
return sig
|
p.mySigs = append(p.mySigs, sig)
|
||||||
|
//p.core.log.Println("DEBUG sig bs:", bs)
|
||||||
|
return sig
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBytesForSig(next *sigPubKey, loc *switchLocator) []byte {
|
func getBytesForSig(next *sigPubKey, loc *switchLocator) []byte {
|
||||||
//bs, err := wire_encode_locator(loc)
|
//bs, err := wire_encode_locator(loc)
|
||||||
//if err != nil { panic(err) }
|
//if err != nil { panic(err) }
|
||||||
bs := append([]byte(nil), next[:]...)
|
bs := append([]byte(nil), next[:]...)
|
||||||
bs = append(bs, wire_encode_locator(loc)...)
|
bs = append(bs, wire_encode_locator(loc)...)
|
||||||
//bs := wire_encode_locator(loc)
|
//bs := wire_encode_locator(loc)
|
||||||
//bs = append(next[:], bs...)
|
//bs = append(next[:], bs...)
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,198 +23,267 @@ package yggdrasil
|
|||||||
// The router then runs some sanity checks before passing it to the tun
|
// The router then runs some sanity checks before passing it to the tun
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
//import "fmt"
|
//import "fmt"
|
||||||
//import "net"
|
//import "net"
|
||||||
|
|
||||||
type router struct {
|
type router struct {
|
||||||
core *Core
|
core *Core
|
||||||
addr address
|
addr address
|
||||||
in <-chan []byte // packets we received from the network, link to peer's "out"
|
in <-chan []byte // packets we received from the network, link to peer's "out"
|
||||||
out func([]byte) // packets we're sending to the network, link to peer's "in"
|
out func([]byte) // packets we're sending to the network, link to peer's "in"
|
||||||
recv chan<- []byte // place where the tun pulls received packets from
|
recv chan<- []byte // place where the tun pulls received packets from
|
||||||
send <-chan []byte // place where the tun puts outgoing packets
|
send <-chan []byte // place where the tun puts outgoing packets
|
||||||
reset chan struct{} // signal that coords changed (re-init sessions/dht)
|
reset chan struct{} // signal that coords changed (re-init sessions/dht)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) init(core *Core) {
|
func (r *router) init(core *Core) {
|
||||||
r.core = core
|
r.core = core
|
||||||
r.addr = *address_addrForNodeID(&r.core.dht.nodeID)
|
r.addr = *address_addrForNodeID(&r.core.dht.nodeID)
|
||||||
in := make(chan []byte, 1) // TODO something better than this...
|
in := make(chan []byte, 1) // TODO something better than this...
|
||||||
p := r.core.peers.newPeer(&r.core.boxPub, &r.core.sigPub)//, out, in)
|
p := r.core.peers.newPeer(&r.core.boxPub, &r.core.sigPub) //, out, in)
|
||||||
// TODO set in/out functions on the new peer...
|
// TODO set in/out functions on the new peer...
|
||||||
p.out = func(packet []byte) { in<-packet } // FIXME in theory it blocks...
|
p.out = func(packet []byte) { in <- packet } // FIXME in theory it blocks...
|
||||||
r.in = in
|
r.in = in
|
||||||
// TODO? make caller responsible for go-ing if it needs to not block
|
// TODO? make caller responsible for go-ing if it needs to not block
|
||||||
r.out = func(packet []byte) { p.handlePacket(packet, nil) }
|
r.out = func(packet []byte) { p.handlePacket(packet, nil) }
|
||||||
// TODO attach these to the tun
|
// TODO attach these to the tun
|
||||||
// Maybe that's the core's job...
|
// Maybe that's the core's job...
|
||||||
// It creates tun, creates the router, creates channels, sets them?
|
// It creates tun, creates the router, creates channels, sets them?
|
||||||
recv := make(chan []byte, 1)
|
recv := make(chan []byte, 1)
|
||||||
send := make(chan []byte, 1)
|
send := make(chan []byte, 1)
|
||||||
r.recv = recv
|
r.recv = recv
|
||||||
r.send = send
|
r.send = send
|
||||||
r.core.tun.recv = recv
|
r.core.tun.recv = recv
|
||||||
r.core.tun.send = send
|
r.core.tun.send = send
|
||||||
r.reset = make(chan struct{}, 1)
|
r.reset = make(chan struct{}, 1)
|
||||||
go r.mainLoop()
|
go r.mainLoop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) mainLoop() {
|
func (r *router) mainLoop() {
|
||||||
ticker := time.NewTicker(time.Second)
|
ticker := time.NewTicker(time.Second)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case p := <-r.in: r.handleIn(p)
|
case p := <-r.in:
|
||||||
case p := <-r.send: r.sendPacket(p)
|
r.handleIn(p)
|
||||||
case info := <-r.core.dht.peers: r.core.dht.insert(info) //r.core.dht.insertIfNew(info)
|
case p := <-r.send:
|
||||||
case <-r.reset: r.core.sessions.resetInits()
|
r.sendPacket(p)
|
||||||
case <-ticker.C: {
|
case info := <-r.core.dht.peers:
|
||||||
// Any periodic maintenance stuff goes here
|
r.core.dht.insert(info) //r.core.dht.insertIfNew(info)
|
||||||
r.core.dht.doMaintenance()
|
case <-r.reset:
|
||||||
util_getBytes() // To slowly drain things
|
r.core.sessions.resetInits()
|
||||||
}
|
case <-ticker.C:
|
||||||
}
|
{
|
||||||
}
|
// Any periodic maintenance stuff goes here
|
||||||
|
r.core.dht.doMaintenance()
|
||||||
|
util_getBytes() // To slowly drain things
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) sendPacket(bs []byte) {
|
func (r *router) sendPacket(bs []byte) {
|
||||||
if len(bs) < 40 { panic("Tried to send a packet shorter than a header...") }
|
if len(bs) < 40 {
|
||||||
var sourceAddr address
|
panic("Tried to send a packet shorter than a header...")
|
||||||
var sourceSubnet subnet
|
}
|
||||||
copy(sourceAddr[:], bs[8:])
|
var sourceAddr address
|
||||||
copy(sourceSubnet[:], bs[8:])
|
var sourceSubnet subnet
|
||||||
if !sourceAddr.isValid() && !sourceSubnet.isValid() { return }
|
copy(sourceAddr[:], bs[8:])
|
||||||
var dest address
|
copy(sourceSubnet[:], bs[8:])
|
||||||
copy(dest[:], bs[24:])
|
if !sourceAddr.isValid() && !sourceSubnet.isValid() {
|
||||||
var snet subnet
|
return
|
||||||
copy(snet[:], bs[24:])
|
}
|
||||||
if !dest.isValid() && !snet.isValid() { return }
|
var dest address
|
||||||
doSearch := func (packet []byte) {
|
copy(dest[:], bs[24:])
|
||||||
var nodeID, mask *NodeID
|
var snet subnet
|
||||||
if dest.isValid() { nodeID, mask = dest.getNodeIDandMask() }
|
copy(snet[:], bs[24:])
|
||||||
if snet.isValid() { nodeID, mask = snet.getNodeIDandMask() }
|
if !dest.isValid() && !snet.isValid() {
|
||||||
sinfo, isIn := r.core.searches.searches[*nodeID]
|
return
|
||||||
if !isIn { sinfo = r.core.searches.createSearch(nodeID, mask) }
|
}
|
||||||
if packet != nil { sinfo.packet = packet }
|
doSearch := func(packet []byte) {
|
||||||
r.core.searches.sendSearch(sinfo)
|
var nodeID, mask *NodeID
|
||||||
}
|
if dest.isValid() {
|
||||||
var sinfo *sessionInfo
|
nodeID, mask = dest.getNodeIDandMask()
|
||||||
var isIn bool
|
}
|
||||||
if dest.isValid() { sinfo, isIn = r.core.sessions.getByTheirAddr(&dest) }
|
if snet.isValid() {
|
||||||
if snet.isValid() { sinfo, isIn = r.core.sessions.getByTheirSubnet(&snet) }
|
nodeID, mask = snet.getNodeIDandMask()
|
||||||
switch {
|
}
|
||||||
case !isIn || !sinfo.init:
|
sinfo, isIn := r.core.searches.searches[*nodeID]
|
||||||
// No or unintiialized session, so we need to search first
|
if !isIn {
|
||||||
doSearch(bs)
|
sinfo = r.core.searches.createSearch(nodeID, mask)
|
||||||
case time.Since(sinfo.time) > 6*time.Second:
|
}
|
||||||
// We haven't heard from the dest in a while; they may have changed coords
|
if packet != nil {
|
||||||
// Maybe the connection is idle, or maybe one of us changed coords
|
sinfo.packet = packet
|
||||||
// Try searching to either ping them (a little overhead) or fix the coords
|
}
|
||||||
doSearch(nil)
|
r.core.searches.sendSearch(sinfo)
|
||||||
fallthrough
|
}
|
||||||
//default: go func() { sinfo.send<-bs }()
|
var sinfo *sessionInfo
|
||||||
default: sinfo.send<-bs
|
var isIn bool
|
||||||
}
|
if dest.isValid() {
|
||||||
|
sinfo, isIn = r.core.sessions.getByTheirAddr(&dest)
|
||||||
|
}
|
||||||
|
if snet.isValid() {
|
||||||
|
sinfo, isIn = r.core.sessions.getByTheirSubnet(&snet)
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case !isIn || !sinfo.init:
|
||||||
|
// No or unintiialized session, so we need to search first
|
||||||
|
doSearch(bs)
|
||||||
|
case time.Since(sinfo.time) > 6*time.Second:
|
||||||
|
// We haven't heard from the dest in a while; they may have changed coords
|
||||||
|
// Maybe the connection is idle, or maybe one of us changed coords
|
||||||
|
// Try searching to either ping them (a little overhead) or fix the coords
|
||||||
|
doSearch(nil)
|
||||||
|
fallthrough
|
||||||
|
//default: go func() { sinfo.send<-bs }()
|
||||||
|
default:
|
||||||
|
sinfo.send <- bs
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) recvPacket(bs []byte, theirAddr *address) {
|
func (r *router) recvPacket(bs []byte, theirAddr *address) {
|
||||||
// TODO pass their NodeID, check *that* instead
|
// TODO pass their NodeID, check *that* instead
|
||||||
// Or store their address in the session?...
|
// Or store their address in the session?...
|
||||||
//fmt.Println("Recv packet")
|
//fmt.Println("Recv packet")
|
||||||
if theirAddr == nil { panic("Should not happen ever") }
|
if theirAddr == nil {
|
||||||
if len(bs) < 24 { return }
|
panic("Should not happen ever")
|
||||||
var source address
|
}
|
||||||
copy(source[:], bs[8:])
|
if len(bs) < 24 {
|
||||||
var snet subnet
|
return
|
||||||
copy(snet[:], bs[8:])
|
}
|
||||||
if !source.isValid() && !snet.isValid() { return }
|
var source address
|
||||||
//go func() { r.recv<-bs }()
|
copy(source[:], bs[8:])
|
||||||
r.recv<-bs
|
var snet subnet
|
||||||
|
copy(snet[:], bs[8:])
|
||||||
|
if !source.isValid() && !snet.isValid() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//go func() { r.recv<-bs }()
|
||||||
|
r.recv <- bs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) handleIn(packet []byte) {
|
func (r *router) handleIn(packet []byte) {
|
||||||
pType, pTypeLen := wire_decode_uint64(packet)
|
pType, pTypeLen := wire_decode_uint64(packet)
|
||||||
if pTypeLen == 0 { return }
|
if pTypeLen == 0 {
|
||||||
switch pType {
|
return
|
||||||
case wire_Traffic: r.handleTraffic(packet)
|
}
|
||||||
case wire_ProtocolTraffic: r.handleProto(packet)
|
switch pType {
|
||||||
default: /*panic("Should not happen in testing") ;*/ return
|
case wire_Traffic:
|
||||||
}
|
r.handleTraffic(packet)
|
||||||
|
case wire_ProtocolTraffic:
|
||||||
|
r.handleProto(packet)
|
||||||
|
default: /*panic("Should not happen in testing") ;*/
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) handleTraffic(packet []byte) {
|
func (r *router) handleTraffic(packet []byte) {
|
||||||
defer util_putBytes(packet)
|
defer util_putBytes(packet)
|
||||||
p := wire_trafficPacket{}
|
p := wire_trafficPacket{}
|
||||||
if !p.decode(packet) { return }
|
if !p.decode(packet) {
|
||||||
sinfo, isIn := r.core.sessions.getSessionForHandle(&p.handle)
|
return
|
||||||
if !isIn { return }
|
}
|
||||||
//go func () { sinfo.recv<-&p }()
|
sinfo, isIn := r.core.sessions.getSessionForHandle(&p.handle)
|
||||||
sinfo.recv<-&p
|
if !isIn {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//go func () { sinfo.recv<-&p }()
|
||||||
|
sinfo.recv <- &p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) handleProto(packet []byte) {
|
func (r *router) handleProto(packet []byte) {
|
||||||
// First parse the packet
|
// First parse the packet
|
||||||
p := wire_protoTrafficPacket{}
|
p := wire_protoTrafficPacket{}
|
||||||
if !p.decode(packet) { return }
|
if !p.decode(packet) {
|
||||||
// Now try to open the payload
|
return
|
||||||
var sharedKey *boxSharedKey
|
}
|
||||||
//var theirPermPub *boxPubKey
|
// Now try to open the payload
|
||||||
if p.toKey == r.core.boxPub {
|
var sharedKey *boxSharedKey
|
||||||
// Try to open using our permanent key
|
//var theirPermPub *boxPubKey
|
||||||
sharedKey = r.core.sessions.getSharedKey(&r.core.boxPriv, &p.fromKey)
|
if p.toKey == r.core.boxPub {
|
||||||
} else { return }
|
// Try to open using our permanent key
|
||||||
bs, isOK := boxOpen(sharedKey, p.payload, &p.nonce)
|
sharedKey = r.core.sessions.getSharedKey(&r.core.boxPriv, &p.fromKey)
|
||||||
if !isOK { return }
|
} else {
|
||||||
// Now do something with the bytes in bs...
|
return
|
||||||
// send dht messages to dht, sessionRefresh to sessions, data to tun...
|
}
|
||||||
// For data, should check that key and IP match...
|
bs, isOK := boxOpen(sharedKey, p.payload, &p.nonce)
|
||||||
bsType, bsTypeLen := wire_decode_uint64(bs)
|
if !isOK {
|
||||||
if bsTypeLen == 0 { return }
|
return
|
||||||
//fmt.Println("RECV bytes:", bs)
|
}
|
||||||
switch bsType {
|
// Now do something with the bytes in bs...
|
||||||
case wire_SessionPing: r.handlePing(bs, &p.fromKey)
|
// send dht messages to dht, sessionRefresh to sessions, data to tun...
|
||||||
case wire_SessionPong: r.handlePong(bs, &p.fromKey)
|
// For data, should check that key and IP match...
|
||||||
case wire_DHTLookupRequest: r.handleDHTReq(bs, &p.fromKey)
|
bsType, bsTypeLen := wire_decode_uint64(bs)
|
||||||
case wire_DHTLookupResponse: r.handleDHTRes(bs, &p.fromKey)
|
if bsTypeLen == 0 {
|
||||||
case wire_SearchRequest: r.handleSearchReq(bs)
|
return
|
||||||
case wire_SearchResponse: r.handleSearchRes(bs)
|
}
|
||||||
default: /*panic("Should not happen in testing") ;*/ return
|
//fmt.Println("RECV bytes:", bs)
|
||||||
}
|
switch bsType {
|
||||||
|
case wire_SessionPing:
|
||||||
|
r.handlePing(bs, &p.fromKey)
|
||||||
|
case wire_SessionPong:
|
||||||
|
r.handlePong(bs, &p.fromKey)
|
||||||
|
case wire_DHTLookupRequest:
|
||||||
|
r.handleDHTReq(bs, &p.fromKey)
|
||||||
|
case wire_DHTLookupResponse:
|
||||||
|
r.handleDHTRes(bs, &p.fromKey)
|
||||||
|
case wire_SearchRequest:
|
||||||
|
r.handleSearchReq(bs)
|
||||||
|
case wire_SearchResponse:
|
||||||
|
r.handleSearchRes(bs)
|
||||||
|
default: /*panic("Should not happen in testing") ;*/
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) handlePing(bs []byte, fromKey *boxPubKey) {
|
func (r *router) handlePing(bs []byte, fromKey *boxPubKey) {
|
||||||
ping := sessionPing{}
|
ping := sessionPing{}
|
||||||
if !ping.decode(bs) { return }
|
if !ping.decode(bs) {
|
||||||
ping.sendPermPub = *fromKey
|
return
|
||||||
r.core.sessions.handlePing(&ping)
|
}
|
||||||
|
ping.sendPermPub = *fromKey
|
||||||
|
r.core.sessions.handlePing(&ping)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) handlePong(bs []byte, fromKey *boxPubKey) {
|
func (r *router) handlePong(bs []byte, fromKey *boxPubKey) {
|
||||||
r.handlePing(bs, fromKey)
|
r.handlePing(bs, fromKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) handleDHTReq(bs []byte, fromKey *boxPubKey) {
|
func (r *router) handleDHTReq(bs []byte, fromKey *boxPubKey) {
|
||||||
req := dhtReq{}
|
req := dhtReq{}
|
||||||
if !req.decode(bs) { return }
|
if !req.decode(bs) {
|
||||||
if req.key != *fromKey { return }
|
return
|
||||||
r.core.dht.handleReq(&req)
|
}
|
||||||
|
if req.key != *fromKey {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.core.dht.handleReq(&req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) handleDHTRes(bs []byte, fromKey *boxPubKey) {
|
func (r *router) handleDHTRes(bs []byte, fromKey *boxPubKey) {
|
||||||
res := dhtRes{}
|
res := dhtRes{}
|
||||||
if !res.decode(bs) { return }
|
if !res.decode(bs) {
|
||||||
if res.key != *fromKey { return }
|
return
|
||||||
r.core.dht.handleRes(&res)
|
}
|
||||||
|
if res.key != *fromKey {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.core.dht.handleRes(&res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) handleSearchReq(bs []byte) {
|
func (r *router) handleSearchReq(bs []byte) {
|
||||||
req := searchReq{}
|
req := searchReq{}
|
||||||
if !req.decode(bs) { return }
|
if !req.decode(bs) {
|
||||||
r.core.searches.handleSearchReq(&req)
|
return
|
||||||
|
}
|
||||||
|
r.core.searches.handleSearchReq(&req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) handleSearchRes(bs []byte) {
|
func (r *router) handleSearchRes(bs []byte) {
|
||||||
res := searchRes{}
|
res := searchRes{}
|
||||||
if !res.decode(bs) { return }
|
if !res.decode(bs) {
|
||||||
r.core.searches.handleSearchRes(&res)
|
return
|
||||||
|
}
|
||||||
|
r.core.searches.handleSearchRes(&res)
|
||||||
}
|
}
|
||||||
|
@ -17,152 +17,162 @@ package yggdrasil
|
|||||||
// This hides bugs, which I don't want to do right now
|
// This hides bugs, which I don't want to do right now
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
//import "fmt"
|
//import "fmt"
|
||||||
|
|
||||||
type searchInfo struct {
|
type searchInfo struct {
|
||||||
dest *NodeID
|
dest *NodeID
|
||||||
mask *NodeID
|
mask *NodeID
|
||||||
time time.Time
|
time time.Time
|
||||||
packet []byte
|
packet []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type searches struct {
|
type searches struct {
|
||||||
core *Core
|
core *Core
|
||||||
searches map[NodeID]*searchInfo
|
searches map[NodeID]*searchInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *searches) init(core *Core) {
|
func (s *searches) init(core *Core) {
|
||||||
s.core = core
|
s.core = core
|
||||||
s.searches = make(map[NodeID]*searchInfo)
|
s.searches = make(map[NodeID]*searchInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *searches) createSearch(dest *NodeID, mask *NodeID) *searchInfo {
|
func (s *searches) createSearch(dest *NodeID, mask *NodeID) *searchInfo {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
for dest, sinfo := range s.searches {
|
for dest, sinfo := range s.searches {
|
||||||
if now.Sub(sinfo.time) > time.Minute {
|
if now.Sub(sinfo.time) > time.Minute {
|
||||||
delete(s.searches, dest)
|
delete(s.searches, dest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info := searchInfo{
|
info := searchInfo{
|
||||||
dest: dest,
|
dest: dest,
|
||||||
mask: mask,
|
mask: mask,
|
||||||
time: now.Add(-time.Second),
|
time: now.Add(-time.Second),
|
||||||
}
|
}
|
||||||
s.searches[*dest] = &info
|
s.searches[*dest] = &info
|
||||||
return &info
|
return &info
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
type searchReq struct {
|
type searchReq struct {
|
||||||
key boxPubKey // Who I am
|
key boxPubKey // Who I am
|
||||||
coords []byte // Where I am
|
coords []byte // Where I am
|
||||||
dest NodeID // Who I'm trying to connect to
|
dest NodeID // Who I'm trying to connect to
|
||||||
}
|
}
|
||||||
|
|
||||||
type searchRes struct {
|
type searchRes struct {
|
||||||
key boxPubKey // Who I am
|
key boxPubKey // Who I am
|
||||||
coords []byte // Where I am
|
coords []byte // Where I am
|
||||||
dest NodeID // Who I was asked about
|
dest NodeID // Who I was asked about
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *searches) sendSearch(info *searchInfo) {
|
func (s *searches) sendSearch(info *searchInfo) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
if now.Sub(info.time) < time.Second { return }
|
if now.Sub(info.time) < time.Second {
|
||||||
loc := s.core.switchTable.getLocator()
|
return
|
||||||
coords := loc.getCoords()
|
}
|
||||||
req := searchReq{
|
loc := s.core.switchTable.getLocator()
|
||||||
key: s.core.boxPub,
|
coords := loc.getCoords()
|
||||||
coords: coords,
|
req := searchReq{
|
||||||
dest: *info.dest,
|
key: s.core.boxPub,
|
||||||
}
|
coords: coords,
|
||||||
info.time = time.Now()
|
dest: *info.dest,
|
||||||
s.handleSearchReq(&req)
|
}
|
||||||
|
info.time = time.Now()
|
||||||
|
s.handleSearchReq(&req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *searches) handleSearchReq(req *searchReq) {
|
func (s *searches) handleSearchReq(req *searchReq) {
|
||||||
lookup := s.core.dht.lookup(&req.dest)
|
lookup := s.core.dht.lookup(&req.dest)
|
||||||
sent := false
|
sent := false
|
||||||
//fmt.Println("DEBUG len:", len(lookup))
|
//fmt.Println("DEBUG len:", len(lookup))
|
||||||
for _, info := range lookup {
|
for _, info := range lookup {
|
||||||
//fmt.Println("DEBUG lup:", info.getNodeID())
|
//fmt.Println("DEBUG lup:", info.getNodeID())
|
||||||
if dht_firstCloserThanThird(info.getNodeID(),
|
if dht_firstCloserThanThird(info.getNodeID(),
|
||||||
&req.dest,
|
&req.dest,
|
||||||
&s.core.dht.nodeID) {
|
&s.core.dht.nodeID) {
|
||||||
s.forwardSearch(req, info)
|
s.forwardSearch(req, info)
|
||||||
sent = true
|
sent = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !sent { s.sendSearchRes(req) }
|
if !sent {
|
||||||
|
s.sendSearchRes(req)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *searches) forwardSearch(req *searchReq, next *dhtInfo) {
|
func (s *searches) forwardSearch(req *searchReq, next *dhtInfo) {
|
||||||
//fmt.Println("DEBUG fwd:", req.dest, next.getNodeID())
|
//fmt.Println("DEBUG fwd:", req.dest, next.getNodeID())
|
||||||
bs := req.encode()
|
bs := req.encode()
|
||||||
shared := s.core.sessions.getSharedKey(&s.core.boxPriv, &next.key)
|
shared := s.core.sessions.getSharedKey(&s.core.boxPriv, &next.key)
|
||||||
payload, nonce := boxSeal(shared, bs, nil)
|
payload, nonce := boxSeal(shared, bs, nil)
|
||||||
p := wire_protoTrafficPacket{
|
p := wire_protoTrafficPacket{
|
||||||
ttl: ^uint64(0),
|
ttl: ^uint64(0),
|
||||||
coords: next.coords,
|
coords: next.coords,
|
||||||
toKey: next.key,
|
toKey: next.key,
|
||||||
fromKey: s.core.boxPub,
|
fromKey: s.core.boxPub,
|
||||||
nonce: *nonce,
|
nonce: *nonce,
|
||||||
payload: payload,
|
payload: payload,
|
||||||
}
|
}
|
||||||
packet := p.encode()
|
packet := p.encode()
|
||||||
s.core.router.out(packet)
|
s.core.router.out(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *searches) sendSearchRes(req *searchReq) {
|
func (s *searches) sendSearchRes(req *searchReq) {
|
||||||
//fmt.Println("DEBUG res:", req.dest, s.core.dht.nodeID)
|
//fmt.Println("DEBUG res:", req.dest, s.core.dht.nodeID)
|
||||||
loc := s.core.switchTable.getLocator()
|
loc := s.core.switchTable.getLocator()
|
||||||
coords := loc.getCoords()
|
coords := loc.getCoords()
|
||||||
res := searchRes{
|
res := searchRes{
|
||||||
key: s.core.boxPub,
|
key: s.core.boxPub,
|
||||||
coords: coords,
|
coords: coords,
|
||||||
dest: req.dest,
|
dest: req.dest,
|
||||||
}
|
}
|
||||||
bs := res.encode()
|
bs := res.encode()
|
||||||
shared := s.core.sessions.getSharedKey(&s.core.boxPriv, &req.key)
|
shared := s.core.sessions.getSharedKey(&s.core.boxPriv, &req.key)
|
||||||
payload, nonce := boxSeal(shared, bs, nil)
|
payload, nonce := boxSeal(shared, bs, nil)
|
||||||
p := wire_protoTrafficPacket{
|
p := wire_protoTrafficPacket{
|
||||||
ttl: ^uint64(0),
|
ttl: ^uint64(0),
|
||||||
coords: req.coords,
|
coords: req.coords,
|
||||||
toKey: req.key,
|
toKey: req.key,
|
||||||
fromKey: s.core.boxPub,
|
fromKey: s.core.boxPub,
|
||||||
nonce: *nonce,
|
nonce: *nonce,
|
||||||
payload: payload,
|
payload: payload,
|
||||||
}
|
}
|
||||||
packet := p.encode()
|
packet := p.encode()
|
||||||
s.core.router.out(packet)
|
s.core.router.out(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *searches) handleSearchRes(res *searchRes) {
|
func (s *searches) handleSearchRes(res *searchRes) {
|
||||||
info, isIn := s.searches[res.dest]
|
info, isIn := s.searches[res.dest]
|
||||||
if !isIn { return }
|
if !isIn {
|
||||||
them := getNodeID(&res.key)
|
return
|
||||||
var destMasked NodeID
|
}
|
||||||
var themMasked NodeID
|
them := getNodeID(&res.key)
|
||||||
for idx := 0 ; idx < NodeIDLen ; idx++ {
|
var destMasked NodeID
|
||||||
destMasked[idx] = info.dest[idx] & info.mask[idx]
|
var themMasked NodeID
|
||||||
themMasked[idx] = them[idx] & info.mask[idx]
|
for idx := 0; idx < NodeIDLen; idx++ {
|
||||||
}
|
destMasked[idx] = info.dest[idx] & info.mask[idx]
|
||||||
//fmt.Println("DEBUG search res1:", themMasked, destMasked)
|
themMasked[idx] = them[idx] & info.mask[idx]
|
||||||
//fmt.Println("DEBUG search res2:", *them, *info.dest, *info.mask)
|
}
|
||||||
if themMasked != destMasked { return }
|
//fmt.Println("DEBUG search res1:", themMasked, destMasked)
|
||||||
// They match, so create a session and send a sessionRequest
|
//fmt.Println("DEBUG search res2:", *them, *info.dest, *info.mask)
|
||||||
sinfo, isIn := s.core.sessions.getByTheirPerm(&res.key)
|
if themMasked != destMasked {
|
||||||
if !isIn {
|
return
|
||||||
sinfo = s.core.sessions.createSession(&res.key)
|
}
|
||||||
_, isIn := s.core.sessions.getByTheirPerm(&res.key)
|
// They match, so create a session and send a sessionRequest
|
||||||
if !isIn { panic("This should never happen") }
|
sinfo, isIn := s.core.sessions.getByTheirPerm(&res.key)
|
||||||
}
|
if !isIn {
|
||||||
// FIXME replay attacks could mess with coords?
|
sinfo = s.core.sessions.createSession(&res.key)
|
||||||
sinfo.coords = res.coords
|
_, isIn := s.core.sessions.getByTheirPerm(&res.key)
|
||||||
sinfo.packet = info.packet
|
if !isIn {
|
||||||
s.core.sessions.ping(sinfo)
|
panic("This should never happen")
|
||||||
// Cleanup
|
}
|
||||||
delete(s.searches, res.dest)
|
}
|
||||||
|
// FIXME replay attacks could mess with coords?
|
||||||
|
sinfo.coords = res.coords
|
||||||
|
sinfo.packet = info.packet
|
||||||
|
s.core.sessions.ping(sinfo)
|
||||||
|
// Cleanup
|
||||||
|
delete(s.searches, res.dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,281 +7,315 @@ package yggdrasil
|
|||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type sessionInfo struct {
|
type sessionInfo struct {
|
||||||
core *Core
|
core *Core
|
||||||
theirAddr address
|
theirAddr address
|
||||||
theirSubnet subnet
|
theirSubnet subnet
|
||||||
theirPermPub boxPubKey
|
theirPermPub boxPubKey
|
||||||
theirSesPub boxPubKey
|
theirSesPub boxPubKey
|
||||||
mySesPub boxPubKey
|
mySesPub boxPubKey
|
||||||
mySesPriv boxPrivKey
|
mySesPriv boxPrivKey
|
||||||
sharedSesKey boxSharedKey // derived from session keys
|
sharedSesKey boxSharedKey // derived from session keys
|
||||||
theirHandle handle
|
theirHandle handle
|
||||||
myHandle handle
|
myHandle handle
|
||||||
theirNonce boxNonce
|
theirNonce boxNonce
|
||||||
myNonce boxNonce
|
myNonce boxNonce
|
||||||
time time.Time // Time we last received a packet
|
time time.Time // Time we last received a packet
|
||||||
coords []byte // coords of destination
|
coords []byte // coords of destination
|
||||||
packet []byte // a buffered packet, sent immediately on ping/pong
|
packet []byte // a buffered packet, sent immediately on ping/pong
|
||||||
init bool // Reset if coords change
|
init bool // Reset if coords change
|
||||||
send chan []byte
|
send chan []byte
|
||||||
recv chan *wire_trafficPacket
|
recv chan *wire_trafficPacket
|
||||||
nonceMask uint64
|
nonceMask uint64
|
||||||
tstamp int64 // tstamp from their last session ping, replay attack mitigation
|
tstamp int64 // tstamp from their last session ping, replay attack mitigation
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME replay attacks (include nonce or some sequence number)
|
// FIXME replay attacks (include nonce or some sequence number)
|
||||||
type sessionPing struct {
|
type sessionPing struct {
|
||||||
sendPermPub boxPubKey // Sender's permanent key
|
sendPermPub boxPubKey // Sender's permanent key
|
||||||
handle handle // Random number to ID session
|
handle handle // Random number to ID session
|
||||||
sendSesPub boxPubKey // Session key to use
|
sendSesPub boxPubKey // Session key to use
|
||||||
coords []byte
|
coords []byte
|
||||||
tstamp int64 // unix time, but the only real requirement is that it increases
|
tstamp int64 // unix time, but the only real requirement is that it increases
|
||||||
isPong bool
|
isPong bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the session was updated, false otherwise
|
// Returns true if the session was updated, false otherwise
|
||||||
func (s *sessionInfo) update(p *sessionPing) bool {
|
func (s *sessionInfo) update(p *sessionPing) bool {
|
||||||
if !(p.tstamp > s.tstamp) { return false }
|
if !(p.tstamp > s.tstamp) {
|
||||||
if p.sendPermPub != s.theirPermPub { return false } // Shouldn't happen
|
return false
|
||||||
if p.sendSesPub != s.theirSesPub {
|
}
|
||||||
// FIXME need to protect against replay attacks
|
if p.sendPermPub != s.theirPermPub {
|
||||||
// Put a sequence number or a timestamp or something in the pings?
|
return false
|
||||||
// Or just return false, make the session time out?
|
} // Shouldn't happen
|
||||||
s.theirSesPub = p.sendSesPub
|
if p.sendSesPub != s.theirSesPub {
|
||||||
s.theirHandle = p.handle
|
// FIXME need to protect against replay attacks
|
||||||
s.sharedSesKey = *getSharedKey(&s.mySesPriv, &s.theirSesPub)
|
// Put a sequence number or a timestamp or something in the pings?
|
||||||
s.theirNonce = boxNonce{}
|
// Or just return false, make the session time out?
|
||||||
s.nonceMask = 0
|
s.theirSesPub = p.sendSesPub
|
||||||
}
|
s.theirHandle = p.handle
|
||||||
s.coords = append([]byte{}, p.coords...)
|
s.sharedSesKey = *getSharedKey(&s.mySesPriv, &s.theirSesPub)
|
||||||
s.time = time.Now()
|
s.theirNonce = boxNonce{}
|
||||||
s.tstamp = p.tstamp
|
s.nonceMask = 0
|
||||||
s.init = true
|
}
|
||||||
return true
|
s.coords = append([]byte{}, p.coords...)
|
||||||
|
s.time = time.Now()
|
||||||
|
s.tstamp = p.tstamp
|
||||||
|
s.init = true
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sessionInfo) timedout() bool {
|
func (s *sessionInfo) timedout() bool {
|
||||||
return time.Since(s.time) > time.Minute
|
return time.Since(s.time) > time.Minute
|
||||||
}
|
}
|
||||||
|
|
||||||
type sessions struct {
|
type sessions struct {
|
||||||
core *Core
|
core *Core
|
||||||
// Maps known permanent keys to their shared key, used by DHT a lot
|
// Maps known permanent keys to their shared key, used by DHT a lot
|
||||||
permShared map[boxPubKey]*boxSharedKey
|
permShared map[boxPubKey]*boxSharedKey
|
||||||
// Maps (secret) handle onto session info
|
// Maps (secret) handle onto session info
|
||||||
sinfos map[handle]*sessionInfo
|
sinfos map[handle]*sessionInfo
|
||||||
// Maps mySesPub onto handle
|
// Maps mySesPub onto handle
|
||||||
byMySes map[boxPubKey]*handle
|
byMySes map[boxPubKey]*handle
|
||||||
// Maps theirPermPub onto handle
|
// Maps theirPermPub onto handle
|
||||||
byTheirPerm map[boxPubKey]*handle
|
byTheirPerm map[boxPubKey]*handle
|
||||||
addrToPerm map[address]*boxPubKey
|
addrToPerm map[address]*boxPubKey
|
||||||
subnetToPerm map[subnet]*boxPubKey
|
subnetToPerm map[subnet]*boxPubKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sessions) init(core *Core) {
|
func (ss *sessions) init(core *Core) {
|
||||||
ss.core = core
|
ss.core = core
|
||||||
ss.permShared = make(map[boxPubKey]*boxSharedKey)
|
ss.permShared = make(map[boxPubKey]*boxSharedKey)
|
||||||
ss.sinfos = make(map[handle]*sessionInfo)
|
ss.sinfos = make(map[handle]*sessionInfo)
|
||||||
ss.byMySes = make(map[boxPubKey]*handle)
|
ss.byMySes = make(map[boxPubKey]*handle)
|
||||||
ss.byTheirPerm = make(map[boxPubKey]*handle)
|
ss.byTheirPerm = make(map[boxPubKey]*handle)
|
||||||
ss.addrToPerm = make(map[address]*boxPubKey)
|
ss.addrToPerm = make(map[address]*boxPubKey)
|
||||||
ss.subnetToPerm = make(map[subnet]*boxPubKey)
|
ss.subnetToPerm = make(map[subnet]*boxPubKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sessions) getSessionForHandle(handle *handle) (*sessionInfo, bool) {
|
func (ss *sessions) getSessionForHandle(handle *handle) (*sessionInfo, bool) {
|
||||||
sinfo, isIn := ss.sinfos[*handle]
|
sinfo, isIn := ss.sinfos[*handle]
|
||||||
if isIn && sinfo.timedout() {
|
if isIn && sinfo.timedout() {
|
||||||
// We have a session, but it has timed out
|
// We have a session, but it has timed out
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
return sinfo, isIn
|
return sinfo, isIn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sessions) getByMySes(key *boxPubKey) (*sessionInfo, bool) {
|
func (ss *sessions) getByMySes(key *boxPubKey) (*sessionInfo, bool) {
|
||||||
h, isIn := ss.byMySes[*key]
|
h, isIn := ss.byMySes[*key]
|
||||||
if !isIn { return nil, false }
|
if !isIn {
|
||||||
sinfo, isIn := ss.getSessionForHandle(h)
|
return nil, false
|
||||||
return sinfo, isIn
|
}
|
||||||
|
sinfo, isIn := ss.getSessionForHandle(h)
|
||||||
|
return sinfo, isIn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sessions) getByTheirPerm(key *boxPubKey) (*sessionInfo, bool) {
|
func (ss *sessions) getByTheirPerm(key *boxPubKey) (*sessionInfo, bool) {
|
||||||
h, isIn := ss.byTheirPerm[*key]
|
h, isIn := ss.byTheirPerm[*key]
|
||||||
if !isIn { return nil, false }
|
if !isIn {
|
||||||
sinfo, isIn := ss.getSessionForHandle(h)
|
return nil, false
|
||||||
return sinfo, isIn
|
}
|
||||||
|
sinfo, isIn := ss.getSessionForHandle(h)
|
||||||
|
return sinfo, isIn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sessions) getByTheirAddr(addr *address) (*sessionInfo, bool) {
|
func (ss *sessions) getByTheirAddr(addr *address) (*sessionInfo, bool) {
|
||||||
p, isIn := ss.addrToPerm[*addr]
|
p, isIn := ss.addrToPerm[*addr]
|
||||||
if !isIn { return nil, false }
|
if !isIn {
|
||||||
sinfo, isIn := ss.getByTheirPerm(p)
|
return nil, false
|
||||||
return sinfo, isIn
|
}
|
||||||
|
sinfo, isIn := ss.getByTheirPerm(p)
|
||||||
|
return sinfo, isIn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sessions) getByTheirSubnet(snet *subnet) (*sessionInfo, bool) {
|
func (ss *sessions) getByTheirSubnet(snet *subnet) (*sessionInfo, bool) {
|
||||||
p, isIn := ss.subnetToPerm[*snet]
|
p, isIn := ss.subnetToPerm[*snet]
|
||||||
if !isIn { return nil, false }
|
if !isIn {
|
||||||
sinfo, isIn := ss.getByTheirPerm(p)
|
return nil, false
|
||||||
return sinfo, isIn
|
}
|
||||||
|
sinfo, isIn := ss.getByTheirPerm(p)
|
||||||
|
return sinfo, isIn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sessions) createSession(theirPermKey *boxPubKey) *sessionInfo {
|
func (ss *sessions) createSession(theirPermKey *boxPubKey) *sessionInfo {
|
||||||
sinfo := sessionInfo{}
|
sinfo := sessionInfo{}
|
||||||
sinfo.core = ss.core
|
sinfo.core = ss.core
|
||||||
sinfo.theirPermPub = *theirPermKey
|
sinfo.theirPermPub = *theirPermKey
|
||||||
pub, priv := newBoxKeys()
|
pub, priv := newBoxKeys()
|
||||||
sinfo.mySesPub = *pub
|
sinfo.mySesPub = *pub
|
||||||
sinfo.mySesPriv = *priv
|
sinfo.mySesPriv = *priv
|
||||||
sinfo.myNonce = *newBoxNonce() // TODO make sure nonceIsOK tolerates this
|
sinfo.myNonce = *newBoxNonce() // TODO make sure nonceIsOK tolerates this
|
||||||
higher := false
|
higher := false
|
||||||
for idx := range ss.core.boxPub {
|
for idx := range ss.core.boxPub {
|
||||||
if ss.core.boxPub[idx] > sinfo.theirPermPub[idx] {
|
if ss.core.boxPub[idx] > sinfo.theirPermPub[idx] {
|
||||||
higher = true
|
higher = true
|
||||||
break
|
break
|
||||||
} else if ss.core.boxPub[idx] < sinfo.theirPermPub[idx] {
|
} else if ss.core.boxPub[idx] < sinfo.theirPermPub[idx] {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if higher {
|
if higher {
|
||||||
// higher => odd nonce
|
// higher => odd nonce
|
||||||
sinfo.myNonce[len(sinfo.myNonce)-1] |= 0x01
|
sinfo.myNonce[len(sinfo.myNonce)-1] |= 0x01
|
||||||
} else {
|
} else {
|
||||||
// lower => even nonce
|
// lower => even nonce
|
||||||
sinfo.myNonce[len(sinfo.myNonce)-1] &= 0xfe
|
sinfo.myNonce[len(sinfo.myNonce)-1] &= 0xfe
|
||||||
}
|
}
|
||||||
sinfo.myHandle = *newHandle()
|
sinfo.myHandle = *newHandle()
|
||||||
sinfo.theirAddr = *address_addrForNodeID(getNodeID(&sinfo.theirPermPub))
|
sinfo.theirAddr = *address_addrForNodeID(getNodeID(&sinfo.theirPermPub))
|
||||||
sinfo.theirSubnet = *address_subnetForNodeID(getNodeID(&sinfo.theirPermPub))
|
sinfo.theirSubnet = *address_subnetForNodeID(getNodeID(&sinfo.theirPermPub))
|
||||||
sinfo.send = make(chan []byte, 1)
|
sinfo.send = make(chan []byte, 1)
|
||||||
sinfo.recv = make(chan *wire_trafficPacket, 1)
|
sinfo.recv = make(chan *wire_trafficPacket, 1)
|
||||||
go sinfo.doWorker()
|
go sinfo.doWorker()
|
||||||
sinfo.time = time.Now()
|
sinfo.time = time.Now()
|
||||||
// Do some cleanup
|
// Do some cleanup
|
||||||
// Time thresholds almost certainly could use some adjusting
|
// Time thresholds almost certainly could use some adjusting
|
||||||
for _, s := range ss.sinfos {
|
for _, s := range ss.sinfos {
|
||||||
if s.timedout() { s.close() }
|
if s.timedout() {
|
||||||
}
|
s.close()
|
||||||
ss.sinfos[sinfo.myHandle] = &sinfo
|
}
|
||||||
ss.byMySes[sinfo.mySesPub] = &sinfo.myHandle
|
}
|
||||||
ss.byTheirPerm[sinfo.theirPermPub] = &sinfo.myHandle
|
ss.sinfos[sinfo.myHandle] = &sinfo
|
||||||
ss.addrToPerm[sinfo.theirAddr] = &sinfo.theirPermPub
|
ss.byMySes[sinfo.mySesPub] = &sinfo.myHandle
|
||||||
ss.subnetToPerm[sinfo.theirSubnet] = &sinfo.theirPermPub
|
ss.byTheirPerm[sinfo.theirPermPub] = &sinfo.myHandle
|
||||||
return &sinfo
|
ss.addrToPerm[sinfo.theirAddr] = &sinfo.theirPermPub
|
||||||
|
ss.subnetToPerm[sinfo.theirSubnet] = &sinfo.theirPermPub
|
||||||
|
return &sinfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sinfo *sessionInfo) close() {
|
func (sinfo *sessionInfo) close() {
|
||||||
delete(sinfo.core.sessions.sinfos, sinfo.myHandle)
|
delete(sinfo.core.sessions.sinfos, sinfo.myHandle)
|
||||||
delete(sinfo.core.sessions.byMySes, sinfo.mySesPub)
|
delete(sinfo.core.sessions.byMySes, sinfo.mySesPub)
|
||||||
delete(sinfo.core.sessions.byTheirPerm, sinfo.theirPermPub)
|
delete(sinfo.core.sessions.byTheirPerm, sinfo.theirPermPub)
|
||||||
delete(sinfo.core.sessions.addrToPerm, sinfo.theirAddr)
|
delete(sinfo.core.sessions.addrToPerm, sinfo.theirAddr)
|
||||||
delete(sinfo.core.sessions.subnetToPerm, sinfo.theirSubnet)
|
delete(sinfo.core.sessions.subnetToPerm, sinfo.theirSubnet)
|
||||||
close(sinfo.send)
|
close(sinfo.send)
|
||||||
close(sinfo.recv)
|
close(sinfo.recv)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sessions) getPing(sinfo *sessionInfo) sessionPing {
|
func (ss *sessions) getPing(sinfo *sessionInfo) sessionPing {
|
||||||
loc := ss.core.switchTable.getLocator()
|
loc := ss.core.switchTable.getLocator()
|
||||||
coords := loc.getCoords()
|
coords := loc.getCoords()
|
||||||
ref := sessionPing{
|
ref := sessionPing{
|
||||||
sendPermPub: ss.core.boxPub,
|
sendPermPub: ss.core.boxPub,
|
||||||
handle: sinfo.myHandle,
|
handle: sinfo.myHandle,
|
||||||
sendSesPub: sinfo.mySesPub,
|
sendSesPub: sinfo.mySesPub,
|
||||||
tstamp: time.Now().Unix(),
|
tstamp: time.Now().Unix(),
|
||||||
coords: coords,
|
coords: coords,
|
||||||
}
|
}
|
||||||
sinfo.myNonce.update()
|
sinfo.myNonce.update()
|
||||||
return ref
|
return ref
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sessions) getSharedKey(myPriv *boxPrivKey,
|
func (ss *sessions) getSharedKey(myPriv *boxPrivKey,
|
||||||
theirPub *boxPubKey) *boxSharedKey {
|
theirPub *boxPubKey) *boxSharedKey {
|
||||||
if skey, isIn := ss.permShared[*theirPub] ; isIn { return skey }
|
if skey, isIn := ss.permShared[*theirPub]; isIn {
|
||||||
// First do some cleanup
|
return skey
|
||||||
const maxKeys = dht_bucket_number*dht_bucket_size
|
}
|
||||||
for key := range ss.permShared {
|
// First do some cleanup
|
||||||
// Remove a random key until the store is small enough
|
const maxKeys = dht_bucket_number * dht_bucket_size
|
||||||
if len(ss.permShared) < maxKeys { break }
|
for key := range ss.permShared {
|
||||||
delete(ss.permShared, key)
|
// Remove a random key until the store is small enough
|
||||||
}
|
if len(ss.permShared) < maxKeys {
|
||||||
ss.permShared[*theirPub] = getSharedKey(myPriv, theirPub)
|
break
|
||||||
return ss.permShared[*theirPub]
|
}
|
||||||
|
delete(ss.permShared, key)
|
||||||
|
}
|
||||||
|
ss.permShared[*theirPub] = getSharedKey(myPriv, theirPub)
|
||||||
|
return ss.permShared[*theirPub]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sessions) ping(sinfo *sessionInfo) {
|
func (ss *sessions) ping(sinfo *sessionInfo) {
|
||||||
ss.sendPingPong(sinfo, false)
|
ss.sendPingPong(sinfo, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sessions) sendPingPong(sinfo *sessionInfo, isPong bool) {
|
func (ss *sessions) sendPingPong(sinfo *sessionInfo, isPong bool) {
|
||||||
ping := ss.getPing(sinfo)
|
ping := ss.getPing(sinfo)
|
||||||
ping.isPong = isPong
|
ping.isPong = isPong
|
||||||
bs := ping.encode()
|
bs := ping.encode()
|
||||||
shared := ss.getSharedKey(&ss.core.boxPriv, &sinfo.theirPermPub)
|
shared := ss.getSharedKey(&ss.core.boxPriv, &sinfo.theirPermPub)
|
||||||
payload, nonce := boxSeal(shared, bs, nil)
|
payload, nonce := boxSeal(shared, bs, nil)
|
||||||
p := wire_protoTrafficPacket{
|
p := wire_protoTrafficPacket{
|
||||||
ttl: ^uint64(0),
|
ttl: ^uint64(0),
|
||||||
coords: sinfo.coords,
|
coords: sinfo.coords,
|
||||||
toKey: sinfo.theirPermPub,
|
toKey: sinfo.theirPermPub,
|
||||||
fromKey: ss.core.boxPub,
|
fromKey: ss.core.boxPub,
|
||||||
nonce: *nonce,
|
nonce: *nonce,
|
||||||
payload: payload,
|
payload: payload,
|
||||||
}
|
}
|
||||||
packet := p.encode()
|
packet := p.encode()
|
||||||
ss.core.router.out(packet)
|
ss.core.router.out(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sessions) handlePing(ping *sessionPing) {
|
func (ss *sessions) handlePing(ping *sessionPing) {
|
||||||
// Get the corresponding session (or create a new session)
|
// Get the corresponding session (or create a new session)
|
||||||
sinfo, isIn := ss.getByTheirPerm(&ping.sendPermPub)
|
sinfo, isIn := ss.getByTheirPerm(&ping.sendPermPub)
|
||||||
if !isIn || sinfo.timedout() {
|
if !isIn || sinfo.timedout() {
|
||||||
if isIn { sinfo.close() }
|
if isIn {
|
||||||
ss.createSession(&ping.sendPermPub)
|
sinfo.close()
|
||||||
sinfo, isIn = ss.getByTheirPerm(&ping.sendPermPub)
|
}
|
||||||
if !isIn { panic("This should not happen") }
|
ss.createSession(&ping.sendPermPub)
|
||||||
}
|
sinfo, isIn = ss.getByTheirPerm(&ping.sendPermPub)
|
||||||
// Update the session
|
if !isIn {
|
||||||
if !sinfo.update(ping) { /*panic("Should not happen in testing")*/ ; return }
|
panic("This should not happen")
|
||||||
if !ping.isPong{ ss.sendPingPong(sinfo, true) }
|
}
|
||||||
if sinfo.packet != nil {
|
}
|
||||||
// send
|
// Update the session
|
||||||
var bs []byte
|
if !sinfo.update(ping) { /*panic("Should not happen in testing")*/
|
||||||
bs, sinfo.packet = sinfo.packet, nil
|
return
|
||||||
go func() { sinfo.send<-bs }()
|
}
|
||||||
}
|
if !ping.isPong {
|
||||||
|
ss.sendPingPong(sinfo, true)
|
||||||
|
}
|
||||||
|
if sinfo.packet != nil {
|
||||||
|
// send
|
||||||
|
var bs []byte
|
||||||
|
bs, sinfo.packet = sinfo.packet, nil
|
||||||
|
go func() { sinfo.send <- bs }()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *boxNonce) minus(m *boxNonce) int64 {
|
func (n *boxNonce) minus(m *boxNonce) int64 {
|
||||||
diff := int64(0)
|
diff := int64(0)
|
||||||
for idx := range n {
|
for idx := range n {
|
||||||
diff *= 256
|
diff *= 256
|
||||||
diff += int64(n[idx]) - int64(m[idx])
|
diff += int64(n[idx]) - int64(m[idx])
|
||||||
if diff > 64 { diff = 64 }
|
if diff > 64 {
|
||||||
if diff < -64 { diff = -64 }
|
diff = 64
|
||||||
}
|
}
|
||||||
return diff
|
if diff < -64 {
|
||||||
|
diff = -64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return diff
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sinfo *sessionInfo) nonceIsOK(theirNonce *boxNonce) bool {
|
func (sinfo *sessionInfo) nonceIsOK(theirNonce *boxNonce) bool {
|
||||||
// The bitmask is to allow for some non-duplicate out-of-order packets
|
// The bitmask is to allow for some non-duplicate out-of-order packets
|
||||||
diff := theirNonce.minus(&sinfo.theirNonce)
|
diff := theirNonce.minus(&sinfo.theirNonce)
|
||||||
if diff > 0 { return true }
|
if diff > 0 {
|
||||||
return ^sinfo.nonceMask & (0x01 << uint64(-diff)) != 0
|
return true
|
||||||
|
}
|
||||||
|
return ^sinfo.nonceMask&(0x01<<uint64(-diff)) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sinfo *sessionInfo) updateNonce(theirNonce *boxNonce) {
|
func (sinfo *sessionInfo) updateNonce(theirNonce *boxNonce) {
|
||||||
// Shift nonce mask if needed
|
// Shift nonce mask if needed
|
||||||
// Set bit
|
// Set bit
|
||||||
diff := theirNonce.minus(&sinfo.theirNonce)
|
diff := theirNonce.minus(&sinfo.theirNonce)
|
||||||
if diff > 0 {
|
if diff > 0 {
|
||||||
sinfo.nonceMask <<= uint64(diff)
|
sinfo.nonceMask <<= uint64(diff)
|
||||||
sinfo.nonceMask &= 0x01
|
sinfo.nonceMask &= 0x01
|
||||||
} else {
|
} else {
|
||||||
sinfo.nonceMask &= 0x01 << uint64(-diff)
|
sinfo.nonceMask &= 0x01 << uint64(-diff)
|
||||||
}
|
}
|
||||||
sinfo.theirNonce = *theirNonce
|
sinfo.theirNonce = *theirNonce
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sessions) resetInits() {
|
func (ss *sessions) resetInits() {
|
||||||
for _, sinfo := range ss.sinfos { sinfo.init = false }
|
for _, sinfo := range ss.sinfos {
|
||||||
|
sinfo.init = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -291,37 +325,53 @@ func (ss *sessions) resetInits() {
|
|||||||
// It's also responsible for keeping nonces consistent
|
// It's also responsible for keeping nonces consistent
|
||||||
|
|
||||||
func (sinfo *sessionInfo) doWorker() {
|
func (sinfo *sessionInfo) doWorker() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case p, ok := <-sinfo.recv: if ok { sinfo.doRecv(p) } else { return }
|
case p, ok := <-sinfo.recv:
|
||||||
case bs, ok := <-sinfo.send: if ok { sinfo.doSend(bs) } else { return }
|
if ok {
|
||||||
}
|
sinfo.doRecv(p)
|
||||||
}
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case bs, ok := <-sinfo.send:
|
||||||
|
if ok {
|
||||||
|
sinfo.doSend(bs)
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sinfo *sessionInfo) doSend(bs []byte) {
|
func (sinfo *sessionInfo) doSend(bs []byte) {
|
||||||
defer util_putBytes(bs)
|
defer util_putBytes(bs)
|
||||||
if !sinfo.init { return } // To prevent using empty session keys
|
if !sinfo.init {
|
||||||
payload, nonce := boxSeal(&sinfo.sharedSesKey, bs, &sinfo.myNonce)
|
return
|
||||||
defer util_putBytes(payload)
|
} // To prevent using empty session keys
|
||||||
p := wire_trafficPacket{
|
payload, nonce := boxSeal(&sinfo.sharedSesKey, bs, &sinfo.myNonce)
|
||||||
ttl: ^uint64(0),
|
defer util_putBytes(payload)
|
||||||
coords: sinfo.coords,
|
p := wire_trafficPacket{
|
||||||
handle: sinfo.theirHandle,
|
ttl: ^uint64(0),
|
||||||
nonce: *nonce,
|
coords: sinfo.coords,
|
||||||
payload: payload,
|
handle: sinfo.theirHandle,
|
||||||
}
|
nonce: *nonce,
|
||||||
packet := p.encode()
|
payload: payload,
|
||||||
sinfo.core.router.out(packet)
|
}
|
||||||
|
packet := p.encode()
|
||||||
|
sinfo.core.router.out(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sinfo *sessionInfo) doRecv(p *wire_trafficPacket) {
|
func (sinfo *sessionInfo) doRecv(p *wire_trafficPacket) {
|
||||||
defer util_putBytes(p.payload)
|
defer util_putBytes(p.payload)
|
||||||
if !sinfo.nonceIsOK(&p.nonce) { return }
|
if !sinfo.nonceIsOK(&p.nonce) {
|
||||||
bs, isOK := boxOpen(&sinfo.sharedSesKey, p.payload, &p.nonce)
|
return
|
||||||
if !isOK { util_putBytes(bs) ; return }
|
}
|
||||||
sinfo.updateNonce(&p.nonce)
|
bs, isOK := boxOpen(&sinfo.sharedSesKey, p.payload, &p.nonce)
|
||||||
sinfo.time = time.Now()
|
if !isOK {
|
||||||
sinfo.core.router.recvPacket(bs, &sinfo.theirAddr)
|
util_putBytes(bs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sinfo.updateNonce(&p.nonce)
|
||||||
|
sinfo.time = time.Now()
|
||||||
|
sinfo.core.router.recvPacket(bs, &sinfo.theirAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,52 +7,63 @@ import "sync"
|
|||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type sigManager struct {
|
type sigManager struct {
|
||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
checked map[sigBytes]knownSig
|
checked map[sigBytes]knownSig
|
||||||
lastCleaned time.Time
|
lastCleaned time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type knownSig struct {
|
type knownSig struct {
|
||||||
bs []byte
|
bs []byte
|
||||||
time time.Time
|
time time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *sigManager) init() {
|
func (m *sigManager) init() {
|
||||||
m.checked = make(map[sigBytes]knownSig)
|
m.checked = make(map[sigBytes]knownSig)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *sigManager) check(key *sigPubKey, sig *sigBytes, bs []byte) bool {
|
func (m *sigManager) check(key *sigPubKey, sig *sigBytes, bs []byte) bool {
|
||||||
if m.isChecked(sig, bs) { return true }
|
if m.isChecked(sig, bs) {
|
||||||
verified := verify(key, bs, sig)
|
return true
|
||||||
if verified { m.putChecked(sig, bs) }
|
}
|
||||||
return verified
|
verified := verify(key, bs, sig)
|
||||||
|
if verified {
|
||||||
|
m.putChecked(sig, bs)
|
||||||
|
}
|
||||||
|
return verified
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *sigManager) isChecked(sig *sigBytes, bs []byte) bool {
|
func (m *sigManager) isChecked(sig *sigBytes, bs []byte) bool {
|
||||||
m.mutex.RLock()
|
m.mutex.RLock()
|
||||||
defer m.mutex.RUnlock()
|
defer m.mutex.RUnlock()
|
||||||
k, isIn := m.checked[*sig]
|
k, isIn := m.checked[*sig]
|
||||||
if !isIn { return false }
|
if !isIn {
|
||||||
if len(bs) != len(k.bs) { return false }
|
return false
|
||||||
for idx := 0 ; idx < len(bs) ; idx++ {
|
}
|
||||||
if bs[idx] != k.bs[idx] { return false }
|
if len(bs) != len(k.bs) {
|
||||||
}
|
return false
|
||||||
k.time = time.Now()
|
}
|
||||||
return true
|
for idx := 0; idx < len(bs); idx++ {
|
||||||
|
if bs[idx] != k.bs[idx] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
k.time = time.Now()
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *sigManager) putChecked(newsig *sigBytes, bs []byte) {
|
func (m *sigManager) putChecked(newsig *sigBytes, bs []byte) {
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
if time.Since(m.lastCleaned) > 60*time.Second {
|
if time.Since(m.lastCleaned) > 60*time.Second {
|
||||||
// Since we have the write lock anyway, do some cleanup
|
// Since we have the write lock anyway, do some cleanup
|
||||||
for s, k := range m.checked {
|
for s, k := range m.checked {
|
||||||
if time.Since(k.time) > 60*time.Second { delete(m.checked, s) }
|
if time.Since(k.time) > 60*time.Second {
|
||||||
}
|
delete(m.checked, s)
|
||||||
m.lastCleaned = now
|
}
|
||||||
}
|
}
|
||||||
k := knownSig{bs: bs, time: now}
|
m.lastCleaned = now
|
||||||
m.checked[*newsig] = k
|
}
|
||||||
|
k := knownSig{bs: bs, time: now}
|
||||||
|
m.checked[*newsig] = k
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,366 +23,414 @@ const switch_timeout = time.Minute
|
|||||||
// 1 signature per coord, from the *sender* to that coord
|
// 1 signature per coord, from the *sender* to that coord
|
||||||
// E.g. A->B->C has sigA(A->B) and sigB(A->B->C)
|
// E.g. A->B->C has sigA(A->B) and sigB(A->B->C)
|
||||||
type switchLocator struct {
|
type switchLocator struct {
|
||||||
root sigPubKey
|
root sigPubKey
|
||||||
tstamp int64
|
tstamp int64
|
||||||
coords []switchPort
|
coords []switchPort
|
||||||
}
|
}
|
||||||
|
|
||||||
func firstIsBetter(first, second *sigPubKey) bool {
|
func firstIsBetter(first, second *sigPubKey) bool {
|
||||||
// Higher TreeID is better
|
// Higher TreeID is better
|
||||||
ftid := getTreeID(first)
|
ftid := getTreeID(first)
|
||||||
stid := getTreeID(second)
|
stid := getTreeID(second)
|
||||||
for idx := 0 ; idx < len(ftid) ; idx++ {
|
for idx := 0; idx < len(ftid); idx++ {
|
||||||
if ftid[idx] == stid[idx] { continue }
|
if ftid[idx] == stid[idx] {
|
||||||
return ftid[idx] > stid[idx]
|
continue
|
||||||
}
|
}
|
||||||
// Edge case, when comparing identical IDs
|
return ftid[idx] > stid[idx]
|
||||||
return false
|
}
|
||||||
|
// Edge case, when comparing identical IDs
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *switchLocator) clone() switchLocator {
|
func (l *switchLocator) clone() switchLocator {
|
||||||
// Used to create a deep copy for use in messages
|
// Used to create a deep copy for use in messages
|
||||||
// Copy required because we need to mutate coords before sending
|
// Copy required because we need to mutate coords before sending
|
||||||
// (By appending the port from us to the destination)
|
// (By appending the port from us to the destination)
|
||||||
loc := *l
|
loc := *l
|
||||||
loc.coords = make([]switchPort, len(l.coords), len(l.coords)+1)
|
loc.coords = make([]switchPort, len(l.coords), len(l.coords)+1)
|
||||||
copy(loc.coords, l.coords)
|
copy(loc.coords, l.coords)
|
||||||
return loc
|
return loc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *switchLocator) dist(dest []byte) int {
|
func (l *switchLocator) dist(dest []byte) int {
|
||||||
// Returns distance (on the tree) from these coords
|
// Returns distance (on the tree) from these coords
|
||||||
offset := 0
|
offset := 0
|
||||||
fdc := 0
|
fdc := 0
|
||||||
for {
|
for {
|
||||||
if fdc >= len(l.coords) { break }
|
if fdc >= len(l.coords) {
|
||||||
coord, length := wire_decode_uint64(dest[offset:])
|
break
|
||||||
if length == 0 { break }
|
}
|
||||||
if l.coords[fdc] != switchPort(coord) { break }
|
coord, length := wire_decode_uint64(dest[offset:])
|
||||||
fdc++
|
if length == 0 {
|
||||||
offset += length
|
break
|
||||||
}
|
}
|
||||||
dist := len(l.coords[fdc:])
|
if l.coords[fdc] != switchPort(coord) {
|
||||||
for {
|
break
|
||||||
_, length := wire_decode_uint64(dest[offset:])
|
}
|
||||||
if length == 0 { break }
|
fdc++
|
||||||
dist++
|
offset += length
|
||||||
offset += length
|
}
|
||||||
}
|
dist := len(l.coords[fdc:])
|
||||||
return dist
|
for {
|
||||||
|
_, length := wire_decode_uint64(dest[offset:])
|
||||||
|
if length == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
dist++
|
||||||
|
offset += length
|
||||||
|
}
|
||||||
|
return dist
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *switchLocator) getCoords() []byte {
|
func (l *switchLocator) getCoords() []byte {
|
||||||
bs := make([]byte, 0, len(l.coords))
|
bs := make([]byte, 0, len(l.coords))
|
||||||
for _, coord := range l.coords {
|
for _, coord := range l.coords {
|
||||||
c := wire_encode_uint64(uint64(coord))
|
c := wire_encode_uint64(uint64(coord))
|
||||||
bs = append(bs, c...)
|
bs = append(bs, c...)
|
||||||
}
|
}
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *switchLocator) isAncestorOf(y *switchLocator) bool {
|
func (x *switchLocator) isAncestorOf(y *switchLocator) bool {
|
||||||
if x.root != y.root { return false }
|
if x.root != y.root {
|
||||||
if len(x.coords) > len(y.coords) { return false }
|
return false
|
||||||
for idx := range x.coords {
|
}
|
||||||
if x.coords[idx] != y.coords[idx] { return false }
|
if len(x.coords) > len(y.coords) {
|
||||||
}
|
return false
|
||||||
return true
|
}
|
||||||
|
for idx := range x.coords {
|
||||||
|
if x.coords[idx] != y.coords[idx] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
type peerInfo struct {
|
type peerInfo struct {
|
||||||
key sigPubKey // ID of this peer
|
key sigPubKey // ID of this peer
|
||||||
locator switchLocator // Should be able to respond with signatures upon request
|
locator switchLocator // Should be able to respond with signatures upon request
|
||||||
degree uint64 // Self-reported degree
|
degree uint64 // Self-reported degree
|
||||||
coords []switchPort // Coords of this peer (taken from coords of the sent locator)
|
coords []switchPort // Coords of this peer (taken from coords of the sent locator)
|
||||||
time time.Time // Time this node was last seen
|
time time.Time // Time this node was last seen
|
||||||
firstSeen time.Time
|
firstSeen time.Time
|
||||||
port switchPort // Interface number of this peer
|
port switchPort // Interface number of this peer
|
||||||
seq uint64 // Seq number we last saw this peer advertise
|
seq uint64 // Seq number we last saw this peer advertise
|
||||||
}
|
}
|
||||||
|
|
||||||
type switchMessage struct {
|
type switchMessage struct {
|
||||||
from sigPubKey // key of the sender
|
from sigPubKey // key of the sender
|
||||||
locator switchLocator // Locator advertised for the receiver, not the sender's loc!
|
locator switchLocator // Locator advertised for the receiver, not the sender's loc!
|
||||||
seq uint64
|
seq uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type switchPort uint64
|
type switchPort uint64
|
||||||
type tableElem struct {
|
type tableElem struct {
|
||||||
locator switchLocator
|
locator switchLocator
|
||||||
firstSeen time.Time
|
firstSeen time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type lookupTable struct {
|
type lookupTable struct {
|
||||||
self switchLocator
|
self switchLocator
|
||||||
elems map[switchPort]tableElem
|
elems map[switchPort]tableElem
|
||||||
}
|
}
|
||||||
|
|
||||||
type switchData struct {
|
type switchData struct {
|
||||||
// All data that's mutable and used by exported Table methods
|
// All data that's mutable and used by exported Table methods
|
||||||
// To be read/written with atomic.Value Store/Load calls
|
// To be read/written with atomic.Value Store/Load calls
|
||||||
locator switchLocator
|
locator switchLocator
|
||||||
seq uint64 // Sequence number, reported to peers, so they know about changes
|
seq uint64 // Sequence number, reported to peers, so they know about changes
|
||||||
peers map[switchPort]peerInfo
|
peers map[switchPort]peerInfo
|
||||||
sigs []sigInfo
|
sigs []sigInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type switchTable struct {
|
type switchTable struct {
|
||||||
core *Core
|
core *Core
|
||||||
key sigPubKey // Our own key
|
key sigPubKey // Our own key
|
||||||
time time.Time // Time when locator.tstamp was last updated
|
time time.Time // Time when locator.tstamp was last updated
|
||||||
parent switchPort // Port of whatever peer is our parent, or self if we're root
|
parent switchPort // Port of whatever peer is our parent, or self if we're root
|
||||||
drop map[sigPubKey]int64 // Tstamp associated with a dropped root
|
drop map[sigPubKey]int64 // Tstamp associated with a dropped root
|
||||||
mutex sync.RWMutex // Lock for reads/writes of switchData
|
mutex sync.RWMutex // Lock for reads/writes of switchData
|
||||||
data switchData
|
data switchData
|
||||||
updater atomic.Value //*sync.Once
|
updater atomic.Value //*sync.Once
|
||||||
table atomic.Value //lookupTable
|
table atomic.Value //lookupTable
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *switchTable) init(core *Core, key sigPubKey) {
|
func (t *switchTable) init(core *Core, key sigPubKey) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
t.core = core
|
t.core = core
|
||||||
t.key = key
|
t.key = key
|
||||||
locator := switchLocator{root: key, tstamp: now.Unix()}
|
locator := switchLocator{root: key, tstamp: now.Unix()}
|
||||||
peers := make(map[switchPort]peerInfo)
|
peers := make(map[switchPort]peerInfo)
|
||||||
t.data = switchData{locator: locator, peers: peers}
|
t.data = switchData{locator: locator, peers: peers}
|
||||||
t.updater.Store(&sync.Once{})
|
t.updater.Store(&sync.Once{})
|
||||||
t.table.Store(lookupTable{elems: make(map[switchPort]tableElem)})
|
t.table.Store(lookupTable{elems: make(map[switchPort]tableElem)})
|
||||||
t.drop = make(map[sigPubKey]int64)
|
t.drop = make(map[sigPubKey]int64)
|
||||||
doTicker := func () {
|
doTicker := func() {
|
||||||
ticker := time.NewTicker(time.Second)
|
ticker := time.NewTicker(time.Second)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
for {
|
for {
|
||||||
<-ticker.C
|
<-ticker.C
|
||||||
t.Tick()
|
t.Tick()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
go doTicker()
|
go doTicker()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *switchTable) getLocator() switchLocator {
|
func (t *switchTable) getLocator() switchLocator {
|
||||||
t.mutex.RLock()
|
t.mutex.RLock()
|
||||||
defer t.mutex.RUnlock()
|
defer t.mutex.RUnlock()
|
||||||
return t.data.locator.clone()
|
return t.data.locator.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *switchTable) Tick() {
|
func (t *switchTable) Tick() {
|
||||||
// Periodic maintenance work to keep things internally consistent
|
// Periodic maintenance work to keep things internally consistent
|
||||||
t.mutex.Lock() // Write lock
|
t.mutex.Lock() // Write lock
|
||||||
defer t.mutex.Unlock() // Release lock when we're done
|
defer t.mutex.Unlock() // Release lock when we're done
|
||||||
t.cleanRoot()
|
t.cleanRoot()
|
||||||
t.cleanPeers()
|
t.cleanPeers()
|
||||||
t.cleanDropped()
|
t.cleanDropped()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *switchTable) cleanRoot() {
|
func (t *switchTable) cleanRoot() {
|
||||||
// TODO rethink how this is done?...
|
// TODO rethink how this is done?...
|
||||||
// Get rid of the root if it looks like its timed out
|
// Get rid of the root if it looks like its timed out
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
doUpdate := false
|
doUpdate := false
|
||||||
//fmt.Println("DEBUG clean root:", now.Sub(t.time))
|
//fmt.Println("DEBUG clean root:", now.Sub(t.time))
|
||||||
if now.Sub(t.time) > switch_timeout {
|
if now.Sub(t.time) > switch_timeout {
|
||||||
//fmt.Println("root timed out", t.data.locator)
|
//fmt.Println("root timed out", t.data.locator)
|
||||||
dropped := t.data.peers[t.parent]
|
dropped := t.data.peers[t.parent]
|
||||||
dropped.time = t.time
|
dropped.time = t.time
|
||||||
t.drop[t.data.locator.root] = t.data.locator.tstamp
|
t.drop[t.data.locator.root] = t.data.locator.tstamp
|
||||||
doUpdate = true
|
doUpdate = true
|
||||||
//t.core.log.Println("DEBUG: switch root timeout", len(t.drop))
|
//t.core.log.Println("DEBUG: switch root timeout", len(t.drop))
|
||||||
}
|
}
|
||||||
// Or, if we're better than our root, root ourself
|
// Or, if we're better than our root, root ourself
|
||||||
if firstIsBetter(&t.key, &t.data.locator.root) {
|
if firstIsBetter(&t.key, &t.data.locator.root) {
|
||||||
//fmt.Println("root is worse than us", t.data.locator.Root)
|
//fmt.Println("root is worse than us", t.data.locator.Root)
|
||||||
doUpdate = true
|
doUpdate = true
|
||||||
//t.core.log.Println("DEBUG: switch root replace with self", t.data.locator.Root)
|
//t.core.log.Println("DEBUG: switch root replace with self", t.data.locator.Root)
|
||||||
}
|
}
|
||||||
// Or, if we are the root, possibly update our timestamp
|
// Or, if we are the root, possibly update our timestamp
|
||||||
if t.data.locator.root == t.key &&
|
if t.data.locator.root == t.key &&
|
||||||
now.Sub(t.time) > switch_timeout/2 {
|
now.Sub(t.time) > switch_timeout/2 {
|
||||||
//fmt.Println("root is self and old, updating", t.data.locator.Root)
|
//fmt.Println("root is self and old, updating", t.data.locator.Root)
|
||||||
doUpdate = true
|
doUpdate = true
|
||||||
}
|
}
|
||||||
if doUpdate {
|
if doUpdate {
|
||||||
t.parent = switchPort(0)
|
t.parent = switchPort(0)
|
||||||
t.time = now
|
t.time = now
|
||||||
if t.data.locator.root != t.key {
|
if t.data.locator.root != t.key {
|
||||||
t.data.seq++
|
t.data.seq++
|
||||||
t.updater.Store(&sync.Once{})
|
t.updater.Store(&sync.Once{})
|
||||||
select {
|
select {
|
||||||
case t.core.router.reset<-struct{}{}:
|
case t.core.router.reset <- struct{}{}:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.data.locator = switchLocator{root: t.key, tstamp: now.Unix()}
|
t.data.locator = switchLocator{root: t.key, tstamp: now.Unix()}
|
||||||
t.data.sigs = nil
|
t.data.sigs = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *switchTable) cleanPeers() {
|
func (t *switchTable) cleanPeers() {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
changed := false
|
changed := false
|
||||||
for idx, info := range t.data.peers {
|
for idx, info := range t.data.peers {
|
||||||
if info.port != switchPort(0) && now.Sub(info.time) > 6*time.Second /*switch_timeout*/ {
|
if info.port != switchPort(0) && now.Sub(info.time) > 6*time.Second /*switch_timeout*/ {
|
||||||
//fmt.Println("peer timed out", t.key, info.locator)
|
//fmt.Println("peer timed out", t.key, info.locator)
|
||||||
delete(t.data.peers, idx)
|
delete(t.data.peers, idx)
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if changed { t.updater.Store(&sync.Once{}) }
|
if changed {
|
||||||
|
t.updater.Store(&sync.Once{})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *switchTable) cleanDropped() {
|
func (t *switchTable) cleanDropped() {
|
||||||
// TODO only call this after root changes, not periodically
|
// TODO only call this after root changes, not periodically
|
||||||
for root, _ := range t.drop {
|
for root := range t.drop {
|
||||||
if !firstIsBetter(&root, &t.data.locator.root) { delete(t.drop, root) }
|
if !firstIsBetter(&root, &t.data.locator.root) {
|
||||||
}
|
delete(t.drop, root)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *switchTable) createMessage(port switchPort) (*switchMessage, []sigInfo) {
|
func (t *switchTable) createMessage(port switchPort) (*switchMessage, []sigInfo) {
|
||||||
t.mutex.RLock()
|
t.mutex.RLock()
|
||||||
defer t.mutex.RUnlock()
|
defer t.mutex.RUnlock()
|
||||||
msg := switchMessage{from: t.key, locator: t.data.locator.clone()}
|
msg := switchMessage{from: t.key, locator: t.data.locator.clone()}
|
||||||
msg.locator.coords = append(msg.locator.coords, port)
|
msg.locator.coords = append(msg.locator.coords, port)
|
||||||
msg.seq = t.data.seq
|
msg.seq = t.data.seq
|
||||||
return &msg, t.data.sigs
|
return &msg, t.data.sigs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *switchTable) handleMessage(msg *switchMessage, fromPort switchPort, sigs []sigInfo) {
|
func (t *switchTable) handleMessage(msg *switchMessage, fromPort switchPort, sigs []sigInfo) {
|
||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
defer t.mutex.Unlock()
|
defer t.mutex.Unlock()
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
if len(msg.locator.coords) == 0 { return } // Should always have >=1 links
|
if len(msg.locator.coords) == 0 {
|
||||||
oldSender, isIn := t.data.peers[fromPort]
|
return
|
||||||
if !isIn { oldSender.firstSeen = now }
|
} // Should always have >=1 links
|
||||||
sender := peerInfo{key: msg.from,
|
oldSender, isIn := t.data.peers[fromPort]
|
||||||
locator: msg.locator,
|
if !isIn {
|
||||||
coords: msg.locator.coords[:len(msg.locator.coords)-1],
|
oldSender.firstSeen = now
|
||||||
time: now,
|
}
|
||||||
firstSeen: oldSender.firstSeen,
|
sender := peerInfo{key: msg.from,
|
||||||
port: fromPort,
|
locator: msg.locator,
|
||||||
seq: msg.seq}
|
coords: msg.locator.coords[:len(msg.locator.coords)-1],
|
||||||
equiv := func (x *switchLocator, y *switchLocator) bool {
|
time: now,
|
||||||
if x.root != y.root { return false }
|
firstSeen: oldSender.firstSeen,
|
||||||
if len(x.coords) != len(y.coords) { return false }
|
port: fromPort,
|
||||||
for idx := range x.coords {
|
seq: msg.seq}
|
||||||
if x.coords[idx] != y.coords[idx] { return false }
|
equiv := func(x *switchLocator, y *switchLocator) bool {
|
||||||
}
|
if x.root != y.root {
|
||||||
return true
|
return false
|
||||||
}
|
}
|
||||||
doUpdate := false
|
if len(x.coords) != len(y.coords) {
|
||||||
if !equiv(&msg.locator, &oldSender.locator) {
|
return false
|
||||||
doUpdate = true
|
}
|
||||||
sender.firstSeen = now
|
for idx := range x.coords {
|
||||||
}
|
if x.coords[idx] != y.coords[idx] {
|
||||||
t.data.peers[fromPort] = sender
|
return false
|
||||||
updateRoot := false
|
}
|
||||||
oldParent, isIn := t.data.peers[t.parent]
|
}
|
||||||
noParent := !isIn
|
return true
|
||||||
noLoop := func () bool {
|
}
|
||||||
for idx := 0 ; idx < len(sigs)-1 ; idx++ {
|
doUpdate := false
|
||||||
if sigs[idx].next == t.core.sigPub { return false }
|
if !equiv(&msg.locator, &oldSender.locator) {
|
||||||
}
|
doUpdate = true
|
||||||
if msg.locator.root == t.core.sigPub { return false }
|
sender.firstSeen = now
|
||||||
return true
|
}
|
||||||
}()
|
t.data.peers[fromPort] = sender
|
||||||
sTime := now.Sub(sender.firstSeen)
|
updateRoot := false
|
||||||
pTime := oldParent.time.Sub(oldParent.firstSeen) + switch_timeout
|
oldParent, isIn := t.data.peers[t.parent]
|
||||||
// Really want to compare sLen/sTime and pLen/pTime
|
noParent := !isIn
|
||||||
// Cross multiplied to avoid divide-by-zero
|
noLoop := func() bool {
|
||||||
cost := len(msg.locator.coords)*int(pTime.Seconds())
|
for idx := 0; idx < len(sigs)-1; idx++ {
|
||||||
pCost := len(t.data.locator.coords)*int(sTime.Seconds())
|
if sigs[idx].next == t.core.sigPub {
|
||||||
dropTstamp, isIn := t.drop[msg.locator.root]
|
return false
|
||||||
// Here be dragons
|
}
|
||||||
switch {
|
}
|
||||||
case !noLoop: // do nothing
|
if msg.locator.root == t.core.sigPub {
|
||||||
case isIn && dropTstamp >= msg.locator.tstamp: // do nothing
|
return false
|
||||||
case firstIsBetter(&msg.locator.root, &t.data.locator.root): updateRoot = true
|
}
|
||||||
case t.data.locator.root != msg.locator.root: // do nothing
|
return true
|
||||||
case t.data.locator.tstamp > msg.locator.tstamp: // do nothing
|
}()
|
||||||
case noParent: updateRoot = true
|
sTime := now.Sub(sender.firstSeen)
|
||||||
case cost < pCost: updateRoot = true
|
pTime := oldParent.time.Sub(oldParent.firstSeen) + switch_timeout
|
||||||
case sender.port == t.parent &&
|
// Really want to compare sLen/sTime and pLen/pTime
|
||||||
(msg.locator.tstamp > t.data.locator.tstamp ||
|
// Cross multiplied to avoid divide-by-zero
|
||||||
!equiv(&msg.locator, &t.data.locator)): updateRoot = true
|
cost := len(msg.locator.coords) * int(pTime.Seconds())
|
||||||
}
|
pCost := len(t.data.locator.coords) * int(sTime.Seconds())
|
||||||
if updateRoot {
|
dropTstamp, isIn := t.drop[msg.locator.root]
|
||||||
if !equiv(&msg.locator, &t.data.locator) {
|
// Here be dragons
|
||||||
doUpdate = true
|
switch {
|
||||||
t.data.seq++
|
case !noLoop: // do nothing
|
||||||
select {
|
case isIn && dropTstamp >= msg.locator.tstamp: // do nothing
|
||||||
case t.core.router.reset<-struct{}{}:
|
case firstIsBetter(&msg.locator.root, &t.data.locator.root):
|
||||||
default:
|
updateRoot = true
|
||||||
}
|
case t.data.locator.root != msg.locator.root: // do nothing
|
||||||
//t.core.log.Println("Switch update:", msg.Locator.Root, msg.Locator.Tstamp, msg.Locator.Coords)
|
case t.data.locator.tstamp > msg.locator.tstamp: // do nothing
|
||||||
//fmt.Println("Switch update:", msg.Locator.Root, msg.Locator.Tstamp, msg.Locator.Coords)
|
case noParent:
|
||||||
}
|
updateRoot = true
|
||||||
if t.data.locator.tstamp != msg.locator.tstamp { t.time = now }
|
case cost < pCost:
|
||||||
t.data.locator = msg.locator
|
updateRoot = true
|
||||||
t.parent = sender.port
|
case sender.port == t.parent &&
|
||||||
t.data.sigs = sigs
|
(msg.locator.tstamp > t.data.locator.tstamp ||
|
||||||
//t.core.log.Println("Switch update:", msg.Locator.Root, msg.Locator.Tstamp, msg.Locator.Coords)
|
!equiv(&msg.locator, &t.data.locator)):
|
||||||
}
|
updateRoot = true
|
||||||
if doUpdate { t.updater.Store(&sync.Once{}) }
|
}
|
||||||
return
|
if updateRoot {
|
||||||
|
if !equiv(&msg.locator, &t.data.locator) {
|
||||||
|
doUpdate = true
|
||||||
|
t.data.seq++
|
||||||
|
select {
|
||||||
|
case t.core.router.reset <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
//t.core.log.Println("Switch update:", msg.Locator.Root, msg.Locator.Tstamp, msg.Locator.Coords)
|
||||||
|
//fmt.Println("Switch update:", msg.Locator.Root, msg.Locator.Tstamp, msg.Locator.Coords)
|
||||||
|
}
|
||||||
|
if t.data.locator.tstamp != msg.locator.tstamp {
|
||||||
|
t.time = now
|
||||||
|
}
|
||||||
|
t.data.locator = msg.locator
|
||||||
|
t.parent = sender.port
|
||||||
|
t.data.sigs = sigs
|
||||||
|
//t.core.log.Println("Switch update:", msg.Locator.Root, msg.Locator.Tstamp, msg.Locator.Coords)
|
||||||
|
}
|
||||||
|
if doUpdate {
|
||||||
|
t.updater.Store(&sync.Once{})
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *switchTable) updateTable() {
|
func (t *switchTable) updateTable() {
|
||||||
// WARNING this should only be called from within t.data.updater.Do()
|
// WARNING this should only be called from within t.data.updater.Do()
|
||||||
// It relies on the sync.Once for synchronization with messages and lookups
|
// It relies on the sync.Once for synchronization with messages and lookups
|
||||||
// TODO use a pre-computed faster lookup table
|
// TODO use a pre-computed faster lookup table
|
||||||
// Instead of checking distance for every destination every time
|
// Instead of checking distance for every destination every time
|
||||||
// Array of structs, indexed by first coord that differs from self
|
// Array of structs, indexed by first coord that differs from self
|
||||||
// Each struct has stores the best port to forward to, and a next coord map
|
// Each struct has stores the best port to forward to, and a next coord map
|
||||||
// Move to struct, then iterate over coord maps until you dead end
|
// Move to struct, then iterate over coord maps until you dead end
|
||||||
// The last port before the dead end should be the closest
|
// The last port before the dead end should be the closest
|
||||||
t.mutex.RLock()
|
t.mutex.RLock()
|
||||||
defer t.mutex.RUnlock()
|
defer t.mutex.RUnlock()
|
||||||
newTable := lookupTable{
|
newTable := lookupTable{
|
||||||
self: t.data.locator.clone(),
|
self: t.data.locator.clone(),
|
||||||
elems: make(map[switchPort]tableElem),
|
elems: make(map[switchPort]tableElem),
|
||||||
}
|
}
|
||||||
for _, pinfo := range t.data.peers {
|
for _, pinfo := range t.data.peers {
|
||||||
//if !pinfo.forward { continue }
|
//if !pinfo.forward { continue }
|
||||||
loc := pinfo.locator.clone()
|
loc := pinfo.locator.clone()
|
||||||
loc.coords = loc.coords[:len(loc.coords)-1] // Remove the them->self link
|
loc.coords = loc.coords[:len(loc.coords)-1] // Remove the them->self link
|
||||||
newTable.elems[pinfo.port] = tableElem {
|
newTable.elems[pinfo.port] = tableElem{
|
||||||
locator: loc,
|
locator: loc,
|
||||||
//degree: pinfo.degree,
|
//degree: pinfo.degree,
|
||||||
firstSeen: pinfo.firstSeen,
|
firstSeen: pinfo.firstSeen,
|
||||||
//forward: pinfo.forward,
|
//forward: pinfo.forward,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.table.Store(newTable)
|
t.table.Store(newTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *switchTable) lookup(dest []byte, ttl uint64) (switchPort, uint64) {
|
func (t *switchTable) lookup(dest []byte, ttl uint64) (switchPort, uint64) {
|
||||||
t.updater.Load().(*sync.Once).Do(t.updateTable)
|
t.updater.Load().(*sync.Once).Do(t.updateTable)
|
||||||
table := t.table.Load().(lookupTable)
|
table := t.table.Load().(lookupTable)
|
||||||
ports := t.core.peers.getPorts()
|
ports := t.core.peers.getPorts()
|
||||||
getBandwidth := func (port switchPort) float64 {
|
getBandwidth := func(port switchPort) float64 {
|
||||||
var bandwidth float64
|
var bandwidth float64
|
||||||
if p, isIn := ports[port]; isIn {
|
if p, isIn := ports[port]; isIn {
|
||||||
bandwidth = p.getBandwidth()
|
bandwidth = p.getBandwidth()
|
||||||
}
|
}
|
||||||
return bandwidth
|
return bandwidth
|
||||||
}
|
}
|
||||||
var best switchPort
|
var best switchPort
|
||||||
myDist := table.self.dist(dest) //getDist(table.self.coords)
|
myDist := table.self.dist(dest) //getDist(table.self.coords)
|
||||||
if !(uint64(myDist) < ttl) { return 0, 0 }
|
if !(uint64(myDist) < ttl) {
|
||||||
// score is in units of bandwidth / distance
|
return 0, 0
|
||||||
bestScore := float64(-1)
|
}
|
||||||
for port, info := range table.elems {
|
// score is in units of bandwidth / distance
|
||||||
if info.locator.root != table.self.root { continue }
|
bestScore := float64(-1)
|
||||||
dist := info.locator.dist(dest) //getDist(info.locator.coords)
|
for port, info := range table.elems {
|
||||||
if !(dist < myDist) { continue }
|
if info.locator.root != table.self.root {
|
||||||
score := getBandwidth(port)
|
continue
|
||||||
score /= float64(1+dist)
|
}
|
||||||
if score > bestScore {
|
dist := info.locator.dist(dest) //getDist(info.locator.coords)
|
||||||
best = port
|
if !(dist < myDist) {
|
||||||
bestScore = score
|
continue
|
||||||
}
|
}
|
||||||
}
|
score := getBandwidth(port)
|
||||||
//t.core.log.Println("DEBUG: sending to", best, "bandwidth", getBandwidth(best))
|
score /= float64(1 + dist)
|
||||||
return best, uint64(myDist)
|
if score > bestScore {
|
||||||
|
best = port
|
||||||
|
bestScore = score
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//t.core.log.Println("DEBUG: sending to", best, "bandwidth", getBandwidth(best))
|
||||||
|
return best, uint64(myDist)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -390,9 +438,8 @@ func (t *switchTable) lookup(dest []byte, ttl uint64) (switchPort, uint64) {
|
|||||||
//Signature stuff
|
//Signature stuff
|
||||||
|
|
||||||
type sigInfo struct {
|
type sigInfo struct {
|
||||||
next sigPubKey
|
next sigPubKey
|
||||||
sig sigBytes
|
sig sigBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -16,189 +16,226 @@ import "errors"
|
|||||||
import "sync"
|
import "sync"
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
const tcp_msgSize = 2048+65535 // TODO figure out what makes sense
|
const tcp_msgSize = 2048 + 65535 // TODO figure out what makes sense
|
||||||
|
|
||||||
type tcpInterface struct {
|
type tcpInterface struct {
|
||||||
core *Core
|
core *Core
|
||||||
serv *net.TCPListener
|
serv *net.TCPListener
|
||||||
mutex sync.Mutex // Protecting the below
|
mutex sync.Mutex // Protecting the below
|
||||||
calls map[string]struct{}
|
calls map[string]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type tcpKeys struct {
|
type tcpKeys struct {
|
||||||
box boxPubKey
|
box boxPubKey
|
||||||
sig sigPubKey
|
sig sigPubKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iface *tcpInterface) init(core *Core, addr string) {
|
func (iface *tcpInterface) init(core *Core, addr string) {
|
||||||
iface.core = core
|
iface.core = core
|
||||||
tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
|
tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
iface.serv, err = net.ListenTCP("tcp", tcpAddr)
|
panic(err)
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
iface.calls = make(map[string]struct{})
|
iface.serv, err = net.ListenTCP("tcp", tcpAddr)
|
||||||
go iface.listener()
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
iface.calls = make(map[string]struct{})
|
||||||
|
go iface.listener()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iface *tcpInterface) listener() {
|
func (iface *tcpInterface) listener() {
|
||||||
defer iface.serv.Close()
|
defer iface.serv.Close()
|
||||||
iface.core.log.Println("Listening on:", iface.serv.Addr().String())
|
iface.core.log.Println("Listening on:", iface.serv.Addr().String())
|
||||||
for {
|
for {
|
||||||
sock, err := iface.serv.AcceptTCP()
|
sock, err := iface.serv.AcceptTCP()
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
go iface.handler(sock)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
go iface.handler(sock)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iface *tcpInterface) call(saddr string) {
|
func (iface *tcpInterface) call(saddr string) {
|
||||||
go func() {
|
go func() {
|
||||||
quit := false
|
quit := false
|
||||||
iface.mutex.Lock()
|
iface.mutex.Lock()
|
||||||
if _, isIn := iface.calls[saddr]; isIn {
|
if _, isIn := iface.calls[saddr]; isIn {
|
||||||
quit = true
|
quit = true
|
||||||
} else {
|
} else {
|
||||||
iface.calls[saddr] = struct{}{}
|
iface.calls[saddr] = struct{}{}
|
||||||
defer func() {
|
defer func() {
|
||||||
iface.mutex.Lock()
|
iface.mutex.Lock()
|
||||||
delete(iface.calls, saddr)
|
delete(iface.calls, saddr)
|
||||||
iface.mutex.Unlock()
|
iface.mutex.Unlock()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
iface.mutex.Unlock()
|
iface.mutex.Unlock()
|
||||||
if !quit {
|
if !quit {
|
||||||
conn, err := net.DialTimeout("tcp", saddr, 6*time.Second)
|
conn, err := net.DialTimeout("tcp", saddr, 6*time.Second)
|
||||||
if err != nil { return }
|
if err != nil {
|
||||||
sock := conn.(*net.TCPConn)
|
return
|
||||||
iface.handler(sock)
|
}
|
||||||
}
|
sock := conn.(*net.TCPConn)
|
||||||
}()
|
iface.handler(sock)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iface *tcpInterface) handler(sock *net.TCPConn) {
|
func (iface *tcpInterface) handler(sock *net.TCPConn) {
|
||||||
defer sock.Close()
|
defer sock.Close()
|
||||||
// Get our keys
|
// Get our keys
|
||||||
keys := []byte{}
|
keys := []byte{}
|
||||||
keys = append(keys, tcp_key[:]...)
|
keys = append(keys, tcp_key[:]...)
|
||||||
keys = append(keys, iface.core.boxPub[:]...)
|
keys = append(keys, iface.core.boxPub[:]...)
|
||||||
keys = append(keys, iface.core.sigPub[:]...)
|
keys = append(keys, iface.core.sigPub[:]...)
|
||||||
_, err := sock.Write(keys)
|
_, err := sock.Write(keys)
|
||||||
if err != nil { return }
|
if err != nil {
|
||||||
timeout := time.Now().Add(6*time.Second)
|
return
|
||||||
sock.SetReadDeadline(timeout)
|
}
|
||||||
n, err := sock.Read(keys)
|
timeout := time.Now().Add(6 * time.Second)
|
||||||
if err != nil { return }
|
sock.SetReadDeadline(timeout)
|
||||||
if n < len(keys) { /*panic("Partial key packet?") ;*/ return }
|
n, err := sock.Read(keys)
|
||||||
ks := tcpKeys{}
|
if err != nil {
|
||||||
if !tcp_chop_keys(&ks.box, &ks.sig, &keys) { /*panic("Invalid key packet?") ;*/ return }
|
return
|
||||||
// Quit the parent call if this is a connection to ourself
|
}
|
||||||
equiv := func(k1, k2 []byte) bool {
|
if n < len(keys) { /*panic("Partial key packet?") ;*/
|
||||||
for idx := range k1 {
|
return
|
||||||
if k1[idx] != k2[idx] { return false }
|
}
|
||||||
}
|
ks := tcpKeys{}
|
||||||
return true
|
if !tcp_chop_keys(&ks.box, &ks.sig, &keys) { /*panic("Invalid key packet?") ;*/
|
||||||
}
|
return
|
||||||
if equiv(ks.box[:], iface.core.boxPub[:]) { return } // testing
|
}
|
||||||
if equiv(ks.sig[:], iface.core.sigPub[:]) { return }
|
// Quit the parent call if this is a connection to ourself
|
||||||
// Note that multiple connections to the same node are allowed
|
equiv := func(k1, k2 []byte) bool {
|
||||||
// E.g. over different interfaces
|
for idx := range k1 {
|
||||||
linkIn := make(chan []byte, 1)
|
if k1[idx] != k2[idx] {
|
||||||
p := iface.core.peers.newPeer(&ks.box, &ks.sig)//, in, out)
|
return false
|
||||||
in := func(bs []byte) {
|
}
|
||||||
p.handlePacket(bs, linkIn)
|
}
|
||||||
}
|
return true
|
||||||
out := make(chan []byte, 1024) // TODO? what size makes sense
|
}
|
||||||
defer close(out)
|
if equiv(ks.box[:], iface.core.boxPub[:]) {
|
||||||
go func() {
|
return
|
||||||
var stack [][]byte
|
} // testing
|
||||||
put := func(msg []byte) {
|
if equiv(ks.sig[:], iface.core.sigPub[:]) {
|
||||||
stack = append(stack, msg)
|
return
|
||||||
for len(stack) > 1024 {
|
}
|
||||||
util_putBytes(stack[0])
|
// Note that multiple connections to the same node are allowed
|
||||||
stack = stack[1:]
|
// E.g. over different interfaces
|
||||||
}
|
linkIn := make(chan []byte, 1)
|
||||||
}
|
p := iface.core.peers.newPeer(&ks.box, &ks.sig) //, in, out)
|
||||||
send := func() {
|
in := func(bs []byte) {
|
||||||
msg := stack[len(stack)-1]
|
p.handlePacket(bs, linkIn)
|
||||||
stack = stack[:len(stack)-1]
|
}
|
||||||
buf := net.Buffers{tcp_msg[:],
|
out := make(chan []byte, 1024) // TODO? what size makes sense
|
||||||
wire_encode_uint64(uint64(len(msg))),
|
defer close(out)
|
||||||
msg}
|
go func() {
|
||||||
size := 0
|
var stack [][]byte
|
||||||
for _, bs := range buf { size += len(bs) }
|
put := func(msg []byte) {
|
||||||
start := time.Now()
|
stack = append(stack, msg)
|
||||||
buf.WriteTo(sock)
|
for len(stack) > 1024 {
|
||||||
timed := time.Since(start)
|
util_putBytes(stack[0])
|
||||||
pType, _ := wire_decode_uint64(msg)
|
stack = stack[1:]
|
||||||
if pType == wire_LinkProtocolTraffic {
|
}
|
||||||
p.updateBandwidth(size, timed)
|
}
|
||||||
}
|
send := func() {
|
||||||
util_putBytes(msg)
|
msg := stack[len(stack)-1]
|
||||||
}
|
stack = stack[:len(stack)-1]
|
||||||
for msg := range out {
|
buf := net.Buffers{tcp_msg[:],
|
||||||
put(msg)
|
wire_encode_uint64(uint64(len(msg))),
|
||||||
for len(stack) > 0 {
|
msg}
|
||||||
// Keep trying to fill the stack (LIFO order) while sending
|
size := 0
|
||||||
select {
|
for _, bs := range buf {
|
||||||
case msg, ok := <-out:
|
size += len(bs)
|
||||||
if !ok { return }
|
}
|
||||||
put(msg)
|
start := time.Now()
|
||||||
default: send()
|
buf.WriteTo(sock)
|
||||||
}
|
timed := time.Since(start)
|
||||||
}
|
pType, _ := wire_decode_uint64(msg)
|
||||||
}
|
if pType == wire_LinkProtocolTraffic {
|
||||||
}()
|
p.updateBandwidth(size, timed)
|
||||||
p.out = func(msg []byte) {
|
}
|
||||||
defer func() { recover() }()
|
util_putBytes(msg)
|
||||||
for {
|
}
|
||||||
select {
|
for msg := range out {
|
||||||
case out<-msg: return
|
put(msg)
|
||||||
default: util_putBytes(<-out)
|
for len(stack) > 0 {
|
||||||
}
|
// Keep trying to fill the stack (LIFO order) while sending
|
||||||
}
|
select {
|
||||||
}
|
case msg, ok := <-out:
|
||||||
sock.SetNoDelay(true)
|
if !ok {
|
||||||
go p.linkLoop(linkIn)
|
return
|
||||||
defer func() {
|
}
|
||||||
// Put all of our cleanup here...
|
put(msg)
|
||||||
p.core.peers.mutex.Lock()
|
default:
|
||||||
oldPorts := p.core.peers.getPorts()
|
send()
|
||||||
newPorts := make(map[switchPort]*peer)
|
}
|
||||||
for k,v := range oldPorts{ newPorts[k] = v }
|
}
|
||||||
delete(newPorts, p.port)
|
}
|
||||||
p.core.peers.putPorts(newPorts)
|
}()
|
||||||
p.core.peers.mutex.Unlock()
|
p.out = func(msg []byte) {
|
||||||
close(linkIn)
|
defer func() { recover() }()
|
||||||
}()
|
for {
|
||||||
them := sock.RemoteAddr()
|
select {
|
||||||
themNodeID := getNodeID(&ks.box)
|
case out <- msg:
|
||||||
themAddr := address_addrForNodeID(themNodeID)
|
return
|
||||||
themAddrString := net.IP(themAddr[:]).String()
|
default:
|
||||||
themString := fmt.Sprintf("%s@%s", themAddrString, them)
|
util_putBytes(<-out)
|
||||||
iface.core.log.Println("Connected:", themString)
|
}
|
||||||
iface.reader(sock, in) // In this goroutine, because of defers
|
}
|
||||||
iface.core.log.Println("Disconnected:", themString)
|
}
|
||||||
return
|
sock.SetNoDelay(true)
|
||||||
|
go p.linkLoop(linkIn)
|
||||||
|
defer func() {
|
||||||
|
// Put all of our cleanup here...
|
||||||
|
p.core.peers.mutex.Lock()
|
||||||
|
oldPorts := p.core.peers.getPorts()
|
||||||
|
newPorts := make(map[switchPort]*peer)
|
||||||
|
for k, v := range oldPorts {
|
||||||
|
newPorts[k] = v
|
||||||
|
}
|
||||||
|
delete(newPorts, p.port)
|
||||||
|
p.core.peers.putPorts(newPorts)
|
||||||
|
p.core.peers.mutex.Unlock()
|
||||||
|
close(linkIn)
|
||||||
|
}()
|
||||||
|
them := sock.RemoteAddr()
|
||||||
|
themNodeID := getNodeID(&ks.box)
|
||||||
|
themAddr := address_addrForNodeID(themNodeID)
|
||||||
|
themAddrString := net.IP(themAddr[:]).String()
|
||||||
|
themString := fmt.Sprintf("%s@%s", themAddrString, them)
|
||||||
|
iface.core.log.Println("Connected:", themString)
|
||||||
|
iface.reader(sock, in) // In this goroutine, because of defers
|
||||||
|
iface.core.log.Println("Disconnected:", themString)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iface *tcpInterface) reader(sock *net.TCPConn, in func([]byte)) {
|
func (iface *tcpInterface) reader(sock *net.TCPConn, in func([]byte)) {
|
||||||
bs := make([]byte, 2*tcp_msgSize)
|
bs := make([]byte, 2*tcp_msgSize)
|
||||||
frag := bs[:0]
|
frag := bs[:0]
|
||||||
for {
|
for {
|
||||||
timeout := time.Now().Add(6*time.Second)
|
timeout := time.Now().Add(6 * time.Second)
|
||||||
sock.SetReadDeadline(timeout)
|
sock.SetReadDeadline(timeout)
|
||||||
n, err := sock.Read(bs[len(frag):])
|
n, err := sock.Read(bs[len(frag):])
|
||||||
if err != nil || n == 0 { break }
|
if err != nil || n == 0 {
|
||||||
frag = bs[:len(frag)+n]
|
break
|
||||||
for {
|
}
|
||||||
msg, ok, err := tcp_chop_msg(&frag)
|
frag = bs[:len(frag)+n]
|
||||||
if err != nil { return }
|
for {
|
||||||
if !ok { break } // We didn't get the whole message yet
|
msg, ok, err := tcp_chop_msg(&frag)
|
||||||
newMsg := append(util_getBytes(), msg...)
|
if err != nil {
|
||||||
in(newMsg)
|
return
|
||||||
util_yield()
|
}
|
||||||
}
|
if !ok {
|
||||||
frag = append(bs[:0], frag...)
|
break
|
||||||
}
|
} // We didn't get the whole message yet
|
||||||
|
newMsg := append(util_getBytes(), msg...)
|
||||||
|
in(newMsg)
|
||||||
|
util_yield()
|
||||||
|
}
|
||||||
|
frag = append(bs[:0], frag...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -208,39 +245,46 @@ var tcp_key = [...]byte{'k', 'e', 'y', 's'}
|
|||||||
var tcp_msg = [...]byte{0xde, 0xad, 0xb1, 0x75} // "dead bits"
|
var tcp_msg = [...]byte{0xde, 0xad, 0xb1, 0x75} // "dead bits"
|
||||||
|
|
||||||
func tcp_chop_keys(box *boxPubKey, sig *sigPubKey, bs *[]byte) bool {
|
func tcp_chop_keys(box *boxPubKey, sig *sigPubKey, bs *[]byte) bool {
|
||||||
// This one is pretty simple: we know how long the message should be
|
// This one is pretty simple: we know how long the message should be
|
||||||
// So don't call this with a message that's too short
|
// So don't call this with a message that's too short
|
||||||
if len(*bs) < len(tcp_key) + len(*box) + len(*sig) { return false }
|
if len(*bs) < len(tcp_key)+len(*box)+len(*sig) {
|
||||||
for idx := range tcp_key {
|
return false
|
||||||
if (*bs)[idx] != tcp_key[idx] { return false }
|
}
|
||||||
}
|
for idx := range tcp_key {
|
||||||
(*bs) = (*bs)[len(tcp_key):]
|
if (*bs)[idx] != tcp_key[idx] {
|
||||||
copy(box[:], *bs)
|
return false
|
||||||
(*bs) = (*bs)[len(box):]
|
}
|
||||||
copy(sig[:], *bs)
|
}
|
||||||
(*bs) = (*bs)[len(sig):]
|
(*bs) = (*bs)[len(tcp_key):]
|
||||||
return true
|
copy(box[:], *bs)
|
||||||
|
(*bs) = (*bs)[len(box):]
|
||||||
|
copy(sig[:], *bs)
|
||||||
|
(*bs) = (*bs)[len(sig):]
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func tcp_chop_msg(bs *[]byte) ([]byte, bool, error) {
|
func tcp_chop_msg(bs *[]byte) ([]byte, bool, error) {
|
||||||
// Returns msg, ok, err
|
// Returns msg, ok, err
|
||||||
if len(*bs) < len(tcp_msg) { return nil, false, nil }
|
if len(*bs) < len(tcp_msg) {
|
||||||
for idx := range tcp_msg {
|
return nil, false, nil
|
||||||
if (*bs)[idx] != tcp_msg[idx] {
|
}
|
||||||
return nil, false, errors.New("Bad message!")
|
for idx := range tcp_msg {
|
||||||
}
|
if (*bs)[idx] != tcp_msg[idx] {
|
||||||
}
|
return nil, false, errors.New("Bad message!")
|
||||||
msgLen, msgLenLen := wire_decode_uint64((*bs)[len(tcp_msg):])
|
}
|
||||||
if msgLen > tcp_msgSize { return nil, false, errors.New("Oversized message!") }
|
}
|
||||||
msgBegin := len(tcp_msg) + msgLenLen
|
msgLen, msgLenLen := wire_decode_uint64((*bs)[len(tcp_msg):])
|
||||||
msgEnd := msgBegin + int(msgLen)
|
if msgLen > tcp_msgSize {
|
||||||
if msgLenLen == 0 || len(*bs) < msgEnd {
|
return nil, false, errors.New("Oversized message!")
|
||||||
// We don't have the full message
|
}
|
||||||
// Need to buffer this and wait for the rest to come in
|
msgBegin := len(tcp_msg) + msgLenLen
|
||||||
return nil, false, nil
|
msgEnd := msgBegin + int(msgLen)
|
||||||
}
|
if msgLenLen == 0 || len(*bs) < msgEnd {
|
||||||
msg := (*bs)[msgBegin:msgEnd]
|
// We don't have the full message
|
||||||
(*bs) = (*bs)[msgEnd:]
|
// Need to buffer this and wait for the rest to come in
|
||||||
return msg, true, nil
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
msg := (*bs)[msgBegin:msgEnd]
|
||||||
|
(*bs) = (*bs)[msgEnd:]
|
||||||
|
return msg, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,50 +7,45 @@ import water "github.com/songgao/water"
|
|||||||
const IPv6_HEADER_LENGTH = 40
|
const IPv6_HEADER_LENGTH = 40
|
||||||
|
|
||||||
type tunDevice struct {
|
type tunDevice struct {
|
||||||
core *Core
|
core *Core
|
||||||
send chan<- []byte
|
send chan<- []byte
|
||||||
recv <-chan []byte
|
recv <-chan []byte
|
||||||
mtu int
|
mtu int
|
||||||
iface *water.Interface
|
iface *water.Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tun *tunDevice) init(core *Core) {
|
func (tun *tunDevice) init(core *Core) {
|
||||||
tun.core = core
|
tun.core = core
|
||||||
}
|
|
||||||
|
|
||||||
func (tun *tunDevice) setup(addr string, mtu int) error {
|
|
||||||
iface, err := water.New(water.Config{ DeviceType: water.TUN })
|
|
||||||
if err != nil { panic(err) }
|
|
||||||
tun.iface = iface
|
|
||||||
tun.mtu = mtu //1280 // Lets default to the smallest thing allowed for now
|
|
||||||
return tun.setupAddress(addr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tun *tunDevice) write() error {
|
func (tun *tunDevice) write() error {
|
||||||
for {
|
for {
|
||||||
data := <-tun.recv
|
data := <-tun.recv
|
||||||
if _, err := tun.iface.Write(data); err != nil { return err }
|
if _, err := tun.iface.Write(data); err != nil {
|
||||||
util_putBytes(data)
|
return err
|
||||||
}
|
}
|
||||||
|
util_putBytes(data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tun *tunDevice) read() error {
|
func (tun *tunDevice) read() error {
|
||||||
buf := make([]byte, tun.mtu)
|
buf := make([]byte, tun.mtu)
|
||||||
for {
|
for {
|
||||||
n, err := tun.iface.Read(buf)
|
n, err := tun.iface.Read(buf)
|
||||||
if err != nil { return err }
|
if err != nil {
|
||||||
if buf[0] & 0xf0 != 0x60 ||
|
return err
|
||||||
n != 256*int(buf[4]) + int(buf[5]) + IPv6_HEADER_LENGTH {
|
}
|
||||||
// Either not an IPv6 packet or not the complete packet for some reason
|
if buf[0]&0xf0 != 0x60 ||
|
||||||
//panic("Should not happen in testing")
|
n != 256*int(buf[4])+int(buf[5])+IPv6_HEADER_LENGTH {
|
||||||
continue
|
// Either not an IPv6 packet or not the complete packet for some reason
|
||||||
}
|
//panic("Should not happen in testing")
|
||||||
packet := append(util_getBytes(), buf[:n]...)
|
continue
|
||||||
tun.send<-packet
|
}
|
||||||
}
|
packet := append(util_getBytes(), buf[:n]...)
|
||||||
|
tun.send <- packet
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tun *tunDevice) close() error {
|
func (tun *tunDevice) close() error {
|
||||||
return tun.iface.Close()
|
return tun.iface.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,30 +7,45 @@ import "fmt"
|
|||||||
import "os/exec"
|
import "os/exec"
|
||||||
import "strings"
|
import "strings"
|
||||||
|
|
||||||
func (tun *tunDevice) setupAddress(addr string) error {
|
import water "github.com/songgao/water"
|
||||||
// Set address
|
|
||||||
cmd := exec.Command("ip", "-f", "inet6",
|
func (tun *tunDevice) setup(ifname string, addr string, mtu int) error {
|
||||||
"addr", "add", addr,
|
config := water.Config{DeviceType: water.TUN}
|
||||||
"dev", tun.iface.Name())
|
if ifname != "" && ifname != "auto" {
|
||||||
tun.core.log.Printf("ip command: %v", strings.Join(cmd.Args, " "))
|
config.Name = ifname
|
||||||
output, err := cmd.CombinedOutput()
|
}
|
||||||
if err != nil {
|
iface, err := water.New(config)
|
||||||
tun.core.log.Printf("Linux ip failed: %v.", err)
|
if err != nil {
|
||||||
tun.core.log.Println(string(output))
|
panic(err)
|
||||||
return err
|
}
|
||||||
}
|
tun.iface = iface
|
||||||
// Set MTU and bring device up
|
tun.mtu = mtu //1280 // Lets default to the smallest thing allowed for now
|
||||||
cmd = exec.Command("ip", "link", "set",
|
return tun.setupAddress(addr)
|
||||||
"dev", tun.iface.Name(),
|
|
||||||
"mtu", fmt.Sprintf("%d", tun.mtu),
|
|
||||||
"up")
|
|
||||||
tun.core.log.Printf("ip command: %v", strings.Join(cmd.Args, " "))
|
|
||||||
output, err = cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
tun.core.log.Printf("Linux ip failed: %v.", err)
|
|
||||||
tun.core.log.Println(string(output))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tun *tunDevice) setupAddress(addr string) error {
|
||||||
|
// Set address
|
||||||
|
cmd := exec.Command("ip", "-f", "inet6",
|
||||||
|
"addr", "add", addr,
|
||||||
|
"dev", tun.iface.Name())
|
||||||
|
tun.core.log.Printf("ip command: %v", strings.Join(cmd.Args, " "))
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
tun.core.log.Printf("Linux ip failed: %v.", err)
|
||||||
|
tun.core.log.Println(string(output))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Set MTU and bring device up
|
||||||
|
cmd = exec.Command("ip", "link", "set",
|
||||||
|
"dev", tun.iface.Name(),
|
||||||
|
"mtu", fmt.Sprintf("%d", tun.mtu),
|
||||||
|
"up")
|
||||||
|
tun.core.log.Printf("ip command: %v", strings.Join(cmd.Args, " "))
|
||||||
|
output, err = cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
tun.core.log.Printf("Linux ip failed: %v.", err)
|
||||||
|
tun.core.log.Println(string(output))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -2,11 +2,23 @@
|
|||||||
|
|
||||||
package yggdrasil
|
package yggdrasil
|
||||||
|
|
||||||
|
import water "github.com/songgao/water"
|
||||||
|
|
||||||
// This is to catch unsupported platforms
|
// This is to catch unsupported platforms
|
||||||
// If your platform supports tun devices, you could try configuring it manually
|
// If your platform supports tun devices, you could try configuring it manually
|
||||||
|
|
||||||
func (tun *tunDevice) setupAddress(addr string) error {
|
func (tun *tunDevice) setup(ifname string, addr string, mtu int) error {
|
||||||
tun.core.log.Println("Platform not supported, you must set the address of", tun.iface.Name(), "to", addr)
|
config := water.Config{DeviceType: water.TUN}
|
||||||
return nil
|
iface, err := water.New(config)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
tun.iface = iface
|
||||||
|
tun.mtu = mtu //1280 // Lets default to the smallest thing allowed for now
|
||||||
|
return tun.setupAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tun *tunDevice) setupAddress(addr string) error {
|
||||||
|
tun.core.log.Println("Platform not supported, you must set the address of", tun.iface.Name(), "to", addr)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -15,247 +15,277 @@ import "sync"
|
|||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
type udpInterface struct {
|
type udpInterface struct {
|
||||||
core *Core
|
core *Core
|
||||||
sock *net.UDPConn // Or more general PacketConn?
|
sock *net.UDPConn // Or more general PacketConn?
|
||||||
mutex sync.RWMutex // each conn has an owner goroutine
|
mutex sync.RWMutex // each conn has an owner goroutine
|
||||||
conns map[connAddr]*connInfo
|
conns map[connAddr]*connInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type connAddr string // TODO something more efficient, but still a valid map key
|
type connAddr string // TODO something more efficient, but still a valid map key
|
||||||
type connInfo struct {
|
type connInfo struct {
|
||||||
addr connAddr
|
addr connAddr
|
||||||
peer *peer
|
peer *peer
|
||||||
linkIn chan []byte
|
linkIn chan []byte
|
||||||
keysIn chan *udpKeys
|
keysIn chan *udpKeys
|
||||||
timeout int // count of how many heartbeats have been missed
|
timeout int // count of how many heartbeats have been missed
|
||||||
in func([]byte)
|
in func([]byte)
|
||||||
out chan []byte
|
out chan []byte
|
||||||
countIn uint8
|
countIn uint8
|
||||||
countOut uint8
|
countOut uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
type udpKeys struct {
|
type udpKeys struct {
|
||||||
box boxPubKey
|
box boxPubKey
|
||||||
sig sigPubKey
|
sig sigPubKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iface *udpInterface) init(core *Core, addr string) {
|
func (iface *udpInterface) init(core *Core, addr string) {
|
||||||
iface.core = core
|
iface.core = core
|
||||||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
iface.sock, err = net.ListenUDP("udp", udpAddr)
|
panic(err)
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
iface.conns = make(map[connAddr]*connInfo)
|
iface.sock, err = net.ListenUDP("udp", udpAddr)
|
||||||
go iface.reader()
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
iface.conns = make(map[connAddr]*connInfo)
|
||||||
|
go iface.reader()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iface *udpInterface) sendKeys(addr connAddr) {
|
func (iface *udpInterface) sendKeys(addr connAddr) {
|
||||||
udpAddr, err := net.ResolveUDPAddr("udp", string(addr))
|
udpAddr, err := net.ResolveUDPAddr("udp", string(addr))
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
msg := []byte{}
|
panic(err)
|
||||||
msg = udp_encode(msg, 0, 0, 0, nil)
|
}
|
||||||
msg = append(msg, iface.core.boxPub[:]...)
|
msg := []byte{}
|
||||||
msg = append(msg, iface.core.sigPub[:]...)
|
msg = udp_encode(msg, 0, 0, 0, nil)
|
||||||
iface.sock.WriteToUDP(msg, udpAddr)
|
msg = append(msg, iface.core.boxPub[:]...)
|
||||||
|
msg = append(msg, iface.core.sigPub[:]...)
|
||||||
|
iface.sock.WriteToUDP(msg, udpAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func udp_isKeys(msg []byte) bool {
|
func udp_isKeys(msg []byte) bool {
|
||||||
keyLen := 3 + boxPubKeyLen + sigPubKeyLen
|
keyLen := 3 + boxPubKeyLen + sigPubKeyLen
|
||||||
return len(msg) == keyLen && msg[0] == 0x00
|
return len(msg) == keyLen && msg[0] == 0x00
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iface *udpInterface) startConn(info *connInfo) {
|
func (iface *udpInterface) startConn(info *connInfo) {
|
||||||
ticker := time.NewTicker(6*time.Second)
|
ticker := time.NewTicker(6 * time.Second)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
defer func () {
|
defer func() {
|
||||||
// Cleanup
|
// Cleanup
|
||||||
// FIXME this still leaks a peer struct
|
// FIXME this still leaks a peer struct
|
||||||
iface.mutex.Lock()
|
iface.mutex.Lock()
|
||||||
delete(iface.conns, info.addr)
|
delete(iface.conns, info.addr)
|
||||||
iface.mutex.Unlock()
|
iface.mutex.Unlock()
|
||||||
iface.core.peers.mutex.Lock()
|
iface.core.peers.mutex.Lock()
|
||||||
oldPorts := iface.core.peers.getPorts()
|
oldPorts := iface.core.peers.getPorts()
|
||||||
newPorts := make(map[switchPort]*peer)
|
newPorts := make(map[switchPort]*peer)
|
||||||
for k,v := range oldPorts{ newPorts[k] = v }
|
for k, v := range oldPorts {
|
||||||
delete(newPorts, info.peer.port)
|
newPorts[k] = v
|
||||||
iface.core.peers.putPorts(newPorts)
|
}
|
||||||
iface.core.peers.mutex.Unlock()
|
delete(newPorts, info.peer.port)
|
||||||
close(info.linkIn)
|
iface.core.peers.putPorts(newPorts)
|
||||||
close(info.keysIn)
|
iface.core.peers.mutex.Unlock()
|
||||||
close(info.out)
|
close(info.linkIn)
|
||||||
iface.core.log.Println("Removing peer:", info.addr)
|
close(info.keysIn)
|
||||||
}()
|
close(info.out)
|
||||||
for {
|
iface.core.log.Println("Removing peer:", info.addr)
|
||||||
select {
|
}()
|
||||||
case ks := <-info.keysIn: {
|
for {
|
||||||
// FIXME? need signatures/sequence-numbers or something
|
select {
|
||||||
// Spoofers could lock out a peer with fake/bad keys
|
case ks := <-info.keysIn:
|
||||||
if ks.box == info.peer.box && ks.sig == info.peer.sig {
|
{
|
||||||
info.timeout = 0
|
// FIXME? need signatures/sequence-numbers or something
|
||||||
}
|
// Spoofers could lock out a peer with fake/bad keys
|
||||||
}
|
if ks.box == info.peer.box && ks.sig == info.peer.sig {
|
||||||
case <-ticker.C: {
|
info.timeout = 0
|
||||||
if info.timeout > 10 { return }
|
}
|
||||||
info.timeout++
|
}
|
||||||
iface.sendKeys(info.addr)
|
case <-ticker.C:
|
||||||
}
|
{
|
||||||
}
|
if info.timeout > 10 {
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
info.timeout++
|
||||||
|
iface.sendKeys(info.addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iface *udpInterface) handleKeys(msg []byte, addr connAddr) {
|
func (iface *udpInterface) handleKeys(msg []byte, addr connAddr) {
|
||||||
//defer util_putBytes(msg)
|
//defer util_putBytes(msg)
|
||||||
var ks udpKeys
|
var ks udpKeys
|
||||||
_, _, _, bs := udp_decode(msg)
|
_, _, _, bs := udp_decode(msg)
|
||||||
switch {
|
switch {
|
||||||
case !wire_chop_slice(ks.box[:], &bs): return
|
case !wire_chop_slice(ks.box[:], &bs):
|
||||||
case !wire_chop_slice(ks.sig[:], &bs): return
|
return
|
||||||
}
|
case !wire_chop_slice(ks.sig[:], &bs):
|
||||||
if ks.box == iface.core.boxPub { return }
|
return
|
||||||
if ks.sig == iface.core.sigPub { return }
|
}
|
||||||
iface.mutex.RLock()
|
if ks.box == iface.core.boxPub {
|
||||||
conn, isIn := iface.conns[addr]
|
return
|
||||||
iface.mutex.RUnlock() // TODO? keep the lock longer?...
|
}
|
||||||
if !isIn {
|
if ks.sig == iface.core.sigPub {
|
||||||
udpAddr, err := net.ResolveUDPAddr("udp", string(addr))
|
return
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
conn = &connInfo{
|
iface.mutex.RLock()
|
||||||
addr: connAddr(addr),
|
conn, isIn := iface.conns[addr]
|
||||||
peer: iface.core.peers.newPeer(&ks.box, &ks.sig),
|
iface.mutex.RUnlock() // TODO? keep the lock longer?...
|
||||||
linkIn: make(chan []byte, 1),
|
if !isIn {
|
||||||
keysIn: make(chan *udpKeys, 1),
|
udpAddr, err := net.ResolveUDPAddr("udp", string(addr))
|
||||||
out: make(chan []byte, 1024),
|
if err != nil {
|
||||||
}
|
panic(err)
|
||||||
/*
|
}
|
||||||
conn.in = func (msg []byte) { conn.peer.handlePacket(msg, conn.linkIn) }
|
conn = &connInfo{
|
||||||
conn.peer.out = func (msg []byte) {
|
addr: connAddr(addr),
|
||||||
start := time.Now()
|
peer: iface.core.peers.newPeer(&ks.box, &ks.sig),
|
||||||
iface.sock.WriteToUDP(msg, udpAddr)
|
linkIn: make(chan []byte, 1),
|
||||||
timed := time.Since(start)
|
keysIn: make(chan *udpKeys, 1),
|
||||||
conn.peer.updateBandwidth(len(msg), timed)
|
out: make(chan []byte, 1024),
|
||||||
util_putBytes(msg)
|
}
|
||||||
} // Old version, always one syscall per packet
|
/*
|
||||||
//*/
|
conn.in = func (msg []byte) { conn.peer.handlePacket(msg, conn.linkIn) }
|
||||||
/*
|
conn.peer.out = func (msg []byte) {
|
||||||
conn.peer.out = func (msg []byte) {
|
start := time.Now()
|
||||||
defer func() { recover() }()
|
iface.sock.WriteToUDP(msg, udpAddr)
|
||||||
select {
|
timed := time.Since(start)
|
||||||
case conn.out<-msg:
|
conn.peer.updateBandwidth(len(msg), timed)
|
||||||
default: util_putBytes(msg)
|
util_putBytes(msg)
|
||||||
}
|
} // Old version, always one syscall per packet
|
||||||
}
|
//*/
|
||||||
go func () {
|
/*
|
||||||
for msg := range conn.out {
|
conn.peer.out = func (msg []byte) {
|
||||||
start := time.Now()
|
defer func() { recover() }()
|
||||||
iface.sock.WriteToUDP(msg, udpAddr)
|
select {
|
||||||
timed := time.Since(start)
|
case conn.out<-msg:
|
||||||
conn.peer.updateBandwidth(len(msg), timed)
|
default: util_putBytes(msg)
|
||||||
util_putBytes(msg)
|
}
|
||||||
}
|
}
|
||||||
}()
|
go func () {
|
||||||
//*/
|
for msg := range conn.out {
|
||||||
//*
|
start := time.Now()
|
||||||
var inChunks uint8
|
iface.sock.WriteToUDP(msg, udpAddr)
|
||||||
var inBuf []byte
|
timed := time.Since(start)
|
||||||
conn.in = func(bs []byte) {
|
conn.peer.updateBandwidth(len(msg), timed)
|
||||||
//defer util_putBytes(bs)
|
util_putBytes(msg)
|
||||||
chunks, chunk, count, payload := udp_decode(bs)
|
}
|
||||||
//iface.core.log.Println("DEBUG:", addr, chunks, chunk, count, len(payload))
|
}()
|
||||||
//iface.core.log.Println("DEBUG: payload:", payload)
|
//*/
|
||||||
if count != conn.countIn {
|
//*
|
||||||
inChunks = 0
|
var inChunks uint8
|
||||||
inBuf = inBuf[:0]
|
var inBuf []byte
|
||||||
conn.countIn = count
|
conn.in = func(bs []byte) {
|
||||||
}
|
//defer util_putBytes(bs)
|
||||||
if chunk <= chunks && chunk == inChunks + 1 {
|
chunks, chunk, count, payload := udp_decode(bs)
|
||||||
//iface.core.log.Println("GOING:", addr, chunks, chunk, count, len(payload))
|
//iface.core.log.Println("DEBUG:", addr, chunks, chunk, count, len(payload))
|
||||||
inChunks += 1
|
//iface.core.log.Println("DEBUG: payload:", payload)
|
||||||
inBuf = append(inBuf, payload...)
|
if count != conn.countIn {
|
||||||
if chunks != chunk { return }
|
inChunks = 0
|
||||||
msg := append(util_getBytes(), inBuf...)
|
inBuf = inBuf[:0]
|
||||||
conn.peer.handlePacket(msg, conn.linkIn)
|
conn.countIn = count
|
||||||
//iface.core.log.Println("DONE:", addr, chunks, chunk, count, len(payload))
|
}
|
||||||
}
|
if chunk <= chunks && chunk == inChunks+1 {
|
||||||
}
|
//iface.core.log.Println("GOING:", addr, chunks, chunk, count, len(payload))
|
||||||
conn.peer.out = func (msg []byte) {
|
inChunks += 1
|
||||||
defer func() { recover() }()
|
inBuf = append(inBuf, payload...)
|
||||||
select {
|
if chunks != chunk {
|
||||||
case conn.out<-msg:
|
return
|
||||||
default: util_putBytes(msg)
|
}
|
||||||
}
|
msg := append(util_getBytes(), inBuf...)
|
||||||
}
|
conn.peer.handlePacket(msg, conn.linkIn)
|
||||||
go func () {
|
//iface.core.log.Println("DONE:", addr, chunks, chunk, count, len(payload))
|
||||||
//var chunks [][]byte
|
}
|
||||||
var out []byte
|
}
|
||||||
for msg := range conn.out {
|
conn.peer.out = func(msg []byte) {
|
||||||
var chunks [][]byte
|
defer func() { recover() }()
|
||||||
bs := msg
|
select {
|
||||||
for len(bs) > udp_chunkSize {
|
case conn.out <- msg:
|
||||||
chunks, bs = append(chunks, bs[:udp_chunkSize]), bs[udp_chunkSize:]
|
default:
|
||||||
}
|
util_putBytes(msg)
|
||||||
chunks = append(chunks, bs)
|
}
|
||||||
//iface.core.log.Println("DEBUG: out chunks:", len(chunks), len(msg))
|
}
|
||||||
if len(chunks) > 255 { continue }
|
go func() {
|
||||||
start := time.Now()
|
//var chunks [][]byte
|
||||||
for idx,bs := range chunks {
|
var out []byte
|
||||||
nChunks, nChunk, count := uint8(len(chunks)), uint8(idx)+1, conn.countOut
|
for msg := range conn.out {
|
||||||
out = udp_encode(out[:0], nChunks, nChunk, count, bs)
|
var chunks [][]byte
|
||||||
//iface.core.log.Println("DEBUG out:", nChunks, nChunk, count, len(bs))
|
bs := msg
|
||||||
iface.sock.WriteToUDP(out, udpAddr)
|
for len(bs) > udp_chunkSize {
|
||||||
}
|
chunks, bs = append(chunks, bs[:udp_chunkSize]), bs[udp_chunkSize:]
|
||||||
timed := time.Since(start)
|
}
|
||||||
conn.countOut += 1
|
chunks = append(chunks, bs)
|
||||||
conn.peer.updateBandwidth(len(msg), timed)
|
//iface.core.log.Println("DEBUG: out chunks:", len(chunks), len(msg))
|
||||||
util_putBytes(msg)
|
if len(chunks) > 255 {
|
||||||
}
|
continue
|
||||||
}()
|
}
|
||||||
//*/
|
start := time.Now()
|
||||||
iface.mutex.Lock()
|
for idx, bs := range chunks {
|
||||||
iface.conns[addr] = conn
|
nChunks, nChunk, count := uint8(len(chunks)), uint8(idx)+1, conn.countOut
|
||||||
iface.mutex.Unlock()
|
out = udp_encode(out[:0], nChunks, nChunk, count, bs)
|
||||||
themNodeID := getNodeID(&ks.box)
|
//iface.core.log.Println("DEBUG out:", nChunks, nChunk, count, len(bs))
|
||||||
themAddr := address_addrForNodeID(themNodeID)
|
iface.sock.WriteToUDP(out, udpAddr)
|
||||||
themAddrString := net.IP(themAddr[:]).String()
|
}
|
||||||
themString := fmt.Sprintf("%s@%s", themAddrString, addr)
|
timed := time.Since(start)
|
||||||
iface.core.log.Println("Adding peer:", themString)
|
conn.countOut += 1
|
||||||
go iface.startConn(conn)
|
conn.peer.updateBandwidth(len(msg), timed)
|
||||||
go conn.peer.linkLoop(conn.linkIn)
|
util_putBytes(msg)
|
||||||
iface.sendKeys(conn.addr)
|
}
|
||||||
}
|
}()
|
||||||
func() {
|
//*/
|
||||||
defer func() { recover() }()
|
iface.mutex.Lock()
|
||||||
select {
|
iface.conns[addr] = conn
|
||||||
case conn.keysIn<-&ks:
|
iface.mutex.Unlock()
|
||||||
default:
|
themNodeID := getNodeID(&ks.box)
|
||||||
}
|
themAddr := address_addrForNodeID(themNodeID)
|
||||||
}()
|
themAddrString := net.IP(themAddr[:]).String()
|
||||||
|
themString := fmt.Sprintf("%s@%s", themAddrString, addr)
|
||||||
|
iface.core.log.Println("Adding peer:", themString)
|
||||||
|
go iface.startConn(conn)
|
||||||
|
go conn.peer.linkLoop(conn.linkIn)
|
||||||
|
iface.sendKeys(conn.addr)
|
||||||
|
}
|
||||||
|
func() {
|
||||||
|
defer func() { recover() }()
|
||||||
|
select {
|
||||||
|
case conn.keysIn <- &ks:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iface *udpInterface) handlePacket(msg []byte, addr connAddr) {
|
func (iface *udpInterface) handlePacket(msg []byte, addr connAddr) {
|
||||||
iface.mutex.RLock()
|
iface.mutex.RLock()
|
||||||
if conn, isIn := iface.conns[addr]; isIn {
|
if conn, isIn := iface.conns[addr]; isIn {
|
||||||
conn.in(msg)
|
conn.in(msg)
|
||||||
}
|
}
|
||||||
iface.mutex.RUnlock()
|
iface.mutex.RUnlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iface *udpInterface) reader() {
|
func (iface *udpInterface) reader() {
|
||||||
bs := make([]byte, 2048) // This needs to be large enough for everything...
|
bs := make([]byte, 2048) // This needs to be large enough for everything...
|
||||||
for {
|
for {
|
||||||
//iface.core.log.Println("Starting read")
|
//iface.core.log.Println("Starting read")
|
||||||
n, udpAddr, err := iface.sock.ReadFromUDP(bs)
|
n, udpAddr, err := iface.sock.ReadFromUDP(bs)
|
||||||
//iface.core.log.Println("Read", n, udpAddr.String(), err)
|
//iface.core.log.Println("Read", n, udpAddr.String(), err)
|
||||||
if err != nil { panic(err) ; break }
|
if err != nil {
|
||||||
if n > 1500 { panic(n) }
|
panic(err)
|
||||||
//msg := append(util_getBytes(), bs[:n]...)
|
break
|
||||||
msg := bs[:n]
|
}
|
||||||
addr := connAddr(udpAddr.String())
|
if n > 1500 {
|
||||||
if udp_isKeys(msg) {
|
panic(n)
|
||||||
iface.handleKeys(msg, addr)
|
}
|
||||||
} else {
|
//msg := append(util_getBytes(), bs[:n]...)
|
||||||
iface.handlePacket(msg, addr)
|
msg := bs[:n]
|
||||||
}
|
addr := connAddr(udpAddr.String())
|
||||||
}
|
if udp_isKeys(msg) {
|
||||||
|
iface.handleKeys(msg, addr)
|
||||||
|
} else {
|
||||||
|
iface.handlePacket(msg, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -263,13 +293,12 @@ func (iface *udpInterface) reader() {
|
|||||||
const udp_chunkSize = 65535
|
const udp_chunkSize = 65535
|
||||||
|
|
||||||
func udp_decode(bs []byte) (chunks, chunk, count uint8, payload []byte) {
|
func udp_decode(bs []byte) (chunks, chunk, count uint8, payload []byte) {
|
||||||
if len(bs) >= 3 {
|
if len(bs) >= 3 {
|
||||||
chunks, chunk, count, payload = bs[0], bs[1], bs[2], bs[3:]
|
chunks, chunk, count, payload = bs[0], bs[1], bs[2], bs[3:]
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func udp_encode(out []byte, chunks, chunk, count uint8, payload []byte) []byte {
|
func udp_encode(out []byte, chunks, chunk, count uint8, payload []byte) []byte {
|
||||||
return append(append(out, chunks, chunk, count), payload...)
|
return append(append(out, chunks, chunk, count), payload...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,41 +4,42 @@ package yggdrasil
|
|||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
import "runtime"
|
import "runtime"
|
||||||
|
|
||||||
//import "sync"
|
//import "sync"
|
||||||
|
|
||||||
func Util_testAddrIDMask() {
|
func Util_testAddrIDMask() {
|
||||||
for idx := 0 ; idx < 16 ; idx++ {
|
for idx := 0; idx < 16; idx++ {
|
||||||
var orig NodeID
|
var orig NodeID
|
||||||
orig[8] = 42
|
orig[8] = 42
|
||||||
for bidx := 0 ; bidx < idx ; bidx++ {
|
for bidx := 0; bidx < idx; bidx++ {
|
||||||
orig[bidx/8] |= (0x80 >> uint8(bidx % 8))
|
orig[bidx/8] |= (0x80 >> uint8(bidx%8))
|
||||||
}
|
}
|
||||||
addr := address_addrForNodeID(&orig)
|
addr := address_addrForNodeID(&orig)
|
||||||
nid, mask := addr.getNodeIDandMask()
|
nid, mask := addr.getNodeIDandMask()
|
||||||
for b := 0 ; b < len(mask) ; b++ {
|
for b := 0; b < len(mask); b++ {
|
||||||
nid[b] &= mask[b]
|
nid[b] &= mask[b]
|
||||||
orig[b] &= mask[b]
|
orig[b] &= mask[b]
|
||||||
}
|
}
|
||||||
if *nid != orig {
|
if *nid != orig {
|
||||||
fmt.Println(orig)
|
fmt.Println(orig)
|
||||||
fmt.Println(*addr)
|
fmt.Println(*addr)
|
||||||
fmt.Println(*nid)
|
fmt.Println(*nid)
|
||||||
fmt.Println(*mask)
|
fmt.Println(*mask)
|
||||||
panic(idx)
|
panic(idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func util_yield() {
|
func util_yield() {
|
||||||
runtime.Gosched()
|
runtime.Gosched()
|
||||||
}
|
}
|
||||||
|
|
||||||
func util_lockthread() {
|
func util_lockthread() {
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
}
|
}
|
||||||
|
|
||||||
func util_unlockthread() {
|
func util_unlockthread() {
|
||||||
runtime.UnlockOSThread()
|
runtime.UnlockOSThread()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -58,22 +59,23 @@ func util_putBytes(bs []byte) {
|
|||||||
var byteStore chan []byte
|
var byteStore chan []byte
|
||||||
|
|
||||||
func util_initByteStore() {
|
func util_initByteStore() {
|
||||||
if byteStore == nil {
|
if byteStore == nil {
|
||||||
byteStore = make(chan []byte, 32)
|
byteStore = make(chan []byte, 32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func util_getBytes() []byte {
|
func util_getBytes() []byte {
|
||||||
select {
|
select {
|
||||||
case bs := <-byteStore: return bs[:0]
|
case bs := <-byteStore:
|
||||||
default: return nil
|
return bs[:0]
|
||||||
}
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func util_putBytes(bs []byte) {
|
func util_putBytes(bs []byte) {
|
||||||
select {
|
select {
|
||||||
case byteStore<-bs:
|
case byteStore <- bs:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,101 +7,107 @@ package yggdrasil
|
|||||||
// TODO? make things still work after reordering (after things stabilize more?)
|
// TODO? make things still work after reordering (after things stabilize more?)
|
||||||
// Type safety would also be nice, `type wire_type uint64`, rewrite as needed?
|
// Type safety would also be nice, `type wire_type uint64`, rewrite as needed?
|
||||||
const (
|
const (
|
||||||
wire_Traffic = iota // data being routed somewhere, handle for crypto
|
wire_Traffic = iota // data being routed somewhere, handle for crypto
|
||||||
wire_ProtocolTraffic // protocol traffic, pub keys for crypto
|
wire_ProtocolTraffic // protocol traffic, pub keys for crypto
|
||||||
wire_LinkProtocolTraffic // link proto traffic, pub keys for crypto
|
wire_LinkProtocolTraffic // link proto traffic, pub keys for crypto
|
||||||
wire_SwitchAnnounce // TODO put inside protocol traffic header
|
wire_SwitchAnnounce // TODO put inside protocol traffic header
|
||||||
wire_SwitchHopRequest // TODO put inside protocol traffic header
|
wire_SwitchHopRequest // TODO put inside protocol traffic header
|
||||||
wire_SwitchHop // TODO put inside protocol traffic header
|
wire_SwitchHop // TODO put inside protocol traffic header
|
||||||
wire_SessionPing // inside protocol traffic header
|
wire_SessionPing // inside protocol traffic header
|
||||||
wire_SessionPong // inside protocol traffic header
|
wire_SessionPong // inside protocol traffic header
|
||||||
wire_DHTLookupRequest // inside protocol traffic header
|
wire_DHTLookupRequest // inside protocol traffic header
|
||||||
wire_DHTLookupResponse // inside protocol traffic header
|
wire_DHTLookupResponse // inside protocol traffic header
|
||||||
wire_SearchRequest // inside protocol traffic header
|
wire_SearchRequest // inside protocol traffic header
|
||||||
wire_SearchResponse // inside protocol traffic header
|
wire_SearchResponse // inside protocol traffic header
|
||||||
//wire_Keys // udp key packet (boxPub, sigPub)
|
//wire_Keys // udp key packet (boxPub, sigPub)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Encode uint64 using a variable length scheme
|
// Encode uint64 using a variable length scheme
|
||||||
// Similar to binary.Uvarint, but big-endian
|
// Similar to binary.Uvarint, but big-endian
|
||||||
func wire_encode_uint64(elem uint64) []byte {
|
func wire_encode_uint64(elem uint64) []byte {
|
||||||
return wire_put_uint64(elem, nil)
|
return wire_put_uint64(elem, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Occasionally useful for appending to an existing slice (if there's room)
|
// Occasionally useful for appending to an existing slice (if there's room)
|
||||||
func wire_put_uint64(elem uint64, out []byte) []byte {
|
func wire_put_uint64(elem uint64, out []byte) []byte {
|
||||||
bs := make([]byte, 0, 10)
|
bs := make([]byte, 0, 10)
|
||||||
bs = append(bs, byte(elem & 0x7f))
|
bs = append(bs, byte(elem&0x7f))
|
||||||
for e := elem >> 7 ; e > 0 ; e >>= 7 {
|
for e := elem >> 7; e > 0; e >>= 7 {
|
||||||
bs = append(bs, byte(e | 0x80))
|
bs = append(bs, byte(e|0x80))
|
||||||
}
|
}
|
||||||
// Now reverse bytes, because we set them in the wrong order
|
// Now reverse bytes, because we set them in the wrong order
|
||||||
// TODO just put them in the right place the first time...
|
// TODO just put them in the right place the first time...
|
||||||
last := len(bs)-1
|
last := len(bs) - 1
|
||||||
for idx := 0 ; idx < len(bs)/2 ; idx++ {
|
for idx := 0; idx < len(bs)/2; idx++ {
|
||||||
bs[idx], bs[last-idx] = bs[last-idx], bs[idx]
|
bs[idx], bs[last-idx] = bs[last-idx], bs[idx]
|
||||||
}
|
}
|
||||||
return append(out, bs...)
|
return append(out, bs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode uint64 from a []byte slice
|
// Decode uint64 from a []byte slice
|
||||||
// Returns the decoded uint64 and the number of bytes used
|
// Returns the decoded uint64 and the number of bytes used
|
||||||
func wire_decode_uint64(bs []byte) (uint64, int) {
|
func wire_decode_uint64(bs []byte) (uint64, int) {
|
||||||
length := 0
|
length := 0
|
||||||
elem := uint64(0)
|
elem := uint64(0)
|
||||||
for _, b := range bs {
|
for _, b := range bs {
|
||||||
elem <<= 7
|
elem <<= 7
|
||||||
elem |= uint64(b & 0x7f)
|
elem |= uint64(b & 0x7f)
|
||||||
length++
|
length++
|
||||||
if b & 0x80 == 0 { break }
|
if b&0x80 == 0 {
|
||||||
}
|
break
|
||||||
return elem, length
|
}
|
||||||
|
}
|
||||||
|
return elem, length
|
||||||
}
|
}
|
||||||
|
|
||||||
func wire_intToUint(i int64) uint64 {
|
func wire_intToUint(i int64) uint64 {
|
||||||
var u uint64
|
var u uint64
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
u = uint64(-i) << 1
|
u = uint64(-i) << 1
|
||||||
u |= 0x01 // sign bit
|
u |= 0x01 // sign bit
|
||||||
} else {
|
} else {
|
||||||
u = uint64(i) << 1
|
u = uint64(i) << 1
|
||||||
}
|
}
|
||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
func wire_intFromUint(u uint64) int64 {
|
func wire_intFromUint(u uint64) int64 {
|
||||||
var i int64
|
var i int64
|
||||||
i = int64(u >> 1)
|
i = int64(u >> 1)
|
||||||
if u & 0x01 != 0 { i *= -1 }
|
if u&0x01 != 0 {
|
||||||
return i
|
i *= -1
|
||||||
|
}
|
||||||
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Takes coords, returns coords prefixed with encoded coord length
|
// Takes coords, returns coords prefixed with encoded coord length
|
||||||
func wire_encode_coords(coords []byte) ([]byte) {
|
func wire_encode_coords(coords []byte) []byte {
|
||||||
coordLen := wire_encode_uint64(uint64(len(coords)))
|
coordLen := wire_encode_uint64(uint64(len(coords)))
|
||||||
bs := make([]byte, 0, len(coordLen)+len(coords))
|
bs := make([]byte, 0, len(coordLen)+len(coords))
|
||||||
bs = append(bs, coordLen...)
|
bs = append(bs, coordLen...)
|
||||||
bs = append(bs, coords...)
|
bs = append(bs, coords...)
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
func wire_put_coords(coords []byte, bs []byte) ([]byte) {
|
func wire_put_coords(coords []byte, bs []byte) []byte {
|
||||||
bs = wire_put_uint64(uint64(len(coords)), bs)
|
bs = wire_put_uint64(uint64(len(coords)), bs)
|
||||||
bs = append(bs, coords...)
|
bs = append(bs, coords...)
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes a packet that begins with coords (starting with coord length)
|
// Takes a packet that begins with coords (starting with coord length)
|
||||||
// Returns a slice of coords and the number of bytes read
|
// Returns a slice of coords and the number of bytes read
|
||||||
func wire_decode_coords(packet []byte) ([]byte, int) {
|
func wire_decode_coords(packet []byte) ([]byte, int) {
|
||||||
coordLen, coordBegin := wire_decode_uint64(packet)
|
coordLen, coordBegin := wire_decode_uint64(packet)
|
||||||
coordEnd := coordBegin+int(coordLen)
|
coordEnd := coordBegin + int(coordLen)
|
||||||
//if coordBegin == 0 { panic("No coords found") } // Testing
|
//if coordBegin == 0 { panic("No coords found") } // Testing
|
||||||
//if coordEnd > len(packet) { panic("Packet too short") } // Testing
|
//if coordEnd > len(packet) { panic("Packet too short") } // Testing
|
||||||
if coordBegin == 0 || coordEnd > len(packet) { return nil, 0 }
|
if coordBegin == 0 || coordEnd > len(packet) {
|
||||||
return packet[coordBegin:coordEnd], coordEnd
|
return nil, 0
|
||||||
|
}
|
||||||
|
return packet[coordBegin:coordEnd], coordEnd
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -109,144 +115,171 @@ func wire_decode_coords(packet []byte) ([]byte, int) {
|
|||||||
|
|
||||||
// Announces that we can send parts of a Message with a particular seq
|
// Announces that we can send parts of a Message with a particular seq
|
||||||
type msgAnnounce struct {
|
type msgAnnounce struct {
|
||||||
root sigPubKey
|
root sigPubKey
|
||||||
tstamp int64
|
tstamp int64
|
||||||
seq uint64
|
seq uint64
|
||||||
len uint64
|
len uint64
|
||||||
//Deg uint64
|
//Deg uint64
|
||||||
//RSeq uint64
|
//RSeq uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *msgAnnounce) encode() []byte {
|
func (m *msgAnnounce) encode() []byte {
|
||||||
bs := wire_encode_uint64(wire_SwitchAnnounce)
|
bs := wire_encode_uint64(wire_SwitchAnnounce)
|
||||||
bs = append(bs, m.root[:]...)
|
bs = append(bs, m.root[:]...)
|
||||||
bs = append(bs, wire_encode_uint64(wire_intToUint(m.tstamp))...)
|
bs = append(bs, wire_encode_uint64(wire_intToUint(m.tstamp))...)
|
||||||
bs = append(bs, wire_encode_uint64(m.seq)...)
|
bs = append(bs, wire_encode_uint64(m.seq)...)
|
||||||
bs = append(bs, wire_encode_uint64(m.len)...)
|
bs = append(bs, wire_encode_uint64(m.len)...)
|
||||||
//bs = append(bs, wire_encode_uint64(m.Deg)...)
|
//bs = append(bs, wire_encode_uint64(m.Deg)...)
|
||||||
//bs = append(bs, wire_encode_uint64(m.RSeq)...)
|
//bs = append(bs, wire_encode_uint64(m.RSeq)...)
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *msgAnnounce) decode(bs []byte) bool {
|
func (m *msgAnnounce) decode(bs []byte) bool {
|
||||||
var pType uint64
|
var pType uint64
|
||||||
var tstamp uint64
|
var tstamp uint64
|
||||||
switch {
|
switch {
|
||||||
case !wire_chop_uint64(&pType, &bs): return false
|
case !wire_chop_uint64(&pType, &bs):
|
||||||
case pType != wire_SwitchAnnounce: return false
|
return false
|
||||||
case !wire_chop_slice(m.root[:], &bs): return false
|
case pType != wire_SwitchAnnounce:
|
||||||
case !wire_chop_uint64(&tstamp, &bs): return false
|
return false
|
||||||
case !wire_chop_uint64(&m.seq, &bs): return false
|
case !wire_chop_slice(m.root[:], &bs):
|
||||||
case !wire_chop_uint64(&m.len, &bs): return false
|
return false
|
||||||
//case !wire_chop_uint64(&m.Deg, &bs): return false
|
case !wire_chop_uint64(&tstamp, &bs):
|
||||||
//case !wire_chop_uint64(&m.RSeq, &bs): return false
|
return false
|
||||||
}
|
case !wire_chop_uint64(&m.seq, &bs):
|
||||||
m.tstamp = wire_intFromUint(tstamp)
|
return false
|
||||||
return true
|
case !wire_chop_uint64(&m.len, &bs):
|
||||||
|
return false
|
||||||
|
//case !wire_chop_uint64(&m.Deg, &bs): return false
|
||||||
|
//case !wire_chop_uint64(&m.RSeq, &bs): return false
|
||||||
|
}
|
||||||
|
m.tstamp = wire_intFromUint(tstamp)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
type msgHopReq struct {
|
type msgHopReq struct {
|
||||||
root sigPubKey
|
root sigPubKey
|
||||||
tstamp int64
|
tstamp int64
|
||||||
seq uint64
|
seq uint64
|
||||||
hop uint64
|
hop uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *msgHopReq) encode() []byte {
|
func (m *msgHopReq) encode() []byte {
|
||||||
bs := wire_encode_uint64(wire_SwitchHopRequest)
|
bs := wire_encode_uint64(wire_SwitchHopRequest)
|
||||||
bs = append(bs, m.root[:]...)
|
bs = append(bs, m.root[:]...)
|
||||||
bs = append(bs, wire_encode_uint64(wire_intToUint(m.tstamp))...)
|
bs = append(bs, wire_encode_uint64(wire_intToUint(m.tstamp))...)
|
||||||
bs = append(bs, wire_encode_uint64(m.seq)...)
|
bs = append(bs, wire_encode_uint64(m.seq)...)
|
||||||
bs = append(bs, wire_encode_uint64(m.hop)...)
|
bs = append(bs, wire_encode_uint64(m.hop)...)
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *msgHopReq) decode(bs []byte) bool {
|
func (m *msgHopReq) decode(bs []byte) bool {
|
||||||
var pType uint64
|
var pType uint64
|
||||||
var tstamp uint64
|
var tstamp uint64
|
||||||
switch {
|
switch {
|
||||||
case !wire_chop_uint64(&pType, &bs): return false
|
case !wire_chop_uint64(&pType, &bs):
|
||||||
case pType != wire_SwitchHopRequest: return false
|
return false
|
||||||
case !wire_chop_slice(m.root[:], &bs): return false
|
case pType != wire_SwitchHopRequest:
|
||||||
case !wire_chop_uint64(&tstamp, &bs): return false
|
return false
|
||||||
case !wire_chop_uint64(&m.seq, &bs): return false
|
case !wire_chop_slice(m.root[:], &bs):
|
||||||
case !wire_chop_uint64(&m.hop, &bs): return false
|
return false
|
||||||
}
|
case !wire_chop_uint64(&tstamp, &bs):
|
||||||
m.tstamp = wire_intFromUint(tstamp)
|
return false
|
||||||
return true
|
case !wire_chop_uint64(&m.seq, &bs):
|
||||||
|
return false
|
||||||
|
case !wire_chop_uint64(&m.hop, &bs):
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
m.tstamp = wire_intFromUint(tstamp)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
type msgHop struct {
|
type msgHop struct {
|
||||||
root sigPubKey
|
root sigPubKey
|
||||||
tstamp int64
|
tstamp int64
|
||||||
seq uint64
|
seq uint64
|
||||||
hop uint64
|
hop uint64
|
||||||
port switchPort
|
port switchPort
|
||||||
next sigPubKey
|
next sigPubKey
|
||||||
sig sigBytes
|
sig sigBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *msgHop) encode() []byte {
|
func (m *msgHop) encode() []byte {
|
||||||
bs := wire_encode_uint64(wire_SwitchHop)
|
bs := wire_encode_uint64(wire_SwitchHop)
|
||||||
bs = append(bs, m.root[:]...)
|
bs = append(bs, m.root[:]...)
|
||||||
bs = append(bs, wire_encode_uint64(wire_intToUint(m.tstamp))...)
|
bs = append(bs, wire_encode_uint64(wire_intToUint(m.tstamp))...)
|
||||||
bs = append(bs, wire_encode_uint64(m.seq)...)
|
bs = append(bs, wire_encode_uint64(m.seq)...)
|
||||||
bs = append(bs, wire_encode_uint64(m.hop)...)
|
bs = append(bs, wire_encode_uint64(m.hop)...)
|
||||||
bs = append(bs, wire_encode_uint64(uint64(m.port))...)
|
bs = append(bs, wire_encode_uint64(uint64(m.port))...)
|
||||||
bs = append(bs, m.next[:]...)
|
bs = append(bs, m.next[:]...)
|
||||||
bs = append(bs, m.sig[:]...)
|
bs = append(bs, m.sig[:]...)
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *msgHop) decode(bs []byte) bool {
|
func (m *msgHop) decode(bs []byte) bool {
|
||||||
var pType uint64
|
var pType uint64
|
||||||
var tstamp uint64
|
var tstamp uint64
|
||||||
switch {
|
switch {
|
||||||
case !wire_chop_uint64(&pType, &bs): return false
|
case !wire_chop_uint64(&pType, &bs):
|
||||||
case pType != wire_SwitchHop: return false
|
return false
|
||||||
case !wire_chop_slice(m.root[:], &bs): return false
|
case pType != wire_SwitchHop:
|
||||||
case !wire_chop_uint64(&tstamp, &bs): return false
|
return false
|
||||||
case !wire_chop_uint64(&m.seq, &bs): return false
|
case !wire_chop_slice(m.root[:], &bs):
|
||||||
case !wire_chop_uint64(&m.hop, &bs): return false
|
return false
|
||||||
case !wire_chop_uint64((*uint64)(&m.port), &bs): return false
|
case !wire_chop_uint64(&tstamp, &bs):
|
||||||
case !wire_chop_slice(m.next[:], &bs): return false
|
return false
|
||||||
case !wire_chop_slice(m.sig[:], &bs): return false
|
case !wire_chop_uint64(&m.seq, &bs):
|
||||||
}
|
return false
|
||||||
m.tstamp = wire_intFromUint(tstamp)
|
case !wire_chop_uint64(&m.hop, &bs):
|
||||||
return true
|
return false
|
||||||
|
case !wire_chop_uint64((*uint64)(&m.port), &bs):
|
||||||
|
return false
|
||||||
|
case !wire_chop_slice(m.next[:], &bs):
|
||||||
|
return false
|
||||||
|
case !wire_chop_slice(m.sig[:], &bs):
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
m.tstamp = wire_intFromUint(tstamp)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format used to check signatures only, so no need to also support decoding
|
// Format used to check signatures only, so no need to also support decoding
|
||||||
func wire_encode_locator(loc *switchLocator) []byte {
|
func wire_encode_locator(loc *switchLocator) []byte {
|
||||||
coords := wire_encode_coords(loc.getCoords())
|
coords := wire_encode_coords(loc.getCoords())
|
||||||
var bs []byte
|
var bs []byte
|
||||||
bs = append(bs, loc.root[:]...)
|
bs = append(bs, loc.root[:]...)
|
||||||
bs = append(bs, wire_encode_uint64(wire_intToUint(loc.tstamp))...)
|
bs = append(bs, wire_encode_uint64(wire_intToUint(loc.tstamp))...)
|
||||||
bs = append(bs, coords...)
|
bs = append(bs, coords...)
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
func wire_chop_slice(toSlice []byte, fromSlice *[]byte) bool {
|
func wire_chop_slice(toSlice []byte, fromSlice *[]byte) bool {
|
||||||
if len(*fromSlice) < len(toSlice) { return false }
|
if len(*fromSlice) < len(toSlice) {
|
||||||
copy(toSlice, *fromSlice)
|
return false
|
||||||
*fromSlice = (*fromSlice)[len(toSlice):]
|
}
|
||||||
return true
|
copy(toSlice, *fromSlice)
|
||||||
|
*fromSlice = (*fromSlice)[len(toSlice):]
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func wire_chop_coords(toCoords *[]byte, fromSlice *[]byte) bool {
|
func wire_chop_coords(toCoords *[]byte, fromSlice *[]byte) bool {
|
||||||
coords, coordLen := wire_decode_coords(*fromSlice)
|
coords, coordLen := wire_decode_coords(*fromSlice)
|
||||||
if coordLen == 0 { return false }
|
if coordLen == 0 {
|
||||||
*toCoords = append((*toCoords)[:0], coords...)
|
return false
|
||||||
*fromSlice = (*fromSlice)[coordLen:]
|
}
|
||||||
return true
|
*toCoords = append((*toCoords)[:0], coords...)
|
||||||
|
*fromSlice = (*fromSlice)[coordLen:]
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func wire_chop_uint64(toUInt64 *uint64, fromSlice *[]byte) bool {
|
func wire_chop_uint64(toUInt64 *uint64, fromSlice *[]byte) bool {
|
||||||
dec, decLen := wire_decode_uint64(*fromSlice)
|
dec, decLen := wire_decode_uint64(*fromSlice)
|
||||||
if decLen == 0 { return false }
|
if decLen == 0 {
|
||||||
*toUInt64 = dec
|
return false
|
||||||
*fromSlice = (*fromSlice)[decLen:]
|
}
|
||||||
return true
|
*toUInt64 = dec
|
||||||
|
*fromSlice = (*fromSlice)[decLen:]
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -254,239 +287,289 @@ func wire_chop_uint64(toUInt64 *uint64, fromSlice *[]byte) bool {
|
|||||||
// Wire traffic packets
|
// Wire traffic packets
|
||||||
|
|
||||||
type wire_trafficPacket struct {
|
type wire_trafficPacket struct {
|
||||||
ttl uint64 // TODO? hide this as a wire format detail, not set by user
|
ttl uint64 // TODO? hide this as a wire format detail, not set by user
|
||||||
coords []byte
|
coords []byte
|
||||||
handle handle
|
handle handle
|
||||||
nonce boxNonce
|
nonce boxNonce
|
||||||
payload []byte
|
payload []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is basically MarshalBinary, but decode doesn't allow that...
|
// This is basically MarshalBinary, but decode doesn't allow that...
|
||||||
func (p *wire_trafficPacket) encode() []byte {
|
func (p *wire_trafficPacket) encode() []byte {
|
||||||
bs := util_getBytes()
|
bs := util_getBytes()
|
||||||
bs = wire_put_uint64(wire_Traffic, bs)
|
bs = wire_put_uint64(wire_Traffic, bs)
|
||||||
bs = wire_put_uint64(p.ttl, bs)
|
bs = wire_put_uint64(p.ttl, bs)
|
||||||
bs = wire_put_coords(p.coords, bs)
|
bs = wire_put_coords(p.coords, bs)
|
||||||
bs = append(bs, p.handle[:]...)
|
bs = append(bs, p.handle[:]...)
|
||||||
bs = append(bs, p.nonce[:]...)
|
bs = append(bs, p.nonce[:]...)
|
||||||
bs = append(bs, p.payload...)
|
bs = append(bs, p.payload...)
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not just UnmarshalBinary becuase the original slice isn't always copied from
|
// Not just UnmarshalBinary becuase the original slice isn't always copied from
|
||||||
func (p *wire_trafficPacket) decode(bs []byte) bool {
|
func (p *wire_trafficPacket) decode(bs []byte) bool {
|
||||||
var pType uint64
|
var pType uint64
|
||||||
switch {
|
switch {
|
||||||
case !wire_chop_uint64(&pType, &bs): return false
|
case !wire_chop_uint64(&pType, &bs):
|
||||||
case pType != wire_Traffic: return false
|
return false
|
||||||
case !wire_chop_uint64(&p.ttl, &bs): return false
|
case pType != wire_Traffic:
|
||||||
case !wire_chop_coords(&p.coords, &bs): return false
|
return false
|
||||||
case !wire_chop_slice(p.handle[:], &bs): return false
|
case !wire_chop_uint64(&p.ttl, &bs):
|
||||||
case !wire_chop_slice(p.nonce[:], &bs): return false
|
return false
|
||||||
}
|
case !wire_chop_coords(&p.coords, &bs):
|
||||||
p.payload = append(util_getBytes(), bs...)
|
return false
|
||||||
return true
|
case !wire_chop_slice(p.handle[:], &bs):
|
||||||
|
return false
|
||||||
|
case !wire_chop_slice(p.nonce[:], &bs):
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
p.payload = append(util_getBytes(), bs...)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
type wire_protoTrafficPacket struct {
|
type wire_protoTrafficPacket struct {
|
||||||
ttl uint64 // TODO? hide this as a wire format detail, not set by user
|
ttl uint64 // TODO? hide this as a wire format detail, not set by user
|
||||||
coords []byte
|
coords []byte
|
||||||
toKey boxPubKey
|
toKey boxPubKey
|
||||||
fromKey boxPubKey
|
fromKey boxPubKey
|
||||||
nonce boxNonce
|
nonce boxNonce
|
||||||
payload []byte
|
payload []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *wire_protoTrafficPacket) encode() []byte {
|
func (p *wire_protoTrafficPacket) encode() []byte {
|
||||||
coords := wire_encode_coords(p.coords)
|
coords := wire_encode_coords(p.coords)
|
||||||
bs := wire_encode_uint64(wire_ProtocolTraffic)
|
bs := wire_encode_uint64(wire_ProtocolTraffic)
|
||||||
bs = append(bs, wire_encode_uint64(p.ttl)...)
|
bs = append(bs, wire_encode_uint64(p.ttl)...)
|
||||||
bs = append(bs, coords...)
|
bs = append(bs, coords...)
|
||||||
bs = append(bs, p.toKey[:]...)
|
bs = append(bs, p.toKey[:]...)
|
||||||
bs = append(bs, p.fromKey[:]...)
|
bs = append(bs, p.fromKey[:]...)
|
||||||
bs = append(bs, p.nonce[:]...)
|
bs = append(bs, p.nonce[:]...)
|
||||||
bs = append(bs, p.payload...)
|
bs = append(bs, p.payload...)
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
func(p *wire_protoTrafficPacket) decode(bs []byte) bool {
|
func (p *wire_protoTrafficPacket) decode(bs []byte) bool {
|
||||||
var pType uint64
|
var pType uint64
|
||||||
switch {
|
switch {
|
||||||
case !wire_chop_uint64(&pType, &bs): return false
|
case !wire_chop_uint64(&pType, &bs):
|
||||||
case pType != wire_ProtocolTraffic: return false
|
return false
|
||||||
case !wire_chop_uint64(&p.ttl, &bs): return false
|
case pType != wire_ProtocolTraffic:
|
||||||
case !wire_chop_coords(&p.coords, &bs): return false
|
return false
|
||||||
case !wire_chop_slice(p.toKey[:], &bs): return false
|
case !wire_chop_uint64(&p.ttl, &bs):
|
||||||
case !wire_chop_slice(p.fromKey[:], &bs): return false
|
return false
|
||||||
case !wire_chop_slice(p.nonce[:], &bs): return false
|
case !wire_chop_coords(&p.coords, &bs):
|
||||||
}
|
return false
|
||||||
p.payload = bs
|
case !wire_chop_slice(p.toKey[:], &bs):
|
||||||
return true
|
return false
|
||||||
|
case !wire_chop_slice(p.fromKey[:], &bs):
|
||||||
|
return false
|
||||||
|
case !wire_chop_slice(p.nonce[:], &bs):
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
p.payload = bs
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
type wire_linkProtoTrafficPacket struct {
|
type wire_linkProtoTrafficPacket struct {
|
||||||
toKey boxPubKey
|
toKey boxPubKey
|
||||||
fromKey boxPubKey
|
fromKey boxPubKey
|
||||||
nonce boxNonce
|
nonce boxNonce
|
||||||
payload []byte
|
payload []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *wire_linkProtoTrafficPacket) encode() []byte {
|
func (p *wire_linkProtoTrafficPacket) encode() []byte {
|
||||||
bs := wire_encode_uint64(wire_LinkProtocolTraffic)
|
bs := wire_encode_uint64(wire_LinkProtocolTraffic)
|
||||||
bs = append(bs, p.toKey[:]...)
|
bs = append(bs, p.toKey[:]...)
|
||||||
bs = append(bs, p.fromKey[:]...)
|
bs = append(bs, p.fromKey[:]...)
|
||||||
bs = append(bs, p.nonce[:]...)
|
bs = append(bs, p.nonce[:]...)
|
||||||
bs = append(bs, p.payload...)
|
bs = append(bs, p.payload...)
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
func(p *wire_linkProtoTrafficPacket) decode(bs []byte) bool {
|
func (p *wire_linkProtoTrafficPacket) decode(bs []byte) bool {
|
||||||
var pType uint64
|
var pType uint64
|
||||||
switch {
|
switch {
|
||||||
case !wire_chop_uint64(&pType, &bs): return false
|
case !wire_chop_uint64(&pType, &bs):
|
||||||
case pType != wire_LinkProtocolTraffic: return false
|
return false
|
||||||
case !wire_chop_slice(p.toKey[:], &bs): return false
|
case pType != wire_LinkProtocolTraffic:
|
||||||
case !wire_chop_slice(p.fromKey[:], &bs): return false
|
return false
|
||||||
case !wire_chop_slice(p.nonce[:], &bs): return false
|
case !wire_chop_slice(p.toKey[:], &bs):
|
||||||
}
|
return false
|
||||||
p.payload = bs
|
case !wire_chop_slice(p.fromKey[:], &bs):
|
||||||
return true
|
return false
|
||||||
|
case !wire_chop_slice(p.nonce[:], &bs):
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
p.payload = bs
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
func (p *sessionPing) encode() []byte {
|
func (p *sessionPing) encode() []byte {
|
||||||
var pTypeVal uint64
|
var pTypeVal uint64
|
||||||
if p.isPong {
|
if p.isPong {
|
||||||
pTypeVal = wire_SessionPong
|
pTypeVal = wire_SessionPong
|
||||||
} else {
|
} else {
|
||||||
pTypeVal = wire_SessionPing
|
pTypeVal = wire_SessionPing
|
||||||
}
|
}
|
||||||
bs := wire_encode_uint64(pTypeVal)
|
bs := wire_encode_uint64(pTypeVal)
|
||||||
//p.sendPermPub used in top level (crypto), so skipped here
|
//p.sendPermPub used in top level (crypto), so skipped here
|
||||||
bs = append(bs, p.handle[:]...)
|
bs = append(bs, p.handle[:]...)
|
||||||
bs = append(bs, p.sendSesPub[:]...)
|
bs = append(bs, p.sendSesPub[:]...)
|
||||||
bs = append(bs, wire_encode_uint64(wire_intToUint(p.tstamp))...)
|
bs = append(bs, wire_encode_uint64(wire_intToUint(p.tstamp))...)
|
||||||
coords := wire_encode_coords(p.coords)
|
coords := wire_encode_coords(p.coords)
|
||||||
bs = append(bs, coords...)
|
bs = append(bs, coords...)
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *sessionPing) decode(bs []byte) bool {
|
func (p *sessionPing) decode(bs []byte) bool {
|
||||||
var pType uint64
|
var pType uint64
|
||||||
var tstamp uint64
|
var tstamp uint64
|
||||||
switch {
|
switch {
|
||||||
case !wire_chop_uint64(&pType, &bs): return false
|
case !wire_chop_uint64(&pType, &bs):
|
||||||
case pType != wire_SessionPing && pType != wire_SessionPong: return false
|
return false
|
||||||
//p.sendPermPub used in top level (crypto), so skipped here
|
case pType != wire_SessionPing && pType != wire_SessionPong:
|
||||||
case !wire_chop_slice(p.handle[:], &bs): return false
|
return false
|
||||||
case !wire_chop_slice(p.sendSesPub[:], &bs): return false
|
//p.sendPermPub used in top level (crypto), so skipped here
|
||||||
case !wire_chop_uint64(&tstamp, &bs): return false
|
case !wire_chop_slice(p.handle[:], &bs):
|
||||||
case !wire_chop_coords(&p.coords, &bs): return false
|
return false
|
||||||
}
|
case !wire_chop_slice(p.sendSesPub[:], &bs):
|
||||||
p.tstamp = wire_intFromUint(tstamp)
|
return false
|
||||||
if pType == wire_SessionPong { p.isPong = true }
|
case !wire_chop_uint64(&tstamp, &bs):
|
||||||
return true
|
return false
|
||||||
|
case !wire_chop_coords(&p.coords, &bs):
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
p.tstamp = wire_intFromUint(tstamp)
|
||||||
|
if pType == wire_SessionPong {
|
||||||
|
p.isPong = true
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
func (r *dhtReq) encode() []byte {
|
func (r *dhtReq) encode() []byte {
|
||||||
coords := wire_encode_coords(r.coords)
|
coords := wire_encode_coords(r.coords)
|
||||||
bs := wire_encode_uint64(wire_DHTLookupRequest)
|
bs := wire_encode_uint64(wire_DHTLookupRequest)
|
||||||
bs = append(bs, r.key[:]...)
|
bs = append(bs, r.key[:]...)
|
||||||
bs = append(bs, coords...)
|
bs = append(bs, coords...)
|
||||||
bs = append(bs, r.dest[:]...)
|
bs = append(bs, r.dest[:]...)
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *dhtReq) decode(bs []byte) bool {
|
func (r *dhtReq) decode(bs []byte) bool {
|
||||||
var pType uint64
|
var pType uint64
|
||||||
switch {
|
switch {
|
||||||
case !wire_chop_uint64(&pType, &bs): return false
|
case !wire_chop_uint64(&pType, &bs):
|
||||||
case pType != wire_DHTLookupRequest: return false
|
return false
|
||||||
case !wire_chop_slice(r.key[:], &bs): return false
|
case pType != wire_DHTLookupRequest:
|
||||||
case !wire_chop_coords(&r.coords, &bs): return false
|
return false
|
||||||
case !wire_chop_slice(r.dest[:], &bs): return false
|
case !wire_chop_slice(r.key[:], &bs):
|
||||||
default: return true
|
return false
|
||||||
}
|
case !wire_chop_coords(&r.coords, &bs):
|
||||||
|
return false
|
||||||
|
case !wire_chop_slice(r.dest[:], &bs):
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *dhtRes) encode() []byte {
|
func (r *dhtRes) encode() []byte {
|
||||||
coords := wire_encode_coords(r.coords)
|
coords := wire_encode_coords(r.coords)
|
||||||
bs := wire_encode_uint64(wire_DHTLookupResponse)
|
bs := wire_encode_uint64(wire_DHTLookupResponse)
|
||||||
bs = append(bs, r.key[:]...)
|
bs = append(bs, r.key[:]...)
|
||||||
bs = append(bs, coords...)
|
bs = append(bs, coords...)
|
||||||
bs = append(bs, r.dest[:]...)
|
bs = append(bs, r.dest[:]...)
|
||||||
for _, info := range r.infos {
|
for _, info := range r.infos {
|
||||||
coords = wire_encode_coords(info.coords)
|
coords = wire_encode_coords(info.coords)
|
||||||
bs = append(bs, info.key[:]...)
|
bs = append(bs, info.key[:]...)
|
||||||
bs = append(bs, coords...)
|
bs = append(bs, coords...)
|
||||||
}
|
}
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *dhtRes) decode(bs []byte) bool {
|
func (r *dhtRes) decode(bs []byte) bool {
|
||||||
var pType uint64
|
var pType uint64
|
||||||
switch {
|
switch {
|
||||||
case !wire_chop_uint64(&pType, &bs): return false
|
case !wire_chop_uint64(&pType, &bs):
|
||||||
case pType != wire_DHTLookupResponse: return false
|
return false
|
||||||
case !wire_chop_slice(r.key[:], &bs): return false
|
case pType != wire_DHTLookupResponse:
|
||||||
case !wire_chop_coords(&r.coords, &bs): return false
|
return false
|
||||||
case !wire_chop_slice(r.dest[:], &bs): return false
|
case !wire_chop_slice(r.key[:], &bs):
|
||||||
}
|
return false
|
||||||
for len(bs) > 0 {
|
case !wire_chop_coords(&r.coords, &bs):
|
||||||
info := dhtInfo{}
|
return false
|
||||||
switch {
|
case !wire_chop_slice(r.dest[:], &bs):
|
||||||
case !wire_chop_slice(info.key[:], &bs): return false
|
return false
|
||||||
case !wire_chop_coords(&info.coords, &bs): return false
|
}
|
||||||
}
|
for len(bs) > 0 {
|
||||||
r.infos = append(r.infos, &info)
|
info := dhtInfo{}
|
||||||
}
|
switch {
|
||||||
return true
|
case !wire_chop_slice(info.key[:], &bs):
|
||||||
|
return false
|
||||||
|
case !wire_chop_coords(&info.coords, &bs):
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
r.infos = append(r.infos, &info)
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
func (r *searchReq) encode() []byte {
|
func (r *searchReq) encode() []byte {
|
||||||
coords := wire_encode_coords(r.coords)
|
coords := wire_encode_coords(r.coords)
|
||||||
bs := wire_encode_uint64(wire_SearchRequest)
|
bs := wire_encode_uint64(wire_SearchRequest)
|
||||||
bs = append(bs, r.key[:]...)
|
bs = append(bs, r.key[:]...)
|
||||||
bs = append(bs, coords...)
|
bs = append(bs, coords...)
|
||||||
bs = append(bs, r.dest[:]...)
|
bs = append(bs, r.dest[:]...)
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *searchReq) decode(bs []byte) bool {
|
func (r *searchReq) decode(bs []byte) bool {
|
||||||
var pType uint64
|
var pType uint64
|
||||||
switch {
|
switch {
|
||||||
case !wire_chop_uint64(&pType, &bs): return false
|
case !wire_chop_uint64(&pType, &bs):
|
||||||
case pType != wire_SearchRequest: return false
|
return false
|
||||||
case !wire_chop_slice(r.key[:], &bs): return false
|
case pType != wire_SearchRequest:
|
||||||
case !wire_chop_coords(&r.coords, &bs): return false
|
return false
|
||||||
case !wire_chop_slice(r.dest[:], &bs): return false
|
case !wire_chop_slice(r.key[:], &bs):
|
||||||
default: return true
|
return false
|
||||||
}
|
case !wire_chop_coords(&r.coords, &bs):
|
||||||
|
return false
|
||||||
|
case !wire_chop_slice(r.dest[:], &bs):
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *searchRes) encode() []byte {
|
func (r *searchRes) encode() []byte {
|
||||||
coords := wire_encode_coords(r.coords)
|
coords := wire_encode_coords(r.coords)
|
||||||
bs := wire_encode_uint64(wire_SearchResponse)
|
bs := wire_encode_uint64(wire_SearchResponse)
|
||||||
bs = append(bs, r.key[:]...)
|
bs = append(bs, r.key[:]...)
|
||||||
bs = append(bs, coords...)
|
bs = append(bs, coords...)
|
||||||
bs = append(bs, r.dest[:]...)
|
bs = append(bs, r.dest[:]...)
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *searchRes) decode(bs []byte) bool {
|
func (r *searchRes) decode(bs []byte) bool {
|
||||||
var pType uint64
|
var pType uint64
|
||||||
switch {
|
switch {
|
||||||
case !wire_chop_uint64(&pType, &bs): return false
|
case !wire_chop_uint64(&pType, &bs):
|
||||||
case pType != wire_SearchResponse: return false
|
return false
|
||||||
case !wire_chop_slice(r.key[:], &bs): return false
|
case pType != wire_SearchResponse:
|
||||||
case !wire_chop_coords(&r.coords, &bs): return false
|
return false
|
||||||
case !wire_chop_slice(r.dest[:], &bs): return false
|
case !wire_chop_slice(r.key[:], &bs):
|
||||||
default: return true
|
return false
|
||||||
}
|
case !wire_chop_coords(&r.coords, &bs):
|
||||||
|
return false
|
||||||
|
case !wire_chop_slice(r.dest[:], &bs):
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
359
yggdrasil.go
359
yggdrasil.go
@ -25,131 +25,172 @@ import . "yggdrasil"
|
|||||||
* It can generate a new config (--genconf)
|
* It can generate a new config (--genconf)
|
||||||
* It can read a config from stdin (--useconf)
|
* It can read a config from stdin (--useconf)
|
||||||
* It can run with an automatic config (--autoconf)
|
* It can run with an automatic config (--autoconf)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type nodeConfig struct {
|
type nodeConfig struct {
|
||||||
Listen string
|
Listen string
|
||||||
Peers []string
|
Peers []string
|
||||||
BoxPub string
|
BoxPub string
|
||||||
BoxPriv string
|
BoxPriv string
|
||||||
SigPub string
|
SigPub string
|
||||||
SigPriv string
|
SigPriv string
|
||||||
Multicast bool
|
Multicast bool
|
||||||
|
IfName string
|
||||||
}
|
}
|
||||||
|
|
||||||
type node struct {
|
type node struct {
|
||||||
core Core
|
core Core
|
||||||
sock *ipv6.PacketConn
|
sock *ipv6.PacketConn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *node) init(cfg *nodeConfig, logger *log.Logger) {
|
func (n *node) init(cfg *nodeConfig, logger *log.Logger) {
|
||||||
boxPub, err := hex.DecodeString(cfg.BoxPub)
|
boxPub, err := hex.DecodeString(cfg.BoxPub)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
boxPriv, err := hex.DecodeString(cfg.BoxPriv)
|
panic(err)
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
sigPub, err := hex.DecodeString(cfg.SigPub)
|
boxPriv, err := hex.DecodeString(cfg.BoxPriv)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
sigPriv, err := hex.DecodeString(cfg.SigPriv)
|
panic(err)
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
n.core.DEBUG_init(boxPub, boxPriv, sigPub, sigPriv)
|
sigPub, err := hex.DecodeString(cfg.SigPub)
|
||||||
n.core.DEBUG_setLogger(logger)
|
if err != nil {
|
||||||
logger.Println("Starting interface...")
|
panic(err)
|
||||||
n.core.DEBUG_setupAndStartGlobalUDPInterface(cfg.Listen)
|
}
|
||||||
logger.Println("Started interface")
|
sigPriv, err := hex.DecodeString(cfg.SigPriv)
|
||||||
go func () {
|
if err != nil {
|
||||||
if len(cfg.Peers) == 0 { return }
|
panic(err)
|
||||||
for {
|
}
|
||||||
for _, p := range cfg.Peers {
|
n.core.DEBUG_init(boxPub, boxPriv, sigPub, sigPriv)
|
||||||
n.core.DEBUG_maybeSendUDPKeys(p)
|
n.core.DEBUG_setLogger(logger)
|
||||||
time.Sleep(time.Second)
|
logger.Println("Starting interface...")
|
||||||
}
|
n.core.DEBUG_setupAndStartGlobalUDPInterface(cfg.Listen)
|
||||||
time.Sleep(time.Minute)
|
logger.Println("Started interface")
|
||||||
}
|
go func() {
|
||||||
}()
|
if len(cfg.Peers) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
for _, p := range cfg.Peers {
|
||||||
|
n.core.DEBUG_maybeSendUDPKeys(p)
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
time.Sleep(time.Minute)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateConfig() *nodeConfig {
|
func generateConfig() *nodeConfig {
|
||||||
core := Core{}
|
core := Core{}
|
||||||
bpub, bpriv := core.DEBUG_newBoxKeys()
|
bpub, bpriv := core.DEBUG_newBoxKeys()
|
||||||
spub, spriv := core.DEBUG_newSigKeys()
|
spub, spriv := core.DEBUG_newSigKeys()
|
||||||
cfg := nodeConfig{}
|
cfg := nodeConfig{}
|
||||||
cfg.Listen = "[::]:0"
|
cfg.Listen = "[::]:0"
|
||||||
cfg.BoxPub = hex.EncodeToString(bpub[:])
|
cfg.BoxPub = hex.EncodeToString(bpub[:])
|
||||||
cfg.BoxPriv = hex.EncodeToString(bpriv[:])
|
cfg.BoxPriv = hex.EncodeToString(bpriv[:])
|
||||||
cfg.SigPub = hex.EncodeToString(spub[:])
|
cfg.SigPub = hex.EncodeToString(spub[:])
|
||||||
cfg.SigPriv = hex.EncodeToString(spriv[:])
|
cfg.SigPriv = hex.EncodeToString(spriv[:])
|
||||||
cfg.Peers = []string{}
|
cfg.Peers = []string{}
|
||||||
cfg.Multicast = true
|
cfg.Multicast = true
|
||||||
return &cfg
|
cfg.IfName = "auto"
|
||||||
|
return &cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
func doGenconf() string {
|
func doGenconf() string {
|
||||||
cfg := generateConfig()
|
cfg := generateConfig()
|
||||||
bs, err := json.MarshalIndent(cfg, "", " ")
|
bs, err := json.MarshalIndent(cfg, "", " ")
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
return string(bs)
|
panic(err)
|
||||||
|
}
|
||||||
|
return string(bs)
|
||||||
}
|
}
|
||||||
|
|
||||||
var multicastAddr = "[ff02::114]:9001"
|
var multicastAddr = "[ff02::114]:9001"
|
||||||
|
|
||||||
func (n *node) listen() {
|
func (n *node) listen() {
|
||||||
groupAddr, err := net.ResolveUDPAddr("udp6", multicastAddr)
|
groupAddr, err := net.ResolveUDPAddr("udp6", multicastAddr)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
bs := make([]byte, 2048)
|
panic(err)
|
||||||
for {
|
}
|
||||||
nBytes, rcm, fromAddr, err := n.sock.ReadFrom(bs)
|
bs := make([]byte, 2048)
|
||||||
if err != nil { panic(err) }
|
for {
|
||||||
//if rcm == nil { continue } // wat
|
nBytes, rcm, fromAddr, err := n.sock.ReadFrom(bs)
|
||||||
//fmt.Println("DEBUG:", "packet from:", fromAddr.String())
|
if err != nil {
|
||||||
if !rcm.Dst.IsLinkLocalMulticast() { continue }
|
panic(err)
|
||||||
if !rcm.Dst.Equal(groupAddr.IP) { continue }
|
}
|
||||||
anAddr := string(bs[:nBytes])
|
//if rcm == nil { continue } // wat
|
||||||
addr, err := net.ResolveUDPAddr("udp6", anAddr)
|
//fmt.Println("DEBUG:", "packet from:", fromAddr.String())
|
||||||
if err != nil { panic(err) ; continue } // Panic for testing, remove later
|
if !rcm.Dst.IsLinkLocalMulticast() {
|
||||||
from := fromAddr.(*net.UDPAddr)
|
continue
|
||||||
//fmt.Println("DEBUG:", "heard:", addr.IP.String(), "from:", from.IP.String())
|
}
|
||||||
if addr.IP.String() != from.IP.String() { continue }
|
if !rcm.Dst.Equal(groupAddr.IP) {
|
||||||
addr.Zone = from.Zone
|
continue
|
||||||
saddr := addr.String()
|
}
|
||||||
//if _, isIn := n.peers[saddr]; isIn { continue }
|
anAddr := string(bs[:nBytes])
|
||||||
//n.peers[saddr] = struct{}{}
|
addr, err := net.ResolveUDPAddr("udp6", anAddr)
|
||||||
n.core.DEBUG_maybeSendUDPKeys(saddr)
|
if err != nil {
|
||||||
//fmt.Println("DEBUG:", "added multicast peer:", saddr)
|
panic(err)
|
||||||
}
|
continue
|
||||||
|
} // Panic for testing, remove later
|
||||||
|
from := fromAddr.(*net.UDPAddr)
|
||||||
|
//fmt.Println("DEBUG:", "heard:", addr.IP.String(), "from:", from.IP.String())
|
||||||
|
if addr.IP.String() != from.IP.String() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addr.Zone = from.Zone
|
||||||
|
saddr := addr.String()
|
||||||
|
//if _, isIn := n.peers[saddr]; isIn { continue }
|
||||||
|
//n.peers[saddr] = struct{}{}
|
||||||
|
n.core.DEBUG_maybeSendUDPKeys(saddr)
|
||||||
|
//fmt.Println("DEBUG:", "added multicast peer:", saddr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *node) announce() {
|
func (n *node) announce() {
|
||||||
groupAddr, err := net.ResolveUDPAddr("udp6", multicastAddr)
|
groupAddr, err := net.ResolveUDPAddr("udp6", multicastAddr)
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
udpaddr := n.core.DEBUG_getGlobalUDPAddr()
|
panic(err)
|
||||||
anAddr, err := net.ResolveUDPAddr("udp6", udpaddr.String())
|
}
|
||||||
if err != nil { panic(err) }
|
udpaddr := n.core.DEBUG_getGlobalUDPAddr()
|
||||||
destAddr, err := net.ResolveUDPAddr("udp6", multicastAddr)
|
anAddr, err := net.ResolveUDPAddr("udp6", udpaddr.String())
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
for {
|
panic(err)
|
||||||
ifaces, err := net.Interfaces()
|
}
|
||||||
if err != nil { panic(err) }
|
destAddr, err := net.ResolveUDPAddr("udp6", multicastAddr)
|
||||||
for _, iface := range ifaces {
|
if err != nil {
|
||||||
n.sock.JoinGroup(&iface, groupAddr)
|
panic(err)
|
||||||
//err := n.sock.JoinGroup(&iface, groupAddr)
|
}
|
||||||
//if err != nil { panic(err) }
|
for {
|
||||||
addrs, err := iface.Addrs()
|
ifaces, err := net.Interfaces()
|
||||||
if err != nil { panic(err) }
|
if err != nil {
|
||||||
for _, addr := range addrs {
|
panic(err)
|
||||||
addrIP, _, _ := net.ParseCIDR(addr.String())
|
}
|
||||||
if addrIP.To4() != nil { continue } // IPv6 only
|
for _, iface := range ifaces {
|
||||||
if !addrIP.IsLinkLocalUnicast() { continue }
|
n.sock.JoinGroup(&iface, groupAddr)
|
||||||
anAddr.IP = addrIP
|
//err := n.sock.JoinGroup(&iface, groupAddr)
|
||||||
anAddr.Zone = iface.Name
|
//if err != nil { panic(err) }
|
||||||
destAddr.Zone = iface.Name
|
addrs, err := iface.Addrs()
|
||||||
msg := []byte(anAddr.String())
|
if err != nil {
|
||||||
n.sock.WriteTo(msg, nil, destAddr)
|
panic(err)
|
||||||
break
|
}
|
||||||
}
|
for _, addr := range addrs {
|
||||||
time.Sleep(time.Second)
|
addrIP, _, _ := net.ParseCIDR(addr.String())
|
||||||
}
|
if addrIP.To4() != nil {
|
||||||
time.Sleep(time.Second)
|
continue
|
||||||
}
|
} // IPv6 only
|
||||||
|
if !addrIP.IsLinkLocalUnicast() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
anAddr.IP = addrIP
|
||||||
|
anAddr.Zone = iface.Name
|
||||||
|
destAddr.Zone = iface.Name
|
||||||
|
msg := []byte(anAddr.String())
|
||||||
|
n.sock.WriteTo(msg, nil, destAddr)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var pprof = flag.Bool("pprof", false, "Run pprof, see http://localhost:6060/debug/pprof/")
|
var pprof = flag.Bool("pprof", false, "Run pprof, see http://localhost:6060/debug/pprof/")
|
||||||
@ -158,53 +199,67 @@ var useconf = flag.Bool("useconf", false, "read config from stdin")
|
|||||||
var autoconf = flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)")
|
var autoconf = flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)")
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
var cfg *nodeConfig
|
var cfg *nodeConfig
|
||||||
switch {
|
switch {
|
||||||
case *autoconf: cfg = generateConfig()
|
case *autoconf:
|
||||||
case *useconf:
|
cfg = generateConfig()
|
||||||
config, err := ioutil.ReadAll(os.Stdin)
|
case *useconf:
|
||||||
if err != nil { panic(err) }
|
config, err := ioutil.ReadAll(os.Stdin)
|
||||||
decoder := json.NewDecoder(bytes.NewReader(config))
|
if err != nil {
|
||||||
err = decoder.Decode(&cfg)
|
panic(err)
|
||||||
if err != nil { panic(err) }
|
}
|
||||||
case *genconf: fmt.Println(doGenconf())
|
decoder := json.NewDecoder(bytes.NewReader(config))
|
||||||
default: flag.PrintDefaults()
|
err = decoder.Decode(&cfg)
|
||||||
}
|
if err != nil {
|
||||||
if cfg == nil { return }
|
panic(err)
|
||||||
logger := log.New(os.Stdout, "", log.Flags())
|
}
|
||||||
if *pprof {
|
case *genconf:
|
||||||
runtime.SetBlockProfileRate(1)
|
fmt.Println(doGenconf())
|
||||||
go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }()
|
default:
|
||||||
}
|
flag.PrintDefaults()
|
||||||
// Setup
|
}
|
||||||
logger.Println("Initializing...")
|
if cfg == nil {
|
||||||
n := node{}
|
return
|
||||||
n.init(cfg, logger)
|
}
|
||||||
logger.Println("Starting tun...")
|
logger := log.New(os.Stdout, "", log.Flags())
|
||||||
n.core.DEBUG_startTun() // 1280, the smallest supported MTU
|
if *pprof {
|
||||||
//n.core.DEBUG_startTunWithMTU(65535) // Largest supported MTU
|
runtime.SetBlockProfileRate(1)
|
||||||
defer func() {
|
go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }()
|
||||||
logger.Println("Closing...")
|
}
|
||||||
n.core.DEBUG_stopTun()
|
// Setup
|
||||||
}()
|
logger.Println("Initializing...")
|
||||||
logger.Println("Started...")
|
n := node{}
|
||||||
if cfg.Multicast {
|
n.init(cfg, logger)
|
||||||
addr, err := net.ResolveUDPAddr("udp", multicastAddr)
|
logger.Println("Starting tun...")
|
||||||
if err != nil { panic(err) }
|
n.core.DEBUG_startTun(cfg.IfName) // 1280, the smallest supported MTU
|
||||||
listenString := fmt.Sprintf("[::]:%v", addr.Port)
|
//n.core.DEBUG_startTunWithMTU(cfg.IfName, 65535) // Largest supported MTU
|
||||||
conn, err := net.ListenPacket("udp6", listenString)
|
defer func() {
|
||||||
if err != nil { panic(err) }
|
logger.Println("Closing...")
|
||||||
//defer conn.Close() // Let it close on its own when the application exits
|
n.core.DEBUG_stopTun()
|
||||||
n.sock = ipv6.NewPacketConn(conn)
|
}()
|
||||||
if err = n.sock.SetControlMessage(ipv6.FlagDst, true) ; err != nil { panic(err) }
|
logger.Println("Started...")
|
||||||
go n.listen()
|
if cfg.Multicast {
|
||||||
go n.announce()
|
addr, err := net.ResolveUDPAddr("udp", multicastAddr)
|
||||||
}
|
if err != nil {
|
||||||
// Catch interrupt to exit gracefully
|
panic(err)
|
||||||
c := make(chan os.Signal, 1)
|
}
|
||||||
signal.Notify(c, os.Interrupt)
|
listenString := fmt.Sprintf("[::]:%v", addr.Port)
|
||||||
<-c
|
conn, err := net.ListenPacket("udp6", listenString)
|
||||||
logger.Println("Stopping...")
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
//defer conn.Close() // Let it close on its own when the application exits
|
||||||
|
n.sock = ipv6.NewPacketConn(conn)
|
||||||
|
if err = n.sock.SetControlMessage(ipv6.FlagDst, true); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
go n.listen()
|
||||||
|
go n.announce()
|
||||||
|
}
|
||||||
|
// Catch interrupt to exit gracefully
|
||||||
|
c := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(c, os.Interrupt)
|
||||||
|
<-c
|
||||||
|
logger.Println("Stopping...")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user