Search code examples
c++socketsqt5udpclientmulticastsocket

UDP multicast is not received when socket is bound to local IP


Multicast sender is an external software, running on a host in same subnet and sending packets to 224.2.2.5:XXXX group, where XXXX is a fixed port number.

Client program, written by me, successfully joins group by using QUdpSocket (Qt5), but is unable to receive packets when run Linux (several Debian flavors, kernel 3.16 or 5.10, libc >2.4) only if socket is bound to 0.0.0.0. If bound to IP of concrete interface, there is no datagram pending. IT's fine for test environment where is only one NI, but not fine for production where a dozen of networks are present.

Binding code

    sock = new QUdpSocket(this);

    bool result = sock->bind( host_addr, port_num,
                             QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
    if(!result)
    {
        debugline("Binding port had failed");
    }
        
    result &= sock->joinMulticastGroup(group);
    if(!result)
    {
        debugline("Joining group had failed");
    }

Receive code

 QHostAddress    addr;
 quint16         port_num;
 qint64          nextSize = sock->pendingDatagramSize();
 if(nextSize < 0) peturn;

 bool gotData = false;
 while ( nextSize > -1 )
 {
     auto res = sock->readDatagram(reinterpret_cast<char*>(inputBuffer),
                                   DataFrame::MaximumFrameSize,  &addr, &port_num);

If host_addr is not "0.0.0.0", pending datagram size remains zero, while tcpdump sregisters incoming packets with TTL=1 and netstat shows open socket.


Solution

  • On linux, with multicast, in general, you will want to either

    1. Bind to the multicast address - This will cause the socket to only receive packets sent to the multicast address
    2. Or Bind to the 0.0.0.0 (any) address - This will cause the socket to receive multicast packets, as well as unicast packets to the same port (or multiple multicast addresses with the same port).

    In most multicast use cases, I prefer #1, but I have had #2 come up from time to time. If you want to control which interfaces a multicast packet can be received on, you will want the overload for joinMulticastGroup which takes the network interface, and you will want to call it repeatedly.