0
votes

I am writing a UDP client/server application. The server is a broadcast server, that broadcasts on a particular port to two clients on the same subnet. Each client receives a datagram and sends a response to the server. Each client knows the ip address of the server in advance.

My client is basically as in the client example of http://man7.org/linux/man-pages/man3/getaddrinfo.3.html, i.e. it uses the connect() function to specify the endpoint of all outgoing packets. By using connected UDP, the client can use read() and write() to the socket file descriptor rather than sendto/recvfrom.

For my server, I want to adopt a similar approach - configure the socket for broadcasting, and call read/write on the file descriptor. I can bind() the socket to listen for incoming datagrams on the specified port, and these are collected fine.

Minus error checking, my server code looks like this:

int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

int broadcast = 1;
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof int);

struct sockaddr_in servaddr;
memset((char*) &servaddr, 0, sizeof servaddr);
servaddr.sin_family = AF_INET;
servaddr.sin_port   = htons(PORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

int success = bind(sockfd, (struct sockaddr*) &servaddr, sizeof servaddr);

int BUFSIZE = 256;
char buf[BUFSIZE];

while (1)
{
    // this works fine
    int bytes_read = read(sockfd, buf, BUFSIZE);

    // WANT TO BROADCAST HERE
    int bytes_written = write(sockfd, buf, bytes_read); 
}

However, when I try and broadcast a packet in the write() line, I get a 'Destination address not specified' error. I could call connect() to set the destination address, but I don't think connect() works on a broadcast socket.

Is there a way of broadcasting using write() rather than sendto?

1

1 Answers

1
votes

The problem with using connect() for broadcast is that (in addition to modifying the behavior of send()/write()), connect() will install a filter on the socket so that it only receives packets whose source-IP field matches the IP address specified in the argument to connect().

That means if you call connect() on your socket with a broadcast-address as its argument, then your socket will only receive packets coming from that broadcast-address -- but packets are never (AFAIK) tagged as coming from a broadcast address -- rather, their Source-IP field is set to the IP address of the computer that sent the packet, as usual. The upshot is that if you connect() your socket to a broadcast address, you won't receive any packets on that socket.