keepsimple1 / mdns-sd

Rust library for mDNS based Service Discovery
Apache License 2.0
88 stars 38 forks source link

prototype: add unicast sockets #187

Closed keepsimple1 closed 3 months ago

keepsimple1 commented 3 months ago

This is to experiment some ideas in issue #65 . It does not fully address the issue (details below) but showing it's possible to bind to multicast address and use separate unicast sockets. (only tested on macOS at the moment).

In theory, it is mainly based on two statements in the book "Unix network programming" by W. Richard Stevens:

  1. In section 19.3 Multicasting versus Broadcasting on A LAN, it says:

... Nothing special is required to send a multicast datagram: the application does not have to join the multicast group.

hence, in this patch, we use uni_sock in the fn send_packet even for sending multicast packets.

  1. In section 19.5 Multicast Socket Options, towards to the end, it says:

.. Some applications also bind the multicast address to the socket, in addition to the port. This prevents any other datagrams that might be received for that port from being delivered to the socket.

Hence, in this patch, we bind the multicast socket to GROUP_ADDR_V4/6, instead of INADDR_ANY, to prevent this socket from receiving unicast packets.

However, there is a problem: even with dedicated unicast sockets, we don't know the source IP of unicast packets received. This is because we are using .read() , not .recv_from(). This is an old problem because in socket2 .recv_from() became unsafe to use since 0.4.0.

In my understanding, a prime use case of issue #65 is that:

  1. a querier sends a query datagram to mDNS Multicast address with QU flag in its question.
  2. a responder receives the query on its multicast socket.
  3. Due to QU flag, the responder sends back responses in unicast back to the querier.
  4. The querier receives the unicast responses.

Although this patch can support receiving the unicast responses, the responder cannot do step 3 as they don't know the unicast IP of the querier.

A more rare use case is that the querier directly sends questions in unicast, which could be supported by this patch.

keepsimple1 commented 3 months ago

The test failure on Ubuntu Linux is:

thread 'service_daemon::tests::service_with_temporarily_invalidated_ptr' panicked at 'calledResult::unwrap()on anErrvalue: Msg("socket bind to [ff02::fb]:5353 failed: Invalid argument (os error 22)")', src/service_daemon.rs:2496:47

The IPv6 addr ff02::fb is a link-local multicast address (according to chatGPT). Binding to it works fine on macOS but for some reason it failed on Linux.