c++socketsubuntu

UDP socket (multicast) not receiving data (Ubuntu)


I'm trying to set up a little test application on Linux (Ubuntu) based on some code I wrote (and that worked) for Winsock. As it stands now, it's just a little test that creates a socket (and seemingly successfully connects) only to hang eternally on recv() instead of receiving datagrams. It's a plain blocking socket.

Here's how I create it:

// Winsock commodities :)
typedef unsigned int SOCKET;
const unsigned int INVALID_SOCKET = -1;

static SOCKET Connect(const std::string &interfaceIP, const std::string &bindIP, unsigned int port)
{
    // Create UDP socket.
    SOCKET sock_fd = socket(AF_INET, SOCK_DGRAM, 0); 
    if (INVALID_SOCKET != sock_fd)
    {
        // "Share" socket address.
        int sockOpt = 1;
        setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&sockOpt), sizeof(int));

        // Enlarge (or embiggen, if you will) recv. buffer.
        sockOpt = 1024*512; // 0x80000;
        setsockopt(sock_fd, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<char *>(&sockOpt), sizeof(int));

        // Bind to interface(s).
        sockaddr_in address;
        memset(&address, 0, sizeof(sockaddr_in));
        address.sin_family = AF_INET;
        address.sin_port = htons(port);
        address.sin_addr.s_addr = inet_addr(interfaceIP.c_str()); /* INADDR_ANY */
        int addrLen = sizeof(sockaddr_in);
        if (0 == bind(sock_fd, reinterpret_cast<sockaddr *>(&address), addrLen))
        {
            // Join multicast.
            ip_mreq multicast;
            multicast.imr_multiaddr.s_addr = inet_addr(bindIP.c_str());
            multicast.imr_interface = address.sin_addr;

            if (0 == setsockopt(sock_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, reinterpret_cast<char *>(&multicast), sizeof(ip_mreq)))
            {
                // Non-blocking socket, please.
//              fcntl(sock_fd, F_SETFL, O_NONBLOCK);

                std::cout << "Socket joined multicast: " << bindIP.c_str() << ":" << port << std::endl;
                return sock_fd;
            }
        }


        close(sock_fd);
    }

    std::cout << "Failed to join multicast: " << bindIP.c_str() << ":" << port << std::endl;

    return INVALID_SOCKET;
}

A few further things tested:

So clearly I'm overlooking something. Help greatly appreciated :-)


Solution

  • So, in the end a little system configuration and bugfixing went a long way:

    a) As root, I'd had to do the following to disable the reverse packet filter: echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter + The same for ethX.

    b) Add a bogus route for the ethX (route add -net 224.0.0.0. netmask 224.0.0.0 ethX)

    c) Bind the socket to the to-be-joined group's IP (otherwise any subsequent socket would get all packets from all groups I joined on that particular port).

    d) Set the interface member of the ip_mreq struct to the IP of the adapter we're receiving on.

    And then all was fine and dandy, test runs fast & smooth (pulling 125 multicast transport streams @ around 800-900 mbit - sure this can be smarter, but still). Thanks for all the pointers.