80 lines
2.0 KiB
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);
|
|
}
|
|
}
|
|
}
|