does poll system call know if remote socket closed or disconnected? - c

int rc = poll(fds, 1, -1);
let us say the remote peer goes down. socket breaks here.
In this case will the poll system call return -1 or
will return > 0 and report the disconnect as an error event on the FD.
Also, what would poll return on 0 timeout.
int rc = poll(fds, nfds, 0);

No it doesn't. All it knows is that something happened on the socket, and whether that was a read event, a write event, or an error event. Peer disconnect counts as a read event.

If the sockets breaks, poll() will return > 0, then you will have to check the return value of recv in order to know if the socket is disconnected (recv() will return 0 in this case).
Also, what would poll return on 0 timeout. int rc = poll(fds, nfds,
0);
poll() will return immediately, and the return value can be >= 0.
You really should read the poll() manpage, there is all you need to know.

From the man page:
The field revents is an output parameter, filled by the kernel with the events
that actually occurred. The bits returned in revents can include any of those
specified in events, or one of the values POLLERR, POLLHUP, or POLLNVAL.
(These three bits are meaningless in the events field, and will be set in the
revents field whenever the corresponding condition is true.)
If none of the events requested (and no error) has occurred for any of the file
descriptors, then poll() blocks until one of the events occurs.
Return Value
On success, a positive number is returned; this is the number of structures which
have nonzero revents fields (in other words, those descriptors with events or
errors reported). A value of 0 indicates that the call timed out and no file
descriptors were ready. On error, -1 is returned, and errno is set appropriately.
So, it clear says that if there is an error in the FD return value > 0 and the revents field is filled with the appropiate value. POLLERR for example.

Related

Adding new FDs to fd_Set while blocking on select

I have a question regarding adding new socket file descriptors to an FDSET. Lets say we've already connected to a socket s1:
fd_set readfds;
//s1 = socket(...);
//connect(s1, ...)...
FD_ZERO(&readfds);
FD_SET(s1, &readfds);
and we are waiting for data to come down the socket, by calling select in a thread:
socket_reader_thread() {
for (;;)
{
int rv = select(n, &readfds, NULL, NULL, &tv);
if (rv == -1) {
perror("select"); // error occurred in select()
}
else if (rv == 0) {
printf("Timeout occurred! No data after 10.5 seconds.\n");
}
else {
// one the descriptors have data
.....
}
}
}
If I now wanted to add another socket (or may be two more socket etc) to the readfds set, given that select is blocking, how should I proceed? how can I interrupt select
Is the trick to add a zero timeout and use select like poll?
You need to use the "pipe-trick".
This is where an additional socket or pipe is created add it to the fd_set.
Then to interrupt a running or pending select, send a 1 byte message to it via another thread.
The select will then return and if the special pipe FD is one of the ones that are ready in the set, that means you need to say look at a list or something "do work" - like add any new FDs to the fd_set before returning to the select call.
You can interrupt select by sending (and catching) a signal to your process, for example using raise. select will return in this case with -1 and errno set to EINTR. You can then change the events you want to wait for and call select again.
Is the trick to add a zero timeout and use select like poll?
One can simply use a timeout of 0 in which case it will just do a non-blocking check if any of the events got triggered, i.e. polling. But this should only be done in a few cases since busy polling instead of a blocking wait uses lots of resources of machine. And I would even consider the interrupting of a blocking select a questionable design, although probably not as bad as busy polling.

Using select() to detect a block on a UIO device file

I'm working on an embedded processor running Yocto. I have a modified uio_pdrv_genirq.c UIO driver.
I am writing a library to control the DMA. There is one function which writes to the device file and initiates the DMA. A second function is intended to wait for the DMA to complete by calling select(). Whilst DMA is in progress the device file blocks. On completion the DMA controller issues an interrupt which releases the block on the device file.
I have the system working as expected using read() but I want to switch to select() so that I can include a time out. However, when I use select(), it doesn't seem to be recognising the block and always returns immediately (before the DMA has completed). I have included a simple version of the code:
int gannet_dma_interrupt_wait(dma_device_t *dma_device,
dma_direction dma_transfer_direction) {
fd_set rfds;
struct timeval timeout;
int select_res;
/* Initialize the file descriptor set and add the device file */
FD_ZERO(&rfds);
FD_SET(dma_device->fd, &rfds);
/* Set the timeout period. */
timeout.tv_sec = 5;
timeout.tv_usec = 0;
/* The device file will block until the DMA transfer has completed. */
select_res = select(FD_SETSIZE, &rfds, NULL, NULL, &timeout);
/* Reset the channel */
gannet_dma_reset(dma_device, dma_transfer_direction);
if (select_res == -1) {
/* Select has encountered an error */
perror("ERROR <Interrupt Select Failed>\n");
exit(0);
}
else if (select_res == 1) {
/* The device file descriptor block released */
return 0;
}
else {
/* The device file descriptor block exceeded timeout */
return EINTR;
}
}
Is there anything obviously wrong with my code? Or can anyone suggest an alternative to select?
It turns out that the UIO driver contains two counters. One records the
number of events (event_count), the other records how many events the
calling function is aware of (listener->event_count).
When you do a read() on a UIO driver it returns the number of events and
makes listener->event_count equal to event_count. ie. the listener is
now up to date with all the events that have occurred.
When you use poll() or select() on a UIO driver, it checks if these two
numbers are different and returns if they are (if they are the same it
waits until they differ and then returns). It does NOT update the
listener->event_count.
Clearly if you do not do a read() between calls to select() then
the listener->event_count will not match the event_count and the second
select() will return immediately. Therefore it is necessary to call
read() in between calls to select().
With hindsight it seems clear that select() should work in this way but it wasn't obvious to me at the time.
This answer assumes that it is possible to use select() as intented for the specified device file (I use select() for socket descriptors only). As an alternative function to select(), you may want to check out the poll() family of functions. What follows will hopefully at least offer hints as to what can be done to resolve your problem with calling select().
The first parameter to the select() function has to be the maximum despriptor number plus 1. Since you have only one descriptor, you can pass it directly to select() as its first parameter and add 1. Also consider that the file descriptor in dma_device could be invalid. Returning EINTR on a timeout may actually be what you intend to do but should that not be the case and to test for an invalid descriptor, here is a different version for you to consider. The select() call could be interrupted by a signal, in which case, the return value is -1 and errno will be set to EINTR. This could be handled internally by your function as in:
FD_ZERO(&rfds);
FD_SET(dma_device->fd, &rfds);
timeout.tv_sec = 5;
timeout.tv_usec = 0;
// restart select() if it's interrupted by a signal;
do {
select_res = select(dma_device->fd + 1, &rfds, NULL, NULL, &timeout);
}
while( select_res < 0 && errno == EINTR);
if (select_res > 0) {
// a file descriptor is legible
}
else {
if (select_res == 0) {
// select() timed-out
}
else {
// an error other than a signal occurred
if (errno == EBADF) {
// your file descriptor is invalid
}
}
}

