Skip to content

Support for sending multicast packets on multiple interfaces with a single socket #86

Closed
@bltavares

Description

@bltavares

Hi there @alexcrichton,

Thanks a lot for the project. It has helped me to get started with a multicast-based project, and it was amazing. I was able to send messages and find peers, until I couldn't anymore. I've dig deep into the depths of the network stack, to find, with amusement, that network is chaos.

One of my computers could find the other announcements, but the other computer would not find the first one. After some analyses, I realized this is related to having multiple interfaces, which is very common on laptops (wifi and cable) and Windows machines with HyperV (and WSL2). To my surprise, I could listen to multicast packets on any of the interfaces, and it would only send on a specific one instead of a broadcast to all.

socket2-rs already supports most of the calls to have a "Single socket, multi interface listeners". If we bind to 0.0.0.0, we can use Socket::join_multicast_v4 for each interface ip (enumerating it is outside the package scope).

As we bind to 0.0.0.0, selecting the interface to use for sending the packets is delegated to the OS, and it might end-up selecting the interface that does not talk to the other computers, leading to partial discovery and something that I find very often with my dual network computer.

I found this StackOverflow answer that shows that it would be possible to use the already available Socket::set_multicast_if_v4 call to determine which interface to use before sending the packet, so we can hop around to respond on the same interface that we received the packet.

As you may already know, the default socket API does not return the origin interface on the packet, which made me despaired to find alternatives and question my own sanity of why I'm shaving this yak. I was surprised to find some incantations using IP_PKTINFO and/or/I'm not sure anymore IP_RECVIF to load the information from a "magic" place of the network stack, using CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_DATA, and WSARecvMsg on Windows.

It looks like this is what Avahi does the interface hopping already, in order to use a single socket to broadcast messages on all interfaces and locate peers happily until the next network topology breaks it again.

My question here; TL; DR; Would it make sense for the socket2-rs project to expose this extra information from CMSG_DATA and WSARecvMsg?

I do think I could make something as a separate crate, but it would also benefit a lot from the already available Windows/Unix infrastructure to build this project on the sys.rs file. If you do think it fits this project, I could try to get something running, but I would also be super ok to ask to have this on another crate.

The alternative seems to be create a socket per interface and put a MultiSocket struct grouping them, which would avoid all this side-quest, but it is not resource efficient, and I'm afraid I would displease Ferris by opening too many sockets.

If you have any other suggestions from your experience, I would love to hear them as well! This is way out of my depth hehehe

Thank you a lot for your attention and time to read this up :)

(PS: I've tried to make this issue funny to read, and I'm sorry ahead of time if it ended up too verbose, or came up weird. This hobby project is leading to so many rabbit holes but I'm learning a lot!)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions