Set resource limits on the server to prevent more than FD_SETSIZE
authorRichard Kettlewell <rjk@greenend.org.uk>
Sun, 15 Feb 2009 11:39:46 +0000 (11:39 +0000)
committerRichard Kettlewell <rjk@greenend.org.uk>
Sun, 15 Feb 2009 11:39:46 +0000 (11:39 +0000)
files being opened.  (It's not unusual for them to be set like this
anyway, but this change guarantees it.)

event.c also checks for FDs being in range.

lib/event.c
lib/trackdb.c
server/disorder-server.h
server/disorderd.c
server/play.c
server/server.c

index 38cb741..ee25024 100644 (file)
@@ -311,6 +311,8 @@ int ev_fd(ev_source *ev,
 
   D(("registering %s fd %d callback %p %p", modenames[mode], fd,
      (void *)callback, u));
+  if(fd >= FD_SETSIZE)
+    return -1;
   assert(mode < ev_nmodes);
   if(ev->mode[mode].nfds >= ev->mode[mode].fdslots) {
     ev->mode[mode].fdslots = (ev->mode[mode].fdslots
index 2218078..e1bbfc8 100644 (file)
@@ -1400,7 +1400,9 @@ void trackdb_stats_subprocess(ev_source *ev,
   pid = subprogram(ev, p[1], "disorder-stats", (char *)0);
   xclose(p[1]);
   ev_child(ev, pid, 0, stats_finished, d);
-  ev_reader_new(ev, p[0], stats_read, stats_error, d, "disorder-stats reader");
+  if(!ev_reader_new(ev, p[0], stats_read, stats_error, d,
+                    "disorder-stats reader"))
+    fatal(0, "ev_reader_new for disorder-stats reader failed");
 }
 
 /** @brief Parse a track name part preference
@@ -1756,8 +1758,9 @@ int trackdb_request_random(ev_source *ev,
   choose_callback = callback;
   choose_output.nvec = 0;
   choose_complete = 0;
-  ev_reader_new(ev, p[0], choose_readable, choose_read_error, 0,
-                "disorder-choose reader"); /* owns p[0] */
+  if(!ev_reader_new(ev, p[0], choose_readable, choose_read_error, 0,
+                    "disorder-choose reader")) /* owns p[0] */
+    fatal(0, "ev_reader_new for disorder-choose reader failed");
   ev_child(ev, choose_pid, 0, choose_exited, 0); /* owns the subprocess */
   return 0;
 }
index 1a52e25..4eb58e4 100644 (file)
@@ -42,6 +42,7 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/un.h>
+#include <sys/resource.h>
 #include <syslog.h>
 #include <time.h>
 #include <unistd.h>
index e03fa42..2342c3c 100644 (file)
@@ -174,6 +174,7 @@ static void fix_path(void) {
 int main(int argc, char **argv) {
   int n, background = 1, logsyslog = 0;
   const char *pidfile = 0;
+  struct rlimit rl[1];
 
   set_progname(argv);
   mem_init();
@@ -208,6 +209,18 @@ int main(int argc, char **argv) {
   srand(time(0));                      /* don't start the same every time */
   /* gcrypt initialization */
   gcry_control(GCRYCTL_INIT_SECMEM, 1);
+  /* make sure we can't have more than FD_SETSIZE files open (event.c does
+   * check but this provides an additional line of defence) */
+  if(getrlimit(RLIMIT_NOFILE, rl) < 0)
+    fatal(errno, "getrlimit RLIMIT_NOFILE");
+  if(rl->rlim_cur > FD_SETSIZE) {
+    rl->rlim_cur = FD_SETSIZE;
+    if(setrlimit(RLIMIT_NOFILE, rl) < 0)
+      fatal(errno, "setrlimit to reduce RLIMIT_NOFILE to %lu",
+            (unsigned long)rl->rlim_cur);
+    info("set RLIM_NOFILE to %lu", (unsigned long)rl->rlim_cur);
+  } else
+    info("RLIM_NOFILE is %lu", (unsigned long)rl->rlim_cur);
   /* create event loop */
   ev = ev_new();
   if(ev_child_setup(ev)) fatal(0, "ev_child_setup failed");
index c60d932..93a7f48 100644 (file)
@@ -128,7 +128,8 @@ void speaker_setup(ev_source *ev) {
   /* Wait for the speaker to be ready */
   speaker_recv(speaker_fd, &sm);
   nonblock(speaker_fd);
-  ev_fd(ev, ev_read, speaker_fd, speaker_readable, 0, "speaker read");
+  if(ev_fd(ev, ev_read, speaker_fd, speaker_readable, 0, "speaker read") < 0)
+    fatal(0, "error registering speaker socket fd");
 }
 
 void speaker_reload(void) {
index 18f6851..2874357 100644 (file)
@@ -1802,8 +1802,18 @@ static int listen_callback(ev_source *ev,
   c->ev = ev;
   c->w = ev_writer_new(ev, fd, writer_error, c,
                       "client writer");
+  if(!c->w) {
+    error(0, "ev_writer_new for file inbound connection (fd=%d) failed",
+          fd);
+    close(fd);
+    return 0;
+  }
   c->r = ev_reader_new(ev, fd, redirect_reader_callback, reader_error, c,
                       "client reader");
+  if(!c->r)
+    /* Main reason for failure is the FD is too big and that will already have
+     * been handled */
+    fatal(0, "ev_reader_new for file inbound connection (fd=%d) failed", fd);
   ev_tie(c->r, c->w);
   c->fd = fd;
   c->reader = reader_callback;