Increasing limit of FD_SETSIZE and select - c

I want to increase FD_SETSIZE macro value for my system.
Is there any way to increase FD_SETSIZE so select will not fail

Per the standards, there is no way to increase FD_SETSIZE. Some programs and libraries (libevent comes to mind) try to work around this by allocating additional space for the fd_set object and passing values larger than FD_SETSIZE to the FD_* macros, but this is a very bad idea since robust implementations may perform bounds-checking on the argument and abort if it's out of range.
I have an alternate solution that should always work (even though it's not required to by the standards). Instead of a single fd_set object, allocate an array of them large enough to hold the max fd you'll need, then use FD_SET(fd%FD_SETSIZE, &fds_array[fd/FD_SETSIZE]) etc. to access the set.

I also suggest using poll if possible. And there exist several "event" processing libraries like libevent or libev (or the event abilities of Glib from GTK, or QtCore, etc) which should help you. There are also things like epoll. And your problem is related to C10k

It would be better (and easy) to replace with poll. Generally poll() is a simple drop-in replacement for select() and isn't limited by the 1024 of FD_SETSIZE...
fd_set fd_read;
int id = 42;
FD_ZERO(fd_read);
FD_SET(id, &fd_read);
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
if (select(id + 1, &fd_read, NULL, NULL, &tv) != 1) {
// Error.
}
becomes:
struct pollfd pfd_read;
int id = 42;
int timeout = 5000;
pfd_read.fd = id;
pfd_read.events = POLLIN;
if (poll(&pfd_read, 1, timeout) != 1) {
// Error
}
You need to include poll.h for the pollfd structure.
If you need to write as well as read then set the events flag as POLLIN | POLLOUT.

In order to use a fd_set larger than FD_SETSIZE, it is possible to define an extended one like this :
#include <sys/select.h>
#include <stdio.h>
#define EXT_FD_SETSIZE 2048
typedef struct
{
long __fds_bits[EXT_FD_SETSIZE / 8 / sizeof(long)];
} ext_fd_set;
int main()
{
ext_fd_set fd;
int s;
printf("FD_SETSIZE:%d sizeof(fd):%ld\n", EXT_FD_SETSIZE, sizeof(fd));
FD_ZERO(&fd);
while ( ((s=dup(0)) != -1) && (s < EXT_FD_SETSIZE) )
{
FD_SET(s, &fd);
}
printf("select:%d\n", select(EXT_FD_SETSIZE,(fd_set*)&fd, NULL, NULL, NULL));
return 0;
}
This prints :
FD_SETSIZE:2048 sizeof(fd):256
select:2045
In order to open more than 1024 filedescriptors, it is needed to increase the limit using for instance ulimit -n 2048.

Actually there IS a way to increase FD_SETSIZE on Windows. It's defined in winsock.h and per Microsoft themselves you can increase it by simply defining it BEFORE you include winsock.h:
See Maximum Number of Sockets an Application Can Use (old link), or the more recent page Maximum Number of Sockets Supported.
I do it all the time and have had no problems. The largest value I have used was around 5000 for a server I was developing.

Related

Is it legal to read a file descriptor into NULL?

Recently, I've been fixing the timestep for the sake of a library that I am writing. Following some research, suppose that I ended up with this prototype, precise and easy to combine with the generic event system of my library:
#include <stdio.h>
#include <unistd.h>
#include <sys/timerfd.h>
#include <poll.h>
struct pollfd fds[1];
struct itimerspec its;
int main(void) {
fds[0] = (struct pollfd) {timerfd_create(CLOCK_MONOTONIC, 0), POLLIN, 0}; //long live clarity
its.it_interval = (struct timespec) {0, 16666667};
its.it_value = (struct timespec) {0, 16666667};
timerfd_settime(fds[0].fd, 0, &its, NULL);
while(1) {
poll(fds, 1, -1);
if(fds[0].revents == POLLIN) {
long long buffer;
read(fds[0].fd, &buffer, 8);
printf("ROFL\n");
} else {
printf("BOOM\n");
break;
}
}
close(fds[0].fd);
return 0;
}
However, it severely hurt me that I've had to pollute my CPU caches with a whole precious 8 bytes of data in order to make the timer's file descriptor reusable. Because of that, I've tried to replace the read() call with lseek(), as follows:
lseek(fds[0].fd, 0, SEEK_END);
Unfortunately, both that and even lseek(fds[0].fd, 8, SEEK_CUR); gave me ESPIPE errors and would not work. But then, I found out that the following actually did its job, despite of giving EFAULTs:
read(fds[0].fd, NULL, 8);
Is it legal, defined behavior to offset the file descriptor like this? If it is not (as the EFAULTs suggested to me, strongly enough to refrain from using that piece of genius), does there exist a function that would discard the read data, without ever writing it down, or otherwise offset my timer's file descriptor?
The POSIX specification of read(2) does not specify the consequences of passing a null pointer as the buffer argument. No specific error code is given, nor does it say whether any data will be read from the descriptor.
The Linux man page has this error, though:
EFAULT buf is outside your accessible address space.
It doesn't say that it will read the 8 bytes and discard them when this happens, though.
So I don't think you can depend on this working as you desire.

read on many real file descriptors

Working on a Linux (Ubuntu) application. I need to read many files in a non-blocking fashion. Unfortunately epoll doesn't support real file descriptor (file descriptor from file), it does support file descriptor that's network socket. select does work on real file descriptors, but it has two drawbacks, 1) it's slow, linearly go through all the file descriptors that are set, 2) it's limited, it typically won't allow more than 1024 file descriptors.
I can change each file descriptors to be non-blocking and use non-blocking "read" to poll, but it's very expensive especially when there are a large number of file descriptors.
What are the options here?
Thanks.
Update 1
The use case here is to create some sort of file server, with many clients requesting for files, serve them in a non-blocking fashion. Due to network side implementation (not standard TCP/IP stack), can't use sendfile().
You could use multiple select calls combined with either threading or forking. This would reduce the number of FD_ISSET calls per select set.
Perhaps you can provide more details about your use-case. It sounds like you are using select to monitor file changes, which doesn't work as you would expect with regular files. Perhaps you are simply looking for flock
You could use Asynchronous IO on Linux. The relevant AIO manpages (all in section 3) appear to have quite a bit of information. I think that aio_read() would probably be the most useful for you.
Here's some code that I believe you should be able to adapt for your usage:
...
#define _GNU_SOURCE
#include <aio.h>
#include <unistd.h>
typedef struct {
struct aiocb *aio;
connection_data *conn;
} cb_data;
void callback (union sigval u) {
// recover file related data prior to freeing
cb_data data = u.sival_ptr;
int fd = data->aio->aio_fildes;
uint8_t *buffer = data->aio->aio_buf;
size_t len = data->aio->aio_nbytes;
free (data->aio);
// recover connection data pointer then free
connection_data *conn = data->conn;
free (data);
...
// finish handling request
...
return;
}
...
int main (int argc, char **argv) {
// initial setup
...
// setup aio for optimal performance
struct aioinit ainit = { 0 };
// online background threads
ainit.aio_threads = sysconf (_SC_NPROCESSORS_ONLN) * 4;
// use defaults if using few core system
ainit.aio_threads = (ainit.aio_threads > 20 ? ainit.aio_threads : 20)
// set num to the maximum number of likely simultaneous requests
ainit.aio_num = 4096;
ainit.aio_idle_time = 5;
aio_init (&ainit);
...
// handle incoming requests
int exit = 0;
while (!exit) {
...
// the [asynchronous] fun begins
struct aiocb *cb = calloc (1, sizeof (struct aiocb));
if (!cb)
// handle OOM error
cb->aio_fildes = file_fd;
cb->aio_offset = 0; // assuming you want to send the entire file
cb->aio_buf = malloc (file_len);
if (!cb->aio_buf)
// handle OOM error
cb->aio_nbytes = file_len;
// execute the callback in a separate thread
cb->aio_sigevent.sigev_notify = SIGEV_THREAD;
cb_data *data = malloc (sizeof (cb_data));
if (!data)
// handle OOM error
data->aio = cb; // so we can free() later
// whatever you need to finish handling the request
data->conn = connection_data;
cb->aio_sigevent.sigev_value.sival_ptr = data; // passed to callback
cb->aio_sigevent.sigev_notify_function = callback;
if ((err = aio_read (cb))) // and you're done!
// handle aio error
// move on to next connection
}
...
return 0;
}
This will result in you no longer having to wait on files being read in your main thread. Of course, you can create more performant systems using AIO, but those are naturally likely to be more complex and this should work for a basic use case.

