191 lines
4.1 KiB
Go
191 lines
4.1 KiB
Go
package node
|
|
|
|
import (
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"net/netip"
|
|
"os"
|
|
"runtime/debug"
|
|
"vppn/m"
|
|
)
|
|
|
|
func panicHandler() {
|
|
if r := recover(); r != nil {
|
|
log.Fatalf("\n %v\n\nstacktrace from panic: %s\n", r, string(debug.Stack()))
|
|
}
|
|
}
|
|
|
|
func Main() {
|
|
defer panicHandler()
|
|
|
|
var (
|
|
netName string
|
|
initURL string
|
|
listenIP string
|
|
port int
|
|
)
|
|
|
|
flag.StringVar(&netName, "name", "", "[REQUIRED] The network name.")
|
|
flag.StringVar(&initURL, "init-url", "", "Initializes peer from the hub URL.")
|
|
flag.StringVar(&listenIP, "listen-ip", "", "IP address to listen on.")
|
|
flag.IntVar(&port, "port", 0, "Port to listen on.")
|
|
flag.Parse()
|
|
|
|
if netName == "" {
|
|
flag.Usage()
|
|
os.Exit(1)
|
|
}
|
|
|
|
if initURL != "" {
|
|
mainInit(netName, initURL)
|
|
return
|
|
}
|
|
|
|
main(netName, listenIP, uint16(port))
|
|
}
|
|
|
|
func mainInit(netName, initURL string) {
|
|
if _, err := loadPeerConfig(netName); err == nil {
|
|
log.Fatalf("Network is already initialized.")
|
|
}
|
|
|
|
resp, err := http.Get(initURL)
|
|
if err != nil {
|
|
log.Fatalf("Failed to fetch data from 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)
|
|
}
|
|
|
|
peerConfig := m.PeerConfig{}
|
|
if err := json.Unmarshal(data, &peerConfig); err != nil {
|
|
log.Fatalf("Failed to parse configuration: %v", err)
|
|
}
|
|
|
|
if err := storePeerConfig(netName, peerConfig); err != nil {
|
|
log.Fatalf("Failed to store configuration: %v", err)
|
|
}
|
|
|
|
log.Print("Initialization successful.")
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
func main(netName, listenIP string, port uint16) {
|
|
conf, err := loadPeerConfig(netName)
|
|
if err != nil {
|
|
log.Fatalf("Failed to load configuration: %v", err)
|
|
}
|
|
|
|
port = determinePort(conf.Port, port)
|
|
|
|
iface, err := openInterface(conf.Network, conf.PeerIP, netName)
|
|
if err != nil {
|
|
log.Fatalf("Failed to open interface: %v", err)
|
|
}
|
|
|
|
myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", listenIP, port))
|
|
if err != nil {
|
|
log.Fatalf("Failed to resolve UDP address: %v", err)
|
|
}
|
|
|
|
conn, err := net.ListenUDP("udp", myAddr)
|
|
if err != nil {
|
|
log.Fatalf("Failed to open UDP port: %v", err)
|
|
}
|
|
|
|
routing := newRoutingTable()
|
|
|
|
w := newConnWriter(conn, conf.PeerIP, routing)
|
|
r := newConnReader(conn, conf.PeerIP, routing)
|
|
|
|
router := newRouter(netName, conf, routing, w)
|
|
|
|
go nodeConnReader(r, w, iface, router)
|
|
nodeIFaceReader(w, iface, router)
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
func determinePort(confPort, portFromCommandLine uint16) uint16 {
|
|
if portFromCommandLine != 0 {
|
|
return portFromCommandLine
|
|
}
|
|
if confPort != 0 {
|
|
return confPort
|
|
}
|
|
return 456
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
func nodeConnReader(r *connReader, w *connWriter, iface io.ReadWriteCloser, router *router) {
|
|
defer panicHandler()
|
|
var (
|
|
remoteAddr netip.AddrPort
|
|
h header
|
|
buf = make([]byte, bufferSize)
|
|
data []byte
|
|
err error
|
|
)
|
|
|
|
for {
|
|
remoteAddr, h, data, err = r.Read(buf)
|
|
if err != nil {
|
|
log.Fatalf("Failed to read from UDP connection: %v", err)
|
|
}
|
|
|
|
switch h.Stream {
|
|
|
|
case streamData:
|
|
if _, err = iface.Write(data); err != nil {
|
|
log.Printf("Malformed data from peer %d: %v", h.SourceIP, err)
|
|
}
|
|
|
|
case streamRouting:
|
|
router.HandlePacket(h.SourceIP, remoteAddr, data)
|
|
|
|
default:
|
|
log.Printf("Dropping unknown stream: %d", h.Stream)
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
func nodeIFaceReader(w *connWriter, iface io.ReadWriteCloser, router *router) {
|
|
|
|
var (
|
|
buf = make([]byte, bufferSize)
|
|
packet []byte
|
|
remoteIP byte
|
|
err error
|
|
)
|
|
|
|
for {
|
|
|
|
packet, remoteIP, err = readNextPacket(iface, buf)
|
|
if err != nil {
|
|
log.Fatalf("Failed to read from interface: %v", err)
|
|
}
|
|
|
|
if remoteIP == w.localIP {
|
|
//log.Printf("Incoming packet for self: %x", packet)
|
|
//iface.Write(packet)
|
|
continue
|
|
}
|
|
|
|
if err := w.WriteTo(remoteIP, streamData, packet); err != nil {
|
|
log.Fatalf("Failed to write to network: %v", err)
|
|
}
|
|
}
|
|
}
|