5
0
mirror of https://github.com/cwinfo/yggdrasil-go.git synced 2025-01-11 07:15:42 +00:00
yggdrasil-go/src/tuntap/debug.go

262 lines
5.7 KiB
Go
Raw Normal View History

2021-05-23 00:54:52 +00:00
package tuntap
import (
"encoding/hex"
"encoding/json"
"errors"
2021-05-23 00:54:52 +00:00
"time"
iwt "github.com/Arceliar/ironwood/types"
"github.com/Arceliar/phony"
)
const (
typeDebugDummy = iota
typeDebugGetSelfRequest
typeDebugGetSelfResponse
typeDebugGetPeersRequest
typeDebugGetPeersResponse
typeDebugGetDHTRequest
typeDebugGetDHTResponse
)
type reqInfo struct {
callback func([]byte)
timer *time.Timer // time.AfterFunc cleanup
2021-05-23 00:54:52 +00:00
}
type debugHandler struct {
phony.Inbox
tun *TunAdapter
sreqs struct{} // TODO
preqs map[keyArray]*reqInfo
dreqs map[keyArray]*reqInfo
}
func (d *debugHandler) init(tun *TunAdapter) {
d.tun = tun
d.preqs = make(map[keyArray]*reqInfo)
d.dreqs = make(map[keyArray]*reqInfo)
}
func (d *debugHandler) handleDebug(from phony.Actor, key keyArray, bs []byte) {
d.Act(from, func() {
d._handleDebug(key, bs)
})
}
func (d *debugHandler) _handleDebug(key keyArray, bs []byte) {
if len(bs) == 0 {
return
}
switch bs[0] {
case typeDebugDummy:
case typeDebugGetSelfRequest:
d._handleGetSelfRequest(key)
case typeDebugGetSelfResponse:
d._handleGetSelfResponse(key, bs[1:])
case typeDebugGetPeersRequest:
d._handleGetPeersRequest(key)
case typeDebugGetPeersResponse:
d._handleGetPeersResponse(key, bs[1:])
case typeDebugGetDHTRequest:
d._handleGetDHTRequest(key)
case typeDebugGetDHTResponse:
d._handleGetDHTResponse(key, bs[1:])
default:
}
}
func (d *debugHandler) _handleGetSelfRequest(key keyArray) {
// TODO
}
func (d *debugHandler) _handleGetSelfResponse(key keyArray, bs []byte) {
// TODO
}
func (d *debugHandler) sendGetPeersRequest(key keyArray, callback func([]byte)) {
d.Act(nil, func() {
if info := d.preqs[key]; info != nil {
info.timer.Stop()
delete(d.preqs, key)
}
info := new(reqInfo)
info.callback = callback
info.timer = time.AfterFunc(time.Minute, func() {
d.Act(nil, func() {
if d.preqs[key] == info {
delete(d.preqs, key)
}
})
})
d.preqs[key] = info
d._sendDebug(key, typeDebugGetPeersRequest, nil)
})
}
2021-05-23 00:54:52 +00:00
func (d *debugHandler) _handleGetPeersRequest(key keyArray) {
peers := d.tun.core.GetPeers()
var bs []byte
for _, p := range peers {
tmp := append(bs, p.Key[:]...)
const responseOverhead = 1
if uint64(len(tmp))+1 > d.tun.maxSessionMTU() {
break
}
bs = tmp
}
d._sendDebug(key, typeDebugGetPeersResponse, bs)
}
func (d *debugHandler) _handleGetPeersResponse(key keyArray, bs []byte) {
if info := d.preqs[key]; info != nil {
info.timer.Stop()
info.callback(bs)
2021-05-23 00:54:52 +00:00
delete(d.preqs, key)
}
}
func (d *debugHandler) sendGetDHTRequest(key keyArray, callback func([]byte)) {
d.Act(nil, func() {
if info := d.dreqs[key]; info != nil {
info.timer.Stop()
delete(d.dreqs, key)
}
info := new(reqInfo)
info.callback = callback
info.timer = time.AfterFunc(time.Minute, func() {
d.Act(nil, func() {
if d.dreqs[key] == info {
delete(d.dreqs, key)
}
})
})
d.dreqs[key] = info
d._sendDebug(key, typeDebugGetDHTRequest, nil)
})
}
2021-05-23 00:54:52 +00:00
func (d *debugHandler) _handleGetDHTRequest(key keyArray) {
dinfos := d.tun.core.GetDHT()
var bs []byte
for _, dinfo := range dinfos {
tmp := append(bs, dinfo.Key[:]...)
const responseOverhead = 1
if uint64(len(tmp))+1 > d.tun.maxSessionMTU() {
break
}
bs = tmp
}
d._sendDebug(key, typeDebugGetDHTResponse, bs)
}
func (d *debugHandler) _handleGetDHTResponse(key keyArray, bs []byte) {
if info := d.dreqs[key]; info != nil {
info.timer.Stop()
info.callback(bs)
2021-05-23 00:54:52 +00:00
delete(d.dreqs, key)
}
}
func (d *debugHandler) _sendDebug(key keyArray, dType uint8, data []byte) {
bs := append([]byte{typeSessionDebug, dType}, data...)
d.tun.core.WriteTo(bs, iwt.Addr(key[:]))
}
// Admin socket stuff
type DebugGetPeersRequest struct {
Key string `json:"key"`
}
type DebugGetPeersResponse map[string]interface{}
func (d *debugHandler) 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)
d.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
}
res := GetNodeInfoResponse{req.Key: msg}
return res, nil
}
}
type DebugGetDHTRequest struct {
Key string `json:"key"`
}
type DebugGetDHTResponse map[string]interface{}
func (d *debugHandler) 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)
d.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
}
res := GetNodeInfoResponse{req.Key: msg}
return res, nil
}
}