diff --git a/src/config.cpp b/src/config.cpp index fc292ae7b..102581b2b 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -416,7 +416,12 @@ void _fromDefs(Config& self, const std::map& defs, boo } if(pickone({"EPICS_PVAS_INTF_ADDR_LIST"})) { - split_addr_into(pickone.name.c_str(), self.interfaces, pickone.val, self.tcp_port, true); + // defaultPort=0, matching the client EPICS_PVA_INTF_ADDR_LIST path below. + // A port-less interface stays at port 0 so the acceptor loop can follow the + // server onto the port actually bound -- including a conflict fallback chosen + // while binding the first interface. Filling in tcp_port here erases that + // "follow me" signal and strands the interface on the unbindable port. + split_addr_into(pickone.name.c_str(), self.interfaces, pickone.val, 0, true); } if(pickone({"EPICS_PVAS_IGNORE_ADDR_LIST"})) { diff --git a/test/testconfig.cpp b/test/testconfig.cpp index 1a3ef6f96..1cd9d253e 100644 --- a/test/testconfig.cpp +++ b/test/testconfig.cpp @@ -141,7 +141,9 @@ void testDefs() testEq(conf.tcp_port, 5678); testFalse(conf.auto_beacon); testEq(conf.beaconDestinations, std::vector({"1.2.1.2:1234", "4.3.2.1:1234"})); - testEq(conf.interfaces, std::vector({"1.1.1.1:5678", "1.2.3.4:5678"})); + // server INTF list round-trips port-less, matching the client path above + // (a port-less interface follows the server's bound TCP port at bind time). + testEq(conf.interfaces, std::vector({"1.1.1.1", "1.2.3.4"})); } } diff --git a/test/testwild.cpp b/test/testwild.cpp index dc11797a3..a1f2e7a0d 100644 --- a/test/testwild.cpp +++ b/test/testwild.cpp @@ -80,11 +80,39 @@ void testconflict(const char* addr) testNotEq(iconf.tcp_port, fconf.tcp_port)<<"w/ "<