Christi258
Christi258

Reputation: 51

invalid argument on boost asio udp socket connect (IPv6)

I'm struggling with an issue for hours: I want to connect an boost asio udo socket to an endpoint. There is no problem doing this in IPv4. But if I try to do the same in IPv6, I get an error-code "invalid argument".

using boost::asio::ip::udp;

struct UdpConnectionParams
{
    udp::endpoint m_localEndpoint;
    udp::endpoint m_remoteEndpoint;
}

boost::system::error_code setupUdpConnection(udp::socket& p_socket, const UdpConnectionParams& p_params)
{
    // close socket
    boost::system::error_code h_ignoreError;
    p_socket.close(h_ignoreError);
    // variables for kind of UDP connection
    udp h_protocol(udp::v4());
    bool h_shallBind{false};
    bool h_shallConnect{false};

    // determine kind of connection
    if(p_params.m_localEndpoint != udp::endpoint())
    {
        h_protocol = p_params.m_localEndpoint.protocol();
        h_shallBind = true;
    }
    if(p_params.m_remoteEndpoint != udp::endpoint())
    {
        h_protocol = p_params.m_remoteEndpoint.protocol();
        h_shallConnect = true;
    }
    if(!h_shallBind && !h_shallConnect)
    {
        // no endpoint specified, return error
        return boost::system::error_code(ENetworkErrorCode::NO_ENDPOINT_SPECIFIED, NetworkErrorCategory::getCategory());
    }

    try
    {
        p_socket.open(h_protocol);
        //bind socket to certain endpoint
        if(h_shallBind)
        {
            p_socket.bind(p_params.m_localEndpoint);
        }
        //connect socket to client. Thus it is possible to use p_socket.send()
        if(h_shallConnect)
        {
            p_socket.connect(p_params.m_remoteEndpoint);
        }
    }
    catch (boost::system::system_error& h_error)
    {
        p_socket.close(h_ignoreError);
        return h_error.code();
    }
    // no error
    return boost::system::error_code();
}

int main()
{
    boost::asio::io_service service;
    udp::socket socket(service);
    boost::system::error_code error;
    UdpConnectionParams params;
    params.m_localEndpoint = udp::endpoint(udp::v6(), 55555);
    params.m_remoteEndpoint = udp::endpoint(boost::asio::ip::address_v6::from_string("ff01::101"), 55555);
    error = setupUdpConnection(socket, params);
    cout << error << error.message() << endl; // "invalid argument"
    return 0;
}

The only way I get no error, is with localhost IP address (::1). There is no difference if I bind the socket to an endpoint. What am I doing wrong?

Upvotes: 1

Views: 1888

Answers (1)

Jeremy Friesner
Jeremy Friesner

Reputation: 73041

What am I doing wrong?

The problem is that you don't specify an interface index/scope in the IPv6 address you are using. IPv6 multicast address require a scope to be specified, so that the network stack will know which of your computer's local network interfaces to associate the IP address with.

i.e. instead of:

 boost::asio::ip::address_v6::from_string("ff01::101"), 55555);

you need something like:

 boost::asio::ip::address_v6::from_string("ff01::101%eth0"), 55555);

(The suffix after the % symbol will depend on the name of the network interface you want to use, of course)

(As a side note, the "ff01::" prefix is for node-local IPv6 multicast groups, which means that your UDP packets will only go to other programs running on the same computer. If that's what you intended, then great; on the other hand, if you wanted your UDP packets to reach other computers on the same LAN, you'll want to use a "ff02::" or "ff12::" prefix instead (ff02:: would be for a well-known multicast address, ff12:: would be for a transient multicast address). See the "Multicast address scope" table on the Wikipedia page for details)

Upvotes: 3

Related Questions