diff --git a/config.mk b/config.mk index 98f1021..71e21c2 100644 --- a/config.mk +++ b/config.mk @@ -18,7 +18,7 @@ LIBS = -L/usr/lib -lc CC = cc # debug build -CFLAGS = -g -std=c99 -Wall -Wextra -Wpedantic -Wno-sign-compare -DVERSION=\"$(VERSION)\" -DDEBUG $(INCS) +CFLAGS = -g -std=c99 -Wall -Wextra -Wpedantic -Wno-sign-compare -DVERSION=\"$(VERSION)\" $(INCS) LDFLAGS = -g $(LIBS) # release build diff --git a/feuille.1 b/feuille.1 index f790afe..80877ba 100644 --- a/feuille.1 +++ b/feuille.1 @@ -68,13 +68,13 @@ Default: \f[V]/var/www/feuille\f[R] .TP \f[B]-s bytes\f[R] Sets the maximum size for every paste (in bytes). -Default: \f[V]1048576\f[R]B (1MiB) +Default: \f[V]2097152\f[R]B (2MiB) .TP \f[B]-t seconds\f[R] Sets the timeout for the client to send the paste (in seconds). If set to zero, no timeout is set. (Not recommended.) -Default: \f[V]2\f[R]s +Default: \f[V]4\f[R]s .TP \f[B]-u\f[R] Sets the user that will be used when dropping root privileges. @@ -99,8 +99,7 @@ Sets the number of processes that will be spawned to handle the connections. Those are \f[I]real\f[R] processes, not green / posix threads, you might not want to set this to a huge number. -Default: the greater of the number of cores in your computer and -\f[V]4\f[R] workers. +Default: the number of threads configured on your machine. .SH EXAMPLES .TP \f[B]sudo feuille\f[R] diff --git a/feuille.1.md b/feuille.1.md index aecc491..b11458d 100644 --- a/feuille.1.md +++ b/feuille.1.md @@ -53,12 +53,12 @@ if possible). **-s bytes** : Sets the maximum size for every paste (in bytes). -: Default: `1048576`B (1MiB) +: Default: `2097152`B (2MiB) **-t seconds** : Sets the timeout for the client to send the paste (in seconds). : If set to zero, no timeout is set. (Not recommended.) -: Default: `2`s +: Default: `4`s **-u** : Sets the user that will be used when dropping root privileges. @@ -83,8 +83,7 @@ client. connections. : Those are *real* processes, not green / posix threads, you might not want to set this to a huge number. -: Default: the greater of the number of cores in your computer and -`4` workers. +: Default: the number of threads configured on your machine. # EXAMPLES diff --git a/feuille.c b/feuille.c index 9c261db..a3064b9 100644 --- a/feuille.c +++ b/feuille.c @@ -44,11 +44,11 @@ Settings settings = { .user = "www", .id_length = 4, - .worker_count = 4, + .worker_count = 1, .port = 9999, - .timeout = 2, - .max_size = 1048576, /* = 1MiB = 1024 * 1024 */ - .buffer_size = 131072, /* = 128KiB = 1024 * 128 */ + .timeout = 4, + .max_size = 2097152, /* = 2MiB = 1024 * 1024 * 2 */ + .buffer_size = 131072, /* = 128KiB = 1024 * 128 */ .verbose = 0, .foreground = 0 @@ -57,7 +57,6 @@ Settings settings = { /* functions declarations */ static void usage(int exit_code); static void version(void); -static void accept_loop(int); /** * Display feuille's basic usage. @@ -77,89 +76,6 @@ void version(void) die(0, "%s %s by Tom MTT. \n", argv0, VERSION); } -/** - * Feuille's accept loop. - * server: the server socket. - */ -void accept_loop(int server) -{ - /* get current process' pid */ - int pid = getpid(); - - /* feed the random number god */ - srand(time(0) + pid); - - /* accept loop */ - int connection; - while ((connection = accept_connection(server))) { - verbose(1, "--- new incoming connection. connection ID: %d:%d ---", pid, time(0)); - - char *paste = NULL; - char *id = NULL; - char *url = NULL; - - /* read paste from connection */ - verbose(1, "reading paste from incoming connection..."); - - if ((paste = read_paste(connection)) != NULL) { - /* generate random ID */ - verbose(1, "done."); - verbose(2, "generating a random ID..."); - - if ((id = generate_id(settings.id_length)) != NULL) { - /* write paste to disk */ - verbose(2, "done."); - verbose(1, "writing paste `%s' to disk...", id); - - if (write_paste(paste, id) == 0) { - /* create URL */ - verbose(1, "done."); - verbose(2, "making the right URL..."); - - if ((url = create_url(id)) != NULL) { - /* send URL */ - verbose(2, "done.", url); - verbose(1, "sending the link to the client..."); - - send_response(connection, url); - - verbose(1, "All done."); - - free(url); - } else { - error("error while making a valid URL."); - send_response(connection, "Could not create your paste URL.\nPlease try again later.\n"); - } - } else { - error("error while writing paste to disk."); - send_response(connection, "Could not write your paste to disk.\nPlease try again later.\n"); - } - - free(id); - } else { - error("error while generating a random ID."); - send_response(connection, "Could not generate your paste ID.\nPlease try again later.\n"); - } - - free(paste); - } else { - if (errno == EFBIG) - send_response(connection, "Paste too big.\n"); - - if (errno == ENOENT) - send_response(connection, "Empty paste.\n"); - - if (errno == EAGAIN) - send_response(connection, "Timeout'd.\n"); - - error("error %d while reading paste from incoming connection.", errno); - } - - /* close connection */ - close_connection(connection); - } -} - /** * Feuille's main function. * argc: the argument count. @@ -171,18 +87,14 @@ int main(int argc, char *argv[]) /* locale */ setlocale(LC_ALL, ""); - /* syslog */ - openlog("feuille", LOG_NDELAY | LOG_PERROR, LOG_USER); - - /* ignore signals that could kill feuille */ - signal(SIGPIPE, SIG_IGN); /* when send(2) or write(2) fails */ - + /* syslog setup */ + openlog("feuille", LOG_NDELAY | LOG_PERROR, LOG_USER); /* settings */ long long tmp; /* set number of workers */ - if ((tmp = sysconf(_SC_NPROCESSORS_ONLN)) > settings.worker_count && tmp <= USHRT_MAX) + if ((tmp = sysconf(_SC_NPROCESSORS_ONLN)) > 0 && tmp <= USHRT_MAX) settings.worker_count = tmp; ARGBEGIN { @@ -351,7 +263,6 @@ int main(int argc, char *argv[]) if ((server = initialize_server()) == -1) die(errno, "Failed to initialize server socket: %s\n", strerror(errno)); - /* make feuille run in the background */ if (!settings.foreground) { verbose(1, "making feuille run in the background..."); @@ -360,6 +271,11 @@ int main(int argc, char *argv[]) daemon(1, 0); } + /* ignore most signals that could kill feuille */ + verbose(3, "ignoring signals that could kill feuille..."); + + signal(SIGPIPE, SIG_IGN); /* when send(2) or write(2) fails */ + /* chroot and drop root permissions */ if (getuid() == 0) { @@ -377,13 +293,12 @@ int main(int argc, char *argv[]) } -#ifdef __OpenBSD__ /* OpenBSD-only security measures */ + #ifdef __OpenBSD__ pledge("proc stdio rpath wpath cpath inet", "stdio rpath wpath cpath inet"); -#endif + #endif -#ifndef DEBUG /* create a thread pool for incoming connections */ verbose(1, "initializing worker pool..."); @@ -391,16 +306,84 @@ int main(int argc, char *argv[]) for (int i = 1; i <= settings.worker_count; i++) { if ((pid = fork()) == 0) { verbose(2, " worker n. %d...", i); - accept_loop(server); + + pid = getpid(); + + /* feed the random number god */ + srand(time(0) + pid); + + /* accept loop */ + int connection; + while ((connection = accept_connection(server))) { + verbose(1, "--- new incoming connection. connection ID: %d:%d ---", pid, time(0)); + + char *paste = NULL; + char *id = NULL; + char *url = NULL; + + /* read paste from connection */ + verbose(1, "reading paste from incoming connection..."); + + if ((paste = read_paste(connection)) != NULL) { + /* generate random ID */ + verbose(1, "done."); + verbose(2, "generating a random ID..."); + + if ((id = generate_id(settings.id_length)) != NULL) { + /* write paste to disk */ + verbose(2, "done."); + verbose(1, "writing paste `%s' to disk...", id); + + if (write_paste(paste, id) == 0) { + /* create URL */ + verbose(1, "done."); + verbose(2, "making the right URL..."); + + if ((url = create_url(id)) != NULL) { + verbose(2, "done.", url); + verbose(1, "sending the link to the client..."); + + send_response(connection, url); + + verbose(1, "All done."); + + free(url); + } else { + error("error while making a valid URL."); + send_response(connection, "Could not create your paste URL.\nPlease try again later.\n"); + } + } else { + error("error while writing paste to disk."); + send_response(connection, "Could not write your paste to disk.\nPlease try again later.\n"); + } + + free(id); + } else { + error("error while generating a random ID."); + send_response(connection, "Could not generate your paste ID.\nPlease try again later.\n"); + } + + free(paste); + } else { + if (errno == EFBIG) + send_response(connection, "Paste too big.\n"); + + if (errno == ENOENT) + send_response(connection, "Empty paste.\n"); + + if (errno == EAGAIN) + send_response(connection, "Timeout'd.\n"); + + error("error %d while reading paste from incoming connection.", errno); + } + + /* close connection */ + close_connection(connection); + } } else if (pid < 0) die(errno, "Could not initialize worker n. %d: %s\n", i, strerror(errno)); } -#else - /* do not create a thread pool if in DEBUG mode */ - verbose(1, "running in DEBUG mode, won't create a worker pool."); - accept_loop(server); -#endif sleep(1); @@ -408,24 +391,10 @@ int main(int argc, char *argv[]) verbose(1, "all workers have been initialized."); verbose(1, "beginning to accept incoming connections."); - - /* fork again if a child dies */ - int status; - int child_pid; - while ((child_pid = wait(&status)) > 0) { - error("child %d unexpectedly died with exit code %d.", child_pid, WEXITSTATUS(status)); - - /* do not fork if child was KILL'ed */ - if (WTERMSIG(status) == 9) - continue; - - if ((pid = fork()) == 0) { - accept_loop(server); - - } else if (pid < 0) - error("could not fork killed child again: ", strerror(errno)); - } - + /* wait for children to finish */ + // TODO: handle children exit codes properly + while (wait(0) > 0); close(server); + return 0; } diff --git a/server.c b/server.c index ff560d7..2a1ec64 100644 --- a/server.c +++ b/server.c @@ -103,19 +103,19 @@ int initialize_server() if (setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int)) < 0) return -1; -#ifndef __OpenBSD__ /* Enable dual-stack mode on supported platforms */ - verbose(3, " IPV6_V6ONLY..."); - if (setsockopt(server, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6_only, sizeof(ipv6_only)) < 0) - return -1; -#else - if (ipv6_only == 0) { - puts(""); - syslog(LOG_WARNING, "dual-stack mode is disabled on OpenBSD."); - syslog(LOG_WARNING, "feuille will only listen on the `::' IPv6 address."); - puts(""); - } -#endif + #ifndef __OpenBSD__ + verbose(3, " IPV6_V6ONLY..."); + if (setsockopt(server, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6_only, sizeof(ipv6_only)) < 0) + return -1; + #else + if (ipv6_only == 0) { + puts(""); + syslog(LOG_WARNING, "dual-stack mode is disabled on OpenBSD."); + syslog(LOG_WARNING, "feuille will only listen on the `::' IPv6 address."); + puts(""); + } + #endif /* bind address and port */ verbose(3, "binding address on the socket...");