--- /dev/null
+/*
+ * A simple preforking daemon, inspired by the logic in Apache 1.3
+ * Martin Mares, September 2007
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#define NUM_CHILDREN 10
+
+static int listening_sk;
+
+/*** Logging functions ***/
+
+static void
+vmsg(char *msg, va_list args)
+{
+ /*
+ * This is a little bit tricky, because we need to be sure that logging
+ * is atomic with respect to other processes. Fortunately, it is sufficient
+ * to prepare everything in a buffer and flush it with a single write().
+ */
+ char buf[1024];
+ int cnt = vsnprintf(buf, sizeof(buf)-1, msg, args);
+ buf[cnt++] = '\n';
+ write(2, buf, cnt);
+}
+
+static void
+msg(char *msg, ...)
+{
+ va_list args;
+ va_start(args, msg);
+ vmsg(msg, args);
+ va_end(args);
+}
+
+static void
+die(char *msg, ...)
+{
+ va_list args;
+ va_start(args, msg);
+ vmsg(msg, args);
+ va_end(args);
+ exit(1);
+}
+
+/*** Child process ***/
+
+static void
+child(void)
+{
+ int count = 0;
+ for (;;)
+ {
+ struct sockaddr_in sa;
+ socklen_t len = sizeof(sa);
+ int sk = accept(listening_sk, (struct sockaddr *) &sa, &len);
+ if (sk < 0)
+ die("Accept failed: %m");
+
+ /* Handle the connection somehow */
+ write(sk, "Hello, world!\n", 14);
+ close(sk);
+
+ /* After processing a certain number of requests, exit. This makes small memory leaks harmless. */
+ if (count++ >= 100)
+ exit(0);
+ }
+}
+
+/*** Master process ***/
+
+int
+main(void)
+{
+ /* Set up the listening socket */
+ int one = 1;
+ listening_sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (listening_sk < 0)
+ die("Cannot create listening socket: %m");
+ if (setsockopt(listening_sk, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
+ die("Cannot set SO_REUSEADDR: %m");
+ struct sockaddr_in sa = { .sin_family = AF_INET, .sin_port = htons(9999) };
+ if (bind(listening_sk, (struct sockaddr *) &sa, sizeof(sa)) < 0)
+ die("Cannot bind: %m");
+ if (listen(listening_sk, 256) < 0)
+ die("Cannot listen: %m");
+
+ /* Main loop */
+ pid_t pid;
+ int children = 0;
+ int status;
+ for (;;)
+ {
+ if (children < NUM_CHILDREN)
+ {
+ pid = fork();
+ if (pid < 0)
+ {
+ /* Temporary resource shortage, better sleep for a while */
+ msg("Fork failed: %m");
+ sleep(1);
+ }
+ else if (pid)
+ children++;
+ else
+ child();
+ continue;
+ }
+ pid = wait(&status);
+ if (pid < 0)
+ die("Wait failed: %m");
+ if (!(WIFEXITED(status) && !WEXITSTATUS(status)))
+ msg("Child %d exited with status %x", (int)pid, status);
+ children--;
+ }
+}