What is exc_fd_set in curl_multi_fdset()? - c

Curl's curl_multi_fdset function has the following declaration:
CURLMcode curl_multi_fdset(CURLM *multi_handle,
fd_set *read_fd_set,
fd_set *write_fd_set,
fd_set *exc_fd_set,
int *max_fd);
Curl documentation does not explain the meaning of exc_fd_set. What is the meaning of exc_fd_set?

I have just updated the curl_multi_fdset() man page to better explain what the arguments are actually used for:
If the read_fd_set argument is not a null pointer, it points to an
object of type fd_set that on returns specifies the file descriptors
to be checked for being ready to read.
If the write_fd_set argument is not a null pointer, it points to an
object of type fd_set that on return specifies the file descriptors to
be checked for being ready to write.
If the exc_fd_set argument is not a null pointer, it points to an
object of type fd_set that on return specifies the file descriptors to
be checked for error conditions pending.

Very likely the same meaning as with select(2), as the function is meant to supply the FD sets for it.
Those listed in readfds will be watched to see if characters become available for reading (more precisely, to see if a read will not block; in particular, a file descriptor is also ready on end-of-file), those in writefds will be watched to see if a write will not block, and those in exceptfds will be watched for exceptions.

Related

FD_SET not putting the file descriptor in the set

I am using the following code to set the value of a file descriptor
fd_set current_sockets, ready_sockets;
FD_SET(sock_fd, &current_sockets);
In the above sock_fd is 3. And after the execution of this line I don't see this value 3 in
current_sockets. In fact I see some weird set of values. What could be the reason for this ?
When you declare fd_set current_sockets, ready_sockets;, both of those variables are uninitialized. man 2 select says this:
FD_ZERO()
This macro clears (removes all file descriptors from) set.
It should be employed as the first step in initializing a
file descriptor set.
But you skipped this non-optional step, so your FD sets are full of random garbage.
Also, the contents of the fd_set structure are unspecified, so you shouldn't expect to be able to make sense of them by any means other than using FD_ISSET.

clear a Pipe in C

I'm sending data from one process to another pipe and I want to clear the pipe after reading.
Is there a function in C that can do this ?
Yes. It's just the read function offered by the stdio library. You have to invoke it as many times as you need in order to be sure the pipe will be empty.
As the documentation suggests, the read function attempts reading count bytes from an I/O channel (a pipe in your case) for which you have passed the file descriptor as first argument, and places its content into a buffer with enough room to accommodate it.
Let's recall that the read function may return a value indicating a number of bytes read that is smaller than that of those requested. This is perfectly fine if there are less bytes to read than what you expected.
Also remeber that reading from a pipe is blocking if there's nothing to read and the writer has not yet closed the relative descriptor, thus meaning that you'll not get EOF until the counterpart closes its descriptor. Therefore you'll stuck while attempting to read from pipe. If you are intended to avoid the aforementioned possibility I suggest to follow the solution below based on the poll function to verify whether there's data to read from a file descriptor:
#include <poll.h>
struct pollfd pfd;
int main(void)
{
/* your operations */
pfd.fd = pipe_fd;
pfd.events = POLLIN;
while (poll(&pfd, 1, 0) == 1)
{
/* there's available data, read it */
}
return 0;
}

what is the usage of F_DUPFD inside fcntl in Linux system call

I am trying to understand what this line of code means:
int dfd;
fd2 = fcntl(dfd, F_DUPFD);
It is intended to set fd2 to another file descriptor referencing the same open-file record as dfd.
There should be a third argument, the lowest acceptable file descriptor to return. Since that third argument is missing, the call might do just about anything. A correct call could look like this:
fd2 = fcntl(dfd, F_DUPFD, 0);
From the fcntl man page:
F_DUPFD (int)
Find the lowest numbered available file descriptor greater than or equal to arg and make it be a copy of fd. This is different from dup2(2), which uses exactly the descriptor specified.
On success, the new descriptor is returned.
See dup(2) for further details.

How to see if a pipe is empty

