Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Behavior of the poll() system call and receiving or sending data afterwards

Lets consider following piece of code

pollfd file_descriptors[1];
file_descriptors[0].fd = sock_fd;
file_descriptors[0].events = POLLIN;

int return_value = poll(file_descriptors, 1, 0);

if (return_value == -1) { cerr << strerror(errno); }
else if (return_value == 0) { cerr << "No data available to be read"; }
else { 
    if (file_descriptors[0].revents & POLLIN) {
        recv(sock_fd, buff, 1024, 0); 
    }
}

Now I have two questions regarding the above code.

  1. If the call to poll() returns neither -1 nor 0 and sets the POLLIN flag in the bitmap revents for the first entry in the file_descriptors array, then will the call to recv() block? If no, then will the data be read in instantaneously?
  2. Assuming the call to poll() goes the same way as mentioned above. How much data is going to be read in? Is it just going to be the same as a regular call to recv()? i.e. an arbitrary (to the programmer) amount less than or equal to 1024 in the above case. Then if I want to poll() before reading again, do I just repeat from the first invocation of poll() until all data has been read in completely (i.e. in a client server scenario this would correspond to the request being completed)?

Thank you!

like image 995
Curious Avatar asked Dec 30 '15 22:12

Curious


2 Answers

If the call to poll() returns neither -1 nor 0 and sets the POLLIN flag in the bitmap revents for the first entry in the file_descriptors array, then will the call to recv() block? If no, then will the data be read in instantaneously?

The call to poll has no effect on the call to recv. Whether or not recv blocks depends on what data is available at the time you call recv and whether the socket is in blocking or non-blocking mode.

Assuming the call to poll() goes the same way as mentioned above. How much data is going to be read in? Is it just going to be the same as a regular call to recv()? i.e. an arbitrary (to the programmer) amount less than or equal to 1024 in the above case. Then if I want to poll() before reading again, do I just repeat from the first invocation of poll() until all data has been read in completely (i.e. in a client server scenario this would correspond to the request being completed)?

Assuming you don't want to block, you should set the socket non-blocking. You have two basic choices. You can call the receive function once and then poll again. Or you can keep calling receive until you get a "would block" indication. If the socket is a TCP connection, you can keep calling the receive function until you either get a "would block" indication or receive fewer bytes than you asked for.

There are three common, non-blocking I/O strategies that you can base around poll or select. All require that the socket be set non-blocking.

1) You can always call poll or select before you perform an I/O operation. You then attempt a single read or write operation only if you get a read or write hit from poll or select.

2) You can attempt the read or write operation first. If it succeeds immediately, great. If not, wait for a poll or select hit before retrying the operation.

3) You can call poll or select before you perform an I/O operation. You then attempt multiple reads or writes until you either finish everything you need to do or get a "would block" indication. When you get a "would block" indication, you wait until select or poll tells you before you attempt another operation in that direction on that socket.

Method 3 is probably the most common for reads. Method 2 is probably the most common for writes.

It is very important to keep in mind that poll is a status reporting function that tells you current information. It does not come with any future guarantees. The assumption that a read indication from poll means that a future read operation will not block is a mistake and it has caused serious bugs with significant security implications in the past. The only way to guarantee that a socket operation will not block is to set the socket non-blocking.

like image 105
David Schwartz Avatar answered Oct 20 '22 00:10

David Schwartz


If the poll() returns a strictly positive value, it means that at least one of your descriptors has some data to return.

The recv() SHOULD therefore not be blocking: as there is data it SHOULD return something. In any case, it is not guaranteed that all the 1024 bytes will be returned by the call.

You must therefore check the number of bytes returned by recv(). Eventually, you have to loop on your polling/receiving until you got all the expected data.

You can control the blocking/non-blocking behaviour either by call with the flag parameter MSG_DONTWAIT, or via fcntl() on a more durable fashion.

Edit: Note that if something goes wrong on the socket (for example a loss of connection) the available data promised by the poll MIGHT be lost and block the recv() against all expectations. It is hence safer to explicitely use the non-blocking flag (and consider that recv() might return an error code instead of a number of bytes read).

like image 33
Christophe Avatar answered Oct 19 '22 22:10

Christophe