SOCKS: as a client, talk SMTP via a socks5 proxy. Bug 1590
[users/jgh/exim.git] / test / src / server.c
index a7e1d2b1d9df5defac1f2014ac9252b3d6b22e7d..e425880a8b2181812c1c813059f5b0ea734610d1 100644 (file)
@@ -43,16 +43,21 @@ on all interfaces, unless the option -noipv6 is given. */
 #include <utime.h>
 
 #ifdef AF_INET6
 #include <utime.h>
 
 #ifdef AF_INET6
-#define HAVE_IPV6 1
+# define HAVE_IPV6 1
 #endif
 
 #ifndef S_ADDR_TYPE
 #endif
 
 #ifndef S_ADDR_TYPE
-#define S_ADDR_TYPE u_long
+# define S_ADDR_TYPE u_long
+#endif
+
+#ifndef CS
+# define CS (char *)
 #endif
 
 
 typedef struct line {
   struct line *next;
 #endif
 
 
 typedef struct line {
   struct line *next;
+  unsigned len;
   char line[1];
 } line;
 
   char line[1];
 } line;
 
@@ -119,6 +124,25 @@ return buffer;
 }
 
 
 }
 
 
+
+static void
+printit(char * s, int n)
+{
+while(n--)
+  {
+  unsigned char c = *s++;
+  if (c == '\\')
+    printf("\\\\");
+  else if (c >= ' ' && c <= '~')       /* assumes ascii */
+    putchar(c);
+  else
+    printf("\\x%02x", c);
+  }
+putchar('\n');
+}
+
+
+
 /*************************************************
 *                 Main Program                   *
 *************************************************/
 /*************************************************
 *                 Main Program                   *
 *************************************************/
@@ -139,6 +163,7 @@ int connection_count = 1;
 int count;
 int on = 1;
 int timeout = 5;
 int count;
 int on = 1;
 int timeout = 5;
+int initial_pause = 0;
 int use_ipv4 = 1;
 int use_ipv6 = 1;
 int debug = 0;
 int use_ipv4 = 1;
 int use_ipv6 = 1;
 int debug = 0;
@@ -147,6 +172,7 @@ line *script = NULL;
 line *last = NULL;
 line *s;
 FILE *in, *out;
 line *last = NULL;
 line *s;
 FILE *in, *out;
+int linebuf = 1;
 
 char *sockname = NULL;
 unsigned char buffer[10240];
 
 char *sockname = NULL;
 unsigned char buffer[10240];
