1 /*
2 Terminal Mixer - multi-point multi-user access to terminal applications
3 Copyright (C) 2007 Lluís Batlle i Rossell
4
5 Please find the license in the provided COPYING file.
6 */
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <assert.h>
10 #include <errno.h>
11 #include <sys/select.h>
12
13 #include "main.h"
14 #include "filter.h"
15 #include "handlers.h"
16
17 /* it uses app_stdin, app_stdout, app_stderr.
18 * They have value -1 if not opened. */
19
20 static struct FilterRules *fr;
21
write_newline_cb(struct FilterRules * myfr,const struct FFilter * ff,char * obuf,int * olen,const char * ibuf,int pos)22 void write_newline_cb(struct FilterRules *myfr,
23 const struct FFilter *ff, char *obuf, int *olen,
24 const char *ibuf, int pos)
25 {
26 obuf[(*olen)++] = '\n';
27 }
28
app_control_start()29 void app_control_start()
30 {
31 struct FFilter *ff;
32 fr = new_filter_rules();
33
34 /* We don't pay attention to any telnet command */
35 ff = new_ftelnet();
36 add_ffilter(fr, ff);
37
38 /* The raw terminal will send \r,
39 * telnet will send \r\0. If we filter all \0, we're fine.
40 * I used to change \r to \n here... It works better if I don't. */
41
42 /* We should trim the telnet's no-operation characters '\0'. */
43 ff = new_fstring_len("\0", 1);
44 add_ffilter(fr, ff);
45 }
46
app_control_shutdown()47 void app_control_shutdown()
48 {
49 }
50
app_control_prepare_read_fdset(fd_set * read_set,int * maxfd)51 void app_control_prepare_read_fdset(fd_set *read_set, int *maxfd)
52 {
53 if (app_stdout != -1)
54 {
55 debugmsg("Considering app_stdout %i", app_stdout);
56 FD_SET(app_stdout, read_set);
57 *maxfd = max(*maxfd, app_stdout);
58 }
59
60 if (app_stderr != -1 && app_stdout != app_stderr)
61 {
62 debugmsg("Considering app_stderr %i", app_stderr);
63 FD_SET(app_stderr, read_set);
64 *maxfd = max(*maxfd, app_stderr);
65 }
66 }
67
68 /* Return -1, finished stdout/stderr. Else, return 0. */
app_control_process_read_fdset(fd_set * read_set)69 int app_control_process_read_fdset(fd_set *read_set)
70 {
71 if (app_stdout != -1 && FD_ISSET(app_stdout, read_set))
72 {
73 int res;
74 debugmsg("Read app_stdout %i", app_stdout);
75 res = read(app_stdout, stream_buffer, stream_buffer_size);
76 if (res == -1 && errno == EIO)
77 {
78 /* I've noticed that when the app dies, read() returns EIO */
79 app_stdout = -1;
80 app_stdin = -1;
81 return -1;
82 }
83 if (res == -1 )
84 error("Error reading from app.");
85 if (res == 0)
86 {
87 debugmsg("Closing app_stdout %i", app_stdout);
88 close(app_stdout);
89 if (!command_line.s_param.nohup)
90 close(1);
91 app_stdout = -1;
92 if (app_stdout == app_stderr || app_stderr == -1)
93 {
94 app_stderr = -1;
95 return -1;
96 }
97 } else
98 {
99 hex_dump("from app", stream_buffer, res);
100 if (!command_line.s_param.nohup)
101 write(1, stream_buffer, res);
102 if (command_line.s_param.serve_unix)
103 s_unix_send_to_connected(stream_buffer, res);
104 if (command_line.s_param.serve_tcp)
105 s_tcp_send_to_connected(stream_buffer, res);
106 #ifdef linux
107 if (command_line.s_param.serve_eth)
108 s_eth_send_to_connected(stream_buffer, res);
109 #endif /* linux */
110 }
111 }
112 if (app_stderr != -1 && app_stdout != app_stderr &&
113 FD_ISSET(app_stderr, read_set))
114 {
115 int res;
116 debugmsg("Read app_stderr %i", app_stdout);
117 res = read(app_stderr, stream_buffer, stream_buffer_size);
118 if (res == 0)
119 {
120 debugmsg("Closing app_stderr %i", app_stderr);
121 close(app_stderr);
122 close(2); /* MOVE */
123 app_stderr = -1;
124 if (app_stdout == -1)
125 return -1;
126 } else
127 {
128 if (!command_line.s_param.nohup)
129 write(2, stream_buffer, res);
130
131 if (command_line.s_param.serve_unix)
132 s_unix_send_to_connected(stream_buffer, res);
133 if (command_line.s_param.serve_tcp)
134 s_tcp_send_to_connected(stream_buffer, res);
135 #ifdef linux
136 if (command_line.s_param.serve_eth)
137 s_eth_send_to_connected(stream_buffer, res);
138 #endif /* linux */
139 }
140 }
141 return 0;
142 }
143
app_control_local_send_to_stdin(const char * buffer,size_t size)144 void app_control_local_send_to_stdin(const char *buffer, size_t size)
145 {
146 if (size == 0)
147 {
148 close(app_stdin);
149 if (app_stdout == app_stdin)
150 app_stdout = -1;
151 if (app_stderr == app_stdin)
152 app_stderr = -1;
153 }
154 else
155 {
156 hex_dump("from local to app", buffer, size);
157 write(app_stdin, buffer, size);
158 }
159 }
160
write_data_to_app_stdin(const char * buffer,size_t size)161 static void write_data_to_app_stdin(const char *buffer, size_t size)
162 {
163 if (size > 0)
164 {
165 hex_dump("to app", buffer, size);
166 if( !command_line.s_param.nohup &&
167 command_line.s_param.echo_in_local_terminal)
168 write(1, buffer, size);
169 write(app_stdin, buffer, size);
170 }
171 }
172
app_control_remote_send_to_stdin(const char * buffer,size_t size)173 void app_control_remote_send_to_stdin(const char *buffer, size_t size)
174 {
175 hex_dump("from client prefilter", buffer, size);
176 if (command_line.s_param.client_can_write)
177 {
178 int osize;
179 if (size > 0)
180 {
181 filter_stream(fr, ostream_buffer, &osize,
182 buffer, size);
183 if (osize > 0)
184 write_data_to_app_stdin(ostream_buffer, osize);
185 } else if (size == 0)
186 {
187 filter_flush(fr, ostream_buffer, &osize);
188 if (osize > 0)
189 write_data_to_app_stdin(ostream_buffer, osize);
190 }
191
192 if (size == 0 && command_line.s_param.client_may_close_app_stdin)
193 {
194 close(app_stdin);
195 if (app_stdout == app_stdin)
196 app_stdout = -1;
197 if (app_stderr == app_stdin)
198 app_stderr = -1;
199 }
200 }
201 }
202
app_control_avoid_sending(fd_set * read_set)203 void app_control_avoid_sending(fd_set *read_set)
204 {
205 }
206