10
votes

I have to receive an UDP broadcast (in Ubuntu if that makes any difference). Using Wireshark, I can see the packet being sent from the server machine, and I can see it being received by my client machine, but my program is completely oblivious. This is what I have:

sockaddr_in si_me, si_other;
int s;
assert((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))!=-1);
int port=6000;
int broadcast=1;

setsockopt(s, SOL_SOCKET, SO_BROADCAST,
            &broadcast, sizeof broadcast);

memset(&si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(port);
si_me.sin_addr.s_addr = INADDR_ANY;

assert(::bind(s, (sockaddr *)&si_me, sizeof(sockaddr))!=-1);

while(1)
{
    char buf[10000];
    unsigned slen=sizeof(sockaddr);
    recvfrom(s, buf, sizeof(buf)-1, 0, (sockaddr *)&si_other, &slen);

    printf("recv: %s\n", buf);
}

It is compiled in debug mode, the asserts aren't being erased during compilation, and my program just blocks on recvfrom.

Is there any other hoop I have to jump through to receive an untargeted UDP broadcast?

Edit: just a bit more info, I have the two computers connected on a dedicated switch, no outside interference. I also have a second network card on my client computer that connects to the company network, which also works.

I can ping both the outside (Internet working) and my server machine (plus I can see the actual packets in Wireshark), but you never know what might cause this problem.

2
This code works for me (after slight modification to make it compile with a C compile). Possible the bind is binding to the wrong interface? What does netstat -an | grep 6000 return on the client machine? - Sean Bright
Yeah it's supposed to work, but it doesn't for me. netstat -an is showing no open 6000 port, I already double checked that (I also tried using the "reuse" udp flag). - Blindy
bind() does not actually open a port. Only connect() and listen() do that. But you do not need to open a port via listen() in order to receive UDP broadcasts. - Remy Lebeau
@RemyLebeau Certainly bind() opens a port. Have a look at netstat after you call it. connect() on the other hand has no visible effect at all. - user207421
Since UDP is connection-less, connect() on a UDP socket merely establishes a static association inside the socket handle between the local and remote IP/Port pairs, nothing more. I was referring to TCP when I mentioned that connect() opens a port. Calling bind() on a UDP socket adds the bound IP/Port to the netstat list but it does not display any state, which is probably true of all UDP connections. - Remy Lebeau

2 Answers

4
votes

As it turns out my code is perfectly fine, as I thought it would be. There was a problem with the network setup itself.

For posterity, I had set up two static IP'd computers on their own hub, instead of using the built in DHCP server on the server machine to allocate the IP address for the other computer. Pretty localized for my problem but you never know..

-1
votes

To send and receive broadcast

  1. Be sure that netmask is correct. in windows mask for broadcast packets does not matters, but not in linux.

  2. bind socket to INADDR_ANY

  3. setsockopt to BROADCAST

  4. call sendto with sendaddr.sin_addr.s_addr = inet_addr("your_interface_broadcast_address"). or - call sento several times for each interface with its broadcast ip address.

  5. call recvfrom. any time before calling recvfrom, set up length parameter.