Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UDP broadcast via sendto() returns "Can't assign requested address" on OS/X but not Linux

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??

like image 635
G. P. Morton Avatar asked Oct 24 '25 04:10

G. P. Morton


1 Answers

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.

like image 118
y_ug Avatar answered Oct 26 '25 17:10

y_ug