1
votes

I wrote a broadcaster and a listener which recvfrom a particular port on the system. I used REUSEADDR option for the socket in listener, to make multiple instances of listener monitor the same port on same system.

When I run the listener on different machines, and send packet from another machine, all the listeners receives the packet. but when I run multiple instances of listener on same machine and if I try sending udp packets, only the first instance of listener gets the packet not all. I want to broadcast UDP packets on same machine and want all the listeners to receive the packet. I am on linux.

I followed the Beej's Guide.

Edit 01

listener code

/*
** listener.c -- a datagram sockets "server" demo
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#define MYPORT "4950"   // the port users will be connecting to

#define MAXBUFLEN 100

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
        if (sa->sa_family == AF_INET) {
                return &(((struct sockaddr_in*)sa)->sin_addr);
        }

        return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main(int argc, char *argv[])
{
        int sockfd;
        struct addrinfo hints, *servinfo, *p;
        int rv;
        int numbytes;
        struct sockaddr_storage their_addr;
        char buf[MAXBUFLEN];
        socklen_t addr_len;
        char s[INET6_ADDRSTRLEN];

        int reuse_addr = 1;


        memset(&hints, 0, sizeof hints);
        hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
        hints.ai_socktype = SOCK_DGRAM;
        hints.ai_flags = AI_PASSIVE; // use my IP

        if ((rv = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) {
                fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
                return 1;
        }

        // loop through all the results and bind to the first we can
        for(p = servinfo; p != NULL; p = p->ai_next) {
                if ((sockfd = socket(p->ai_family, p->ai_socktype,
                                p->ai_protocol)) == -1) {
                        perror("listener: socket");
                        continue;
                }

                if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {

                        if(errno == EADDRINUSE)
                        {
                                if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
                                                &reuse_addr, sizeof reuse_addr) < 0)
                                        perror("setsockopt(): REUSEADDR\n"),exit(1);
                        }
                        else
                        {
                                close(sockfd);
                                perror("listener: bind");
                                continue;
                        }
                }
                break;
        }

        if (p == NULL) {
                fprintf(stderr, "listener: failed to bind socket\n");
                return 2;
        }

        freeaddrinfo(servinfo);

        printf("listener: waiting to recvfrom...\n");

        addr_len = sizeof their_addr;
        if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0,
                (struct sockaddr *)&their_addr, &addr_len)) == -1) {
                perror("recvfrom");
                exit(1);
        }

        printf("listener: got packet from %s\n",
                inet_ntop(their_addr.ss_family,
                        get_in_addr((struct sockaddr *)&their_addr),
                        s, sizeof s));
        printf("listener: packet is %d bytes long\n", numbytes);
        buf[numbytes] = '\0';
        printf("listener: packet contains \"%s\"\n", buf);

        close(sockfd);

        return 0;
}
2
What IP address is your sender sending to? If it's sending to 127.0.0.1, then it's sending unicast packets and only one listener will receive them. If it's sending to your local network's broadcast address (e.g. 192.168.0.255 if you're on a 192.168.0.x network, or 10.255.255.255 if you're on a 10.0.x.y network, and so on) then all the listeners should receive the packet.Jeremy Friesner
I tried sending to 255.255.255.255, localhost and to 0.0.0.0. in all the cases only one listener gets the packet.selvakumar
Try your LAN's broadcast address (which is basically your IP address bitwise-or'd with the bitwise-not of your netmask; e.g. for ip=192.168.2.5 netmask=255.255.255.0, broadcast_address=(192.168.2.5 | 0.0.0.255) = 192.168.2.255Jeremy Friesner
I tried that too now. it didn't work. I also tried to set SO_REUSEPORT option. but it seems it is not available in linux; gcc throws compilation errorselvakumar
can you post the listner code?sujin

2 Answers

0
votes

Set socket option to SO_REUSEPORT in linstener.

SO_REUSEPORT - socket option allows multiple sockets on the same host to bind to the same port

0
votes

Make accept_local as 1 using echo in SYSFS.

/proc/sys/net/ipv4/conf/all # cat accept_local
1

This will allow local communication.