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 <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 <fcntl.h>
#include "main.h"
#include "handlers.h"
/* signals.c */
extern int child_died;
/* app_control.c */
extern int savefile;
/*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 */
if (command_line.s_param.savefile)
{
savefile = open(command_line.s_param.savefile, O_CREAT | O_RDWR, 0666);
}
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;
}