1

The following example program creates two udp sockets, joins them to two different multicast groups, then binds both of them to INET_ANY on the same port (using SO_REUSEADDR).

The program also sends a datagram to one of the two multicast groups, for illustration purposes.

#include <iostream>
#include <boost/asio/ip/udp.hpp>
#include <boost/asio/ip/multicast.hpp>

int main()
{
    namespace ip = boost::asio::ip;
    using udp = ip::udp;

    boost::asio::io_context context;
    const auto addr1 = ip::address::from_string("224.111.0.0");
    const auto addr2 = ip::address::from_string("224.112.0.0");
    const unsigned short port = 10001;

    udp::socket receiver1( context, udp::v4() );
    udp::socket receiver2( context, udp::v4() );
    receiver1.set_option( ip::multicast::join_group(addr1) );
    receiver2.set_option( ip::multicast::join_group(addr2) );
    receiver1.set_option( udp::socket::reuse_address(true) );
    receiver2.set_option( udp::socket::reuse_address(true) );
    receiver1.non_blocking(true);
    receiver2.non_blocking(true);
    receiver1.bind( udp::endpoint(ip::address_v4::any(), port ) );
    receiver2.bind( udp::endpoint(ip::address_v4::any(), port ) );

    char data[1] = {};

    // Dummy sender
    udp::socket sender( context, udp::v4() );
    sender.send_to( boost::asio::buffer(data), udp::endpoint(addr2,port) );

    udp::endpoint sender_ep;
    boost::system::error_code ec;
    std::size_t count;

    count = receiver1.receive_from(boost::asio::buffer(data), sender_ep, 0, ec );
    std::cout << "Receive1 : " << count << " from: " << sender_ep << std::endl;

    count = receiver2.receive_from(boost::asio::buffer(data), sender_ep, 0, ec );
    std::cout << "Receive2 : " << count << " from: " << sender_ep << std::endl;
}

On my linux machine (kernel 5.1.15), the output is:

Receive1 : 1 from: 192.168.1.67:37165
Receive2 : 1 from: 192.168.1.67:37165

That is, both sockets received the single datagram that was sent to 224.112.0.0, even if receiver1 has not joined that group.

The same code compiled for windows, tested on my windows 7 x64 virtual machine, outputs instead:

Receive1 : 0 from: 0.0.0.0:0
Receive2 : 1 from: 192.168.56.101:54670

That is, only the socket that joined the group 224.112.0.0. receives the datagram.

Questions:

  • Is this difference intended? If so, is it documented anywhere?
  • If I cannot modify the receiving application, is there some way, either via configuration of the sending socket, or OS config, to mimic the windows behavior on my linux machine?

Some context:

I am trying to run two instances of a 3rd party windows binary on linux using wine. I figured that each instance does something along the lines of the example code (the exact multicast group is configurable, but not the port it uses). Wine approximately converts winsock to posix 1-to-1, so the program running on wine behaves in the same way as the example on native linux. At the moment I am unable to control the two instances individually, since both receive the same data.

dbush
  • 162,826
  • 18
  • 167
  • 209
sbabbi
  • 10,402
  • 2
  • 24
  • 51

1 Answers1

0

Try changing your binds to use the multicast address rather than 'any'.

See What does it mean to bind a multicast (UDP) socket?

David
  • 26
  • 2
  • But only on Linux, this is another misfeature of theirs. You can't bind to the multicast address on other platforms. – user207421 Jul 22 '19 at 08:02
  • I dont't have access to the code that binds the sockets. I know that if I bind to the multicast address everything works correctly on both platform, but unfortunately I cannot do that. – sbabbi Jul 22 '19 at 10:57