Reputation: 1121
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
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
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
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