Adding a feature: save all stdin/stdout traffic of the server into a file.
/*
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 <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;
int savefile = -1;
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 raw terminal will send \r,
* telnet will send \r\0. If we filter all \0, we're fine.
* I used to change \r to \n here... It works better if I don't. */
/* We should trim the telnet's no-operation characters '\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)
{
if (app_stdout != -1)
{
debugmsg("Considering app_stdout %i", app_stdout);
FD_SET(app_stdout, read_set);
*maxfd = max(*maxfd, app_stdout);
}
if (app_stderr != -1 && app_stdout != app_stderr)
{
debugmsg("Considering app_stderr %i", 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;
debugmsg("Read app_stdout %i", app_stdout);
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)
{
debugmsg("Closing app_stdout %i", app_stdout);
close(app_stdout);
if (!command_line.s_param.nohup)
close(1);
app_stdout = -1;
if (app_stdout == app_stderr || app_stderr == -1)
{
app_stderr = -1;
return -1;
}
} else
{
hex_dump("from app", stream_buffer, res);
if (!command_line.s_param.nohup)
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);
#ifdef linux
if (command_line.s_param.serve_eth)
s_eth_send_to_connected(stream_buffer, res);
#endif /* linux */
if (savefile != -1)
write(savefile, stream_buffer, res);
}
}
if (app_stderr != -1 && app_stdout != app_stderr &&
FD_ISSET(app_stderr, read_set))
{
int res;
debugmsg("Read app_stderr %i", app_stdout);
res = read(app_stderr, stream_buffer, stream_buffer_size);
if (res == 0)
{
debugmsg("Closing app_stderr %i", app_stderr);
close(app_stderr);
close(2); /* MOVE */
app_stderr = -1;
if (app_stdout == -1)
return -1;
} else
{
if (!command_line.s_param.nohup)
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);
#ifdef linux
if (command_line.s_param.serve_eth)
s_eth_send_to_connected(stream_buffer, res);
#endif /* linux */
}
}
return 0;
}
void app_control_local_send_to_stdin(const char *buffer, size_t size)
{
if (size == 0)
{
close(app_stdin);
if (app_stdout == app_stdin)
app_stdout = -1;
if (app_stderr == app_stdin)
app_stderr = -1;
}
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.nohup &&
command_line.s_param.echo_in_local_terminal)
write(1, buffer, size);
write(app_stdin, buffer, size);
if (savefile != -1)
write(savefile, 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);
if (app_stdout == app_stdin)
app_stdout = -1;
if (app_stderr == app_stdin)
app_stderr = -1;
}
}
}
void app_control_avoid_sending(fd_set *read_set)
{
}