rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.27k stars 12.71k forks source link

Multicast with multiple NICs #25346

Closed GGist closed 9 years ago

GGist commented 9 years ago

I am having some issues using UdpSockets to listen on multiple network interfaces for multicast messages. It seems that when I spin up two UdpSockets, one bound to the Local Area Connection and the other to Hamachi, and I subscribe to a specific multicast address on both sockets, only one of them (usually the default interface) will ever receive multicast messages during an execution of the program.

I coded up a quick C solution and I was able to get my application working (I am using Windows so minor modifications should allow it to run on Linux).

I noticed in the libstd crate that for all UdpSockets it looks like the multicast interface is set as 0x0, aka, 0.0.0.0. As far as I know, in Windows this tells the operating system to subscribe to multicast on the default interface. And it looks like a similar situation on linux (under IP_ADD_MEMBERSHIP). Although on Linux it uses the wording "an appropriate interface is chosen by the system" which may not mean the default interface but I am not sure.

I know I read in a previous issue that the current sockets API was going to be revamped to allow greater flexibility for socket creation options, but to me it looks like the current implementation is possibly broken. For example, when I was doing some tests I noticed, again at least on Windows, that if I bind to a local interface that is not set as the default interface in the system and join multicast, I wont receive multicast at all from that socket.

Unless it is a different situation in Linux, I think it would make a lot more sense to use the address bound to the UdpSocket as the interface in the ip_mreq struct instead of 0x0. Also, when/if the sockets API is revamped, it would be nice if I could bind to 0.0.0.0 and choose which interfaces I receive multicast from (like I did in my example) so I can use one socket for multiple receiving interfaces.

alexcrichton commented 9 years ago

Thanks for the report! I think most of this is already covered by https://github.com/rust-lang/rfcs/issues/957, however, so I'm going to close this in favor of that. I have an RFC-in-progress that I hope to post soon as well for upcoming additions to the std::net module, and I believe that it should address most of the concerns you've listed here. Specifically though:

For example, when I was doing some tests I noticed, again at least on Windows, that if I bind to a local interface that is not set as the default interface in the system and join multicast, I wont receive multicast at all from that socket.

After reviewing the implementations recently I agree that some of the methods involved here aren't giving you enough of a low-level interface as one might expect. The RFC will propose exposing all arguments for each socket option, including all fields of ip_mreq (which you've found we default some to 0).

Unless it is a different situation in Linux

The current design of the std::net module is to not deal with many platform differences itself beyond what APIs are exposed. For example the shutdown method can have subtly different semantics depending on what system you're on, but part of the contract that the standard library is providing is that you have a clear connection to the underlying primitives being called so you know what's happening. The revamp of socket options and creation (my upcoming RFC) should address this as well!

GGist commented 9 years ago

Awesome, thanks for the link to the current RFC, and I look forward to reading your upcoming RFC as well.