Files
Marc SchierandCopilot aeeef5b420 Send UDP multicast on the network interface the transport joins (#4711)
# Description

`UdpDatagramTransport` joined multicast groups on the resolved network
interface: the connection address's `NetworkInterface`, the
`PreferredNetworkInterface` option, or the first operational interface.
It never set `IP_MULTICAST_IF` / `IPV6_MULTICAST_IF`, though, so
multicast data and discovery announcements left through the operating
system's default multicast route. On a computer with several network
interfaces, a publisher configured for one network sent on another, and
subscribers on the configured network missed the messages (OPC 10000-14
§7.3.2.2, `NetworkAddressDataType.NetworkInterface`).

`ConfigureSocket` now sets the multicast send interface to the resolved
interface for IPv4 and IPv6 sockets. That includes the separate socket
that sends discovery announcements for loopback-bound connections. A
failure is logged at Debug level, like the other socket options.

**Behavior change:** without a configured interface, multicast now
leaves through the first operational non-loopback interface, which is
the interface subscribers join on, instead of the default multicast
route. `docs/PubSub.md` and the XML docs of `PreferredNetworkInterface`
and `UdpNetworkInterfaceResolver` describe this and recommend naming the
interface on multi-homed computers.

Tests (`UdpDatagramTransportMulticastInterfaceTests`):

- The IPv4 and IPv6 egress options equal the resolved interface. Before
the fix they were `0.0.0.0` and `0`.
- A publisher and subscriber pinned to the loopback interface exchange a
payload. A raw control sender tells a host without loopback multicast
apart from a publisher that sends elsewhere. The test fails with the bug
on Linux; Windows also delivers local copies sent on other interfaces,
so there it only confirms the exchange.

### Validation

| Command | Result |
| --- | --- |
| `dotnet test tests/Opc.Ua.PubSub.Udp.Tests -f net10.0
-p:CustomTestTarget=net10.0 --filter
"FullyQualifiedName~UdpDatagramTransportMulticastInterfaceTests"`, with
the fix temporarily disabled | IPv4 and IPv6 option tests failed
(`Expected: <192.168.178.101> But was: <0.0.0.0>`, `Expected: 4 But was:
0`) |
| The same tests from the Windows-built binaries in a Linux container
(`mcr.microsoft.com/dotnet/sdk:10.0`, `dotnet test
Opc.Ua.PubSub.Udp.Tests.dll`), fix disabled, 5 runs | 3 of 3 failed in
every run, including the loopback exchange (the control sender arrived,
the publisher's multicast did not) |
| Same, with the fix, 5 runs | 3 of 3 passed in every run |
| `dotnet test tests/Opc.Ua.PubSub.Udp.Tests -f net10.0
-p:CustomTestTarget=net10.0` | 237 passed (Windows, and the same
binaries in the Linux container) |
| `dotnet test tests/Opc.Ua.PubSub.Udp.Tests -f net48
-p:CustomTestTarget=net48` | 232 passed |
| `dotnet test tests/Opc.Ua.PubSub.Tests -f net10.0
-p:CustomTestTarget=net10.0` | 1490 passed, 1 skipped |
| `dotnet build src/Opc.Ua.PubSub.Udp -c Release` (net10.0, net9.0,
net8.0, net48) | 0 warnings |
| The docs/PubSub.md first exchange (unicast loopback), run verbatim,
with #4710 applied | 11 DataSets; the unsecured-frame warning appears
once, as documented |

## Related Issues

- No tracking issue. Found while verifying the PubSub first-exchange
documentation (follow-up to #4555).

## Checklist

- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [x] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [x] I have added all necessary documentation.
- [x] I have verified that my changes do not introduce (new) build or
analyzer warnings.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [ ] I have addressed **all** PR feedback received.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-09 15:17:51 +02:00
..