Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
--- a/Makefile Sun Sep 23 23:43:49 2007 +0200
+++ b/Makefile Mon Sep 24 13:45:24 2007 +0200
@@ -9,7 +9,11 @@
user_term.o \
tcp_server.o \
simple_math.o \
- xterm.o
+ xterm.o \
+ dump.o \
+ filter.o \
+ filter_string.o \
+ filter_telnet.o
all: tm test_filter
@@ -38,4 +42,6 @@
filter.o: filter.c filter.h main.h
test_filter.o: test_filter.c filter.h
filter_string.o: filter_string.c filter.h
+filter_telnet.o: filter_telnet.c filter.h
xterm.o: xterm.c main.h
+dump.o: dump.c main.h
--- a/app_control.c Sun Sep 23 23:43:49 2007 +0200
+++ b/app_control.c Mon Sep 24 13:45:24 2007 +0200
@@ -5,11 +5,41 @@
#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()
{
@@ -58,6 +88,7 @@
} 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);
@@ -96,16 +127,43 @@
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);
- else
- write(app_stdin, buffer, size);
}
}
--- a/client.c Sun Sep 23 23:43:49 2007 +0200
+++ b/client.c Mon Sep 24 13:45:24 2007 +0200
@@ -7,8 +7,11 @@
#include <string.h>
#include "main.h"
+#include "filter.h"
#include "handlers.h"
+struct FilterRules *client_fr = 0;
+
static void loop(Net_c_prepare_read_fdset net_prepare,
Net_c_process_read_fdset net_process,
Net_c_send net_send)
@@ -55,6 +58,14 @@
Net_c_process_read_fdset net_process_read_fdset;
Net_c_send net_send;
+ /* Prepare the filter */
+ {
+ struct FFilter *ff;
+ client_fr = new_filter_rules();
+ ff = new_ftelnet();
+ add_ffilter(client_fr, ff);
+ }
+
if (command_line.c_param.transport == UNIX)
/* Will be 'tcp', 'ether', ... */
{
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dump.c Mon Sep 24 13:45:24 2007 +0200
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "main.h"
+
+const int should_dump = 0;
+
+void dump_line(const char *msg, ...)
+{
+ va_list v;
+ FILE *f;
+
+ if (!should_dump) return;
+
+ va_start(v, msg);
+ f = fopen("/tmp/dump.txt", "a");
+ if (f == 0) return;
+
+ vfprintf(f, msg, v);
+ fclose(f);
+}
+
+void hex_dump(const char *head, const unsigned char *data, int len)
+{
+ int i;
+ FILE *f;
+
+ if (!should_dump) return;
+
+ f = fopen("/tmp/dump.txt", "a");
+ if (f == 0) return;
+
+ fprintf(f, "%s: ", head);
+ for(i=0;i<len; ++i)
+ {
+ int c;
+ if (i > 0)
+ fprintf(f," ");
+ c = data[i];
+ if (c >= 32 && c <= 127)
+ fprintf(f, "'%c'", c);
+ else
+ fprintf(f, "%2x", c);
+ }
+ fputc('\n', f);
+ fclose(f);
+}
--- a/filter.h Sun Sep 23 23:43:49 2007 +0200
+++ b/filter.h Mon Sep 24 13:45:24 2007 +0200
@@ -33,3 +33,7 @@
/* filter_string.c */
struct FFilter *new_fstring(char *p);
+struct FFilter *new_fstring_len(char *p, int len);
+
+/* filter_telnet.c */
+struct FFilter *new_ftelnet();
--- a/filter_string.c Sun Sep 23 23:43:49 2007 +0200
+++ b/filter_string.c Mon Sep 24 13:45:24 2007 +0200
@@ -21,8 +21,13 @@
if (fs->p[fs->base.matched] == c)
fs->base.matched++;
else
+ {
/* A SAC */
- fs->base.matched = 0;
+ if (fs->p[0] == c)
+ fs->base.matched = 1;
+ else
+ fs->base.matched = 0;
+ }
if (fs->base.matched == fs->len)
return 1;
@@ -43,3 +48,18 @@
return (struct FFilter *) fs;
}
+
+struct FFilter *new_fstring_len(char *p, int len)
+{
+ struct FString *fs;
+ fs = (struct FString *) malloc(sizeof(*fs));
+
+ fs->p = strdup(p);
+ fs->len = len;
+ fs->base.matched = 0;
+ fs->base.function = fstring_function;
+ fs->base.reset = fstring_reset;
+ fs->base.callback = 0;
+
+ return (struct FFilter *) fs;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/filter_telnet.c Mon Sep 24 13:45:24 2007 +0200
@@ -0,0 +1,92 @@
+#include <stdlib.h>
+#include "main.h"
+#include "filter.h"
+
+enum TState
+{
+ NOTHING,
+ RECEIVED_IAC,
+ RECEIVED_OPT,
+ SUBNEGOTIATED
+};
+
+enum Chars
+{
+ IAC = 255,
+ SB = 250,
+ SE = 240
+};
+
+struct FTelnet
+{
+ struct FFilter base;
+ enum TState state;
+};
+
+static void ftelnet_reset(struct FFilter *ff)
+{
+ struct FTelnet *ft = (struct FTelnet *) ff;
+ dump_line("ftelnet reset.\n");
+ ft->state = NOTHING;
+}
+
+static int ftelnet_function(struct FFilter *ff, unsigned char c)
+{
+ struct FTelnet *ft = (struct FTelnet *) ff;
+
+ dump_line("ftelnet_function called\n");
+ switch (ft->state)
+ {
+ case NOTHING:
+ dump_line("ftelnet still in NOTHING.\n");
+ if (c == IAC)
+ {
+ dump_line("ftelnet received IAC\n");
+ ft->state = RECEIVED_IAC;
+ ft->base.matched++;
+ }
+ break;
+ case RECEIVED_IAC:
+ if (c == SB)
+ {
+ dump_line("ftelnet received SB\n");
+ ft->state = SUBNEGOTIATED;
+ ft->base.matched++;
+ } else /* Received the control char */
+ {
+ ft->state = RECEIVED_OPT;
+ dump_line("ftelnet received command.\n");
+ ft->base.matched++;
+ }
+ break;
+ case RECEIVED_OPT:
+ dump_line("ftelnet received option.\n");
+ ft->base.matched++;
+ return 1;
+ break;
+ case SUBNEGOTIATED:
+ ft->base.matched++;
+ dump_line("ftelnet still in SUBNEGOTIATED.\n");
+ if (c == SE)
+ {
+ dump_line("ftelnet received SE. Filtering.\n");
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
+struct FFilter *new_ftelnet()
+{
+ struct FTelnet *ft;
+ ft = (struct FTelnet *) malloc(sizeof(*ft));
+
+ ft->state = NOTHING;
+ ft->base.matched = 0;
+ ft->base.function = ftelnet_function;
+ ft->base.reset = ftelnet_reset;
+ ft->base.callback = 0;
+
+ return (struct FFilter *) ft;
+}
--- a/gen_sockets.c Sun Sep 23 23:43:49 2007 +0200
+++ b/gen_sockets.c Mon Sep 24 13:45:24 2007 +0200
@@ -1,6 +1,8 @@
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
+#include <string.h>
+#include <sys/socket.h>
#include "main.h"
char *stream_buffer = 0;
@@ -19,3 +21,41 @@
ostream_buffer = (char *) malloc(ostream_buffer_size);
}
}
+
+static void send_xterm_resize_string_to_socket(int s)
+{
+ char *term;
+ term = getenv("TERM");
+ /* I prefer it to send the xterm string always. */
+ if (1 || term == 0 || strcmp(term, "xterm") == 0)
+ {
+ char *xterm_str;
+ xterm_str = get_xterm_resize_string();
+ hex_dump("xterm_resize", xterm_str, strlen(xterm_str));
+ send(s, xterm_str, strlen(xterm_str), 0);
+ }
+}
+
+static void telnet_send_noecho(int s)
+{
+ char seq[] = { 255 /*IAC*/, 251 /*WILL*/, 1 /*ECHO*/ };
+ hex_dump("telnet_send_noecho", seq, sizeof seq);
+ send(s, seq, sizeof seq, 0);
+}
+
+static void telnet_send_suppress_go_ahead(int s)
+{
+ char seq[] = { 255 /*IAC*/, 251 /*WILL*/, 3 /*ECHO*/ };
+ hex_dump("telnet_send_suppress_go_ahead", seq, sizeof seq);
+ send(s, seq, sizeof seq, 0);
+}
+
+void welcome_new_client_socket(int s)
+{
+ if (command_line.s_param.run_in_subterminal)
+ {
+ telnet_send_noecho(s);
+ telnet_send_suppress_go_ahead(s);
+ send_xterm_resize_string_to_socket(s);
+ }
+}
--- a/handlers.h Sun Sep 23 23:43:49 2007 +0200
+++ b/handlers.h Mon Sep 24 13:45:24 2007 +0200
@@ -12,6 +12,7 @@
void s_unix_send_to_connected(const char *buffer, size_t size);
/* app_control.c */
+void app_control_start();
void app_control_shutdown();
void app_control_prepare_read_fdset(fd_set *read_set, int *maxfd);
int app_control_process_read_fdset(fd_set *read_set);
--- a/main.c Sun Sep 23 23:43:49 2007 +0200
+++ b/main.c Mon Sep 24 13:45:24 2007 +0200
@@ -37,14 +37,17 @@
printf(" a stdin server on $SM_SOCKET or /tmp/socket-sm.UID.\n");
printf(" If not given, it starts a stdin client for the same socket.\n");
printf("options: \n");
- printf(" -h Show help\n");
- printf(" -P Run the child as connected to a pipe (default)\n");
+ printf(" -h Show help.\n");
+ printf(" -P Run the child as connected to a pipe (default).\n");
printf(" -t Run the child as connected to a terminal (raw mode in "
- "client)\n");
- printf(" -n MAX Serve at most MAX sockets for each transport\n");
+ "client).\n");
+ printf(" -n MAX Serve at most MAX sockets for each transport (1 default)."
+ "\n");
printf(" -w The remote clients can write to the application.\n");
printf(" -x The remote clients end will close app's stdin.\n");
- printf(" -p NUM Listen to tcp port NUM, and not listen to any Unix socket.\n");
+ printf(" -p NUM Listen to tcp port NUM, and not listen to any Unix socket."
+ "\n");
+ printf(" -e Echo remote input to the server terminal.\n");
return 0;
}
@@ -82,6 +85,7 @@
command_line.s_param.client_may_close_app_stdin = 0;
command_line.s_param.detach = 0;
command_line.s_param.client_can_write = 0;
+ command_line.s_param.echo_in_local_terminal = 0;
command_line.tcp_port = 40000; /* Arbitrary */
command_line.buffer_size = 4096; /* Arbitrary */
@@ -100,7 +104,7 @@
extern int optind, opterr, optopt;
while(1) {
- c = my_getopt(argc, argv, "tp:NrdPn:c:hwx");
+ c = my_getopt(argc, argv, "tp:NrdPn:c:hwxe");
if (c == -1)
break;
@@ -141,6 +145,9 @@
case 'x':
command_line.s_param.client_may_close_app_stdin = 1;
break;
+ case 'e':
+ command_line.s_param.echo_in_local_terminal = 1;
+ break;
case '?':
error("Wrong option %c.\n", optopt);
}
--- a/main.h Sun Sep 23 23:43:49 2007 +0200
+++ b/main.h Mon Sep 24 13:45:24 2007 +0200
@@ -14,6 +14,7 @@
int serve_unix; /* yes/no */
int max_served; /* how many */
char run_in_subterminal; /* use opentty */
+ char echo_in_local_terminal;
char use_blocking_sockets;
char send_xterm_resize;
char client_may_close_app_stdin;
@@ -52,6 +53,7 @@
extern char *ostream_buffer;
extern int ostream_buffer_size;
void init_stream_buffers();
+void welcome_new_client_socket(int s);
/* server.c */
int server();
@@ -66,5 +68,9 @@
void prepare_user_terminal();
void restore_user_terminal();
-/* xterm.h */
+/* xterm.c */
char * get_xterm_resize_string();
+
+/* dump.c */
+void hex_dump(const char *head, const unsigned char *data, int len);
+void dump_line(const char *msg, ...);
--- a/server.c Sun Sep 23 23:43:49 2007 +0200
+++ b/server.c Mon Sep 24 13:45:24 2007 +0200
@@ -67,6 +67,8 @@
command_line.is_server = 1;
+ app_control_start();
+
child = fork_app(command_line.s_param.command);
if (command_line.s_param.run_in_subterminal)
--- a/tcp_server.c Sun Sep 23 23:43:49 2007 +0200
+++ b/tcp_server.c Mon Sep 24 13:45:24 2007 +0200
@@ -28,6 +28,13 @@
if (ls == -1)
error("Cannot create the tcp listen socket in the server");
+ {
+ int on = 1;
+ res = setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ if (res == -1)
+ error("Cannot set SO_REUSEADDR");
+ }
+
addr.sin_family = AF_INET;
addr.sin_port = htons(command_line.tcp_port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
@@ -157,15 +164,10 @@
{
if (FD_ISSET(listen_socket, read_set))
{
- conn_sockets[connected_sockets++] =
- accept_connection(listen_socket);
- if (command_line.s_param.run_in_subterminal)
- {
- char *xterm_str;
- xterm_str = get_xterm_resize_string();
- send(conn_sockets[connected_sockets-1],
- xterm_str, strlen(xterm_str), 0);
- }
+ int s;
+ s = accept_connection(listen_socket);
+ conn_sockets[connected_sockets++] = s;
+ welcome_new_client_socket(s);
}
}
}
--- a/unix_client.c Sun Sep 23 23:43:49 2007 +0200
+++ b/unix_client.c Mon Sep 24 13:45:24 2007 +0200
@@ -5,9 +5,12 @@
#include "main.h"
#include "handlers.h"
+#include "filter.h"
static int conn_socket = -1;
+extern struct FilterRules *client_fr;
+
void c_unix_connect_socket()
{
struct sockaddr_un addr;
@@ -40,15 +43,27 @@
int res;
if (FD_ISSET(conn_socket, read_set))
{
+ int olen;
res = read(conn_socket, stream_buffer, stream_buffer_size);
if (res == 0) /* EOF */
+ {
+ filter_flush(client_fr, ostream_buffer, &olen);
+ if (olen > 0)
+ send_to_client_stdout(ostream_buffer, olen);
return -1;
- send_to_client_stdout(stream_buffer, res);
+ }
+ hex_dump("recv_unix_client",stream_buffer, res);
+
+ filter_stream(client_fr, ostream_buffer, &olen, stream_buffer,
+ res);
+ if (olen > 0)
+ send_to_client_stdout(ostream_buffer, olen);
}
return 0;
}
void c_unix_send(const char *buf, int len)
{
+ hex_dump("send_unix_client",buf, len);
write(conn_socket, stream_buffer, len);
}
--- a/unix_server.c Sun Sep 23 23:43:49 2007 +0200
+++ b/unix_server.c Mon Sep 24 13:45:24 2007 +0200
@@ -189,15 +189,10 @@
{
if (FD_ISSET(listen_socket, read_set))
{
- conn_sockets[connected_sockets++] =
- accept_connection(listen_socket);
- if (command_line.s_param.run_in_subterminal)
- {
- char *xterm_str;
- xterm_str = get_xterm_resize_string();
- send(conn_sockets[connected_sockets-1],
- xterm_str, strlen(xterm_str), 0);
- }
+ int s;
+ s = accept_connection(listen_socket);
+ conn_sockets[connected_sockets++] = s;
+ welcome_new_client_socket(s);
}
}
}