X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/c55a77db55ebf46a399f136eeb3a928b1e862772..fc4a7f705d4c5911220cf9dbb0995d9f5dbabf02:/test/src/server.c?ds=sidebyside diff --git a/test/src/server.c b/test/src/server.c index f35d80ba2..b2f1bc754 100644 --- a/test/src/server.c +++ b/test/src/server.c @@ -1,5 +1,3 @@ -/* $Cambridge: exim/test/src/server.c,v 1.1 2006/02/06 16:24:05 ph10 Exp $ */ - /* A little hacked up program that listens on a given port and allows a script to play the part of a remote MTA for testing purposes. This scripted version is hacked from my original interactive version. A further hack allows it to listen @@ -45,16 +43,21 @@ on all interfaces, unless the option -noipv6 is given. */ #include #ifdef AF_INET6 -#define HAVE_IPV6 1 +# define HAVE_IPV6 1 #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; + unsigned len; char line[1]; } line; @@ -121,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 * *************************************************/ @@ -141,6 +163,7 @@ int connection_count = 1; int count; int on = 1; int timeout = 5; +int initial_pause = 0; int use_ipv4 = 1; int use_ipv6 = 1; int debug = 0; @@ -149,6 +172,8 @@ line *script = NULL; line *last = NULL; line *s; FILE *in, *out; +int linebuf = 1; +char *pidfile = NULL; char *sockname = NULL; unsigned char buffer[10240]; @@ -173,16 +198,31 @@ int len = sizeof(accepted); /* Sort out the arguments */ +if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) + { + printf("Usage: %s [options]\n", argv[0]); + puts("Options" + "\n\t-d debug" + "\n\t-i n n seconds initial delay" + "\n\t-noipv4 disable ipv4" + "\n\t-noipv6 disable ipv6" + "\n\t-oP file write PID to file" + "\n\t-t n n seconds timeout" + ); + exit(0); + } 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]); + 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 if (strcmp(argv[na], "-oP") == 0) pidfile = argv[++na]; else { - printf("server: unknown option %s\n", argv[na]); + printf("server: unknown option %s, try -h or --help\n", argv[na]); exit(1); } na++; @@ -211,11 +251,22 @@ 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 */ { - 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) { @@ -373,24 +424,57 @@ for (i = 0; i <= skn; i++) } +if (pidfile) + { + FILE * p; + if (!(p = fopen(pidfile, "w"))) + { + fprintf(stderr, "pidfile create failed: %s\n", strerror(errno)); + exit(1); + } + fprintf(p, "%ld\n", (long)getpid()); + fclose(p); + } + /* This program handles only a fixed number of connections, in sequence. Before waiting for the first connection, read the standard input, which contains the 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 -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; - 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; - if (strcmp(buffer, "++++") == 0) break; + if (strcmp(CS buffer, "++++") == 0) break; 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; @@ -466,7 +550,7 @@ for (count = 0; count < connection_count; count++) 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"); @@ -514,7 +598,8 @@ for (count = 0; count < connection_count; count++) if (ss[0] == '>') { char *end = "\r\n"; - printf("%s\n", ss++); + unsigned len = s->len; + printit(ss++, len--); if (strncmp(ss, "*eof", 4) == 0) { @@ -523,13 +608,14 @@ for (count = 0; count < connection_count; count++) } if (*ss == '>') - { end = ""; ss++; } + { end = ""; ss++; len--; } else if (strncmp(ss, "CR>", 3) == 0) - { end = "\r"; ss += 3; } + { end = "\r"; ss += 3; len -= 3; } 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])) @@ -554,47 +640,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 - 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; - if (ss[0] == '<') + if (ss[0] != '<') + offset = 0; + else { buffer[0] = '<'; - offset = 1; + if (ss[1] != '<') + offset = 1; + else + { + buffer[1] = '<'; + offset = 2; + } } - else offset = 0; 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; + } + } } }