Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
authorviric@llimona
Mon, 24 Sep 2007 13:45:24 +0200
changeset 36 da427c23d755
parent 35 69dbea6c3882
child 37 b0588bddef91
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
Makefile
app_control.c
client.c
dump.c
filter.h
filter_string.c
filter_telnet.c
gen_sockets.c
handlers.h
main.c
main.h
server.c
tcp_server.c
unix_client.c
unix_server.c
--- 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);
         }
     }
 }