@@ -176,6 +202,7 @@ while (na < argc && argv[na][0] == '-')
   {
   if (strcmp(argv[na], "-d") == 0) debug = 1;
   else if (strcmp(argv[na], "-t") == 0) timeout = atoi(argv[++na]);
   {
   if (strcmp(argv[na], "-d") == 0) debug = 1;
   else if (strcmp(argv[na], "-t") == 0) timeout = atoi(argv[++na]);
+  else if (strcmp(argv[na], "-i") == 0) initial_pause = atoi(argv[++na]);
   else if (strcmp(argv[na], "-noipv4") == 0) use_ipv4 = 0;
   else if (strcmp(argv[na], "-noipv6") == 0) use_ipv6 = 0;
   else
   else if (strcmp(argv[na], "-noipv4") == 0) use_ipv4 = 0;
   else if (strcmp(argv[na], "-noipv6") == 0) use_ipv6 = 0;
   else
@@ -209,11 +236,22 @@ na++;
 if (na < argc) connection_count = atoi(argv[na]);
 
 
 if (na < argc) connection_count = atoi(argv[na]);
 
 
+/* Initial pause (before creating listen sockets */
+if (initial_pause > 0)
+  {
+  if (debug)
+    printf("%d: Inital pause of %d seconds\n", time(NULL), initial_pause);
+  else
+    printf("Inital pause of %d seconds\n", initial_pause);
+  while (initial_pause > 0)
+    initial_pause = sleep(initial_pause);
+  }
+
 /* Create sockets */
 
 if (port == 0)  /* Unix domain */
   {
 /* Create sockets */
 
 if (port == 0)  /* Unix domain */
   {
-  if (debug) printf("Creating Unix domain socket\n");
+  if (debug) printf("%d: Creating Unix domain socket\n", time(NULL));
   listen_socket[udn] = socket(PF_UNIX, SOCK_STREAM, 0);
   if (listen_socket[udn] < 0)
     {
   listen_socket[udn] = socket(PF_UNIX, SOCK_STREAM, 0);
   if (listen_socket[udn] < 0)
     {
@@ -377,18 +415,39 @@ script of things to do. A line containing "++++" is treated as end of file.
 This is so that the Perl driving script doesn't have to close the pipe -
 because that would cause it to wait for this process, which it doesn't yet want
 to do. The driving script adds the "++++" automatically - it doesn't actually
 This is so that the Perl driving script doesn't have to close the pipe -
 because that would cause it to wait for this process, which it doesn't yet want
 to do. The driving script adds the "++++" automatically - it doesn't actually
-appear in the test script. */
+appear in the test script. Within lines we interpret \xNN and \\ groups */
 
 
-while (fgets(buffer, sizeof(buffer), stdin) != NULL)
+while (fgets(CS buffer, sizeof(buffer), stdin) != NULL)
   {
   line *next;
   {
   line *next;
-  int n = (int)strlen(buffer);
+  char * d;
+  int n = (int)strlen(CS buffer);
+
+  if (n > 1 && buffer[0] == '>' && buffer[1] == '>')
+    linebuf = 0;
   while (n > 0 && isspace(buffer[n-1])) n--;
   buffer[n] = 0;
   while (n > 0 && isspace(buffer[n-1])) n--;
   buffer[n] = 0;
-  if (strcmp(buffer, "++++") == 0) break;
+  if (strcmp(CS buffer, "++++") == 0) break;
   next = malloc(sizeof(line) + n);
   next->next = NULL;
   next = malloc(sizeof(line) + n);
   next->next = NULL;
-  strcpy(next->line, buffer);
+  d = next->line;
+    {
+    char * s = CS buffer;
+    do
+      {
+      char ch;
+      char cl = *s;
+      if (cl == '\\' && (cl = *++s) == 'x')
+       {
+       if ((ch = *++s - '0') > 9 && (ch -= 'A'-'9'-1) > 15) ch -= 'a'-'A';
+       if ((cl = *++s - '0') > 9 && (cl -= 'A'-'9'-1) > 15) cl -= 'a'-'A';
+       cl |= ch << 4;
+       }
+      *d++ = cl;
+      }
+    while (*s++);
+    }
+  next->len = d - next->line - 1;
   if (last == NULL) script = last = next;
     else last->next = next;
   last = next;
   if (last == NULL) script = last = next;
     else last->next = next;
   last = next;
@@ -464,7 +523,7 @@ for (count = 0; count < connection_count; count++)
   dup_accept_socket = dup(accept_socket);
 
   if (port > 0)
   dup_accept_socket = dup(accept_socket);
 
   if (port > 0)
-    printf("\nConnection request from [%s]\n", host_ntoa(&accepted, buffer));
+    printf("\nConnection request from [%s]\n", host_ntoa(&accepted, CS buffer));
   else
     {
     printf("\nConnection request\n");
   else
     {
     printf("\nConnection request\n");
@@ -512,7 +571,8 @@ for (count = 0; count < connection_count; count++)
     if (ss[0] == '>')
       {
       char *end = "\r\n";
     if (ss[0] == '>')
       {
       char *end = "\r\n";
-      printf("%s\n", ss++);
+      unsigned len = s->len;
+      printit(ss++, len--);
 
       if (strncmp(ss, "*eof", 4) == 0)
         {
 
       if (strncmp(ss, "*eof", 4) == 0)
         {
@@ -521,13 +581,14 @@ for (count = 0; count < connection_count; count++)
         }
 
       if (*ss == '>')
         }
 
       if (*ss == '>')
-        { end = ""; ss++; }
+        { end = ""; ss++; len--; }
       else if (strncmp(ss, "CR>", 3) == 0)
       else if (strncmp(ss, "CR>", 3) == 0)
-        { end = "\r"; ss += 3; }
+        { end = "\r"; ss += 3; len -= 3; }
       else if (strncmp(ss, "LF>", 3) == 0)
       else if (strncmp(ss, "LF>", 3) == 0)
-        { end = "\n"; ss += 3; }
+        { end = "\n"; ss += 3; len -= 3; }
 
 
-      fprintf(out, "%s%s", ss, end);
+      fwrite(ss, 1, len, out);
+      if (*end) fprintf(out, end);
       }
 
     else if (isdigit((unsigned char)ss[0]))
       }
 
     else if (isdigit((unsigned char)ss[0]))
@@ -552,47 +613,93 @@ for (count = 0; count < connection_count; count++)
     connection. Read command line or data lines; the latter are indicated
     by the expected line being just ".". If the line starts with '<', that
     doesn't form part of the expected input. (This allows for incoming data
     connection. Read command line or data lines; the latter are indicated
     by the expected line being just ".". If the line starts with '<', that
     doesn't form part of the expected input. (This allows for incoming data
-    starting with a digit.) */
+    starting with a digit.) If the line starts with '<<' we operate in
+    unbuffered rather than line mode and assume that a single read gets the
+    entire message. */
 
     else
       {
       int offset;
       int data = strcmp(ss, ".") == 0;
 
 
     else
       {
       int offset;
       int data = strcmp(ss, ".") == 0;
 
-      if (ss[0] == '<')
+      if (ss[0] != '<')
+       offset = 0;
+      else
         {
         buffer[0] = '<';
         {
         buffer[0] = '<';
-        offset = 1;
+       if (ss[1] != '<')
+         offset = 1;
+       else
+         {
+         buffer[1] = '<';
+         offset = 2;
+         }
         }
         }
-      else offset = 0;
 
       fflush(out);
 
 
       fflush(out);
 
-      for (;;)
-        {
-        int n;
-        alarm(timeout);
-        if (fgets(buffer+offset, sizeof(buffer)-offset, in) == NULL)
-          {
-          printf("%sxpected EOF read from client\n",
-            (strncmp(ss, "*eof", 4) == 0)? "E" : "Une");
-          s = s->next;
-          goto END_OFF;
-          }
-        alarm(0);
-        n = (int)strlen(buffer);
-        while (n > 0 && isspace(buffer[n-1])) n--;
-        buffer[n] = 0;
-        printf("%s\n", buffer);
-        if (!data || strcmp(buffer, ".") == 0) break;
-        }
-
-      if (strncmp(ss, buffer, (int)strlen(ss)) != 0)
-        {
-        printf("Comparison failed - bailing out\n");
-        printf("Expected: %s\n", ss);
-        break;
-        }
+      if (!linebuf)
+       {
+       int n;
+       char c;
+
+       alarm(timeout);
+       n = read(dup_accept_socket, CS buffer+offset, s->len - offset);
+       if (n == 0)
+         {
+         printf("%sxpected EOF read from client\n",
+           (strncmp(ss, "*eof", 4) == 0)? "E" : "Une");
+         s = s->next;
+         goto END_OFF;
+         }
+       if (offset != 2)
+         while (read(dup_accept_socket, &c, 1) == 1 && c != '\n') ;
+       alarm(0);
+       n += offset;
+
+       printit(buffer, n);
+
+       if (data) do
+         {
+         n = (read(dup_accept_socket, &c, 1) == 1 && c == '.');
+         while (c != '\n' && read(dup_accept_socket, &c, 1) == 1)
+           ;
+         } while (!n);
+       else if (memcmp(ss, buffer, n) != 0)
+         {
+         printf("Comparison failed - bailing out\nExpected: ");
+         printit(ss, n);
+         break;
+         }
+       }
+      else
+       {
+       for (;;)
+         {
+         int n;
+         alarm(timeout);
+         if (fgets(CS buffer+offset, sizeof(buffer)-offset, in) == NULL)
+           {
+           printf("%sxpected EOF read from client\n",
+             (strncmp(ss, "*eof", 4) == 0)? "E" : "Une");
+           s = s->next;
+           goto END_OFF;
+           }
+         alarm(0);
+         n = (int)strlen(CS buffer);
+         while (n > 0 && isspace(buffer[n-1])) n--;
+         buffer[n] = 0;
+         printf("%s\n", buffer);
+         if (!data || strcmp(CS buffer, ".") == 0) break;
+         }
+
+       if (strncmp(ss, CS buffer, (int)strlen(ss)) != 0)
+         {
+         printf("Comparison failed - bailing out\n");
+         printf("Expected: %s\n", ss);
+         break;
+         }
+       }
       }
     }
 
       }
     }