#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
#include "signal_action.h"
/* TODO
* - should check for close() errors, theoretically
* - what kind of error checking is needed for inet_aton, etc.?
* - More debugging output
*/
int connections_left = 40;
static void sigchld_handler(int sig) {
pid_t pid;
/* Looping here because there isn't necessarily one signal per child
* in the queue */
while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
connections_left++;
}
if ((pid == -1) && (errno != ECHILD)) {
perror("waitpid");
exit(1);
}
}
void child(int socket, char *const argv[]) {
setsid();
if ((dup2(socket, STDIN_FILENO) == -1)
|| (dup2(socket, STDOUT_FILENO) == -1)) {
perror("dup");
exit(1);
}
close(socket);
execvp(*argv, argv);
perror("execvp");
exit(1);
}
int main(int argc, char *const argv[]) {
int socket;
pid_t pid;
char *const *new_argv;
int option;
sigset_t sigfullmask, sigemptymask;
sigfillset(&sigfullmask);
sigemptyset(&sigemptymask);
/* Blocking signals everywhere but in accept() and sigsuspend() */
sigprocmask(SIG_SETMASK, &sigfullmask, NULL);
if (signal_action(SIGCHLD, sigchld_handler) != 0) {
perror("signal_action");
exit(1);
}
while ((option = getopt(argc, argv, "c:")) != -1) {
switch (option) {
case 'c':
connections_left = atoi(optarg);
break;
}
}
new_argv = argv + optind;
if (*new_argv == NULL) {
fputs("Must provide a command to execute\n", stderr);
exit(1);
}
while (1) {
while (connections_left < 1) {
/* Wait until one of the children dies and we receive a SIGCHLD. */
sigsuspend(&sigemptymask);
}
/* This should be the only place we block (other than sigsuspend
* above). A good place to catch signals, if such a place exists */
sigprocmask(SIG_SETMASK, &sigemptymask, NULL);
do {
socket = accept(STDIN_FILENO, NULL, NULL);
} while ((socket < 0) && (errno == EINTR));
sigprocmask(SIG_SETMASK, &sigfullmask, NULL);
if (socket < 0) {
perror("accept");
exit(1);
}
pid = fork();
if (pid == 0) {
child(socket, new_argv);
}
else if (pid < 0) {
perror("fork");
exit(1);
}
close(socket);
connections_left--;
}
}
syntax highlighted by Code2HTML, v. 0.9.1