serve/serve.c

80 lines
2.0 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
void
die(const char *s, ...)
{
va_list argp;
va_start(argp, s);
vfprintf(stderr, s, argp);
fputc('\n', stderr);
va_end(argp);
exit(1);
}
int
main(int argc, char *argv[], char *envp[])
{
if (argc < 3)
die("usage: serve port program args ...");
short port = atoi(argv[1]);
if (port == 0) {
die("invalid port number");
}
/* now skip the two first args so that we can pass argv to execve later */
argv += 2;
int sfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server, client;
if (sfd < 0)
die("error encountered while initializing socket");
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0)
die("setsockopt(SO_REUSEADDR) failed");
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
/* assigning an address to the socket */
if (bind(sfd, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("bind");
exit(1);
}
/* start accepting connections */
if (listen(sfd, 10) < 0)
die("error encountered while trying to listen for connections");
/* handling connections */
for (;;) {
socklen_t client_len = sizeof(client);
int cfd = accept(sfd, (struct sockaddr *)&client, &client_len);
if (cfd < 0)
die("error encountered while accepting connection");
/* start new process and change stdout/stdin so that the process can
* read/write to the client */
pid_t p = fork();
if (!p) {
/* in the new process */
dup2(cfd, STDIN_FILENO);
dup2(cfd, STDOUT_FILENO);
int err = execve(argv[0], argv, envp);
die("execve() error: %d\n", err);
}
else {
/* in the old process */
close(cfd);
}
}
}