Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If a nonblocking recv with MSG_PEEK succeeds, will a subsequent recv without MSG_PEEK also succeed?

Here's a simplified version of some code I'm working on:

void
stuff(int fd)
{
    int ret1, ret2;
    char buffer[32];

    ret1 = recv(fd, buffer, 32, MSG_PEEK | MSG_DONTWAIT);

    /* Error handling -- and EAGAIN handling -- would go here.  Bail if
       necessary.  Otherwise, keep going.  */

    /* Can this call to recv fail, setting errno to EAGAIN?  */
    ret2 = recv(fd, buffer, ret1, 0);
}

If we assume that the first call to recv succeeds, returning a value between 1 and 32, is it safe to assume that the second call will also succeed? Can ret2 ever be less than ret1? In which cases?

(For clarity's sake, assume that there are no other error conditions during the second call to recv: that no signal is delivered, that it won't set ENOMEM, etc. Also assume that no other threads will look at fd.

I'm on Linux, but MSG_DONTWAIT is, I believe, the only Linux-specific thing here. Assume that the right fnctl was set previously on other platforms.)

like image 587
Michael Wolf Avatar asked May 14 '09 17:05

Michael Wolf


2 Answers

The POSIX standard specifies about MSG_PEEK:

the data is treated as unread and the next recv() or similar function will still return this data

That seems to mean that unless ret2 is -1, it will be the same as ret1.

like image 128
Don Avatar answered Jan 04 '23 08:01

Don


You must also consider the possibility that a different recv call, on a different thread, might be called between ret1 and ret2. That other call would get your data, leaving ret2 to end up with no data, or unexpectedly less data.

If your app isn't multi-threaded, or is designed so that the fd is only used by these two calls, then you can ignore this. But if this is a risk, then you should put the two calls inside a locking mechanism.

like image 32
abelenky Avatar answered Jan 04 '23 10:01

abelenky