1

I have a dual multicast setup where each multicast group needs to connect to a specific interface on my server.

Coliru

#include <boost/asio.hpp>
#include <iostream>

namespace ip = boost::asio::ip;
using ip::udp;

boost::asio::io_service io;

struct Connection {
    int32_t timeout = 5000;
    udp::socket sock {io};
    ip::address addr;

    bool Connect(std::string const& localAddr, std::string const& addrStr, int port, boost::system::error_code& ec) {
        // Multicast socket
        udp::endpoint local(ip::address::from_string(localAddr), port); // leaving host/port unbound doesn't seem to help

        std::cout << "Using local " << local << "\n";
        addr = ip::address::from_string(addrStr);
        udp::endpoint multicastEndpoint(addr, port);

        sock.open(multicastEndpoint.protocol());
        // The commented flags don't seem to have any effect on the findings
        //sock.set_option(ip::multicast::enable_loopback());
        sock.bind(local, ec);
        sock.set_option(ip::multicast::join_group(addr.to_v4()));
        sock.set_option(udp::socket::reuse_address(true));
        //setsockopt(sock.native(), SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout));

        return ec? false : true;
    }
};

struct ConnectionPair {
    Connection a, b;

    bool Connect(std::string const& addrStrA, int portA, std::string const& addrStrB, int portB, boost::system::error_code& ec) {
        // Example adresses; Replace with your local adapter addresses
        return a.Connect("172.17.0.1",     addrStrA, portA, ec) 
            && b.Connect("192.168.195.62", addrStrB, portB, ec);
    }
};

int main() {
    try {
        ConnectionPair pair;
        boost::system::error_code ec;

        // all hosts multicast groups
        if (pair.Connect("224.0.0.251", 5656, "224.0.0.1", 5657, ec)) {
            std::cout << "Both connected... ";
            boost::asio::deadline_timer dlt(io, boost::posix_time::seconds(5));
            dlt.wait();
        } else {
            std::cout << "Connection error: " << ec.message() << "\n";
        }
    } catch(std::exception const& e) {
        std::cout << "Exception: '" << e.what() << "'\n";
    }
    std::cout << "Bye\n";
}

Problem is, when using this to connect, socket A is getting no data. Using netsh interface ip show join, it shows that both multicast groups have been joined in the interface corresponding to localAddrB, instead of each in their place.

When using mdump to join the multicast groups, each is connecting to the proper location and receiving data.

I can't figure out where I went wrong with my code.

sehe
  • 328,274
  • 43
  • 416
  • 565
Eyal K.
  • 949
  • 5
  • 18
  • Have you seen http://stackoverflow.com/questions/10692956/what-does-it-mean-to-bind-a-multicast-udp-socket? All these answers seem to say it doesn't work this way. Frankly I agree with you, though when reading [§2.4 Receiving Multicast Datagrams](http://www.tldp.org/HOWTO/Multicast-HOWTO-2.html#ss2.4). And I can also confirm it doesn't seem to work - at least using Boost 1.62 – sehe May 04 '17 at 22:56
  • No difference with Boost 1.64 – sehe May 04 '17 at 23:35
  • @sehe So how do I get a specific multicast to be received by a specific local interface? This is obviously possible since mdump does it. – Eyal K. May 05 '17 at 13:40
  • I didn't try to answer the question. I'm not motivated to try without boost (C is not my hobby) and hence I'm not sure whether it's a bug in Asio. Perhaps, try looking at the source code of `mdump`, if possible. – sehe May 05 '17 at 13:41
  • @sehe mdump uses windows sockets, I wanted to know how to get it done in boost – Eyal K. May 05 '17 at 13:44
  • Still, by zooming in on the differences, you are more likely to spot the difference that makes it work. It's not useful to just sit concluding "it doesn't work". You need to know why. All sources of information are valuable. – sehe May 05 '17 at 13:46

1 Answers1

1

You can specifiy the interface on which to broadcast/join the multicast group.

http://www.boost.org/doc/libs/1_47_0/boost/asio/ip/detail/socket_option.hpp

These 2 lines:

this->socket.set_option(ip::multicast::outbound_interface(ip::address_v4::from_string(this->address)));

this->socket.set_option(ip::multicast::join_group(joinAddress, listenInterface));

In context:

  • Server Code:

    this->socket.open(ip::udp::v4());
    this->socket.set_option(ip::udp::socket::reuse_address(true));
    this->socket.set_option(ip::multicast::enable_loopback(true));
    this->socket.set_option(ip::multicast::hops(HOPS));
    
    this->socket.set_option(ip::multicast::outbound_interface(ip::address_v4::from_string(this->address)));
    this->socket.bind(ip::udp::endpoint(ip::address_v4::from_string(this->address), 0)); // any port
    
    this->ioService.run(); // blocking
    
  • Client Code:

    udp::endpoint bindEndpoint(ip::address_v4::any(), UDPMulticastServer::PORT);
    this->socket.open(ip::udp::v4());
    this->socket.set_option(ip::udp::socket::reuse_address(true));
    this->socket.bind(bindEndpoint);
    
    // Join the multicast group on a specific interface
    ip::address_v4 joinAddress = ip::address_v4::from_string(UDPMulticastServer::MULTICAST_ADDRESS);
    ip::address_v4 listenInterface = ip::address_v4::from_string(this->address);
    this->socket.set_option(ip::multicast::join_group(joinAddress, listenInterface));
    
    this->listenForBroadcast();
    this->ioService.run(); // blocking
    
sehe
  • 328,274
  • 43
  • 416
  • 565
Ayush Jain
  • 44
  • 6