How to distinguish the incoming packets when joining multiple multicast feeds in udpsocket

I need to listen 2 UDP multicast addresses. One is 233.113.216.73:21001 and the other is 233.113.216.71:21001. Due to their ports are same I can't bind to them separately.

use std::net::UdpSocket;

let socket = UdpSocket::bind("0.0.0.0:21001").unwrap();
udp_socket.join_multicast_v4(&Ipv4Addr::new(233, 113, 216, 71), &Ipv4Addr::UNSPECIFIED)?;
udp_socket.join_multicast_v4(&Ipv4Addr::new(233, 113, 216, 73), &Ipv4Addr::UNSPECIFIED)?;

I can listen both of the feed with udp_socket.recv_from(&mut self.buffer) without any issues. However, I can't know the incoming packet's multicast group. recv_from returns the IP address of the client, not the multicast group.

Is there any way to get the multicast group of the incoming datagram?

Thanks for your help in advance.

I don't think this is possible with a single socket.

maybe you could try to use two sockets that binds to the same port instead of a single socket.

however, since SO_REUSEPORT is very low level, rust's standard library doesn't have an abstraction for it, so you'll have to resort to platform specific crates. for example, with socket2, you probably could try something like:

// create socket
let socket1 = Socket::new(Domain::IPV4, Type::DATAGRAM, None)?;
// set socket option SO_REUSEPORT
socket1.set_reuse_port(true)?;
// bind to the address
socket1.bind(&addr)?;
// convert to standard library `UdpSocket`
let socket1: UdpSocket = socket1.into();
// join the first multicast group
socket1.join_multicast_v4(&Ipv4Addr::new(233, 113, 216, 71), &Ipv4Addr::UNSPECIFIED)?;

// do the same for the other multicast group
let socket2 = Socket::new(Domain::IPV4, Type::DATAGRAM, None)?;
socket2.set_reuse_port(true)?;
socket2.bind(&addr)?;
let socket2: UdpSocket = socket2.into();
socket2.join_multicast_v4(&Ipv4Addr::new(233, 113, 216, 73), &Ipv4Addr::UNSPECIFIED)?;

to keep it simple, you can use different threads for each socket. I think it's also possible to use async sockets if the multiple threads don't scale well for you special case, but I don't have any experience for this.

DISCLAIMER:

I have never encountered such special use cases, I don't know if this would work at all, but worth a try.

you'll have to drop to lower-level APIs for that.
Set IP_PKTINFO via socket options, use recvmsg and fish the packet info out of the cmsg ancillary data.

The rustix crate almost provides that, but its RecvAncillaryMessage type seems too limited to represent the cmsg of interest. Maybe there's some other crate that does.

1 Like