mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-12 22:10:28 +00:00
374 lines
8.5 KiB
Go
374 lines
8.5 KiB
Go
package core
|
|
|
|
import (
|
|
"crypto/ed25519"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"time"
|
|
|
|
iwt "github.com/Arceliar/ironwood/types"
|
|
"github.com/Arceliar/phony"
|
|
|
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
|
)
|
|
|
|
const (
|
|
typeDebugDummy = iota
|
|
typeDebugGetSelfRequest
|
|
typeDebugGetSelfResponse
|
|
typeDebugGetPeersRequest
|
|
typeDebugGetPeersResponse
|
|
typeDebugGetDHTRequest
|
|
typeDebugGetDHTResponse
|
|
)
|
|
|
|
type reqInfo struct {
|
|
callback func([]byte)
|
|
timer *time.Timer // time.AfterFunc cleanup
|
|
}
|
|
|
|
type keyArray [ed25519.PublicKeySize]byte
|
|
|
|
type protoHandler struct {
|
|
phony.Inbox
|
|
|
|
core *Core
|
|
nodeinfo nodeinfo
|
|
|
|
selfRequests map[keyArray]*reqInfo
|
|
peersRequests map[keyArray]*reqInfo
|
|
dhtRequests map[keyArray]*reqInfo
|
|
}
|
|
|
|
func (p *protoHandler) init(core *Core) {
|
|
p.core = core
|
|
p.nodeinfo.init(p)
|
|
|
|
p.selfRequests = make(map[keyArray]*reqInfo)
|
|
p.peersRequests = make(map[keyArray]*reqInfo)
|
|
p.dhtRequests = make(map[keyArray]*reqInfo)
|
|
}
|
|
|
|
// Common functions
|
|
|
|
func (p *protoHandler) handleProto(from phony.Actor, key keyArray, bs []byte) {
|
|
if len(bs) == 0 {
|
|
return
|
|
}
|
|
switch bs[0] {
|
|
case typeProtoDummy:
|
|
case typeProtoNodeInfoRequest:
|
|
p.nodeinfo.handleReq(p, key)
|
|
case typeProtoNodeInfoResponse:
|
|
p.nodeinfo.handleRes(p, key, bs[1:])
|
|
case typeProtoDebug:
|
|
p.handleDebug(from, key, bs[1:])
|
|
}
|
|
}
|
|
|
|
func (p *protoHandler) handleDebug(from phony.Actor, key keyArray, bs []byte) {
|
|
p.Act(from, func() {
|
|
p._handleDebug(key, bs)
|
|
})
|
|
}
|
|
|
|
func (p *protoHandler) _handleDebug(key keyArray, bs []byte) {
|
|
if len(bs) == 0 {
|
|
return
|
|
}
|
|
switch bs[0] {
|
|
case typeDebugDummy:
|
|
case typeDebugGetSelfRequest:
|
|
p._handleGetSelfRequest(key)
|
|
case typeDebugGetSelfResponse:
|
|
p._handleGetSelfResponse(key, bs[1:])
|
|
case typeDebugGetPeersRequest:
|
|
p._handleGetPeersRequest(key)
|
|
case typeDebugGetPeersResponse:
|
|
p._handleGetPeersResponse(key, bs[1:])
|
|
case typeDebugGetDHTRequest:
|
|
p._handleGetDHTRequest(key)
|
|
case typeDebugGetDHTResponse:
|
|
p._handleGetDHTResponse(key, bs[1:])
|
|
}
|
|
}
|
|
|
|
func (p *protoHandler) _sendDebug(key keyArray, dType uint8, data []byte) {
|
|
bs := append([]byte{typeSessionProto, typeProtoDebug, dType}, data...)
|
|
_, _ = p.core.PacketConn.WriteTo(bs, iwt.Addr(key[:]))
|
|
}
|
|
|
|
// Get self
|
|
|
|
func (p *protoHandler) sendGetSelfRequest(key keyArray, callback func([]byte)) {
|
|
p.Act(nil, func() {
|
|
if info := p.selfRequests[key]; info != nil {
|
|
info.timer.Stop()
|
|
delete(p.selfRequests, key)
|
|
}
|
|
info := new(reqInfo)
|
|
info.callback = callback
|
|
info.timer = time.AfterFunc(time.Minute, func() {
|
|
p.Act(nil, func() {
|
|
if p.selfRequests[key] == info {
|
|
delete(p.selfRequests, key)
|
|
}
|
|
})
|
|
})
|
|
p.selfRequests[key] = info
|
|
p._sendDebug(key, typeDebugGetSelfRequest, nil)
|
|
})
|
|
}
|
|
|
|
func (p *protoHandler) _handleGetSelfRequest(key keyArray) {
|
|
self := p.core.GetSelf()
|
|
res := map[string]string{
|
|
"key": hex.EncodeToString(self.Key[:]),
|
|
"coords": fmt.Sprintf("%v", self.Coords),
|
|
}
|
|
bs, err := json.Marshal(res) // FIXME this puts keys in base64, not hex
|
|
if err != nil {
|
|
return
|
|
}
|
|
p._sendDebug(key, typeDebugGetSelfResponse, bs)
|
|
}
|
|
|
|
func (p *protoHandler) _handleGetSelfResponse(key keyArray, bs []byte) {
|
|
if info := p.selfRequests[key]; info != nil {
|
|
info.timer.Stop()
|
|
info.callback(bs)
|
|
delete(p.selfRequests, key)
|
|
}
|
|
}
|
|
|
|
// Get peers
|
|
|
|
func (p *protoHandler) sendGetPeersRequest(key keyArray, callback func([]byte)) {
|
|
p.Act(nil, func() {
|
|
if info := p.peersRequests[key]; info != nil {
|
|
info.timer.Stop()
|
|
delete(p.peersRequests, key)
|
|
}
|
|
info := new(reqInfo)
|
|
info.callback = callback
|
|
info.timer = time.AfterFunc(time.Minute, func() {
|
|
p.Act(nil, func() {
|
|
if p.peersRequests[key] == info {
|
|
delete(p.peersRequests, key)
|
|
}
|
|
})
|
|
})
|
|
p.peersRequests[key] = info
|
|
p._sendDebug(key, typeDebugGetPeersRequest, nil)
|
|
})
|
|
}
|
|
|
|
func (p *protoHandler) _handleGetPeersRequest(key keyArray) {
|
|
peers := p.core.GetPeers()
|
|
var bs []byte
|
|
for _, pinfo := range peers {
|
|
tmp := append(bs, pinfo.Key[:]...)
|
|
const responseOverhead = 2 // 1 debug type, 1 getpeers type
|
|
if uint64(len(tmp))+responseOverhead > p.core.MTU() {
|
|
break
|
|
}
|
|
bs = tmp
|
|
}
|
|
p._sendDebug(key, typeDebugGetPeersResponse, bs)
|
|
}
|
|
|
|
func (p *protoHandler) _handleGetPeersResponse(key keyArray, bs []byte) {
|
|
if info := p.peersRequests[key]; info != nil {
|
|
info.timer.Stop()
|
|
info.callback(bs)
|
|
delete(p.peersRequests, key)
|
|
}
|
|
}
|
|
|
|
// Get DHT
|
|
|
|
func (p *protoHandler) sendGetDHTRequest(key keyArray, callback func([]byte)) {
|
|
p.Act(nil, func() {
|
|
if info := p.dhtRequests[key]; info != nil {
|
|
info.timer.Stop()
|
|
delete(p.dhtRequests, key)
|
|
}
|
|
info := new(reqInfo)
|
|
info.callback = callback
|
|
info.timer = time.AfterFunc(time.Minute, func() {
|
|
p.Act(nil, func() {
|
|
if p.dhtRequests[key] == info {
|
|
delete(p.dhtRequests, key)
|
|
}
|
|
})
|
|
})
|
|
p.dhtRequests[key] = info
|
|
p._sendDebug(key, typeDebugGetDHTRequest, nil)
|
|
})
|
|
}
|
|
|
|
func (p *protoHandler) _handleGetDHTRequest(key keyArray) {
|
|
dinfos := p.core.GetDHT()
|
|
var bs []byte
|
|
for _, dinfo := range dinfos {
|
|
tmp := append(bs, dinfo.Key[:]...)
|
|
const responseOverhead = 2 // 1 debug type, 1 getdht type
|
|
if uint64(len(tmp))+responseOverhead > p.core.MTU() {
|
|
break
|
|
}
|
|
bs = tmp
|
|
}
|
|
p._sendDebug(key, typeDebugGetDHTResponse, bs)
|
|
}
|
|
|
|
func (p *protoHandler) _handleGetDHTResponse(key keyArray, bs []byte) {
|
|
if info := p.dhtRequests[key]; info != nil {
|
|
info.timer.Stop()
|
|
info.callback(bs)
|
|
delete(p.dhtRequests, key)
|
|
}
|
|
}
|
|
|
|
// Admin socket stuff for "Get self"
|
|
|
|
type DebugGetSelfRequest struct {
|
|
Key string `json:"key"`
|
|
}
|
|
|
|
type DebugGetSelfResponse map[string]interface{}
|
|
|
|
func (p *protoHandler) getSelfHandler(in json.RawMessage) (interface{}, error) {
|
|
var req DebugGetSelfRequest
|
|
if err := json.Unmarshal(in, &req); err != nil {
|
|
return nil, err
|
|
}
|
|
var key keyArray
|
|
var kbs []byte
|
|
var err error
|
|
if kbs, err = hex.DecodeString(req.Key); err != nil {
|
|
return nil, err
|
|
}
|
|
copy(key[:], kbs)
|
|
ch := make(chan []byte, 1)
|
|
p.sendGetSelfRequest(key, func(info []byte) {
|
|
ch <- info
|
|
})
|
|
timer := time.NewTimer(6 * time.Second)
|
|
defer timer.Stop()
|
|
select {
|
|
case <-timer.C:
|
|
return nil, errors.New("timeout")
|
|
case info := <-ch:
|
|
var msg json.RawMessage
|
|
if err := msg.UnmarshalJSON(info); err != nil {
|
|
return nil, err
|
|
}
|
|
ip := net.IP(address.AddrForKey(kbs)[:])
|
|
res := DebugGetSelfResponse{ip.String(): msg}
|
|
return res, nil
|
|
}
|
|
}
|
|
|
|
// Admin socket stuff for "Get peers"
|
|
|
|
type DebugGetPeersRequest struct {
|
|
Key string `json:"key"`
|
|
}
|
|
|
|
type DebugGetPeersResponse map[string]interface{}
|
|
|
|
func (p *protoHandler) getPeersHandler(in json.RawMessage) (interface{}, error) {
|
|
var req DebugGetPeersRequest
|
|
if err := json.Unmarshal(in, &req); err != nil {
|
|
return nil, err
|
|
}
|
|
var key keyArray
|
|
var kbs []byte
|
|
var err error
|
|
if kbs, err = hex.DecodeString(req.Key); err != nil {
|
|
return nil, err
|
|
}
|
|
copy(key[:], kbs)
|
|
ch := make(chan []byte, 1)
|
|
p.sendGetPeersRequest(key, func(info []byte) {
|
|
ch <- info
|
|
})
|
|
timer := time.NewTimer(6 * time.Second)
|
|
defer timer.Stop()
|
|
select {
|
|
case <-timer.C:
|
|
return nil, errors.New("timeout")
|
|
case info := <-ch:
|
|
ks := make(map[string][]string)
|
|
bs := info
|
|
for len(bs) >= len(key) {
|
|
ks["keys"] = append(ks["keys"], hex.EncodeToString(bs[:len(key)]))
|
|
bs = bs[len(key):]
|
|
}
|
|
js, err := json.Marshal(ks)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var msg json.RawMessage
|
|
if err := msg.UnmarshalJSON(js); err != nil {
|
|
return nil, err
|
|
}
|
|
ip := net.IP(address.AddrForKey(kbs)[:])
|
|
res := DebugGetPeersResponse{ip.String(): msg}
|
|
return res, nil
|
|
}
|
|
}
|
|
|
|
// Admin socket stuff for "Get DHT"
|
|
|
|
type DebugGetDHTRequest struct {
|
|
Key string `json:"key"`
|
|
}
|
|
|
|
type DebugGetDHTResponse map[string]interface{}
|
|
|
|
func (p *protoHandler) getDHTHandler(in json.RawMessage) (interface{}, error) {
|
|
var req DebugGetDHTRequest
|
|
if err := json.Unmarshal(in, &req); err != nil {
|
|
return nil, err
|
|
}
|
|
var key keyArray
|
|
var kbs []byte
|
|
var err error
|
|
if kbs, err = hex.DecodeString(req.Key); err != nil {
|
|
return nil, err
|
|
}
|
|
copy(key[:], kbs)
|
|
ch := make(chan []byte, 1)
|
|
p.sendGetDHTRequest(key, func(info []byte) {
|
|
ch <- info
|
|
})
|
|
timer := time.NewTimer(6 * time.Second)
|
|
defer timer.Stop()
|
|
select {
|
|
case <-timer.C:
|
|
return nil, errors.New("timeout")
|
|
case info := <-ch:
|
|
ks := make(map[string][]string)
|
|
bs := info
|
|
for len(bs) >= len(key) {
|
|
ks["keys"] = append(ks["keys"], hex.EncodeToString(bs[:len(key)]))
|
|
bs = bs[len(key):]
|
|
}
|
|
js, err := json.Marshal(ks)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var msg json.RawMessage
|
|
if err := msg.UnmarshalJSON(js); err != nil {
|
|
return nil, err
|
|
}
|
|
ip := net.IP(address.AddrForKey(kbs)[:])
|
|
res := DebugGetDHTResponse{ip.String(): msg}
|
|
return res, nil
|
|
}
|
|
}
|