app_control.c
author viric@llimona
Mon, 24 Sep 2007 13:59:40 +0200
changeset 38 f1e581c862d5
parent 36 da427c23d755
child 41 954941c6e40a
permissions -rw-r--r--
Improved help. Moving to 0.2.

#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <sys/select.h>

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

/* it uses app_stdin, app_stdout, app_stderr.
 * They have value -1 if not opened. */

static struct FilterRules *fr;

void write_newline_cb(struct FilterRules *myfr,
        const struct FFilter *ff, char *obuf, int *olen,
        const char *ibuf, int pos)
{
    obuf[(*olen)++] = '\n';
}

void app_control_start()
{
    struct FFilter *ff;
    fr = new_filter_rules();

    /* We don't pay attention to any telnet command */
    ff = new_ftelnet();
    add_ffilter(fr, ff);

    /* The client will send \r\0 on enter */
    ff = new_fstring_len("\r\0", 2);
    ff->callback = write_newline_cb;
    add_ffilter(fr, ff);

    /* We should trim the no operation characters '\0'.
     * We rely on the filter application order. First \r\0 above,
     * then \0. */
    ff = new_fstring_len("\0", 1);
    add_ffilter(fr, ff);
}

void app_control_shutdown()
{
}

void app_control_prepare_read_fdset(fd_set *read_set, int *maxfd)
{
    assert(app_stdout != -1 || app_stderr != -1);

    if (app_stdout != -1)
    {
        FD_SET(app_stdout, read_set);
        *maxfd = max(*maxfd, app_stdout);
    }

    if (app_stderr != -1 && app_stdout != app_stderr)
    {
        FD_SET(app_stderr, read_set);
        *maxfd = max(*maxfd, app_stderr);
    }
}

/* Return -1, finished stdout/stderr. Else, return 0. */
int app_control_process_read_fdset(fd_set *read_set)
{
    if (app_stdout != -1 && FD_ISSET(app_stdout, read_set))
    {
        int res;
        res = read(app_stdout, stream_buffer, stream_buffer_size);
        if (res == -1 && errno == EIO)
        {
            /* I've noticed that when the app dies, read() returns EIO */
            app_stdout = -1;
            app_stdin = -1;
            return -1;
        }
        if (res == -1 )
            error("Error reading from app.");
        if (res == 0)
        {
            close(app_stdout);
            close(1); /* MOVE */
            app_stdout = -1;
            if (app_stdout == app_stderr || app_stderr == -1)
                return -1;
        } else
        {
            /* MOVE */
            hex_dump("from app", stream_buffer, res);
            write(1, stream_buffer, res);
            if (command_line.s_param.serve_unix)
                s_unix_send_to_connected(stream_buffer, res);
            if (command_line.s_param.serve_tcp)
                s_tcp_send_to_connected(stream_buffer, res);
        }
    }
    if (app_stderr != -1 && app_stdout != app_stderr &&
            FD_ISSET(app_stderr, read_set))
    {
        int res;
        res = read(app_stderr, stream_buffer, stream_buffer_size);
        if (res == 0)
        {
            close(app_stderr);
            close(2); /* MOVE */
            app_stderr = -1;
            if (app_stdout == -1)
                return -1;
        } else
        {
            /* MOVE */
            write(2, stream_buffer, res);

            if (command_line.s_param.serve_unix)
                s_unix_send_to_connected(stream_buffer, res);
            if (command_line.s_param.serve_tcp)
                s_tcp_send_to_connected(stream_buffer, res);
        }
    }
    return 0;
}

void app_control_local_send_to_stdin(const char *buffer, size_t size)
{
    if (size == 0)
        close(app_stdin);
    else
    {
        hex_dump("from local to app", buffer, size);
        write(app_stdin, buffer, size);
    }
}

static void write_data_to_app_stdin(const char *buffer, size_t size)
{
    if (size > 0)
    {
        hex_dump("to app", buffer, size);
        if(command_line.s_param.echo_in_local_terminal)
            write(1, buffer, size);
        write(app_stdin, buffer, size);
    }
}

void app_control_remote_send_to_stdin(const char *buffer, size_t size)
{
    hex_dump("from client prefilter", buffer, size);
    if (command_line.s_param.client_can_write)
    {
        int osize;
        if (size > 0)
        {
            filter_stream(fr, ostream_buffer, &osize,
                    buffer, size);
            if (osize > 0)
                write_data_to_app_stdin(ostream_buffer, osize);
        } else if (size == 0)
        {
            filter_flush(fr, ostream_buffer, &osize);
            if (osize > 0)
                write_data_to_app_stdin(ostream_buffer, osize);
        }

        if (size == 0 && command_line.s_param.client_may_close_app_stdin)
            close(app_stdin);
    }
}