How to fix EPIPE after reconnecting to Server

I have a C socket client program where one thread is for receiving data and another for sending. If the server shuts down then the sender gets EPIPE. If I reconnect the same socket then it can receive data but the sender still gets EPIPE.
How to fix this?
Update:
Actually sender seems to send data as I see number of byte sent. But errno is still set to broken pipe. Before I only checked errno. Shouldn't it be changed to successful?
If I reconnect the same socket then it can receive data but the sender still gets EPIPE.
That can only mean that the sender is still sending via the old socket; also that you haven't closed the old socket.
sender seems to send data as I see number of byte sent. But errno is still set to broken pipe. Before I only checked errno. Shouldn't it be changed to successful?
No. It is only valid to check errno when an immediately prior system call has returned -1. Example:
int rc = send(...);
if (rc < 0)
{
if (errno == EWOULDBLOCK) // or EAGAIN *and* we are in non-blocking mode
{
// queue the write and return to the select() loop
}
else
{
perror("send"); // for example
}
}
else
{
// write succeeded ...
}

The poll() function returns a non-zero positive value with no events from the sockets i have registered for

This continues to occur for an infinite amount of time until a valid event occurs on the corresponding socket. Then again, it goes back to normal behavior. Unable to trace the trigger for this issue.
What other events should I look for in the sockets other than the events I have registered for and why? I have currently registered for POLLIN & POLLHUP.
while ( 1 )
{
//Calling POLL Function;
//Sockets in List ( One Server Socket TCP )
//Sockets of Open TCP Connections
int rv = poll ( ufds , nfds , - 1 );
if (rv == -1)
{
//Error Occured in POLL
}
else if ( rv == 0 )
{
//Time out fromData Recieved
}
else if ( rv > 0 )
{
//Look for events POLLIN or POLLHUP and act correspondingly
}
}
(MOST POSSIBLE)Trigger for the issue -
//Called by Main Thread when another thread is
//polling on the respective socket_fd
recv(socket_fd, buffer, 1024, MSG_PEEK | MSG_DONTWAIT);
I am doing a MSG_PEEK to see whether the peer connected to this socket is alive.
The POLLHUP, POLLERR and POLLNVAL events will cause poll to return even if these events have not been specified in events (in fact, setting these in events will be ignored). Check revents to see if any of these events happened for your file descriptors.

Will poll return -1 if any POLLERR, POLLHUP, or POLLNVAL revents are set?

From a poll man page:
The bits returned in revents can include any of those specified in
events, or one of the values POLLERR, POLLHUP, or POLLNVAL
Return Value:
On success, a positive number is returned; this is the number of structures which have nonzero revents fields (in other words, those descriptors with events or errors reported). A value of 0 indicates that the call timed out and no file descriptors were ready. On error, -1 is returned, and errno is set appropriately.
If poll sets one of POLLERR, POLLHUP, or POLLNVAL in revents, does this mean that the poll function will return -1? If not, when will poll return -1?
My guess is no, since the first sentence in the return value explanation is that the return is the number of structures which have nonzero revents fields. So if POLLERR is set, then there is at least 1 structure with nonzero revents.
If poll sets one of POLLERR, POLLHUP, or POLLNVAL in revents, does this mean that the poll function will return -1?
No. If poll() sets any revents values then it will return >0 to indicate that. You then have to check the individual items to see which ones have revents values assigned.
If not, when will poll return -1?
poll() returns -1 only if poll() itself fails, not if any of the items being polled fail.

Resources