Assuming a pipe,
int pipe_fd[2];
pipe(pipe_fd);
We fork, and expect that one process will write into the pipe at an arbitrary time. In one of the processes, we want to be able to check the contents of the pipe without blocking.
i.e. While a typical read will block if nothing is present and the write end remains open. I want to go do other stuff and potentially even read a bit at a time, do some stuff, and then check back to see if there's more, a la:
close(pipe_fd[1]);
while(1){
if(/**Check pipe contents**/){
int present_chars = 0;
while( read(pipe_fd[0],&buffer[present_chars],1) != 0)
++present_chars;
//do something
}
else
//do something else
}
Your logic is wrong in that read will not return 0 when it runs out of characters; instead, it will block until it receives more, unless you put the file in non-blocking mode, but then it will return -1 and set errno to EWOULDBLOCK or EAGAIN rather than returning 0. The only time read can ever return 0 is when the size argument was 0 or end-of-file has been reached. And, for pipes, end-of-file means the writing end of the pipe has been closed; end-of-file status does not occur just because there's not any input available yet.
With that said, the simplest way to check is:
if (poll(&(struct pollfd){ .fd = fd, .events = POLLIN }, 1, 0)==1) {
/* data available */
}
but unless you're using nonblocking mode, you'll need to make this check before every single read operation. Passing a larger buffer to read rather than doing it a byte-at-a-time would eliminate most of the cost of checking.
You can check if there is data to be read with the read() function. From read(3):
When attempting to read from an empty pipe or FIFO:
* If some process has the pipe open for writing and
O_NONBLOCK is set, read() shall return -1 and set
errno to [EAGAIN].
* If some process has the pipe open for writing and
O_NONBLOCK is clear, read() shall block the calling
thread until some data is written or the pipe is
closed by all processes that had the pipe open for
writing.
The read() function shall fail if:
EAGAIN or EWOULDBLOCK
The file descriptor is for a socket, is marked
O_NONBLOCK, and no data is waiting to be received.
So if you set O_NONBLOCK, you will be able to tell if something is to be read on the pipe, by simply calling read().
As a reminder, from open(3):
SYNOPSIS
int open(const char *path, int oflag, ... );
DESCRIPTION
Values for oflag are constructed by a
bitwise-inclusive OR of flags from the following
list, defined in <fcntl.h>. Applications shall
specify exactly one of the first three values
(file access modes) below in the value of oflag:
O_NONBLOCK [...]
I hope it helps.
R..'s answer is good however poll returns the number of file descriptor structs that have flags set in "revents". This will be 1 if you can read from fd but will also be 1 if any of the error flags are set. This means R..'s answer will say the pipe is readable if it ever enters an error state. A more robust check could be something like this:
bool canReadFromPipe(){
//file descriptor struct to check if POLLIN bit will be set
//fd is the file descriptor of the pipe
struct pollfd fds{ .fd = fd, .events = POLLIN };
//poll with no wait time
int res = poll(&fds, 1, 0);
//if res < 0 then an error occurred with poll
//POLLERR is set for some other errors
//POLLNVAL is set if the pipe is closed
if(res < 0||fds.revents&(POLLERR|POLLNVAL))
{
//an error occurred, check errno
}
return fds.revents&POLLIN;
}

Is 0 or 1 valid return values for socket() function call

Could the socket function call in C return 0 or 1 as the value for the socket descriptor?
int socket(int domain, int type, int protocol);
According to the man page I have:
RETURN VALUE
-1 is returned if an error occurs; otherwise the return value is a
descriptor referencing the socket.
It seems like it could, or at least the man page makes no mention of any reserved values. Is it written somewhere else that valid socket descriptors need to be 2 or greater?
I'm specifically running on a linux 2.4.22 kernel, but I'm curious to know for any unix based implementation of socket.
Both 0 and 1 are valid return vales, and might indeed be returned if the application has closed its standard input or output file descriptors.
When your process starts, 0 is stdin and 1 is stdout, but you can close them, and therefore, you could get these FD back
0 or 1 will precisely come if you have closed the stdin or stdout descriptors. This could be happening, because by mistake you might be passing a variable (most probably the one in which you store your socket descriptor) to the socket closing function after initialization. Since the variable might be initialized to 0, it might cause closure of stdin.
The only values that are not valid file descriptors are those less than 0. -1 will indicate an error and errno will be set. You shouldn't ever see a negative value that is not -1.
According to the man page, yes, it could.

Resources