X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/7eb6c37c5084760c1d1469bd4be652b479a8df55..6598bbe5404a01571b06009a75819b5b5604aa32:/test/src/server.c?ds=sidebyside diff --git a/test/src/server.c b/test/src/server.c index e425880a8..d433ebe0e 100644 --- a/test/src/server.c +++ b/test/src/server.c @@ -26,9 +26,10 @@ on all interfaces, unless the option -noipv6 is given. */ #include #include #include +#include #ifdef HAVE_NETINET_IP_VAR_H -#include +# include #endif #include @@ -52,6 +53,7 @@ on all interfaces, unless the option -noipv6 is given. */ #ifndef CS # define CS (char *) +# define CCS (const char *) #endif @@ -61,17 +63,22 @@ typedef struct line { char line[1]; } line; +typedef unsigned BOOL; +#define FALSE 0 +#define TRUE 1 + /************************************************* * SIGALRM handler - crash out * *************************************************/ +int tmo_noerror = 0; static void sigalrm_handler(int sig) { sig = sig; /* Keep picky compilers happy */ printf("\nServer timed out\n"); -exit(99); +exit(tmo_noerror ? 0 : 99); } @@ -163,7 +170,7 @@ int connection_count = 1; int count; int on = 1; int timeout = 5; -int initial_pause = 0; +int initial_pause = 0, tfo = 0; int use_ipv4 = 1; int use_ipv6 = 1; int debug = 0; @@ -173,6 +180,7 @@ line *last = NULL; line *s; FILE *in, *out; int linebuf = 1; +char *pidfile = NULL; char *sockname = NULL; unsigned char buffer[10240]; @@ -197,17 +205,36 @@ int len = sizeof(accepted); /* Sort out the arguments */ +if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) + { + printf("Usage: %s [options] port|socket [connection count]\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" + "\n\t-tfo enable TCP Fast Open" + ); + 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], "-tfo") == 0) tfo = 1; + else if (strcmp(argv[na], "-t") == 0) + { + if (tmo_noerror = ((timeout = atoi(argv[++na])) < 0)) timeout = -timeout; + } 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++; @@ -271,7 +298,15 @@ else printf("IPv6 socket creation failed: %s\n", strerror(errno)); exit(1); } - +#ifdef TCP_FASTOPEN + if (tfo) + { + int backlog = 5; + if (setsockopt(listen_socket[v6n], IPPROTO_TCP, TCP_FASTOPEN, + &backlog, sizeof(backlog))) + if (debug) printf("setsockopt TCP_FASTOPEN: %s\n", strerror(errno)); + } +#endif /* If this is an IPv6 wildcard socket, set IPV6_V6ONLY if that option is available. */ @@ -295,6 +330,15 @@ else printf("IPv4 socket creation failed: %s\n", strerror(errno)); exit(1); } +#ifdef TCP_FASTOPEN + if (tfo) + { + int backlog = 5; + if (setsockopt(listen_socket[v4n], IPPROTO_TCP, TCP_FASTOPEN, + &backlog, sizeof(backlog))) + if (debug) printf("setsockopt TCP_FASTOPEN: %s\n", strerror(errno)); + } +#endif } } @@ -357,7 +401,7 @@ else sin6.sin6_addr = anyaddr6; if (bind(listen_socket[i], (struct sockaddr *)&sin6, sizeof(sin6)) < 0) { - printf("IPv6 socket bind() failed: %s\n", strerror(errno)); + printf("IPv6 socket bind(port %d) failed: %s\n", port, strerror(errno)); exit(1); } } @@ -374,10 +418,9 @@ else sin4.sin_addr.s_addr = (S_ADDR_TYPE)INADDR_ANY; sin4.sin_port = htons(port); if (bind(listen_socket[i], (struct sockaddr *)&sin4, sizeof(sin4)) < 0) - { if (listen_socket[v6n] < 0 || errno != EADDRINUSE) { - printf("IPv4 socket bind() failed: %s\n", strerror(errno)); + printf("IPv4 socket bind(port %d) failed: %s\n", port, strerror(errno)); exit(1); } else @@ -385,7 +428,6 @@ else close(listen_socket[i]); listen_socket[i] = -1; } - } } } } @@ -409,6 +451,18 @@ 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. @@ -465,6 +519,11 @@ s = script; for (count = 0; count < connection_count; count++) { + struct { + int left; + BOOL in_use; + } content_length = { 0, FALSE }; + alarm(timeout); if (port <= 0) { @@ -490,8 +549,7 @@ for (count = 0; count < connection_count; count++) if (listen_socket[i] > max_socket) max_socket = listen_socket[i]; } - lcount = select(max_socket + 1, &select_listen, NULL, NULL, NULL); - if (lcount < 0) + if ((lcount = select(max_socket + 1, &select_listen, NULL, NULL, NULL)) < 0) { printf("Select failed\n"); fflush(stdout); @@ -500,7 +558,6 @@ for (count = 0; count < connection_count; count++) accept_socket = -1; for (i = 0; i < skn; i++) - { if (listen_socket[i] > 0 && FD_ISSET(listen_socket[i], &select_listen)) { accept_socket = accept(listen_socket[i], @@ -508,7 +565,6 @@ for (count = 0; count < connection_count; count++) FD_CLR(listen_socket[i], &select_listen); break; } - } } alarm(0); @@ -541,6 +597,7 @@ for (count = 0; count < connection_count; count++) cr.pid, cr.uid, cr.gid); --------------*****************/ } + fflush(stdout); if (dup_accept_socket < 0) { @@ -559,7 +616,7 @@ for (count = 0; count < connection_count; count++) doesn't work for other tests (e.g. ident tests) so we have explicit '<' and '>' flags for input and output as well as the defaults. */ - for (; s != NULL; s = s->next) + for (; s; s = s->next) { char *ss = s->line; @@ -608,6 +665,38 @@ for (count = 0; count < connection_count; count++) sleep(sleepfor); } + /* If the script line starts with "*data " we expect a numeric argument, + and we expect to read (and discard) that many data bytes from the input. */ + + else if (strncmp(ss, "*data ", 6) == 0) + { + int dlen = atoi(ss+6); + int n; + + alarm(timeout); + + if (!linebuf) + while (dlen > 0) + { + n = dlen < sizeof(buffer) ? dlen : sizeof(buffer); + if ((n = read(dup_accept_socket, CS buffer, n)) == 0) + { + printf("Unexpected EOF read from client\n"); + s = s->next; + goto END_OFF; + } + dlen -= n; + } + else + while (dlen-- > 0) + if (fgetc(in) == EOF) + { + printf("Unexpected EOF read from client\n"); + s = s->next; + goto END_OFF; + } + } + /* Otherwise the script line is the start of an input line we are expecting from the client, or "*eof" indicating we expect the client to close the connection. Read command line or data lines; the latter are indicated @@ -645,6 +734,7 @@ for (count = 0; count < connection_count; count++) alarm(timeout); n = read(dup_accept_socket, CS buffer+offset, s->len - offset); + if (content_length.in_use) content_length.left -= n; if (n == 0) { printf("%sxpected EOF read from client\n", @@ -657,13 +747,14 @@ for (count = 0; count < connection_count; count++) alarm(0); n += offset; - printit(buffer, n); + printit(CS buffer, n); if (data) do { n = (read(dup_accept_socket, &c, 1) == 1 && c == '.'); + if (content_length.in_use) content_length.left--; while (c != '\n' && read(dup_accept_socket, &c, 1) == 1) - ; + if (content_length.in_use) content_length.left--; } while (!n); else if (memcmp(ss, buffer, n) != 0) { @@ -686,7 +777,8 @@ for (count = 0; count < connection_count; count++) goto END_OFF; } alarm(0); - n = (int)strlen(CS buffer); + n = strlen(CS buffer); + if (content_length.in_use) content_length.left -= (n - offset); while (n > 0 && isspace(buffer[n-1])) n--; buffer[n] = 0; printf("%s\n", buffer); @@ -700,6 +792,11 @@ for (count = 0; count < connection_count; count++) break; } } + + if (sscanf(CCS buffer, "