sven
sven

Reputation: 1121

UDP server socket IP assignment

I run the server code below to open a UDP socket. I have two network interfaces on my linux machine and two interfaces are connected to two different networks. I would like the program to listen a specified network (by assigning IP address), therefore I assign an IP address on the UDP socket.

If I use servaddr.sin_addr.s_addr = htonl(INADDR_ANY); the server is able to receive the broadcast and unicast messages. However, if I define the servaddr.sin_addr.s_addr =inet_addr("10.0.0.6");then the server can receive the messages originated to 10.0.0.6 but cannot receive the broadcast 10.0.0.255 message (the netmask is /24). here is the code that broadcasts the message, and the unicast code is here.

Am I assigning the IP address wrong or is the broadcast code wrong?

Server code is:

#define BUFSIZE 512
char *SERVER_IP = "10.0.0.6";

int main() {
    int error_count=0, r=0, n=0;
    int sockfd = 0;
    struct sockaddr_in servaddr, cliaddr ,a ;
    socklen_t len; //integer type of width of at least 32 bits
    char mesg[1000];

    sockfd = socket(AF_INET, SOCK_DGRAM, 0); // for datagram
    while(sockfd < 0){ //error handling for socket opening
        usleep(500000);
        if (++error_count == 20){//10 times itteration
             fprintf(stderr, "errno:%s - socket opening error - line 223\n ", strerror(errno));
            exit(1);
        }
         sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    }
error_count = 0;

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(33333); //server listens on this port


   // servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
     servaddr.sin_addr.s_addr =inet_addr(SERVER_IP);
    printf("servaddr.sin_addr:%lu\n",servaddr.sin_addr );
    printf("a.sin_addr:%lu\n",a.sin_addr );

    r = bind(sockfd,(struct sockaddr *) &servaddr, sizeof(servaddr));
    while(r < 0){ //error handling for socket binding
        usleep(500000);
        if (++error_count == 20){//10 times itteration
             fprintf(stderr, "errno:%s - socket binding error - line 239\n ", strerror(errno));
            exit(1);
        }
          r = bind(sockfd,(struct sockaddr *) &servaddr, sizeof(servaddr));
    }
error_count = 0;


    while(1){
       len = sizeof(cliaddr);
    next:
printf("server is listening\n");
       n = recvfrom(sockfd, mesg, 1000, 0, (struct sockaddr *) &cliaddr, &len);
printf("line195: packet is received: %s\n", mesg);
       if(n < 0){
           fprintf(stderr, "recvfrom error occured - line254\n");
           n = 0;
           goto next;
       }
}
  return 0;
}

here is my ifconfig -a wlan8

wlan8     Link encap:Ethernet  HWaddr 64:70:02:18:1f:b6  
          inet addr:10.0.0.6  Bcast:10.0.0.255  Mask:255.255.255.0
          inet6 addr: fe80::6670:2ff:fe18:1fb6/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:206 errors:0 dropped:0 overruns:0 frame:0
          TX packets:297 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:37857 (37.8 KB)  TX bytes:54526 (54.5 KB)

Upvotes: 3

Views: 8671

Answers (3)

Giacomo Tesio
Giacomo Tesio

Reputation: 7210

You can get your server to work as you need with INADDR_ANY and proper call to setsockopt.

It should be something like this, just after the socket creation:

memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "wlan8");
if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
            (void *)&ifr, sizeof(ifr)) < 0) {
     fprintf(stderr, "error at setsockopt, ensure it is running as root.\n");
     exit(1);
}

Obviously, you have also to #include <net/if.h> and define struct ifreq ifr; at the beginning of main.

This way your server will recieve every datagram that targets any of the address of the wlan8 interface (both broadcast and unicast), but it will ignore other interfaces.

SO_BINDTODEVICE has been introduced to linux for DHCP client and server, but requires root permission. You can use sudo or execute the following command from root to set SUID (thus you have control the program execution via group associations)

chmod 4750 server_name

Obviously you should be careful with such kind of programs, or you will open security a hole in your system.

Finally I suggest you to read

Upvotes: 2

Fred
Fred

Reputation: 8602

You aren't doing anything wrong. Linux won't receive broadcast datagrams unless the socket is bound to the broadcast address or INADDR_ANY. You'll need to bind one socket to the unicast address and another socket to the broadcast address, or you can use IP_PKTINFO to find the destination address if you bind to INADDR_ANY. There is some example code over at Get destination address of a received UDP packet.

Upvotes: 1

fredrik
fredrik

Reputation: 6638

If you want it to listen to interface wlan8 only, try with listening to the entire network - 10.0.0.0 in this case. If you bind to the IP of the interface it probably will receive only messages with it as destination.

Upvotes: 0

Related Questions