From 011687dc32a98aea62cddfa61d06fd3722c9f601 Mon Sep 17 00:00:00 2001 From: Abe Winter Date: Mon, 16 Dec 2024 13:10:13 -0500 Subject: [PATCH 1/4] add mdnsMode, when true start mdnsServer --- go.mod | 2 +- subsystems/provisioning/grpc.go | 5 ++- subsystems/provisioning/networkmanager.go | 38 +++++++++++++++++------ subsystems/provisioning/portal.go | 15 ++++++++- subsystems/provisioning/provisioning.go | 9 ++++-- 5 files changed, 54 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 35a030d..38b820f 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.23.1 require ( github.com/Masterminds/semver/v3 v3.3.0 github.com/Otterverse/gonetworkmanager/v2 v2.2.1 + github.com/edaniels/zeroconf v1.0.10 github.com/google/uuid v1.6.0 github.com/jessevdk/go-flags v1.6.1 github.com/nightlyone/lockfile v1.0.0 @@ -29,7 +30,6 @@ require ( github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dgottlieb/smarty-assertions v1.2.5 // indirect github.com/edaniels/golog v0.0.0-20230215213219-28954395e8d0 // indirect - github.com/edaniels/zeroconf v1.0.10 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.1 // indirect diff --git a/subsystems/provisioning/grpc.go b/subsystems/provisioning/grpc.go index 5aee5ef..90e818a 100644 --- a/subsystems/provisioning/grpc.go +++ b/subsystems/provisioning/grpc.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "net" + "strconv" "time" errw "github.com/pkg/errors" @@ -12,8 +13,10 @@ import ( "google.golang.org/grpc" ) +const GRPCPort = 4772 + func (w *Provisioning) startGRPC() error { - bind := PortalBindAddr + ":4772" + bind := w.listenAddr() + ":" + strconv.Itoa(GRPCPort) lis, err := net.Listen("tcp", bind) if err != nil { return errw.Wrapf(err, "listening on: %s", bind) diff --git a/subsystems/provisioning/networkmanager.go b/subsystems/provisioning/networkmanager.go index 9e0c297..b8728b2 100644 --- a/subsystems/provisioning/networkmanager.go +++ b/subsystems/provisioning/networkmanager.go @@ -9,9 +9,12 @@ import ( "time" gnm "github.com/Otterverse/gonetworkmanager/v2" + "github.com/edaniels/zeroconf" errw "github.com/pkg/errors" ) +const provisioningMDNSHost = "provisioning-poc" + func (w *Provisioning) warnIfMultiplePrimaryNetworks() { if w.cfg.RoamingMode { return @@ -166,16 +169,18 @@ func (w *Provisioning) StartProvisioning(ctx context.Context, inputChan chan<- u defer w.opMu.Unlock() w.logger.Info("Starting provisioning mode.") - _, err := w.addOrUpdateConnection(NetworkConfig{ - Type: NetworkTypeHotspot, - Interface: w.Config().HotspotInterface, - SSID: w.Config().hotspotSSID, - }) - if err != nil { - return err - } - if err := w.activateConnection(ctx, w.Config().HotspotInterface, w.Config().hotspotSSID); err != nil { - return errw.Wrap(err, "starting provisioning mode hotspot") + if !w.mdnsMode { + _, err := w.addOrUpdateConnection(NetworkConfig{ + Type: NetworkTypeHotspot, + Interface: w.Config().HotspotInterface, + SSID: w.Config().hotspotSSID, + }) + if err != nil { + return err + } + if err := w.activateConnection(ctx, w.Config().HotspotInterface, w.Config().hotspotSSID); err != nil { + return errw.Wrap(err, "starting provisioning mode hotspot") + } } // start portal with ssid list and known connections @@ -184,6 +189,16 @@ func (w *Provisioning) StartProvisioning(ctx context.Context, inputChan chan<- u return errw.Wrap(err, "starting web/grpc portal") } + if w.mdnsMode { + w.logger.Infof("mdnsMode is set, advertising provisioning host %s", provisioningMDNSHost) + var err error + w.mdnsServer, err = zeroconf.RegisterDynamic( + provisioningMDNSHost, "_rpc._tcp", "local.", GRPCPort, []string{"grpc"}, nil, w.logger.AsZap()) + if err != nil { + return err + } + } + w.connState.setProvisioning(true) return nil } @@ -286,6 +301,9 @@ func (w *Provisioning) DeactivateConnection(ifName, ssid string) error { } func (w *Provisioning) deactivateConnection(ifName, ssid string) error { + if w.mdnsMode { + return nil + } activeConn := w.netState.ActiveConn(ifName) if activeConn == nil { return errw.Wrapf(ErrNoActiveConnectionFound, "interface: %s", ifName) diff --git a/subsystems/provisioning/portal.go b/subsystems/provisioning/portal.go index 086a944..1320364 100644 --- a/subsystems/provisioning/portal.go +++ b/subsystems/provisioning/portal.go @@ -45,6 +45,14 @@ func (w *Provisioning) startPortal(inputChan chan<- userInput) error { return nil } +// the address to listen on. +func (w *Provisioning) listenAddr() string { + if w.mdnsMode { + return "0.0.0.0" + } + return PortalBindAddr +} + func (w *Provisioning) startWeb() error { mux := http.NewServeMux() mux.HandleFunc("/", w.portalIndex) @@ -53,7 +61,7 @@ func (w *Provisioning) startWeb() error { Handler: mux, ReadTimeout: time.Second * 10, } - bind := PortalBindAddr + ":80" + bind := w.listenAddr() + ":80" lis, err := net.Listen("tcp", bind) if err != nil { return errw.Wrapf(err, "listening on: %s", bind) @@ -89,6 +97,11 @@ func (w *Provisioning) stopPortal() error { w.portalData.workers.Wait() w.portalData = &portalData{input: &userInput{}} + if w.mdnsServer != nil { + w.mdnsServer.Shutdown() + w.mdnsServer = nil + } + return err } diff --git a/subsystems/provisioning/provisioning.go b/subsystems/provisioning/provisioning.go index a40ef5f..1142c16 100644 --- a/subsystems/provisioning/provisioning.go +++ b/subsystems/provisioning/provisioning.go @@ -11,6 +11,7 @@ import ( semver "github.com/Masterminds/semver/v3" gnm "github.com/Otterverse/gonetworkmanager/v2" + "github.com/edaniels/zeroconf" errw "github.com/pkg/errors" "github.com/viamrobotics/agent" "github.com/viamrobotics/agent/subsystems" @@ -38,8 +39,11 @@ type Provisioning struct { cancel context.CancelFunc // only set during NewProvisioning, no lock - nm gnm.NetworkManager - settings gnm.Settings + nm gnm.NetworkManager + settings gnm.Settings + // when mdnsMode is true, advertise via mdns on pre-existing network + // instead of using static IP and captive portal. + mdnsMode bool hostname string logger logging.Logger AppCfgPath string @@ -60,6 +64,7 @@ type Provisioning struct { // portal webServer *http.Server grpcServer *grpc.Server + mdnsServer *zeroconf.Server portalData *portalData pb.UnimplementedProvisioningServiceServer From 82b8f88b2040d733e5c6e376315a0d984c0e30e1 Mon Sep 17 00:00:00 2001 From: Abe Winter Date: Mon, 16 Dec 2024 13:13:25 -0500 Subject: [PATCH 2/4] move it to json config --- subsystems/provisioning/definitions.go | 3 +++ subsystems/provisioning/networkmanager.go | 6 +++--- subsystems/provisioning/portal.go | 2 +- subsystems/provisioning/provisioning.go | 7 ++----- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/subsystems/provisioning/definitions.go b/subsystems/provisioning/definitions.go index c1134c6..3c3c467 100644 --- a/subsystems/provisioning/definitions.go +++ b/subsystems/provisioning/definitions.go @@ -370,6 +370,9 @@ type Config struct { // If set, will explicitly enable or disable power save for all wifi connections managed by NetworkManager. WifiPowerSave *bool `json:"wifi_power_save"` + + // When true, advertise via mdns on pre-existing network instead of using static IP and captive portal. + MDNSMode bool `json:"mdns_mode"` } // Timeout allows parsing golang-style durations (1h20m30s) OR seconds-as-float from/to json. diff --git a/subsystems/provisioning/networkmanager.go b/subsystems/provisioning/networkmanager.go index b8728b2..d2a99b3 100644 --- a/subsystems/provisioning/networkmanager.go +++ b/subsystems/provisioning/networkmanager.go @@ -169,7 +169,7 @@ func (w *Provisioning) StartProvisioning(ctx context.Context, inputChan chan<- u defer w.opMu.Unlock() w.logger.Info("Starting provisioning mode.") - if !w.mdnsMode { + if !w.cfg.MDNSMode { _, err := w.addOrUpdateConnection(NetworkConfig{ Type: NetworkTypeHotspot, Interface: w.Config().HotspotInterface, @@ -189,7 +189,7 @@ func (w *Provisioning) StartProvisioning(ctx context.Context, inputChan chan<- u return errw.Wrap(err, "starting web/grpc portal") } - if w.mdnsMode { + if w.cfg.MDNSMode { w.logger.Infof("mdnsMode is set, advertising provisioning host %s", provisioningMDNSHost) var err error w.mdnsServer, err = zeroconf.RegisterDynamic( @@ -301,7 +301,7 @@ func (w *Provisioning) DeactivateConnection(ifName, ssid string) error { } func (w *Provisioning) deactivateConnection(ifName, ssid string) error { - if w.mdnsMode { + if w.cfg.MDNSMode { return nil } activeConn := w.netState.ActiveConn(ifName) diff --git a/subsystems/provisioning/portal.go b/subsystems/provisioning/portal.go index 1320364..7217b51 100644 --- a/subsystems/provisioning/portal.go +++ b/subsystems/provisioning/portal.go @@ -47,7 +47,7 @@ func (w *Provisioning) startPortal(inputChan chan<- userInput) error { // the address to listen on. func (w *Provisioning) listenAddr() string { - if w.mdnsMode { + if w.cfg.MDNSMode { return "0.0.0.0" } return PortalBindAddr diff --git a/subsystems/provisioning/provisioning.go b/subsystems/provisioning/provisioning.go index 1142c16..05b709f 100644 --- a/subsystems/provisioning/provisioning.go +++ b/subsystems/provisioning/provisioning.go @@ -39,11 +39,8 @@ type Provisioning struct { cancel context.CancelFunc // only set during NewProvisioning, no lock - nm gnm.NetworkManager - settings gnm.Settings - // when mdnsMode is true, advertise via mdns on pre-existing network - // instead of using static IP and captive portal. - mdnsMode bool + nm gnm.NetworkManager + settings gnm.Settings hostname string logger logging.Logger AppCfgPath string From 6fee36bf62594bb2ef91fb9b32b47d738381bd91 Mon Sep 17 00:00:00 2001 From: Abe Winter Date: Mon, 16 Dec 2024 13:23:59 -0500 Subject: [PATCH 3/4] ready to test --- subsystems/provisioning/definitions.go | 1 + subsystems/provisioning/networkmanager.go | 3 +++ subsystems/provisioning/provisioning.go | 7 +++++++ 3 files changed, 11 insertions(+) diff --git a/subsystems/provisioning/definitions.go b/subsystems/provisioning/definitions.go index 3c3c467..f445759 100644 --- a/subsystems/provisioning/definitions.go +++ b/subsystems/provisioning/definitions.go @@ -372,6 +372,7 @@ type Config struct { WifiPowerSave *bool `json:"wifi_power_save"` // When true, advertise via mdns on pre-existing network instead of using static IP and captive portal. + // (Instead of the default behavior of starting a captive portal). MDNSMode bool `json:"mdns_mode"` } diff --git a/subsystems/provisioning/networkmanager.go b/subsystems/provisioning/networkmanager.go index d2a99b3..023e64c 100644 --- a/subsystems/provisioning/networkmanager.go +++ b/subsystems/provisioning/networkmanager.go @@ -65,6 +65,9 @@ func (w *Provisioning) getLastNetworkTried() NetworkInfo { } func (w *Provisioning) checkOnline(force bool) error { + if w.cfg.MDNSMode { + return nil + } if force { if err := w.nm.CheckConnectivity(); err != nil { w.logger.Error(err) diff --git a/subsystems/provisioning/provisioning.go b/subsystems/provisioning/provisioning.go index 05b709f..d2cc0ed 100644 --- a/subsystems/provisioning/provisioning.go +++ b/subsystems/provisioning/provisioning.go @@ -145,6 +145,10 @@ func (w *Provisioning) init(ctx context.Context) error { w.mainLoopHealth.MarkGood() w.bgLoopHealth.MarkGood() + if w.cfg.MDNSMode { + w.logger.Info("skipping networkmanager init because mdnsmode") + return nil + } nm, err := w.getNM() if err != nil { return err @@ -386,6 +390,9 @@ func (w *Provisioning) updateHotspotSSID(cfg *Config) { // must be run inside dataMu lock. func (w *Provisioning) writeWifiPowerSave(ctx context.Context) error { + if w.cfg.MDNSMode { + return nil + } contents := wifiPowerSaveContentsDefault if w.cfg.WifiPowerSave != nil { if *w.cfg.WifiPowerSave { From 06e7271d4a636a80f6eba024d501ecf71aa24793 Mon Sep 17 00:00:00 2001 From: bashar-515 Date: Mon, 16 Dec 2024 22:23:32 +0000 Subject: [PATCH 4/4] [AW-MDNS-Provision] Skip Background Loop (#53) --- subsystems/provisioning/networkmanager.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/subsystems/provisioning/networkmanager.go b/subsystems/provisioning/networkmanager.go index 023e64c..8cf61c5 100644 --- a/subsystems/provisioning/networkmanager.go +++ b/subsystems/provisioning/networkmanager.go @@ -571,6 +571,11 @@ func (w *Provisioning) backgroundLoop(ctx context.Context, scanChan chan<- bool) return } + if w.cfg.MDNSMode { + w.logger.Info("skipping background loop because mdnsmode") + return + } + w.checkConfigured() if err := w.networkScan(ctx); err != nil { w.logger.Error(err)