Is it reasonable to expect that in Linux, fd < maximum number of open file descriptors?

I'm writing a server that needs to handle many open sockets, so I use setrlimit() to set the maximum number of open file descriptors (as root, before dropping privileges) like so:
#include <sys/resource.h>
#define MAX_FD_C 9001
if (setrlimit(
RLIMIT_NOFILE, &(struct rlimit){.rlim_cur = MAX_FD_C, .rlim_max = MAX_FD_C}
) == -1) {
perror("Failed to set the maximum number of open file descriptors");
return EXIT_FAILURE;
}
Now, I realize there probably won't be any guarantees and that I'm at the mercy of whatever method the Linux kernel uses to implements file descriptor tables; but in practice, is it reasonable to assume that any fd this program receives from the Linux kernel will have a value less than the MAX_FD_C I set above?
I'd like to keep per socket data as compact as possible which could mean simply using an array like static struct client clients[MAX_FD_C] = {{0}}; and using the fd as the index to the client struct (which would basically be my own version of the FDT).
There are functions in the POSIX standard which assume this already. Have a look at FD_SETSIZE, select(), FD_SET.

Linux timerfd> calling a function every x seconds without blocking the code execution

Need to call a function every X (let's say 5) seconds and the below code does it.
But it is blocking the execution of code. As I want it to work like setitimer(), where I can (for example) call a function every 5 sec and do something else.
#include <sys/timerfd.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h> /* Definition of uint64_t */
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{
struct itimerspec new_value;
int max_exp, fd;
struct timespec now;
uint64_t exp, tot_exp;
ssize_t s;
if (clock_gettime(CLOCK_REALTIME, &now) == -1)
handle_error("clock_gettime");
/* Create a CLOCK_REALTIME absolute timer with initial
expiration and interval as specified in command line */
new_value.it_value.tv_sec = now.tv_sec + 1;
new_value.it_value.tv_nsec = now.tv_nsec;
new_value.it_interval.tv_sec = 5;
new_value.it_interval.tv_nsec = 0;
max_exp = 5; //say 5 times
fd = timerfd_create(CLOCK_REALTIME, 0);
if (fd == -1)
handle_error("timerfd_create");
if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL) == -1)
handle_error("timerfd_settime");
printf("timer started\n");
for (tot_exp = 0; tot_exp < max_exp;) {
s = read(fd, &exp, sizeof(uint64_t));
if (s != sizeof(uint64_t))
handle_error("read");
tot_exp += exp;
printf("read: %llu; total=%llu\n",
(unsigned long long) exp,
(unsigned long long) tot_exp);
}
//Do something else ?
//while(1);
exit(EXIT_SUCCESS);
}
EDIT
I have one more question.
On changing these lines in above code from
new_value.it_interval.tv_sec = 5;
new_value.it_interval.tv_nsec = 0;
to
new_value.it_interval.tv_sec = 0;
new_value.it_interval.tv_nsec = 5000000000;
I see that there is no 5 seconds delay. Whats happening here?
You need to understand how to use multiplexing syscalls like poll(2) (or the older select(2) which tends to become obsolete) and use them to test the readability of the file descriptor obtained by timerfd_create(2) before read(2)-ing it.
However, be aware that timerfd_create works only when that read call succeeded. So only when the poll says you that the fd is not readable can you do something else. That something else should be quick (last less than 5 seconds).
You might want to investigate event loop libraries, like e.g. libevent (wrapping poll). If you are coding a graphical application (using Qt or Gtk) it does already have its own event loop. If clever enough, you could do your 5-second period without any timerfd_create, just thru your event loop (by carefully setting the timeout given to poll, etc.).
Addenda:
the tv_nsec field should always be non-negative and less than 1000000000 (the number of nanoseconds in a second).
Any reason you have to use timerfd? Just schedule an alarm and make a handler for SIGALRM to call your function.
If you don't want to use signals, just create an extra thread to block on your timer fd and proceed as normal in the main thread.
If you don't like either of those and you want to do work while you're waiting, you have to poll. You can do it as basile suggests, or you could just store the current time and check whenever you would poll to see if the desired period has elapsed.

