Platon Technologies
neprihlásený Prihlásiť Registrácia
SlovakEnglish
open source software development oslavujeme 10 rokov vývoja otvoreného softvéru! Štvrtok, 28. marec 2024

Súbor: [Platon] / libplaton / utils / server-backend / server-backend.c (stiahnutie)

Revízia 1.1, Wed Oct 3 21:03:41 2001 UTC (22 years, 5 months ago) by jombik9

Initial revision

/*
 * 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()
 *
 * TODO
 * - write debug infomations to STDERR
 */

#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-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 <port> <process> <arg1> ... <argn>\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;
}



Platon Group <platon@platon.sk> http://platon.sk/
Copyright © 2002-2006 Platon Group
Stránka používa redakčný systém Metafox
Na začiatok