DeVadder
DeVadder

Reputation: 1404

Bind a socket to a specific interface with unknown Ip

I have a host with two interfaces. In my specific case I am trying to join a multicast group using boost::asio::ip::multicast::join_group which appears to only work if i use the constructor that includes the local address. However i do not know in advance the ip address of the local interface connected to the remote host that will do the multicasting. I do however know that it will be eth1. Of course, i could make it configurable but that seems like introducing a useless opportunity to misconfigure, seeing how the same address would have to be configured for the interface and my application.

Ideally there would be a glaringly obvious way to create a boost::asio::endpoint or boost::asio::address from an interface instead of an address that i somehow missed. Alternatively i would of course be just as happy with any other way to deduce an interfaces Ip that works both, with and without a DHCP-Server supplying the Ip.

Is there a proper way to do either or should i just trust users to never fumble with the configuration?

To make sure that this is not completely a XY Problem, here is the code i used while testing to join a multicast group:

m_socket.open(boost_ip::udp::v4());
m_socket.bind(boost_ip::udp::endpoint(boost_ip::udp::v4(), listeningPort));

m_socket.set_option(boost::asio::ip::udp::socket::reuse_address(true));
m_socket.set_option(boost::asio::ip::multicast::join_group(
                  boost::asio::ip::address::from_string("225.x.x.10").to_v4(),  // remote
                  boost::asio::ip::address::from_string("192.x.x.3").to_v4())); // local

This does work but when i discard the last line to not be dependent on the current local address (that might be changed in deployment), i no longer receive any packets.

Upvotes: 1

Views: 1279

Answers (2)

DeVadder
DeVadder

Reputation: 1404

I came up with an answer to my question myself. This works for me but I will leave the question open in case anyone has a more straightforward solution.

I settled with using <ifaddrs.h> to just find my current ip for the interface and use that to join the multicast group. This is the code i ended up with to determine my ip:

#include <ifaddrs.h>
#include <boost/asio.hpp>
#include <cstring>

std::string getInterfaceAddress(const std::string & interfaceName)
{
    ifaddrs* firstNetIf = 0;
    getifaddrs(&firstNetIf);

    ifaddrs* netIf = 0;
    for(netIf = firstNetIf; netIf != 0; netIf = netIf->ifa_next)
    {
        if(netIf->ifa_addr->sa_family == AF_INET && std::strncmp(netIf->ifa_name, interfaceName.c_str(), interfaceName.length()) == 0)
        {
            break;
        }
    }

    unsigned long address =
            netIf != 0 ? reinterpret_cast<sockaddr_in*>(netIf->ifa_addr)->sin_addr.s_addr : 0;

    if(firstNetIf != 0)
    {
        freeifaddrs(firstNetIf);
    }

    return boost::asio::ip::address_v4(htonl(address)).to_string();
}

Of course in my case i could compare with "eth1" and return the boost::asio::ip::address directly but it turns out that this code can be used at one other place as well this way.

Upvotes: 1

Vivek
Vivek

Reputation: 330

Multicast uses the IGMP protocol to form a multicast group. Since IGMP operates on the network layer, it requires the local ip address of the end-point that is joining the multicast group.

The application should wait for an event indicating an ip address has been assigned to the ethernet interface and then call the join_group method to join the multicast group.

Upvotes: 1

Related Questions