diff --git a/commonLibs/livoxProto1/udpCommandDemuxer.cpp b/commonLibs/livoxProto1/udpCommandDemuxer.cpp index 2f6fb2e..888ec4d 100644 --- a/commonLibs/livoxProto1/udpCommandDemuxer.cpp +++ b/commonLibs/livoxProto1/udpCommandDemuxer.cpp @@ -125,6 +125,17 @@ void UdpCommandDemuxer::setupCommandSocket() + ": Failed to create socket: " + strerror(errno)); } + // Set SO_REUSEADDR to allow binding even if port is in TIME_WAIT + int reuse = 1; + if (setsockopt( + socketGuard.getFd(), SOL_SOCKET, SO_REUSEADDR, + &reuse, sizeof(reuse)) < 0) + { + throw std::runtime_error( + std::string(__func__) + + ": Failed to set SO_REUSEADDR: " + strerror(errno)); + } + // Set socket to non-blocking mode int flags = fcntl(socketGuard.getFd(), F_GETFL, 0); if (flags < 0 || fcntl( @@ -135,7 +146,23 @@ void UdpCommandDemuxer::setupCommandSocket() + ": Failed to set non-blocking mode: " + strerror(errno)); } - // Bind to command port + /** EXPLANATION: + * Bind to command port. + * + * WSL2 NAT PORT TRANSLATION ISSUE: + * On Windows 10, WSL2 uses NAT that translates UDP source ports when + * forwarding packets from WSL to the physical network. A socket bound to + * port 56001 in WSL may send from port 52511 on the wire. + * + * The device should use the cmd_port from the handshake message (56001), + * not the translated source port, so this may not break functionality. + * However, Windows NAT behavior can be unpredictable. + * + * Solutions: + * - Windows 11 22H2+: Use WSL2 mirror networking mode (.wslconfig) + * - Run natively on Linux + * - Accept the limitation (may work if device uses cmd_port from handshake) + */ struct sockaddr_in localAddr; memset(&localAddr, 0, sizeof(localAddr)); localAddr.sin_family = AF_INET; @@ -151,6 +178,31 @@ void UdpCommandDemuxer::setupCommandSocket() + std::to_string(commandPort) + ": " + strerror(errno)); } + /* Verify the socket is actually bound to the expected port + * This helps catch WSL/Windows networking issues. + */ + struct sockaddr_in boundAddr; + socklen_t boundAddrLen = sizeof(boundAddr); + if (getsockname( + socketGuard.getFd(), + (struct sockaddr *)&boundAddr, &boundAddrLen) == 0) + { + uint16_t boundPort = ntohs(boundAddr.sin_port); + if (boundPort != commandPort) + { + std::cerr << __func__ << ": WARNING: Socket bound to port " + << boundPort << " instead of expected port " + << commandPort << std::endl; + } +#if 1 + else + { + std::cout << __func__ << ": Successfully bound command socket " + "to port " << boundPort << std::endl; + } +#endif + } + // Create boost wrapper for async operations cmdEndpointFdDesc = std::make_shared( componentThread->getIoService(), socketGuard.getFd());