Using select and recv to obtain a file from a web server through a socket

I'm having trouble receiving "large" files from a web server using C sockets; namely when these files (or so I suspect) are larger than the size of the buffer I'm using to receive them. If I attempt to ask (through a GET request) for a simple index.html that's not bigger than a few bytes, I get it fine, but anything else fails. I'm assuming that my lack of knowledge on select() or recv() is what's failing me. See here:
fd_set read_fd_set;
FD_ZERO(&read_fd_set);
FD_SET((unsigned int)socketId, &read_fd_set);
/* Initialize the timeout data structure. */
struct timeval timeout;
timeout.tv_sec = 2;
timeout.tv_usec = 0;
// Receives reply from the server
int headerReceived = 0;
do {
select(socketId+1, &read_fd_set, NULL, NULL, &timeout);
if (!(FD_ISSET(socketId, &read_fd_set))) {
break;
}
byteSize = recv(socketId, buffer, sizeof buffer, 0);
if (byteSize == 0 || (byteSize < BUFFER_SIZE && headerReceived)) {
break;
}
headerReceived = 1;
} while(1);
That's right, after sending the GET request to the web server, which I'm pretty sure the server is getting just fine, and GET requests from any other client (like any web browser) are working as intended.
Thanks in advance, any help is greatly appreciated.
if (byteSize == 0 || (byteSize < BUFFER_SIZE && headerReceived))
{
break;
}
headerReceived is set to true after the first read. It is entirely possible and likely subsequent recv()s will be less than BUFFER_SIZE. You are out of the read loop at that point. Recv() is going to return whatever number of bytes there are to read, not necessarily how many you request.
Also either stick with BUFFER_SIZE or sizeof(buffer). Mixing and matching is just asking for a bug somewhere down the road.
One thing that I spot is that you don't reinitialize the selection during the loop. This is probably why you get small files successfully; they are received in one go and the loop doesn't have to be iterated.
I suggest you put the:
FD_ZERO(&read_fd_set);
FD_SET((unsigned int)socketId, &read_fd_set);
timeout.tv_sec = 2;
timeout.tv_usec = 0;
inside the loop (before you invoke select), and it might just work.
You did not say what O/S you are using, but according to the POSIX spec:
Upon successful completion, the select() function may modify the
object pointed to by the timeout argument.
(And I believe Linux, for example, does precisely this.)
So it is very possible that later invocations of your loop have the timeout set to zero, which will cause select to return immediately with no descriptors ready.
I would suggest re-initializing the timeout structure immediately before calling select every time through the loop.

Resources