Narrator
Narrator

Reputation: 113

socket binding with INADDR_ANY and specific interface in multicast with multiple interface

I'm trying to write multicast server. I've two questions:

  1. How to send multicast announcements on multiple interfaces like ethernet/ wifi interface. Do I need to create multiple sockets for each interface and bind?

  2. When bind socket with INADDR_ANY address, descriptor is ready to do I/O operation (using select call )but when I bind with specific interface address e.g ethernet/wifi then descriptor is not ready to perform any operation it is stuck at select api only. So what is the difference between binding a socket with default address (INADDR_ANY) or specific interface address?

    int sd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sd < 0) {
            printf("scoket() failed");
            return sd;
    }
    
    int r = -1;
    
    int on = 1;
    if ((r = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on))) < 0) {
            printf("recv setsockopt(SO_REUSEADDR) failed");
            return r;
    }
    // add membership to receiving socket
    struct ip_mreq mreq;
    memset(&mreq, 0, sizeof(struct ip_mreq));
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    mreq.imr_multiaddr.s_addr = inet_addr(MDNS_ADDR);
    if ((r = setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq))) < 0) {
            printf("recv setsockopt(IP_ADD_MEM) failed");
            return r;
    }
     // enable loopback in case someone else needs the data
    if ((r = setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &on, sizeof(on))) < 0) {
            printf("recv setsockopt(IP_MULTICAST_LOOP) failed");
            return r;
    }
    
    
    #ifdef IP_PKTINFO
    if ((r = setsockopt(sd, SOL_IP, IP_PKTINFO, (char *) &on, sizeof(on))) < 0) {
            printf("recv setsockopt(IP_PKTINFO) failed");
            return r;
    }
    #endif
    /* bind to an address */
    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(MDNS_PORT);
    //serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);       /* receive multicast */
    serveraddr.sin_addr.s_addr = inet_addr("192.168.10.23");        /* receive multicast */
    if ((r = bind(sd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) < 0) {
            printf("recv bind()");
    }
    

In thread waiting for descriptors to ready for I/O (basically all are read file descriptors)

            FD_ZERO(&sockfd_set);
            FD_SET(svr->sockfd, &sockfd_set);
            FD_SET(svr->notify_pipe[0], &sockfd_set);
            printf("before select\n");
            select(max_fd + 1, &sockfd_set, NULL, NULL, NULL);
            printf("after select\n");

When socket id bind with INADD_ANY address select will returns and I'm able to read with file descriptor but when bind with specific interface then select never returns coz there is no file descriptors available to read.

Upvotes: 2

Views: 3611

Answers (2)

user207421
user207421

Reputation: 311008

  1. How to send multicast announcements on multiple interfaces like ethernet/ wifi interface. Do I need to create multiple sockets for each interface and bind?

No. Loop over the network interfaces and call setsockopt() with an appropriate join parameters for each interface in turn. You only need one socket.

  1. When bind socket with INADDR_ANY address, descriptor is ready to do I/O operation (using select call)

That's not correct. Your code only checks for readability.

but when I bind with specific interface address e.g ethernet/wifi then descriptor is not ready to perform any operation

Again that's not correct. You're only checking for readability, not 'any operation'. All this means is that no multicasts are coming in via the address you bound to.

it is stuck at select api only. So what is the difference between binding a socket with default address (INADDR_ANY) or specific interface address?

It determines the IP address you send and receive via.

Upvotes: 1

Stian Skjelstad
Stian Skjelstad

Reputation: 2335

Binding a socket with a specific address is a generic way to lock it down to a device. This method is a bit old-fashion, since addresses can be changed on a device after your program has started up. In general I would recommend to bind to INADDR_ANY.

You can change the output multicast device on a socket whenever you want.

Options to consider:

man 7 ip :
IP_MULTICAST_ALL - deliver to all devices (default 1)
IP_MULTICAST_IF - I'm pretty sure this only sets the output device

man 7 socket :
SO_BINDTODEVICE

Just play a little with the options and see what the result is

Upvotes: 0

Related Questions