/* * server_backend.c - network server socketing backend * * (c) 2001 Ondrej Jombik * * History * - 19/9/2001 - initial release * - 20/9/2001 - minor bugfixes * - waitpid() used as substitute of wait() * * TODO * - write debug infomations to STDERR */ #include #include #include #include #include #include #include #include #include #include #include /* wait() */ #include /* struct timeval */ #include /* signal() */ #include #include "server-backend.h" int main(int argc, char *argv[]) { register int k; int port; int listen_sock; fd_set fds; struct sockaddr_in bind_addr; struct client *client_first = NULL; char **process; char *fake_argv[] = { "vim", "parser.h", "parser.c", "config.h", "main.h", "main.c", NULL }; if (argc < 3) { fprintf(stderr, "Usage: %s ... \n", PROG_NAME); return 1; } port = atoi(argv[1]); port = port > 0 ? port : PORT; 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(SIGBRK, 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, 10)) { 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) { int pid; struct client *client; struct timeval tv; /* for (pid = 0, client = client_first; client != NULL; client = client->next) pid++; fprintf(stderr, "debug: %d active clients\n", pid); */ FD_ZERO(&fds); FD_SET(listen_sock, &fds); tv.tv_sec = 1; tv.tv_usec = 0; if (select(FD_SETSIZE, &fds, NULL, NULL, &tv) == -1) continue; if (FD_ISSET(listen_sock, &fds)) { struct client *client_new; struct sockaddr_in acc_addr; unsigned int size; int accept_sock; struct hostent *host; size = sizeof(struct sockaddr_in); accept_sock = accept(listen_sock, (struct sockaddr*) &acc_addr, &size); if (accept_sock > 0 && (client_new = (struct client*) malloc(sizeof(struct client))) != NULL) { client_new->fd = accept_sock; /* Geting client IP address. */ strncpy(client_new->ip, (char*)inet_ntoa(acc_addr.sin_addr), IP_SIZE); client_new->ip[IP_SIZE] = '\0'; /* Geting host name. */ host = gethostbyaddr((char *)&acc_addr.sin_addr, 4, AF_INET); if (host == NULL) strncpy(client_new->host, client_new->ip, HOST_SIZE); else strncpy(client_new->host, host->h_name, HOST_SIZE); client_new->host[HOST_SIZE] = '\0'; client_new->port = ntohs(acc_addr.sin_port); client_new->next = NULL; if (client_first == NULL) { client_first = client_new; } else { for (client = client_first; client->next != NULL; client = client->next) ; client->next = client_new; } switch (pid = fork()) { case -1: perror(PROG_NAME); return errno; break; case 0: /* child */ close(0); dup(client_new->fd); close(1); dup(client_new->fd); close(2); dup(client_new->fd); close(listen_sock); /* write(client_new->fd, "----------------\n\r", 18); */ /* execvp(argv[2], argv + 2); */ execvp(process[0], process); write(client_new->fd, "execlp() failure\n\r", 18); break; default: /* parent */ client_new->pid = pid; close(client_new->fd); break; } } } /* * Terminated childs remove stuff. */ while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) { for (client = client_first; client != NULL; ) { /* fprintf(stderr, "debug: trying to removing pid %d, comparing with %d\n", pid, client->pid); */ if (client->pid == pid) { /* fprintf(stderr, "debug: removing pid %d\n", pid); */ shutdown(client->fd, 2); close(client->fd); if (client_first != client) { struct client* prev; for (prev = client_first; prev->next != client; prev = prev->next ) ; prev->next = client->next; free(client); client = prev->next; } else { client_first = client->next; free(client); client = client_first; } } else { client = client->next; } } } } /* while (1) */ return 0; }