/* 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 #include #include #include #include #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 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) { 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); if (!command_line.s_param.nohup) close(1); if (app_stdout == app_stderr || app_stderr == -1) return -1; app_stdout = -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 (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 { 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); 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); } } 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); } } void app_control_avoid_sending(fd_set *read_set) { }