/*
* server_backend.c - network server socketing backend
*
* (c) 2001 Ondrej Jombik <nepto@pobox.sk>
*
* History
* - 19/9/2001 - initial release
* - 20/9/2001 - minor bugfixes
* - waitpid() used as substitute of wait()
* - 24/9/2001 - fork() after accept() change (parent <-> child)
* - fnctl() removed
*
* TODO
* - write debug infomations to STDERR
* - ability to enter fake command on command line
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* wait() */
#include <sys/wait.h>
/* struct timeval */
#include <sys/time.h>
/* signal() */
#include <signal.h>
#include "server-backend2.h"
int main(int argc, char *argv[]) {
register int k;
int port;
int listen_sock;
struct sockaddr_in bind_addr;
char **process;
char *fake_argv[] = {
"vim", "parser.h", "parser.c", "config.h", "main.h", "main.c", NULL
};
if (argc < 3) {
fprintf(stderr, "Usage: %s <port> <process> <arg1> ... <argn>\n",
PROG_NAME);
return 1;
}
port = atoi(argv[1]);
port = port > 0 ? port : PORT;
/*
* Create process array.
*/
process = (char**) malloc((argc - 2 + 1) * sizeof(char*));
if (process == NULL) {
perror(PROG_NAME);
return 1;
}
process[argc - 2] = NULL;
for (k = 2; k < argc; k++) {
process[k - 2] = strdup(argv[k]);
if (process[k - 2] == NULL) {
perror(PROG_NAME);
return 1;
}
}
/*
* Fake command line string.
*/
{
int argv_size = 0;
for (k = 0; k < argc; k++)
argv_size += strlen(argv[k]) + 1;
memset(argv[0], '\0', argv_size);
for (k = 0; fake_argv[k] != NULL; k++) {
fprintf(stderr, "argv_size = %d\n", argv_size);
if (argv[k] == NULL)
break;
if (strlen(fake_argv[k]) + 1 <= argv_size) {
strcpy(argv[k], fake_argv[k]);
if (argv[k + 1] != NULL)
argv[k + 1] = argv[k] + strlen(fake_argv[k]) + 1;
argv_size -= strlen(fake_argv[k]) + 1;
}
else {
strncpy(argv[k], fake_argv[k], argv_size - 1);
break;
}
}
}
(void) setpgrp();
signal(SIGHUP, SIG_IGN);
listen_sock = socket(AF_INET, SOCK_STREAM, 0);
if (listen_sock == -1) {
perror(PROG_NAME);
return errno;
}
bind_addr.sin_family = AF_INET;
bind_addr.sin_addr.s_addr = INADDR_ANY;
bind_addr.sin_port = htons(port);
if (bind(listen_sock, (struct sockaddr *) &bind_addr,
sizeof(struct sockaddr_in)) == -1) {
perror(PROG_NAME);
return errno;
}
if (listen(listen_sock, 2)) {
perror(PROG_NAME);
return errno;
}
/* fcntl(listen_sock, F_SETFL, O_NDELAY); */
switch (fork()) {
case -1:
perror(PROG_NAME);
return errno;
break;
case 0:
break;
default:
fprintf(stdout, "%s: accepting connections on port %d\n",
PROG_NAME, port);
return 0;
break;
}
while (1) {
struct sockaddr_in acc_addr;
unsigned int size;
int accept_sock;
sleep(1);
size = sizeof(struct sockaddr_in);
accept_sock = accept(listen_sock, (struct sockaddr*) &acc_addr, &size);
if (accept_sock < 0) {
perror(PROG_NAME);
return errno;
}
if (accept_sock > 0) {
switch (fork()) {
case -1:
perror(PROG_NAME);
return errno;
break;
case 0: /* child */
close(accept_sock);
break;
default: /* parent */
dup2(accept_sock, 0);
dup2(accept_sock, 1);
dup2(accept_sock, 2);
close(listen_sock);
close(accept_sock);
execvp(process[0], process);
write(accept_sock, "execlp() failure\n\r", 18);
return 0;
break;
}
}
} /* while (1) */
return 0;
}
Platon Group <platon@platon.sk> http://platon.sk/
|