I am trying to broadcast a string via UDP using the sendto() function.
The code below works fine on a Linux box (e.g. a Raspberry Pi) but fails under OS/X on an iMac and MacBook Air.
#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
int main(int argc, char*argv[])
{
const char *msg_str = "hello, world";
const char *bcast_addr = argv[1];
int port = atoi(argv[2]);
struct sockaddr_in sock_in;
int yes = 1;
int sinlen = sizeof(struct sockaddr_in);
memset(&sock_in, 0, sinlen);
int sock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if ( sock < 0 ) {
printf("socket: %d %s\n", errno, strerror(errno));
exit(-1);
}
sock_in.sin_addr.s_addr=inet_addr(bcast_addr);
sock_in.sin_port = htons(port);
sock_in.sin_family = PF_INET;
if ( bind(sock, (struct sockaddr *)&sock_in, sinlen) < 0 ) {
printf("bind: %s %d %s\n", bcast_addr, errno, strerror(errno));
exit(-1);
}
if ( setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(int) ) < 0 ) {
printf("setsockopt: %d %s\n", errno, strerror(errno));
exit(-1);
}
if ( sendto(sock, msg_str, strlen(msg_str), 0, (struct sockaddr *)&sock_in, sinlen) < 0 ) {
printf("sendto: %d %s str='%s', sinlen=%d\n", errno, strerror(errno), msg_str, sinlen);
exit(-1);
}
printf("message sent!\n");
}
My OS/X box is on a local network with an IP address of 192.168.0.4 and a broadcast address of 192.168.0.255. The output of ifconfig en1 | grep broadcast produces the following:
inet 192.168.0.4 netmask 0xffffff00 broadcast 192.168.0.255
If I run the code above above like this:
a.out 192.168.0.255 1234
The bind() and setsockopt() functions work, but sendto() returns errno 49. My program prints the following:
sendto: 49 Can't assign requested address str='hello, world', sinlen=16
But if I run it like this:
a.out 192.168.0.4 1234
Then everything works fine. But of course the broadcast only goes to the local box.
When I use the broadcast address (e.g. 192.168.0.255) on a Linux box on the same network, it works fine. On my Mac I have tried running both as a regular user and as root, with the same results. I seem to remember this working a few versions of OS/X ago (I know it did not work on Mavericks).
Any idea what Apple is doing here??
It looks like linux is just less restrictive. The problem should be with an attempt to bind to a non-local address 192.168.0.255:
sock_in.sin_addr.s_addr=inet_addr(bcast_addr);
Why don't you use 0.0.0.0 or 127.0.0.1 as a source address?
Or if you want to bind just to a particular interface you can process information about network addresses and netmasks using e.g. getifaddrs/freeifaddrs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With