tags:

views:

207

answers:

2

Using UNIX socket APIs on Linux, is there any way to guarantee that I read one UDP packet, and only one UDP packet? I'm currently reading packets off a non-blocking socket using recvmsg, with a buffer size a little larger than the MTU of our internal network. This should ensure that I can always receive the full UDP packet, but I'm not sure I can guarantee that I'll never receive more than one packet per recvmsg call, if the packets are small.

The recvmsg man pages reference the MSG_WAITALL option, which attempts to wait until the buffer is filled. We're not using this, so does that imply that recvmsg will always return after one datagram is read? Is there any way to guarantee this?

Ideally I'd like a cross-UNIX solution, but if that doesn't exist is there something Linux specific?

+2  A: 

recvmsg will return you one packet, and it will be the entire packet (as long as the buffer you provide it is large enough).

From the POSIX documentation:

The recvmsg() function shall receive a message from a connection-mode or connectionless-mode socket.

"a message" means exactly one message (or packet), and,

For message-based sockets, such as SOCK_DGRAM and SOCK_SEQPACKET, the entire message shall be read in a single operation.

James McNellis
A: 

One option (I say option) is to use pcap_next using libpcap and take it apart to see if it is a udp packet. You can do this with:

/* jump pass the ethernet header */
ipdata = (struct ip*)(packet + sizeof(struct ether_header));
length -= sizeof(struct ether_header);

(Borrowed from tcpdump)

and then test the ip struct to see if it is a udp packet by doing:

if ( ipdata->ip_p == IPPROTO_UDP )

And if this fails, keep looping (calling pcap_next) until you get your udp packet. Of course, extraction of the udp datagram is harder this way, but it does let you into the packet internals quite nicely. Refer to the tcpdump source to see how to strip info out and what comes out.

Ninefingers