client.c
author viric <viriketo@gmail.com>
Wed, 16 Feb 2011 21:07:11 +0100
branchsaveflie
changeset 95 13360d8af313
parent 86 c972d3312fbd
permissions -rw-r--r--
Fixing a problem on savefile (stdin was not saved well, and the file not truncated)

/*
    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 <signal.h>
#include <errno.h>
#include <string.h>

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

struct FilterRules *client_recv_fr = 0;
struct FilterRules *client_termin_fr = 0;

static void loop(Net_c_prepare_read_fdset net_prepare,
        Net_c_process_read_fdset net_process,
        Net_c_send net_send)
{
    fd_set read_set;
    sigset_t sigempty,signoalarm;
    int maxfd;
    int res;

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

    do
    {
        FD_ZERO(&read_set);

        FD_SET(0, &read_set); /* stdin */
        maxfd = 0;

        net_prepare(&read_set, &maxfd);

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

#ifdef linux
        if (command_line.s_param.serve_eth)
        {
            int res;
            /* This will check if the timeout occurred,
             * and will not do anything otherwise.
               Will return false when the connection is lost. */
            res = eth_proto_process_timeouts();
            if (!res)
            {
                printf("Connection lost (no ACK received).\n");
                break;
            }
        }
#endif

        res = pselect(maxfd + 1, &read_set, 0, 0, 0, &sigempty);
#ifdef linux
        if (command_line.c_param.transport == ETHERNET)
            /* If there isn't a good result, we quit */
            if (!eth_proto_process_timeouts())
            {
                    printf("Connection lost (no ACK received).\n");
                    break;
            }
#endif
        if (res == -1)
        {
            if (errno == EINTR)
                continue;
            else
                error("Error in select()");
        }

        res = net_process(&read_set);
        if (res == -1) /* EOF */
            break;

        if (FD_ISSET(0, &read_set))
        {
            res = read(0, stream_buffer, stream_buffer_size);
            if (client_termin_fr)
            {
                int olen;
                /* We use ostream_buffer2 for data from the
                 * keyboard to the tm client, because
                 * *_client.c use the ostream_buffer for data
                 * from the server to us (tm client). */
                hex_dump("Client prefilter", stream_buffer, res);
                filter_stream(client_termin_fr, ostream_buffer2, &olen,
                        stream_buffer,
                        res);
                if (olen > 0)
                    net_send(ostream_buffer2, olen);
            }
            else
                net_send(stream_buffer, res);
            if (res == 0) /* EOF */
                break;
        }
    } while (1);
}

void filtercb_tildes(struct FilterRules *fr, const struct FFilter *ff,
        char *obuf, int *olen, const char *ibuf, int pos)
{
    dump_line("filtercb_tildes: '%c'\n", ibuf[pos+3]);
    if (ibuf[pos+3] == '.')
        kill(getpid(), SIGINT);
    else
    {
        obuf[(*olen)++] = '~';
        obuf[(*olen)++] = '~';
        obuf[(*olen)++] = '~';
    }
}

int client()
{
    Net_c_prepare_read_fdset net_prepare_read_fdset;
    Net_c_process_read_fdset net_process_read_fdset;
    Net_c_send net_send;

    /* Prepare the filter */
    {
        struct FFilter *ff;
        client_recv_fr = new_filter_rules();
        ff = new_ftelnet();
        add_ffilter(client_recv_fr, ff);
        if (command_line.c_param.raw_mode)
        {
            client_termin_fr = new_filter_rules();
            ff = new_ftildes();
            ff->callback = filtercb_tildes;
            add_ffilter(client_termin_fr, ff);
        }
    }

    if (command_line.c_param.transport == UNIX)
        /* Will be 'tcp', 'ether', ... */
    {
        c_unix_connect_socket();
        net_prepare_read_fdset = c_unix_prepare_read_fdset;
        net_process_read_fdset = c_unix_process_read_fdset;
        net_send = c_unix_send;
    }
#ifdef linux
    else if (command_line.c_param.transport == ETHERNET)
    {
        c_eth_init();
        net_prepare_read_fdset = c_eth_prepare_read_fdset;
        net_process_read_fdset = c_eth_process_read_fdset;
        net_send = c_eth_send_to_connected;
    }
#endif /* linux */

    if (command_line.c_param.raw_mode)
        prepare_user_terminal();

    loop(net_prepare_read_fdset, net_process_read_fdset, net_send);

    if (command_line.c_param.raw_mode)
        restore_user_terminal();

    return 0;
}