190 lines
4.2 KiB
Go
190 lines
4.2 KiB
Go
package peer
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"math"
|
|
"net"
|
|
"net/http"
|
|
"net/netip"
|
|
"net/url"
|
|
"os"
|
|
"vppn/m"
|
|
)
|
|
|
|
type peerMain struct {
|
|
Globals
|
|
ifReader *IFReader
|
|
connReader *ConnReader
|
|
hubPoller *HubPoller
|
|
}
|
|
|
|
type mainArgs struct {
|
|
NetName string
|
|
HubAddress string
|
|
APIKey string
|
|
}
|
|
|
|
func newPeerMain(args mainArgs) *peerMain {
|
|
logf := func(s string, args ...any) {
|
|
log.Printf("[Main] "+s, args...)
|
|
}
|
|
|
|
config, err := loadPeerConfig(args.NetName)
|
|
if err != nil {
|
|
logf("Failed to load configuration: %v", err)
|
|
logf("Initializing...")
|
|
initPeerWithHub(args)
|
|
|
|
config, err = loadPeerConfig(args.NetName)
|
|
if err != nil {
|
|
log.Fatalf("Failed to load configuration: %v", err)
|
|
}
|
|
}
|
|
|
|
state, err := loadNetworkState(args.NetName)
|
|
if err != nil {
|
|
log.Fatalf("Failed to load network state: %v", err)
|
|
}
|
|
|
|
startupCount, err := loadStartupCount(args.NetName)
|
|
if err != nil {
|
|
if !os.IsNotExist(err) {
|
|
log.Fatalf("Failed to load startup count: %v", err)
|
|
}
|
|
}
|
|
|
|
if startupCount.Count == math.MaxUint16 {
|
|
log.Fatalf("Startup counter overflow.")
|
|
}
|
|
startupCount.Count += 1
|
|
|
|
if err := storeStartupCount(args.NetName, startupCount); err != nil {
|
|
log.Fatalf("Failed to write startup count: %v", err)
|
|
}
|
|
|
|
iface, err := openInterface(config.Network, config.LocalPeerIP, args.NetName)
|
|
if err != nil {
|
|
log.Fatalf("Failed to open interface: %v", err)
|
|
}
|
|
|
|
localPeer := state.Peers[config.LocalPeerIP]
|
|
|
|
log.Printf("Local peer %d: %v", config.LocalPeerIP, localPeer)
|
|
myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", localPeer.Port))
|
|
if err != nil {
|
|
log.Fatalf("Failed to resolve UDP address: %v", err)
|
|
}
|
|
|
|
logf("Listening on %v...", myAddr)
|
|
conn, err := net.ListenUDP("udp", myAddr)
|
|
if err != nil {
|
|
log.Fatalf("Failed to open UDP port: %v", err)
|
|
}
|
|
|
|
conn.SetReadBuffer(1024 * 1024 * 8)
|
|
conn.SetWriteBuffer(1024 * 1024 * 8)
|
|
|
|
var localAddr netip.AddrPort
|
|
ip, localAddrValid := netip.AddrFromSlice(localPeer.PublicIP)
|
|
if localAddrValid {
|
|
localAddr = netip.AddrPortFrom(ip, localPeer.Port)
|
|
}
|
|
|
|
g := NewGlobals(config, startupCount, localAddr, conn, iface)
|
|
|
|
hubPoller, err := NewHubPoller(g, args.NetName, args.HubAddress, args.APIKey)
|
|
if err != nil {
|
|
log.Fatalf("Failed to create hub poller: %v", err)
|
|
}
|
|
|
|
return &peerMain{
|
|
Globals: g,
|
|
ifReader: NewIFReader(g),
|
|
connReader: NewConnReader(g, conn),
|
|
hubPoller: hubPoller,
|
|
}
|
|
}
|
|
|
|
func (p *peerMain) Run() {
|
|
for i := range p.RemotePeers {
|
|
remote := p.RemotePeers[i].Load()
|
|
go newRemoteFSM(remote).Run()
|
|
}
|
|
|
|
go p.ifReader.Run()
|
|
go p.connReader.Run()
|
|
|
|
if !p.LocalAddrValid {
|
|
go RunMCWriter(p.LocalPeerIP, p.PrivSignKey)
|
|
go RunMCReader(p.Globals)
|
|
}
|
|
|
|
go p.hubPoller.Run()
|
|
|
|
select {}
|
|
}
|
|
|
|
func initPeerWithHub(args mainArgs) {
|
|
keys := generateKeys()
|
|
|
|
initURL, err := url.Parse(args.HubAddress)
|
|
if err != nil {
|
|
log.Fatalf("Failed to parse hub URL: %v", err)
|
|
}
|
|
initURL.Path = "/peer/init/"
|
|
|
|
initArgs := m.PeerInitArgs{
|
|
EncPubKey: keys.PubKey,
|
|
PubSignKey: keys.PubSignKey,
|
|
}
|
|
|
|
buf := &bytes.Buffer{}
|
|
if err := json.NewEncoder(buf).Encode(initArgs); err != nil {
|
|
log.Fatalf("Failed to encode init args: %v", err)
|
|
}
|
|
|
|
req, err := http.NewRequest(http.MethodPost, initURL.String(), buf)
|
|
if err != nil {
|
|
log.Fatalf("Failed to construct request: %v", err)
|
|
}
|
|
req.SetBasicAuth("", args.APIKey)
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
log.Fatalf("Failed to init with hub: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
data, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
log.Fatalf("Failed to read response body: %v", err)
|
|
}
|
|
|
|
initResp := m.PeerInitResp{}
|
|
if err := json.Unmarshal(data, &initResp); err != nil {
|
|
log.Fatalf("Failed to parse configuration: %v\n%s", err, data)
|
|
}
|
|
|
|
config := LocalConfig{}
|
|
config.LocalPeerIP = initResp.PeerIP
|
|
config.Network = initResp.Network
|
|
config.PubKey = keys.PubKey
|
|
config.PrivKey = keys.PrivKey
|
|
config.PubSignKey = keys.PubSignKey
|
|
config.PrivSignKey = keys.PrivSignKey
|
|
|
|
if err := storeNetworkState(args.NetName, initResp.NetworkState); err != nil {
|
|
log.Fatalf("Failed to store network state: %v", err)
|
|
}
|
|
|
|
if err := storePeerConfig(args.NetName, config); err != nil {
|
|
log.Fatalf("Failed to store configuration: %v", err)
|
|
}
|
|
|
|
log.Print("Initialization successful.")
|
|
}
|