server.c
author viric@mandarina
Mon, 28 Apr 2008 21:42:48 +0200
changeset 92 faf9db07c037
parent 86 c972d3312fbd
child 94 330324fc7c20
permissions -rw-r--r--
Makefile with 'install'

/*
    Terminal Mixer - multi-point multi-user access to terminal applications
    Copyright (C) 2007  LluĂ­s Batlle i Rossell

    Please find the license in the provided COPYING file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/select.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <string.h>

#include "main.h"
#include "handlers.h"

/* signals.c */
extern int child_died;

/*extern*/
void fdset_dump(fd_set *set, int maxfd);

static void loop()
{
    fd_set read_set;
    sigset_t sigempty,signoalarm;
    int maxfd;
    int stdin_opened;
    int res;

    if (command_line.s_param.nohup)
        stdin_opened = 0;
    else
        stdin_opened = 1;

    /* Prepare the sigset for blocking alarm */
    sigemptyset(&signoalarm);
    sigaddset(&signoalarm, SIGALRM);
    sigemptyset(&sigempty);

    do
    {
        FD_ZERO(&read_set);

        maxfd = -1;
        if (stdin_opened)
        {
            FD_SET(0, &read_set);
            maxfd = 0;
        }

        app_control_prepare_read_fdset(&read_set, &maxfd);
        if (command_line.s_param.serve_unix)
            s_unix_prepare_read_fdset(&read_set, &maxfd);
        if (command_line.s_param.serve_tcp)
            s_tcp_prepare_read_fdset(&read_set, &maxfd);
#ifdef linux
        if (command_line.s_param.serve_eth)
            s_eth_prepare_read_fdset(&read_set, &maxfd);
#endif /* linux */

        /* Prepare checking for timeout */
        sigprocmask(SIG_BLOCK, &signoalarm, 0);

#ifdef linux
        if (command_line.s_param.serve_eth)
            /* This will check if the timeout occurred,
             * and will not do anything otherwise. */
            eth_proto_process_timeouts();
#endif

        if (maxfd == -1)
          error("No fds in select");

        debugmsg("Blocking in pselect");
        if (child_died == 1)
          break;

        /* Will block */
        res = pselect(maxfd + 1, &read_set, 0, 0, 0, &sigempty);
#ifdef linux
        if (command_line.s_param.serve_eth)
            eth_proto_process_timeouts();
#endif
        if (res == -1)
        {
            if (errno == EINTR)
            {
                dump_line("Signal received in server select()\n");
                continue;
            }
            else
                error("Error in select()");
        }

        res = app_control_process_read_fdset(&read_set);
        if (res == -1) /* app_stdout and app_stderr closed */
            break;

        if (stdin_opened && FD_ISSET(0, &read_set))
        {
            res = read(0, stream_buffer, stream_buffer_size);
            /* if res is 0, the fcall will close app_stdin */
            app_control_local_send_to_stdin(stream_buffer, res);
            if (res == 0)
            {
                debugmsg("Closing stdin\n");
                stdin_opened = 0;
            }
        }

        if (command_line.s_param.serve_unix)
            s_unix_process_read_fdset(&read_set);
        if (command_line.s_param.serve_tcp)
            s_tcp_process_read_fdset(&read_set);
#ifdef linux
        if (command_line.s_param.serve_eth)
            s_eth_process_read_fdset(&read_set);
#endif /* linux */
    } while(1);
}

int server()
{
    int child;

    command_line.is_server = 1;

    app_control_start();

    /* in raw mode, the signals for Control-C, ... will be generated by the
     * slave pty. The master will receive the key codes. */
    if (command_line.s_param.serve_unix)
        s_unix_update_served(command_line.s_param.max_served);

    if (command_line.s_param.serve_tcp)
        s_tcp_update_served(command_line.s_param.max_served);

#ifdef linux
    if (command_line.s_param.serve_eth)
        s_eth_init();
#endif /* linux */

    child = fork_app(command_line.s_param.command);

    if (command_line.s_param.nohup)
    {
        ignore_sighup();
        close(0);
        close(1);
        close(2);
    } else
        if (command_line.s_param.run_in_subterminal)
            prepare_user_terminal();

    install_signal_forwarders(child);

    loop();

    if (command_line.s_param.serve_unix)
        s_unix_shutdown();

    if (command_line.s_param.serve_tcp)
        s_tcp_shutdown();

#ifdef linux
    if (command_line.s_param.serve_eth)
        s_eth_shutdown();
#endif /* linux */

    if (!command_line.s_param.nohup &&
            command_line.s_param.run_in_subterminal)
        restore_user_terminal();

    return 0;
}