views:

158

answers:

5

Hi All,

I am implementing a kind of IP finder for a particular type of network multimedia device. I want to find out all the alive devices of that type in the LAN, with their IP address and other details.

The device has its own way of device discovery.

It works as follows: A client sends a broadcast request over the LAN via UDP.
The destination port number is fixed.
In reply, all the servers in the LAN that understand the format of this request will respond to this request providing information about themselves.

I am broadcasting the UDP request message using sendto().

Now my problem is that I don't know how many devices (i.e.servers) will respond to the request.

How many times will I have to call recvfrom()?
When will I come to know that I have handled the response from all the devices?
Or in general, is recvfrom() the right choice for receiving response from multiple servers?
Is there any better (or CORRECT if I am wrong here) way of accomplishing the same?

I am programming in C/C++, planning to code for both Windows and Linux.
Many thanks in advance.

Edit: So with the help of all the network programming wizards out here, I have found the solution to my problem :)
select() is just the thing for me...
Thanks a lot to all of you who took out time to help me

+2  A: 
jschmier
If all the servers would respond at the same time, how would that be handled?
puffadder
Thanks for the response. But do I really need a thread to process each response? Is there any other way out?
puffadder
answer updated - what do you do with these responses after they are received?
jschmier
The responses contain IP address and device ID of the responders, among other things. I want to parse the responses and store the required data.
puffadder
IF all the servers respond at the same time, their packets will be queued inside some of your switches and spewed out serially. Those switches might have a bit too much to handle and could simply drop the packets - UDP is unreliable after all, even on a LAN. Should you be on an ancient lan, or a lan connected by hubs instead of switches, ethernet collision detection would prevent several nodes to send at the exact same time.
nos
A: 

I hope you are not re-inventing ARP.

ArunSaha
nope, I am not :)
puffadder
+2  A: 

Use a select(2)/poll(2) with a timeout in a loop, decrementing the timeout every time you get a response from a device. You'd have to come up with appropriate timeout yourself.

Alternatively, if you are able to recognize/parse the discovery response message, just add the device to the list upon receiving such message.

You will probably have to deal with timeouts anyway for when devices register but fail at a later point.

Nikolai N Fetissov
+2  A: 

If you don't know how many servers are going to respond, then you don't know how many times you have to call recvfrom(). I would probably handle this with a select() loop with a suitable timeout, something like the following, which is completely untested and probably full of stupid bugs:

/* create and bind socket */

fd_set fds;
struct timeval tv;

tv.tv_sec = 2; 
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(sock, &fds);
int ret;

while((ret = select(sock + 1, &fds, NULL, NULL, &tv)) > 0) {
    char buf[BUFLEN];
    struct sockaddr addr;

    if(recvfrom(sock, buf, BUFLEN, MSG_DONTWAIT, &addr, sizeof(struct sockaddr)) > 0) {
        /* handle response */
    } else {
        /* handle error */
    }        
}
if(ret < 0) {
    /* handle error */
} else {
    /* select() timed out; we're theoretically done */
}

This will keep calling recvfrom() until no reply has been received for 2 seconds, which of course means that it will block for a minimum of 2 seconds. Depending on the underlying protocol, you can probably get away with a much shorter timeout; indeed you can decrease it on each response. Some testing and tuning will be required to find the optimum configuration. You don't need to worry about servers responding at the same time; the Ethernet layer will handle that.

ceo
Do I need to necessarily "bind" to use select function? Currently I am not binding the socket...
puffadder
@pufadder - No, you do not need to `bind`. `select()` takes a set of file descriptors, and you will receive a file descriptor to add to the set when you create the socket.
jschmier
Even if you do know how many servers were going to respond, you don't know how many messages you are going to get. Some of the packets might be dropped along the way.
nos
You should also add an outer loop, to repeat the entire "send probe and wait for responses" process two or three times, to be robust in the face of lost packets. (You'll also have to be prepared to ignore duplicate responses - but you could theoretically see those even with just one probe anyway).
caf
A: 

You can't know. Its unknowable.

Presumably, from your description: I want to find out all the alive devices, the devices can transition from dead to alive and back again any time they want to. This means that you will have to poll continuously: ie send the broadcast request every few seconds (but not too often) and see who responds.

If I've got this right, that UDP is inherently unreliable, you are going to have to retro-fit some reliability on top of UDP:

  • Send the broadcast out every few seconds, since devices may not receive it every time.
  • You may not receive their replies, but you might the next time.
  • A reply confirms that a device is alive.
  • Wait for 'n' non-responses before declaring a device dead.

Do you know the maximum number of possible devices? If you do you may find that you have to call recvfrom() that many times.

quamrana