/* * 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 "utils.h" #include "server-backend.h" int main(int argc, char *argv[]) { int port; int listen_sock; fd_set fds; struct client *client_first = NULL; char **process; if (argc < 3) { fprintf(stderr, "Usage: %s ... \n", PROG_NAME); return 1; } port = get_port(argv[1]); if ((process = create_process_array(argc, argv, 2)) == NULL) { perror(PROG_NAME); return 32; } fake_command_line(argc, argv); if ((listen_sock = bind_to_port(port)) == -1) { perror(PROG_NAME); return 16; } if (0) { (void) setpgrp(); signal(SIGHUP, SIG_IGN); } if (1) fcntl(listen_sock,F_SETFL,O_NDELAY); switch (fork()) { case -1: perror(PROG_NAME); return errno; break; case 0: break; default: fprintf(stderr, "%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; }