5
0
mirror of https://github.com/cwinfo/yggdrasil-go.git synced 2024-11-25 15:01:34 +00:00
yggdrasil-go/contrib/mobile/mobile.go
Neil Alexander 6d92edd405
Move src/mobile into main repository (#864)
* Move `src/mobile` into main repository

* Update go.mod/go.sum

* Move to `contrib`, separate mobile build script
2022-01-30 19:48:32 +00:00

179 lines
4.6 KiB
Go

package mobile
import (
"encoding/hex"
"encoding/json"
"fmt"
"net"
"github.com/gologme/log"
"github.com/yggdrasil-network/yggdrasil-go/src/address"
"github.com/yggdrasil-network/yggdrasil-go/src/config"
"github.com/yggdrasil-network/yggdrasil-go/src/core"
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
"github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc"
"github.com/yggdrasil-network/yggdrasil-go/src/multicast"
"github.com/yggdrasil-network/yggdrasil-go/src/version"
_ "golang.org/x/mobile/bind"
)
// Yggdrasil mobile package is meant to "plug the gap" for mobile support, as
// Gomobile will not create headers for Swift/Obj-C etc if they have complex
// (non-native) types. Therefore for iOS we will expose some nice simple
// functions. Note that in the case of iOS we handle reading/writing to/from TUN
// in Swift therefore we use the "dummy" TUN interface instead.
type Yggdrasil struct {
core core.Core
iprwc *ipv6rwc.ReadWriteCloser
config *config.NodeConfig
multicast multicast.Multicast
log MobileLogger
}
// StartAutoconfigure starts a node with a randomly generated config
func (m *Yggdrasil) StartAutoconfigure() error {
return m.StartJSON([]byte("{}"))
}
// StartJSON starts a node with the given JSON config. You can get JSON config
// (rather than HJSON) by using the GenerateConfigJSON() function
func (m *Yggdrasil) StartJSON(configjson []byte) error {
logger := log.New(m.log, "", 0)
logger.EnableLevel("error")
logger.EnableLevel("warn")
logger.EnableLevel("info")
m.config = defaults.GenerateConfig()
if err := json.Unmarshal(configjson, &m.config); err != nil {
return err
}
m.config.IfName = "none"
if err := m.core.Start(m.config, logger); err != nil {
logger.Errorln("An error occured starting Yggdrasil:", err)
return err
}
mtu := m.config.IfMTU
m.iprwc = ipv6rwc.NewReadWriteCloser(&m.core)
if m.iprwc.MaxMTU() < mtu {
mtu = m.iprwc.MaxMTU()
}
m.iprwc.SetMTU(mtu)
if len(m.config.MulticastInterfaces) > 0 {
if err := m.multicast.Init(&m.core, m.config, logger, nil); err != nil {
logger.Errorln("An error occurred initialising multicast:", err)
return err
}
if err := m.multicast.Start(); err != nil {
logger.Errorln("An error occurred starting multicast:", err)
return err
}
}
return nil
}
// Send sends a packet to Yggdrasil. It should be a fully formed
// IPv6 packet
func (m *Yggdrasil) Send(p []byte) error {
if m.iprwc == nil {
return nil
}
_, _ = m.iprwc.Write(p)
return nil
}
// Recv waits for and reads a packet coming from Yggdrasil. It
// will be a fully formed IPv6 packet
func (m *Yggdrasil) Recv() ([]byte, error) {
if m.iprwc == nil {
return nil, nil
}
var buf [65535]byte
n, _ := m.iprwc.Read(buf[:])
return buf[:n], nil
}
// Stop the mobile Yggdrasil instance
func (m *Yggdrasil) Stop() error {
logger := log.New(m.log, "", 0)
logger.EnableLevel("info")
logger.Infof("Stop the mobile Yggdrasil instance %s", "")
if err := m.multicast.Stop(); err != nil {
return err
}
m.core.Stop()
return nil
}
// GenerateConfigJSON generates mobile-friendly configuration in JSON format
func GenerateConfigJSON() []byte {
nc := defaults.GenerateConfig()
nc.IfName = "none"
if json, err := json.Marshal(nc); err == nil {
return json
}
return nil
}
// GetAddressString gets the node's IPv6 address
func (m *Yggdrasil) GetAddressString() string {
ip := m.core.Address()
return ip.String()
}
// GetSubnetString gets the node's IPv6 subnet in CIDR notation
func (m *Yggdrasil) GetSubnetString() string {
subnet := m.core.Subnet()
return subnet.String()
}
// GetPublicKeyString gets the node's public key in hex form
func (m *Yggdrasil) GetPublicKeyString() string {
return hex.EncodeToString(m.core.GetSelf().Key)
}
// GetCoordsString gets the node's coordinates
func (m *Yggdrasil) GetCoordsString() string {
return fmt.Sprintf("%v", m.core.GetSelf().Coords)
}
func (m *Yggdrasil) GetPeersJSON() (result string) {
peers := []struct {
core.Peer
IP string
}{}
for _, v := range m.core.GetPeers() {
a := address.AddrForKey(v.Key)
ip := net.IP(a[:]).String()
peers = append(peers, struct {
core.Peer
IP string
}{
Peer: v,
IP: ip,
})
}
if res, err := json.Marshal(peers); err == nil {
return string(res)
} else {
return "{}"
}
}
func (m *Yggdrasil) GetDHTJSON() (result string) {
if res, err := json.Marshal(m.core.GetDHT()); err == nil {
return string(res)
} else {
return "{}"
}
}
// GetMTU returns the configured node MTU. This must be called AFTER Start.
func (m *Yggdrasil) GetMTU() int {
return int(m.core.MTU())
}
func GetVersion() string {
return version.BuildVersion()
}