From 68de46bc8660025f8c2af362876c806c6855696d Mon Sep 17 00:00:00 2001 From: David Schinazi Date: Thu, 9 Jan 2025 21:03:09 -0800 Subject: [PATCH] Refactor Network localDeviceId to be const --- src/jazzlights/network/arduino_esp_wifi.cpp | 5 +- src/jazzlights/network/arduino_esp_wifi.h | 9 ++- src/jazzlights/network/arduino_ethernet.cpp | 12 +++- src/jazzlights/network/arduino_ethernet.h | 7 +- src/jazzlights/network/esp32_ble.cpp | 21 +++--- src/jazzlights/network/esp32_ble.h | 12 ++-- src/jazzlights/network/esp32_ethernet.cpp | 22 +++++-- src/jazzlights/network/esp32_ethernet.h | 6 +- src/jazzlights/network/esp32_wifi.cpp | 19 +++--- src/jazzlights/network/esp32_wifi.h | 6 +- src/jazzlights/network/network.h | 4 +- src/jazzlights/network/unix_udp.cpp | 73 ++++++++++++--------- src/jazzlights/network/unix_udp.h | 10 +-- src/jazzlights/player.cpp | 2 +- 14 files changed, 125 insertions(+), 83 deletions(-) diff --git a/src/jazzlights/network/arduino_esp_wifi.cpp b/src/jazzlights/network/arduino_esp_wifi.cpp index abca85ae..d07054c0 100644 --- a/src/jazzlights/network/arduino_esp_wifi.cpp +++ b/src/jazzlights/network/arduino_esp_wifi.cpp @@ -97,14 +97,15 @@ std::string WiFiReasonToString(uint8_t reason) { } } // namespace -ArduinoEspWiFiNetwork::ArduinoEspWiFiNetwork() { +// static +NetworkDeviceId ArduinoEspWiFiNetwork::QueryLocalDeviceId() { uint8_t macAddress[6] = {}; if (WiFi.macAddress(&macAddress[0]) == nullptr) { uint64_t efuseMac64 = ESP.getEfuseMac(); if (efuseMac64 == 0) { jll_fatal("%u Wi-Fi failed to read MAC address from both Wi-Fi and EFUSE", timeMillis()); } memcpy(macAddress, &efuseMac64, sizeof(macAddress)); } - localDeviceId_ = NetworkDeviceId(macAddress); + return NetworkDeviceId(macAddress); } void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) { diff --git a/src/jazzlights/network/arduino_esp_wifi.h b/src/jazzlights/network/arduino_esp_wifi.h index 1bdb3528..18448c70 100644 --- a/src/jazzlights/network/arduino_esp_wifi.h +++ b/src/jazzlights/network/arduino_esp_wifi.h @@ -25,7 +25,7 @@ class ArduinoEspWiFiNetwork : public UdpNetwork { NetworkStatus update(NetworkStatus status, Milliseconds currentTime) override; int recv(void* buf, size_t bufsize, std::string* details) override; void send(void* buf, size_t bufsize) override; - NetworkDeviceId getLocalDeviceId() override { return localDeviceId_; } + NetworkDeviceId getLocalDeviceId() const override { return localDeviceId_; } NetworkType type() const override { return NetworkType::kWiFi; } std::string getStatusStr(Milliseconds currentTime) override; @@ -36,14 +36,17 @@ class ArduinoEspWiFiNetwork : public UdpNetwork { }; private: - ArduinoEspWiFiNetwork(); + explicit ArduinoEspWiFiNetwork() {} + static constexpr wl_status_t kUninitialized = static_cast(123); static std::string WiFiStatusToString(wl_status_t status); + static NetworkDeviceId QueryLocalDeviceId(); + uint16_t port_ = DefaultUdpPort(); const char* mcastAddr_ = DefaultMulticastAddress(); WiFiUDP udp_; StaticConf* staticConf_ = nullptr; - NetworkDeviceId localDeviceId_; + const NetworkDeviceId localDeviceId_ = QueryLocalDeviceId(); wl_status_t currentWiFiStatus_ = kUninitialized; Milliseconds timeOfLastWiFiStatusTransition_ = -1; bool attemptingDhcp_ = true; diff --git a/src/jazzlights/network/arduino_ethernet.cpp b/src/jazzlights/network/arduino_ethernet.cpp index 2ebc58cd..b9c957b0 100644 --- a/src/jazzlights/network/arduino_ethernet.cpp +++ b/src/jazzlights/network/arduino_ethernet.cpp @@ -35,12 +35,16 @@ std::string EthernetHardwareStatusToString(EthernetHardwareStatus hwStatus) { } // namespace -ArduinoEthernetNetwork::ArduinoEthernetNetwork() { +// static +NetworkDeviceId ArduinoEthernetNetwork::QueryLocalDeviceId() { uint8_t wifiMacAddress[6] = {}; uint64_t efuseMac64 = ESP.getEfuseMac(); if (efuseMac64 == 0) { jll_fatal("%u Wi-Fi failed to read MAC address from EFUSE", timeMillis()); } memcpy(wifiMacAddress, &efuseMac64, sizeof(wifiMacAddress)); - localDeviceId_ = NetworkDeviceId(wifiMacAddress).PlusOne(); + return NetworkDeviceId(wifiMacAddress).PlusOne(); +} + +ArduinoEthernetNetwork::ArduinoEthernetNetwork() { jll_info("%u Starting Ethernet with MAC address " DEVICE_ID_FMT, timeMillis(), DEVICE_ID_HEX(localDeviceId_)); #if JL_CORE2AWS_ETHERNET // These pins work with the M5Stack Core2AWS connected to the Ethernet W5500 module. @@ -100,7 +104,9 @@ NetworkStatus ArduinoEthernetNetwork::update(NetworkStatus status, Milliseconds constexpr unsigned long kResponseTimeoutMs = 1000; // TODO move Ethernet.begin() call to its own thread because it performs DHCP synchronously // and currently blocks our main thread while waiting for a DHCP response. - int beginRes = Ethernet.begin(localDeviceId_.data(), kDhcpTimeoutMs, kResponseTimeoutMs); + uint8_t macAddress[6]; + localDeviceId_.writeTo(macAddress); + int beginRes = Ethernet.begin(macAddress, kDhcpTimeoutMs, kResponseTimeoutMs); if (beginRes == 0) { jll_error("%u Ethernet DHCP failed", currentTime); // TODO add support for IPv4 link-local addresses. diff --git a/src/jazzlights/network/arduino_ethernet.h b/src/jazzlights/network/arduino_ethernet.h index 7eda18bb..a854ad23 100644 --- a/src/jazzlights/network/arduino_ethernet.h +++ b/src/jazzlights/network/arduino_ethernet.h @@ -19,13 +19,16 @@ class ArduinoEthernetNetwork : public UdpNetwork { NetworkStatus update(NetworkStatus status, Milliseconds currentTime) override; int recv(void* buf, size_t bufsize, std::string* details) override; void send(void* buf, size_t bufsize) override; - NetworkDeviceId getLocalDeviceId() override { return localDeviceId_; } + NetworkDeviceId getLocalDeviceId() const override { return localDeviceId_; } NetworkType type() const override { return NetworkType::kEthernet; } std::string getStatusStr(Milliseconds currentTime) override; private: explicit ArduinoEthernetNetwork(); - NetworkDeviceId localDeviceId_; + + static NetworkDeviceId QueryLocalDeviceId(); + + const NetworkDeviceId localDeviceId_ = QueryLocalDeviceId(); uint16_t port_ = DefaultUdpPort(); const char* mcastAddr_ = DefaultMulticastAddress(); EthernetUDP udp_; diff --git a/src/jazzlights/network/esp32_ble.cpp b/src/jazzlights/network/esp32_ble.cpp index cc5a0f4d..12ebe947 100644 --- a/src/jazzlights/network/esp32_ble.cpp +++ b/src/jazzlights/network/esp32_ble.cpp @@ -408,7 +408,8 @@ NetworkStatus Esp32BleNetwork::update(NetworkStatus status, Milliseconds current } } -Esp32BleNetwork::Esp32BleNetwork() { +// static +NetworkDeviceId Esp32BleNetwork::InitBluetoothStackAndQueryLocalDeviceId() { // Initialize ESP Bluetooth stack. ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); @@ -430,15 +431,6 @@ Esp32BleNetwork::Esp32BleNetwork() { if (esp_random() == 0xdeadbeef) { (void)btStarted(); } #endif // JL_BLE4 - // Initialize localDeviceId_. - uint8_t addressType; - esp_bd_addr_t localAddress; - memset(localAddress, 0, sizeof(localAddress)); - ESP_ERROR_CHECK(esp_ble_gap_get_local_used_addr(localAddress, &addressType)); - jll_info("%u Initialized BLE with local MAC address " ESP_BD_ADDR_STR " (type %u)", timeMillis(), - ESP_BD_ADDR_HEX(localAddress), addressType); - localDeviceId_ = NetworkDeviceId(localAddress); - lastReceiveTime_ = -1; // Override callbacks away from BLEDevice back to us. ESP_ERROR_CHECK(esp_ble_gap_register_callback(&Esp32BleNetwork::GapCallback)); // Configure scanning parameters. @@ -450,6 +442,15 @@ Esp32BleNetwork::Esp32BleNetwork() { scanParams.scan_window = 16000; // 10s (unit is 625us). scanParams.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE; ESP_ERROR_CHECK(esp_ble_gap_set_scan_params(&scanParams)); + + // Initialize localDeviceId_. + uint8_t addressType; + esp_bd_addr_t localAddress; + memset(localAddress, 0, sizeof(localAddress)); + ESP_ERROR_CHECK(esp_ble_gap_get_local_used_addr(localAddress, &addressType)); + jll_info("%u Initialized BLE with local MAC address " ESP_BD_ADDR_STR " (type %u)", timeMillis(), + ESP_BD_ADDR_HEX(localAddress), addressType); + return NetworkDeviceId(localAddress); } void Esp32BleNetwork::runLoopImpl(Milliseconds currentTime) { MaybeUpdateAdvertisingState(currentTime); } diff --git a/src/jazzlights/network/esp32_ble.h b/src/jazzlights/network/esp32_ble.h index 1be4b783..90103cbb 100644 --- a/src/jazzlights/network/esp32_ble.h +++ b/src/jazzlights/network/esp32_ble.h @@ -31,7 +31,7 @@ class Esp32BleNetwork : public Network { void triggerSendAsap(Milliseconds currentTime) override; // Get this device's BLE MAC address. - NetworkDeviceId getLocalDeviceId() override { return localDeviceId_; } + NetworkDeviceId getLocalDeviceId() const override { return localDeviceId_; } NetworkType type() const override { return NetworkType::kBLE; } bool shouldEcho() const override { return true; } Milliseconds getLastReceiveTime() const override { return lastReceiveTime_; } @@ -61,7 +61,7 @@ class Esp32BleNetwork : public Network { // 29 is dictated by the BLE standard. static constexpr size_t kMaxInnerPayloadLength = 29; - explicit Esp32BleNetwork(); + explicit Esp32BleNetwork() {} void StartScanning(Milliseconds currentTime); void StopScanning(Milliseconds currentTime); void StartAdvertising(Milliseconds currentTime); @@ -79,8 +79,10 @@ class Esp32BleNetwork : public Network { static void GapCallback(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param); - NetworkDeviceId localDeviceId_; - std::atomic lastReceiveTime_; + static NetworkDeviceId InitBluetoothStackAndQueryLocalDeviceId(); + + const NetworkDeviceId localDeviceId_ = InitBluetoothStackAndQueryLocalDeviceId(); + std::atomic lastReceiveTime_{-1}; std::mutex mutex_; // All the variables below are protected by mutex_. State state_ = State::kIdle; @@ -106,7 +108,7 @@ class Esp32BleNetwork : public Network { void setMessageToSend(const NetworkMessage& /*messageToSend*/, Milliseconds /*currentTime*/) override {} void disableSending(Milliseconds /*currentTime*/) override {} void triggerSendAsap(Milliseconds /*currentTime*/) override {} - NetworkDeviceId getLocalDeviceId() override { return NetworkDeviceId(); } + NetworkDeviceId getLocalDeviceId() const override { return NetworkDeviceId(); } NetworkType type() const override { return NetworkType::kBLE; } bool shouldEcho() const override { return false; } Milliseconds getLastReceiveTime() const override { return -1; } diff --git a/src/jazzlights/network/esp32_ethernet.cpp b/src/jazzlights/network/esp32_ethernet.cpp index 322f7a91..8cb184ba 100644 --- a/src/jazzlights/network/esp32_ethernet.cpp +++ b/src/jazzlights/network/esp32_ethernet.cpp @@ -335,6 +335,18 @@ void Esp32EthernetNetwork::RunTask() { } } +// static +NetworkDeviceId Esp32EthernetNetwork::QueryLocalDeviceId() { + // W5500 SPI Ethernet modules do not have a MAC address, so we instead add one to the Wi-Fi MAC. + uint8_t wifi_mac_addr[6]; +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) + ESP_ERROR_CHECK(esp_read_mac(wifi_mac_addr, ESP_MAC_EFUSE_FACTORY)); +#else + ESP_ERROR_CHECK(esp_efuse_mac_get_default(wifi_mac_addr)); +#endif + return NetworkDeviceId(wifi_mac_addr).PlusOne(); +} + Esp32EthernetNetwork::Esp32EthernetNetwork() : eventQueue_(xQueueCreate(/*num_queue_items=*/1, /*queue_item_size=*/sizeof(Esp32EthernetNetworkEvent))) { if (eventQueue_ == nullptr) { jll_fatal("Failed to create Esp32EthernetNetwork queue"); } @@ -366,12 +378,6 @@ Esp32EthernetNetwork::Esp32EthernetNetwork() } ESP_ERROR_CHECK(spiInitErr); - // The SPI Ethernet module(s) do not have a MAC address, so we instead add one to the Wi-Fi MAC. - uint8_t wifi_mac_addr[6]; - ESP_ERROR_CHECK(esp_read_mac(wifi_mac_addr, ESP_MAC_EFUSE_FACTORY)); - NetworkDeviceId wifi_mac(wifi_mac_addr); - localDeviceId_ = wifi_mac.PlusOne(); - eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); phy_config.phy_addr = host_id; @@ -400,7 +406,9 @@ Esp32EthernetNetwork::Esp32EthernetNetwork() esp_eth_config_t eth_config_spi = ETH_DEFAULT_CONFIG(mac, phy); ESP_ERROR_CHECK(esp_eth_driver_install(ð_config_spi, ð_handle)); - ESP_ERROR_CHECK(esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, localDeviceId_.data())); + uint8_t mac_address[6]; + localDeviceId_.writeTo(mac_address); + ESP_ERROR_CHECK(esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, mac_address)); InitializeNetStack(); diff --git a/src/jazzlights/network/esp32_ethernet.h b/src/jazzlights/network/esp32_ethernet.h index 5f8a317e..70421f8c 100644 --- a/src/jazzlights/network/esp32_ethernet.h +++ b/src/jazzlights/network/esp32_ethernet.h @@ -23,7 +23,7 @@ class Esp32EthernetNetwork : public Network { ~Esp32EthernetNetwork(); NetworkStatus update(NetworkStatus status, Milliseconds currentTime) override; - NetworkDeviceId getLocalDeviceId() override { return localDeviceId_; } + NetworkDeviceId getLocalDeviceId() const override { return localDeviceId_; } NetworkType type() const override { return NetworkType::kEthernet; } std::string getStatusStr(Milliseconds currentTime) override; void setMessageToSend(const NetworkMessage& messageToSend, Milliseconds currentTime) override; @@ -63,8 +63,10 @@ class Esp32EthernetNetwork : public Network { void CreateSocket(); void CloseSocket(); + static NetworkDeviceId QueryLocalDeviceId(); + QueueHandle_t eventQueue_; - NetworkDeviceId localDeviceId_; // Only modified in constructor. + const NetworkDeviceId localDeviceId_ = QueryLocalDeviceId(); TaskHandle_t taskHandle_ = nullptr; // Only modified in constructor. struct in_addr multicastAddress_ = {}; // Only modified in constructor. int socket_ = -1; // Only used on our task. diff --git a/src/jazzlights/network/esp32_wifi.cpp b/src/jazzlights/network/esp32_wifi.cpp index 0501b072..6b9396f4 100644 --- a/src/jazzlights/network/esp32_wifi.cpp +++ b/src/jazzlights/network/esp32_wifi.cpp @@ -385,13 +385,7 @@ void Esp32WiFiNetwork::RunTask() { } } -Esp32WiFiNetwork::Esp32WiFiNetwork() - : eventQueue_(xQueueCreate(/*num_queue_items=*/1, /*queue_item_size=*/sizeof(Esp32WiFiNetworkEvent))) { - if (eventQueue_ == nullptr) { jll_fatal("Failed to create Esp32WiFiNetwork queue"); } - udpPayload_ = reinterpret_cast(malloc(kReceiveBufferLength)); - if (udpPayload_ == nullptr) { - jll_fatal("Esp32WiFiNetwork failed to allocate receive buffer of length %zu", kReceiveBufferLength); - } +NetworkDeviceId Esp32WiFiNetwork::InitWiFiStackAndQueryLocalDeviceId() { InitializeNetStack(); esp_netif_create_default_wifi_sta(); @@ -420,7 +414,16 @@ Esp32WiFiNetwork::Esp32WiFiNetwork() uint8_t macAddress[6]; ESP_ERROR_CHECK(esp_wifi_get_mac(WIFI_IF_STA, macAddress)); - localDeviceId_ = NetworkDeviceId(macAddress); + return NetworkDeviceId(macAddress); +} + +Esp32WiFiNetwork::Esp32WiFiNetwork() + : eventQueue_(xQueueCreate(/*num_queue_items=*/1, /*queue_item_size=*/sizeof(Esp32WiFiNetworkEvent))) { + if (eventQueue_ == nullptr) { jll_fatal("Failed to create Esp32WiFiNetwork queue"); } + udpPayload_ = reinterpret_cast(malloc(kReceiveBufferLength)); + if (udpPayload_ == nullptr) { + jll_fatal("Esp32WiFiNetwork failed to allocate receive buffer of length %zu", kReceiveBufferLength); + } if (inet_pton(AF_INET, DefaultMulticastAddress(), &multicastAddress_) != 1) { jll_fatal("Esp32WiFiNetwork failed to parse multicast address"); diff --git a/src/jazzlights/network/esp32_wifi.h b/src/jazzlights/network/esp32_wifi.h index 478ed39b..9024a618 100644 --- a/src/jazzlights/network/esp32_wifi.h +++ b/src/jazzlights/network/esp32_wifi.h @@ -24,7 +24,7 @@ class Esp32WiFiNetwork : public Network { ~Esp32WiFiNetwork(); NetworkStatus update(NetworkStatus status, Milliseconds currentTime) override; - NetworkDeviceId getLocalDeviceId() override { return localDeviceId_; } + NetworkDeviceId getLocalDeviceId() const override { return localDeviceId_; } NetworkType type() const override { return NetworkType::kWiFi; } std::string getStatusStr(Milliseconds currentTime) override; void setMessageToSend(const NetworkMessage& messageToSend, Milliseconds currentTime) override; @@ -66,8 +66,10 @@ class Esp32WiFiNetwork : public Network { void CreateSocket(); void CloseSocket(); + NetworkDeviceId InitWiFiStackAndQueryLocalDeviceId(); + QueueHandle_t eventQueue_; - NetworkDeviceId localDeviceId_; // Only modified in constructor. + const NetworkDeviceId localDeviceId_ = InitWiFiStackAndQueryLocalDeviceId(); TaskHandle_t taskHandle_ = nullptr; // Only modified in constructor. struct in_addr multicastAddress_ = {}; // Only modified in constructor. int socket_ = -1; // Only used on our task. diff --git a/src/jazzlights/network/network.h b/src/jazzlights/network/network.h index 38676edb..214b942c 100644 --- a/src/jazzlights/network/network.h +++ b/src/jazzlights/network/network.h @@ -146,8 +146,8 @@ class Network { // Request an immediate send. virtual void triggerSendAsap(Milliseconds currentTime) = 0; - // Returns this device's unique ID, often using its MAC address. Not const to allow taking locks. - virtual NetworkDeviceId getLocalDeviceId() = 0; + // Returns this device's unique ID, often using its MAC address. + virtual NetworkDeviceId getLocalDeviceId() const = 0; // The type of this network. virtual NetworkType type() const = 0; diff --git a/src/jazzlights/network/unix_udp.cpp b/src/jazzlights/network/unix_udp.cpp index 1080f69d..5ba7313e 100644 --- a/src/jazzlights/network/unix_udp.cpp +++ b/src/jazzlights/network/unix_udp.cpp @@ -59,14 +59,14 @@ int UnixUdpNetwork::setupSocketForInterface(const char* ifName, struct in_addr l sockaddr_in sin = { .sin_family = AF_INET, - .sin_port = htons(port_), + .sin_port = htons(DefaultUdpPort()), // .sin_addr = localAddr, .sin_addr = {htonl(INADDR_ANY)}, .sin_zero = {}, }; if (bind(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0) { - jll_error("Failed to bind UDP socket %d ifName %s to port %d: %s", fd, ifName, port_, strerror(errno)); + jll_error("Failed to bind UDP socket %d ifName %s to port %d: %s", fd, ifName, DefaultUdpPort(), strerror(errno)); break; } @@ -75,8 +75,8 @@ int UnixUdpNetwork::setupSocketForInterface(const char* ifName, struct in_addr l .imr_interface = localAddr, }; if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcastGroup, sizeof(mcastGroup)) < 0) { - jll_error("Failed to add UDP socket %d ifName %s to multicast group %s: %s", fd, ifName, mcastAddrStr_, - strerror(errno)); + jll_error("Failed to add UDP socket %d ifName %s to multicast group %s: %s", fd, ifName, + DefaultMulticastAddress(), strerror(errno)); break; } @@ -89,8 +89,8 @@ int UnixUdpNetwork::setupSocketForInterface(const char* ifName, struct in_addr l sockets_[ifName] = fd; - jll_info("Joined multicast group %s, listening on port %d, UDP socket %d, ifName %s", mcastAddrStr_, port_, fd, - ifName); + jll_info("Joined multicast group %s, listening on port %d, UDP socket %d, ifName %s", DefaultMulticastAddress(), + DefaultUdpPort(), fd, ifName); return 2; } while (false); @@ -116,37 +116,49 @@ void UnixUdpNetwork::invalidateSocket(std::string ifName) { jll_info("Invalidated socket %d for ifName %s", fd, ifName.c_str()); } -bool UnixUdpNetwork::setupSockets() { +// static +NetworkDeviceId UnixUdpNetwork::QueryLocalDeviceId() { + NetworkDeviceId localAddress; struct ifaddrs* ifaddr = NULL; - if (getifaddrs(&ifaddr) == -1) { - jll_error("getifaddrs failed: %s", strerror(errno)); - return false; - } - - uint32_t newValidSockets = 0; - for (struct ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { - if (ifa->ifa_addr == NULL) { - jll_error("Skipping interface without data \"%s\"", ifa->ifa_name); - continue; - } - if (localDeviceId_ == NetworkDeviceId()) { - // Fill in localDeviceId_. + if (getifaddrs(&ifaddr) != -1) { + for (struct ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) { continue; } #if defined(__APPLE__) if (ifa->ifa_addr->sa_family != AF_LINK) { continue; } struct sockaddr_dl* dlAddress = reinterpret_cast(ifa->ifa_addr); - NetworkDeviceId localAddress(reinterpret_cast(&dlAddress->sdl_data[dlAddress->sdl_nlen])); + localAddress = NetworkDeviceId(reinterpret_cast(&dlAddress->sdl_data[dlAddress->sdl_nlen])); #elif defined(linux) || defined(__linux) || defined(__linux__) if (ifa->ifa_addr->sa_family != AF_PACKET) { continue; } - NetworkDeviceId localAddress((reinterpret_cast(ifa->ifa_addr)->sll_addr)); + localAddress = NetworkDeviceId((reinterpret_cast(ifa->ifa_addr)->sll_addr)); #else #error "Unsupported platform" #endif if (localAddress != NetworkDeviceId()) { jll_info("Choosing local MAC address " DEVICE_ID_FMT " from interface %s", DEVICE_ID_HEX(localAddress), ifa->ifa_name); - localDeviceId_ = localAddress; + break; } } + freeifaddrs(ifaddr); + } else { + jll_fatal("getifaddrs failed: %s", strerror(errno)); + } + return localAddress; +} + +bool UnixUdpNetwork::setupSockets() { + struct ifaddrs* ifaddr = NULL; + if (getifaddrs(&ifaddr) == -1) { + jll_error("getifaddrs failed: %s", strerror(errno)); + return false; + } + + uint32_t newValidSockets = 0; + for (struct ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) { + jll_error("Skipping interface without data \"%s\"", ifa->ifa_name); + continue; + } if (ifa->ifa_addr->sa_family != AF_INET) { // We currently only support IPv4. continue; @@ -166,12 +178,10 @@ bool UnixUdpNetwork::setupSockets() { return !sockets_.empty(); } -UnixUdpNetwork::UnixUdpNetwork(uint16_t port, const char* addr) : port_(port) { - assert(strnlen(addr, sizeof(mcastAddrStr_) + 1) < sizeof(mcastAddrStr_)); - strncpy(mcastAddrStr_, addr, sizeof(mcastAddrStr_)); - int parsed = inet_pton(AF_INET, addr, &mcastAddr_); - assert(parsed == 1); - // Make sure localDeviceId_ is filled in. +UnixUdpNetwork::UnixUdpNetwork() { + if (inet_pton(AF_INET, DefaultMulticastAddress(), &mcastAddr_) != 1) { + jll_fatal("UnixUdpNetwork failed to parse multicast address"); + } setupSockets(); } @@ -233,7 +243,7 @@ void UnixUdpNetwork::send(void* buf, size_t bufsize) { setupSockets(); sockaddr_in sin = { .sin_family = AF_INET, - .sin_port = htons(port_), + .sin_port = htons(DefaultUdpPort()), .sin_addr = mcastAddr_, .sin_zero = {}, }; @@ -266,7 +276,8 @@ void UnixUdpNetwork::send(void* buf, size_t bufsize) { // Exit loop since sockets_ has been modified, and that invalidates the loop iterator. break; } - jll_debug("Sent %zu bytes on UDP socket %d ifName %s to %s:%d", bufsize, fd, ifName.c_str(), mcastAddrStr_, port_); + jll_debug("Sent %zu bytes on UDP socket %d ifName %s to %s:%d", bufsize, fd, ifName.c_str(), + DefaultMulticastAddress(), DefaultUdpPort()); } } diff --git a/src/jazzlights/network/unix_udp.h b/src/jazzlights/network/unix_udp.h index 88b6c29b..11458c93 100644 --- a/src/jazzlights/network/unix_udp.h +++ b/src/jazzlights/network/unix_udp.h @@ -14,10 +14,10 @@ namespace jazzlights { class UnixUdpNetwork : public UdpNetwork { public: - UnixUdpNetwork(uint16_t port = DefaultUdpPort(), const char* addr = DefaultMulticastAddress()); + explicit UnixUdpNetwork(); NetworkStatus update(NetworkStatus status, Milliseconds currentTime) override; - NetworkDeviceId getLocalDeviceId() override { return localDeviceId_; } + NetworkDeviceId getLocalDeviceId() const override { return localDeviceId_; } int recv(void* buf, size_t bufsize, std::string* details) override; void send(void* buf, size_t bufsize) override; NetworkType type() const override { return NetworkType::kOther; } @@ -28,10 +28,10 @@ class UnixUdpNetwork : public UdpNetwork { void invalidateSocket(std::string ifName); bool setupSockets(); - NetworkDeviceId localDeviceId_; + static NetworkDeviceId QueryLocalDeviceId(); + + const NetworkDeviceId localDeviceId_ = QueryLocalDeviceId(); struct in_addr mcastAddr_; - char mcastAddrStr_[sizeof("255.255.255.255")]; - const uint16_t port_; std::unordered_map sockets_; }; diff --git a/src/jazzlights/player.cpp b/src/jazzlights/player.cpp index 2d99dbeb..b48b3b46 100644 --- a/src/jazzlights/player.cpp +++ b/src/jazzlights/player.cpp @@ -255,7 +255,7 @@ void Player::begin(Milliseconds currentTime) { // Figure out localDeviceId_. if (!randomizeLocalDeviceId_) { - for (Network* network : networks_) { + for (const Network* network : networks_) { NetworkDeviceId localDeviceId = network->getLocalDeviceId(); if (localDeviceId != NetworkDeviceId()) { localDeviceId_ = localDeviceId;