Annotation of embedaddon/curl/tests/runtests.pl, revision 1.1.1.1

1.1       misho       1: #!/usr/bin/env perl
                      2: #***************************************************************************
                      3: #                                  _   _ ____  _
                      4: #  Project                     ___| | | |  _ \| |
                      5: #                             / __| | | | |_) | |
                      6: #                            | (__| |_| |  _ <| |___
                      7: #                             \___|\___/|_| \_\_____|
                      8: #
                      9: # Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
                     10: #
                     11: # This software is licensed as described in the file COPYING, which
                     12: # you should have received as part of this distribution. The terms
                     13: # are also available at https://curl.haxx.se/docs/copyright.html.
                     14: #
                     15: # You may opt to use, copy, modify, merge, publish, distribute and/or sell
                     16: # copies of the Software, and permit persons to whom the Software is
                     17: # furnished to do so, under the terms of the COPYING file.
                     18: #
                     19: # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
                     20: # KIND, either express or implied.
                     21: #
                     22: ###########################################################################
                     23: 
                     24: # Experimental hooks are available to run tests remotely on machines that
                     25: # are able to run curl but are unable to run the test harness.
                     26: # The following sections need to be modified:
                     27: #
                     28: #  $HOSTIP, $HOST6IP - Set to the address of the host running the test suite
                     29: #  $CLIENTIP, $CLIENT6IP - Set to the address of the host running curl
                     30: #  runclient, runclientoutput - Modify to copy all the files in the log/
                     31: #    directory to the system running curl, run the given command remotely
                     32: #    and save the return code or returned stdout (respectively), then
                     33: #    copy all the files from the remote system's log/ directory back to
                     34: #    the host running the test suite.  This can be done a few ways, such
                     35: #    as using scp & ssh, rsync & telnet, or using a NFS shared directory
                     36: #    and ssh.
                     37: #
                     38: # 'make && make test' needs to be done on both machines before making the
                     39: # above changes and running runtests.pl manually.  In the shared NFS case,
                     40: # the contents of the tests/server/ directory must be from the host
                     41: # running the test suite, while the rest must be from the host running curl.
                     42: #
                     43: # Note that even with these changes a number of tests will still fail (mainly
                     44: # to do with cookies, those that set environment variables, or those that
                     45: # do more than touch the file system in a <precheck> or <postcheck>
                     46: # section). These can be added to the $TESTCASES line below,
                     47: # e.g. $TESTCASES="!8 !31 !63 !cookies..."
                     48: #
                     49: # Finally, to properly support -g and -n, checktestcmd needs to change
                     50: # to check the remote system's PATH, and the places in the code where
                     51: # the curl binary is read directly to determine its type also need to be
                     52: # fixed. As long as the -g option is never given, and the -n is always
                     53: # given, this won't be a problem.
                     54: 
                     55: 
                     56: # These should be the only variables that might be needed to get edited:
                     57: 
                     58: BEGIN {
                     59:     push(@INC, $ENV{'srcdir'}) if(defined $ENV{'srcdir'});
                     60:     push(@INC, ".");
                     61:     # run time statistics needs Time::HiRes
                     62:     eval {
                     63:         no warnings "all";
                     64:         require Time::HiRes;
                     65:         import  Time::HiRes qw( time );
                     66:     }
                     67: }
                     68: 
                     69: use strict;
                     70: use warnings;
                     71: use Cwd;
                     72: use Digest::MD5 qw(md5);
                     73: 
                     74: # Subs imported from serverhelp module
                     75: use serverhelp qw(
                     76:     serverfactors
                     77:     servername_id
                     78:     servername_str
                     79:     servername_canon
                     80:     server_pidfilename
                     81:     server_portfilename
                     82:     server_logfilename
                     83:     );
                     84: 
                     85: # Variables and subs imported from sshhelp module
                     86: use sshhelp qw(
                     87:     $sshdexe
                     88:     $sshexe
                     89:     $sftpexe
                     90:     $sshconfig
                     91:     $sftpconfig
                     92:     $sshdlog
                     93:     $sshlog
                     94:     $sftplog
                     95:     $sftpcmds
                     96:     display_sshdconfig
                     97:     display_sshconfig
                     98:     display_sftpconfig
                     99:     display_sshdlog
                    100:     display_sshlog
                    101:     display_sftplog
                    102:     exe_ext
                    103:     find_sshd
                    104:     find_ssh
                    105:     find_sftp
                    106:     find_httptlssrv
                    107:     sshversioninfo
                    108:     );
                    109: 
                    110: use pathhelp;
                    111: 
                    112: require "getpart.pm"; # array functions
                    113: require "valgrind.pm"; # valgrind report parser
                    114: require "ftp.pm";
                    115: require "azure.pm";
                    116: require "appveyor.pm";
                    117: 
                    118: my $HOSTIP="127.0.0.1";   # address on which the test server listens
                    119: my $HOST6IP="[::1]";      # address on which the test server listens
                    120: my $CLIENTIP="127.0.0.1"; # address which curl uses for incoming connections
                    121: my $CLIENT6IP="[::1]";    # address which curl uses for incoming connections
                    122: 
                    123: my $base = 8990; # base port number
                    124: my $minport;     # minimum used port number
                    125: my $maxport;     # maximum used port number
                    126: 
                    127: my $noport="[not running]";
                    128: 
                    129: my $NOLISTENPORT=47;     # port number we use for a local non-listening service
                    130: my $MQTTPORT=$noport;    # MQTT server port
                    131: my $HTTPPORT=$noport;    # HTTP server port
                    132: my $HTTP6PORT=$noport;   # HTTP IPv6 server port
                    133: my $HTTPSPORT=$noport;   # HTTPS (stunnel) server port
                    134: my $FTPPORT=$noport;     # FTP server port
                    135: my $FTP2PORT=$noport;    # FTP server 2 port
                    136: my $FTPSPORT=$noport;    # FTPS (stunnel) server port
                    137: my $FTP6PORT=$noport;    # FTP IPv6 server port
                    138: my $TFTPPORT=$noport;    # TFTP
                    139: my $TFTP6PORT=$noport;   # TFTP
                    140: my $SSHPORT=$noport;     # SCP/SFTP
                    141: my $SOCKSPORT=$noport;   # SOCKS4/5 port
                    142: my $POP3PORT=$noport;    # POP3
                    143: my $POP36PORT=$noport;   # POP3 IPv6 server port
                    144: my $IMAPPORT=$noport;    # IMAP
                    145: my $IMAP6PORT=$noport;   # IMAP IPv6 server port
                    146: my $SMTPPORT=$noport;    # SMTP
                    147: my $SMTP6PORT=$noport;   # SMTP IPv6 server port
                    148: my $RTSPPORT=$noport;    # RTSP
                    149: my $RTSP6PORT=$noport;   # RTSP IPv6 server port
                    150: my $GOPHERPORT=$noport;  # Gopher
                    151: my $GOPHER6PORT=$noport; # Gopher IPv6 server port
                    152: my $HTTPTLSPORT=$noport; # HTTP TLS (non-stunnel) server port
                    153: my $HTTPTLS6PORT=$noport; # HTTP TLS (non-stunnel) IPv6 server port
                    154: my $HTTPPROXYPORT=$noport; # HTTP proxy port, when using CONNECT
                    155: my $HTTP2PORT=$noport;   # HTTP/2 server port
                    156: my $DICTPORT=$noport;    # DICT server port
                    157: my $SMBPORT=$noport;     # SMB server port
                    158: my $SMBSPORT=$noport;    # SMBS server port
                    159: my $NEGTELNETPORT=$noport; # TELNET server port with negotiation
                    160: my $HTTPUNIXPATH;        # HTTP server Unix domain socket path
                    161: 
                    162: my $SSHSRVMD5 = "[uninitialized]"; # MD5 of ssh server public key
                    163: 
                    164: my $srcdir = $ENV{'srcdir'} || '.';
                    165: my $CURL="../src/curl".exe_ext('TOOL'); # what curl executable to run on the tests
                    166: my $VCURL=$CURL;   # what curl binary to use to verify the servers with
                    167:                    # VCURL is handy to set to the system one when the one you
                    168:                    # just built hangs or crashes and thus prevent verification
                    169: my $DBGCURL=$CURL; #"../src/.libs/curl";  # alternative for debugging
                    170: my $LOGDIR="log";
                    171: my $TESTDIR="$srcdir/data";
                    172: my $LIBDIR="./libtest";
                    173: my $UNITDIR="./unit";
                    174: # TODO: change this to use server_inputfilename()
                    175: my $SERVERIN="$LOGDIR/server.input"; # what curl sent the server
                    176: my $SERVER2IN="$LOGDIR/server2.input"; # what curl sent the second server
                    177: my $PROXYIN="$LOGDIR/proxy.input"; # what curl sent the proxy
                    178: my $CURLLOG="commands.log"; # all command lines run
                    179: my $FTPDCMD="$LOGDIR/ftpserver.cmd"; # copy server instructions here
                    180: my $SERVERLOGS_LOCK="$LOGDIR/serverlogs.lock"; # server logs advisor read lock
                    181: my $CURLCONFIG="../curl-config"; # curl-config from current build
                    182: 
                    183: # Normally, all test cases should be run, but at times it is handy to
                    184: # simply run a particular one:
                    185: my $TESTCASES="all";
                    186: 
                    187: # To run specific test cases, set them like:
                    188: # $TESTCASES="1 2 3 7 8";
                    189: 
                    190: #######################################################################
                    191: # No variables below this point should need to be modified
                    192: #
                    193: 
                    194: # invoke perl like this:
                    195: my $perl="perl -I$srcdir";
                    196: my $server_response_maxtime=13;
                    197: 
                    198: my $debug_build=0;          # built debug enabled (--enable-debug)
                    199: my $has_memory_tracking=0;  # built with memory tracking (--enable-curldebug)
                    200: my $libtool;
                    201: my $repeat = 0;
                    202: 
                    203: # name of the file that the memory debugging creates:
                    204: my $memdump="$LOGDIR/memdump";
                    205: 
                    206: # the path to the script that analyzes the memory debug output file:
                    207: my $memanalyze="$perl $srcdir/memanalyze.pl";
                    208: 
                    209: my $pwd = getcwd();          # current working directory
                    210: my $posix_pwd = $pwd;
                    211: 
                    212: my $start;
                    213: my $ftpchecktime=1; # time it took to verify our test FTP server
                    214: my $scrambleorder;
                    215: my $stunnel = checkcmd("stunnel4") || checkcmd("tstunnel") || checkcmd("stunnel");
                    216: my $valgrind = checktestcmd("valgrind");
                    217: my $valgrind_logfile="--logfile";
                    218: my $valgrind_tool;
                    219: my $gdb = checktestcmd("gdb");
                    220: my $httptlssrv = find_httptlssrv();
                    221: 
                    222: my $uname_release = `uname -r`;
                    223: my $is_wsl = $uname_release =~ /Microsoft$/;
                    224: 
                    225: my $has_ssl;        # set if libcurl is built with SSL support
                    226: my $has_largefile;  # set if libcurl is built with large file support
                    227: my $has_idn;        # set if libcurl is built with IDN support
                    228: my $http_ipv6;      # set if HTTP server has IPv6 support
                    229: my $http_unix;      # set if HTTP server has Unix sockets support
                    230: my $ftp_ipv6;       # set if FTP server has IPv6 support
                    231: my $tftp_ipv6;      # set if TFTP server has IPv6 support
                    232: my $gopher_ipv6;    # set if Gopher server has IPv6 support
                    233: my $has_ipv6;       # set if libcurl is built with IPv6 support
                    234: my $has_unix;       # set if libcurl is built with Unix sockets support
                    235: my $has_libz;       # set if libcurl is built with libz support
                    236: my $has_brotli;     # set if libcurl is built with brotli support
                    237: my $has_getrlimit;  # set if system has getrlimit()
                    238: my $has_ntlm;       # set if libcurl is built with NTLM support
                    239: my $has_ntlm_wb;    # set if libcurl is built with NTLM delegation to winbind
                    240: my $has_sspi;       # set if libcurl is built with Windows SSPI
                    241: my $has_gssapi;     # set if libcurl is built with a GSS-API library
                    242: my $has_kerberos;   # set if libcurl is built with Kerberos support
                    243: my $has_spnego;     # set if libcurl is built with SPNEGO support
                    244: my $has_charconv;   # set if libcurl is built with CharConv support
                    245: my $has_tls_srp;    # set if libcurl is built with TLS-SRP support
                    246: my $has_metalink;   # set if curl is built with Metalink support
                    247: my $has_http2;      # set if libcurl is built with HTTP2 support
                    248: my $has_crypto;     # set if libcurl is built with cryptographic support
                    249: my $has_cares;      # set if built with c-ares
                    250: my $has_threadedres;# set if built with threaded resolver
                    251: my $has_psl;        # set if libcurl is built with PSL support
                    252: my $has_altsvc;     # set if libcurl is built with alt-svc support
                    253: my $has_ldpreload;  # set if curl is built for systems supporting LD_PRELOAD
                    254: my $has_multissl;   # set if curl is build with MultiSSL support
                    255: my $has_manual;     # set if curl is built with built-in manual
                    256: my $has_win32;      # set if curl is built for Windows
                    257: my $has_mingw;      # set if curl is built with MinGW (as opposed to MinGW-w64)
                    258: 
                    259: # this version is decided by the particular nghttp2 library that is being used
                    260: my $h2cver = "h2c";
                    261: 
                    262: my $has_openssl;    # built with a lib using an OpenSSL-like API
                    263: my $has_gnutls;     # built with GnuTLS
                    264: my $has_nss;        # built with NSS
                    265: my $has_wolfssl;    # built with wolfSSL
                    266: my $has_winssl;     # built with WinSSL    (Secure Channel aka Schannel)
                    267: my $has_darwinssl;  # built with DarwinSSL (Secure Transport)
                    268: my $has_boringssl;  # built with BoringSSL
                    269: my $has_libressl;   # built with libressl
                    270: my $has_mbedtls;    # built with mbedTLS
                    271: my $has_mesalink;   # built with MesaLink
                    272: 
                    273: my $has_sslpinning; # built with a TLS backend that supports pinning
                    274: 
                    275: my $has_shared = "unknown";  # built shared
                    276: 
                    277: my $resolver;       # name of the resolver backend (for human presentation)
                    278: 
                    279: my $has_textaware;  # set if running on a system that has a text mode concept
                    280:                     # on files. Windows for example
                    281: my @protocols;   # array of lowercase supported protocol servers
                    282: 
                    283: my $skipped=0;  # number of tests skipped; reported in main loop
                    284: my %skipped;    # skipped{reason}=counter, reasons for skip
                    285: my @teststat;   # teststat[testnum]=reason, reasons for skip
                    286: my %disabled_keywords;  # key words of tests to skip
                    287: my %ignored_keywords;   # key words of tests to ignore results
                    288: my %enabled_keywords;   # key words of tests to run
                    289: my %disabled;           # disabled test cases
                    290: my %ignored;            # ignored results of test cases
                    291: 
                    292: my $sshdid;      # for socks server, ssh daemon version id
                    293: my $sshdvernum;  # for socks server, ssh daemon version number
                    294: my $sshdverstr;  # for socks server, ssh daemon version string
                    295: my $sshderror;   # for socks server, ssh daemon version error
                    296: 
                    297: my $defserverlogslocktimeout = 2; # timeout to await server logs lock removal
                    298: my $defpostcommanddelay = 0; # delay between command and postcheck sections
                    299: 
                    300: my $timestats;   # time stamping and stats generation
                    301: my $fullstats;   # show time stats for every single test
                    302: my %timeprepini; # timestamp for each test preparation start
                    303: my %timesrvrini; # timestamp for each test required servers verification start
                    304: my %timesrvrend; # timestamp for each test required servers verification end
                    305: my %timetoolini; # timestamp for each test command run starting
                    306: my %timetoolend; # timestamp for each test command run stopping
                    307: my %timesrvrlog; # timestamp for each test server logs lock removal
                    308: my %timevrfyend; # timestamp for each test result verification end
                    309: 
                    310: my $testnumcheck; # test number, set in singletest sub.
                    311: my %oldenv;
                    312: my %feature;      # array of enabled features
                    313: my %keywords;     # array of keywords from the test spec
                    314: 
                    315: #######################################################################
                    316: # variables that command line options may set
                    317: #
                    318: 
                    319: my $short;
                    320: my $automakestyle;
                    321: my $verbose;
                    322: my $debugprotocol;
                    323: my $anyway;
                    324: my $gdbthis;      # run test case with gdb debugger
                    325: my $gdbxwin;      # use windowed gdb when using gdb
                    326: my $keepoutfiles; # keep stdout and stderr files after tests
                    327: my $listonly;     # only list the tests
                    328: my $postmortem;   # display detailed info about failed tests
                    329: my $run_event_based; # run curl with --test-event to test the event API
                    330: 
                    331: my %run;          # running server
                    332: my %doesntrun;    # servers that don't work, identified by pidfile
                    333: my %serverpidfile;# all server pid file names, identified by server id
                    334: my %serverportfile;# all server port file names, identified by server id
                    335: my %runcert;      # cert file currently in use by an ssl running server
                    336: 
                    337: # torture test variables
                    338: my $torture;
                    339: my $tortnum;
                    340: my $tortalloc;
                    341: my $shallow;
                    342: my $randseed = 0;
                    343: 
                    344: # Azure Pipelines specific variables
                    345: my $AZURE_RUN_ID = 0;
                    346: my $AZURE_RESULT_ID = 0;
                    347: 
                    348: #######################################################################
                    349: # logmsg is our general message logging subroutine.
                    350: #
                    351: sub logmsg {
                    352:     for(@_) {
                    353:         my $line = $_;
                    354:         if ($is_wsl) {
                    355:             # use \r\n for WSL shell
                    356:             $line =~ s/\r?\n$/\r\n/g;
                    357:         }
                    358:         print "$line";
                    359:     }
                    360: }
                    361: 
                    362: # get the name of the current user
                    363: my $USER = $ENV{USER};          # Linux
                    364: if (!$USER) {
                    365:     $USER = $ENV{USERNAME};     # Windows
                    366:     if (!$USER) {
                    367:         $USER = $ENV{LOGNAME};  # Some Unix (I think)
                    368:     }
                    369: }
                    370: 
                    371: # enable memory debugging if curl is compiled with it
                    372: $ENV{'CURL_MEMDEBUG'} = $memdump;
                    373: $ENV{'CURL_ENTROPY'}="12345678";
                    374: $ENV{'CURL_FORCETIME'}=1; # for debug NTLM magic
                    375: $ENV{'HOME'}=$pwd;
                    376: $ENV{'COLUMNS'}=79; # screen width!
                    377: 
                    378: sub catch_zap {
                    379:     my $signame = shift;
                    380:     logmsg "runtests.pl received SIG$signame, exiting\n";
                    381:     stopservers($verbose);
                    382:     die "Somebody sent me a SIG$signame";
                    383: }
                    384: $SIG{INT} = \&catch_zap;
                    385: $SIG{TERM} = \&catch_zap;
                    386: 
                    387: ##########################################################################
                    388: # Clear all possible '*_proxy' environment variables for various protocols
                    389: # to prevent them to interfere with our testing!
                    390: 
                    391: my $protocol;
                    392: foreach $protocol (('ftp', 'http', 'ftps', 'https', 'no', 'all')) {
                    393:     my $proxy = "${protocol}_proxy";
                    394:     # clear lowercase version
                    395:     delete $ENV{$proxy} if($ENV{$proxy});
                    396:     # clear uppercase version
                    397:     delete $ENV{uc($proxy)} if($ENV{uc($proxy)});
                    398: }
                    399: 
                    400: # make sure we don't get affected by other variables that control our
                    401: # behaviour
                    402: 
                    403: delete $ENV{'SSL_CERT_DIR'} if($ENV{'SSL_CERT_DIR'});
                    404: delete $ENV{'SSL_CERT_PATH'} if($ENV{'SSL_CERT_PATH'});
                    405: delete $ENV{'CURL_CA_BUNDLE'} if($ENV{'CURL_CA_BUNDLE'});
                    406: 
                    407: #######################################################################
                    408: # Load serverpidfile and serverportfile hashes with file names for all
                    409: # possible servers.
                    410: #
                    411: sub init_serverpidfile_hash {
                    412:   for my $proto (('ftp', 'http', 'imap', 'pop3', 'smtp', 'http/2')) {
                    413:     for my $ssl (('', 's')) {
                    414:       for my $ipvnum ((4, 6)) {
                    415:         for my $idnum ((1, 2, 3)) {
                    416:           my $serv = servername_id("$proto$ssl", $ipvnum, $idnum);
                    417:           my $pidf = server_pidfilename("$proto$ssl", $ipvnum, $idnum);
                    418:           $serverpidfile{$serv} = $pidf;
                    419:           my $portf = server_portfilename("$proto$ssl", $ipvnum, $idnum);
                    420:           $serverportfile{$serv} = $portf;
                    421:         }
                    422:       }
                    423:     }
                    424:   }
                    425:   for my $proto (('tftp', 'sftp', 'socks', 'ssh', 'rtsp', 'gopher', 'httptls',
                    426:                   'dict', 'smb', 'smbs', 'telnet', 'mqtt')) {
                    427:     for my $ipvnum ((4, 6)) {
                    428:       for my $idnum ((1, 2)) {
                    429:         my $serv = servername_id($proto, $ipvnum, $idnum);
                    430:         my $pidf = server_pidfilename($proto, $ipvnum, $idnum);
                    431:         $serverpidfile{$serv} = $pidf;
                    432:         my $portf = server_portfilename($proto, $ipvnum, $idnum);
                    433:         $serverportfile{$serv} = $portf;
                    434:       }
                    435:     }
                    436:   }
                    437:   for my $proto (('http', 'imap', 'pop3', 'smtp', 'http/2')) {
                    438:     for my $ssl (('', 's')) {
                    439:       my $serv = servername_id("$proto$ssl", "unix", 1);
                    440:       my $pidf = server_pidfilename("$proto$ssl", "unix", 1);
                    441:       $serverpidfile{$serv} = $pidf;
                    442:       my $portf = server_portfilename("$proto$ssl", "unix", 1);
                    443:       $serverportfile{$serv} = $portf;
                    444:     }
                    445:   }
                    446: }
                    447: 
                    448: #######################################################################
                    449: # Check if a given child process has just died. Reaps it if so.
                    450: #
                    451: sub checkdied {
                    452:     use POSIX ":sys_wait_h";
                    453:     my $pid = $_[0];
                    454:     if((not defined $pid) || $pid <= 0) {
                    455:         return 0;
                    456:     }
                    457:     my $rc = pidwait($pid, &WNOHANG);
                    458:     return ($rc == $pid)?1:0;
                    459: }
                    460: 
                    461: #######################################################################
                    462: # Start a new thread/process and run the given command line in there.
                    463: # Return the pids (yes plural) of the new child process to the parent.
                    464: #
                    465: sub startnew {
                    466:     my ($cmd, $pidfile, $timeout, $fake)=@_;
                    467: 
                    468:     logmsg "startnew: $cmd\n" if ($verbose);
                    469: 
                    470:     my $child = fork();
                    471:     my $pid2 = 0;
                    472: 
                    473:     if(not defined $child) {
                    474:         logmsg "startnew: fork() failure detected\n";
                    475:         return (-1,-1);
                    476:     }
                    477: 
                    478:     if(0 == $child) {
                    479:         # Here we are the child. Run the given command.
                    480: 
                    481:         # Put an "exec" in front of the command so that the child process
                    482:         # keeps this child's process ID.
                    483:         exec("exec $cmd") || die "Can't exec() $cmd: $!";
                    484: 
                    485:         # exec() should never return back here to this process. We protect
                    486:         # ourselves by calling die() just in case something goes really bad.
                    487:         die "error: exec() has returned";
                    488:     }
                    489: 
                    490:     # Ugly hack but ssh client and gnutls-serv don't support pid files
                    491:     if ($fake) {
                    492:         if(open(OUT, ">$pidfile")) {
                    493:             print OUT $child . "\n";
                    494:             close(OUT);
                    495:             logmsg "startnew: $pidfile faked with pid=$child\n" if($verbose);
                    496:         }
                    497:         else {
                    498:             logmsg "startnew: failed to write fake $pidfile with pid=$child\n";
                    499:         }
                    500:         # could/should do a while connect fails sleep a bit and loop
                    501:         portable_sleep($timeout);
                    502:         if (checkdied($child)) {
                    503:             logmsg "startnew: child process has failed to start\n" if($verbose);
                    504:             return (-1,-1);
                    505:         }
                    506:     }
                    507: 
                    508:     my $count = $timeout;
                    509:     while($count--) {
                    510:         if(-f $pidfile && -s $pidfile && open(PID, "<$pidfile")) {
                    511:             $pid2 = 0 + <PID>;
                    512:             close(PID);
                    513:             if(($pid2 > 0) && pidexists($pid2)) {
                    514:                 # if $pid2 is valid, then make sure this pid is alive, as
                    515:                 # otherwise it is just likely to be the _previous_ pidfile or
                    516:                 # similar!
                    517:                 last;
                    518:             }
                    519:             # invalidate $pid2 if not actually alive
                    520:             $pid2 = 0;
                    521:         }
                    522:         if (checkdied($child)) {
                    523:             logmsg "startnew: child process has died, server might start up\n"
                    524:                 if($verbose);
                    525:             # We can't just abort waiting for the server with a
                    526:             # return (-1,-1);
                    527:             # because the server might have forked and could still start
                    528:             # up normally. Instead, just reduce the amount of time we remain
                    529:             # waiting.
                    530:             $count >>= 2;
                    531:         }
                    532:         sleep(1);
                    533:     }
                    534: 
                    535:     # Return two PIDs, the one for the child process we spawned and the one
                    536:     # reported by the server itself (in case it forked again on its own).
                    537:     # Both (potentially) need to be killed at the end of the test.
                    538:     return ($child, $pid2);
                    539: }
                    540: 
                    541: 
                    542: #######################################################################
                    543: # Check for a command in the PATH of the test server.
                    544: #
                    545: sub checkcmd {
                    546:     my ($cmd)=@_;
                    547:     my @paths=(split(":", $ENV{'PATH'}), "/usr/sbin", "/usr/local/sbin",
                    548:                "/sbin", "/usr/bin", "/usr/local/bin",
                    549:                "./libtest/.libs", "./libtest");
                    550:     for(@paths) {
                    551:         if( -x "$_/$cmd" && ! -d "$_/$cmd") {
                    552:             # executable bit but not a directory!
                    553:             return "$_/$cmd";
                    554:         }
                    555:     }
                    556: }
                    557: 
                    558: #######################################################################
                    559: # Get the list of tests that the tests/data/Makefile.am knows about!
                    560: #
                    561: my $disttests;
                    562: sub get_disttests {
                    563:     my @dist = `cd data && make show`;
                    564:     $disttests = join("", @dist);
                    565: }
                    566: 
                    567: #######################################################################
                    568: # Check for a command in the PATH of the machine running curl.
                    569: #
                    570: sub checktestcmd {
                    571:     my ($cmd)=@_;
                    572:     return checkcmd($cmd);
                    573: }
                    574: 
                    575: #######################################################################
                    576: # Run the application under test and return its return code
                    577: #
                    578: sub runclient {
                    579:     my ($cmd)=@_;
                    580:     my $ret = system($cmd);
                    581:     print "CMD ($ret): $cmd\n" if($verbose && !$torture);
                    582:     return $ret;
                    583: 
                    584: # This is one way to test curl on a remote machine
                    585: #    my $out = system("ssh $CLIENTIP cd \'$pwd\' \\; \'$cmd\'");
                    586: #    sleep 2;    # time to allow the NFS server to be updated
                    587: #    return $out;
                    588: }
                    589: 
                    590: #######################################################################
                    591: # Run the application under test and return its stdout
                    592: #
                    593: sub runclientoutput {
                    594:     my ($cmd)=@_;
                    595:     return `$cmd`;
                    596: 
                    597: # This is one way to test curl on a remote machine
                    598: #    my @out = `ssh $CLIENTIP cd \'$pwd\' \\; \'$cmd\'`;
                    599: #    sleep 2;    # time to allow the NFS server to be updated
                    600: #    return @out;
                    601:  }
                    602: 
                    603: #######################################################################
                    604: # Memory allocation test and failure torture testing.
                    605: #
                    606: sub torture {
                    607:     my ($testcmd, $testnum, $gdbline) = @_;
                    608: 
                    609:     # remove memdump first to be sure we get a new nice and clean one
                    610:     unlink($memdump);
                    611: 
                    612:     # First get URL from test server, ignore the output/result
                    613:     runclient($testcmd);
                    614: 
                    615:     logmsg " CMD: $testcmd\n" if($verbose);
                    616: 
                    617:     # memanalyze -v is our friend, get the number of allocations made
                    618:     my $count=0;
                    619:     my @out = `$memanalyze -v $memdump`;
                    620:     for(@out) {
                    621:         if(/^Operations: (\d+)/) {
                    622:             $count = $1;
                    623:             last;
                    624:         }
                    625:     }
                    626:     if(!$count) {
                    627:         logmsg " found no functions to make fail\n";
                    628:         return 0;
                    629:     }
                    630: 
                    631:     my @ttests = (1 .. $count);
                    632:     if($shallow && ($shallow < $count)) {
                    633:         my $discard = scalar(@ttests) - $shallow;
                    634:         my $percent = sprintf("%.2f%%", $shallow * 100 / scalar(@ttests));;
                    635:         logmsg " $count functions found, but only fail $shallow ($percent)\n";
                    636:         while($discard) {
                    637:             my $rm;
                    638:             do {
                    639:                 # find a test to discard
                    640:                 $rm = rand(scalar(@ttests));
                    641:             } while(!$ttests[$rm]);
                    642:             $ttests[$rm] = undef;
                    643:             $discard--;
                    644:         }
                    645:     }
                    646:     else {
                    647:         logmsg " $count functions to make fail\n";
                    648:     }
                    649: 
                    650:     for (@ttests) {
                    651:         my $limit = $_;
                    652:         my $fail;
                    653:         my $dumped_core;
                    654: 
                    655:         if(!defined($limit)) {
                    656:             # --shallow can undefine them
                    657:             next;
                    658:         }
                    659:         if($tortalloc && ($tortalloc != $limit)) {
                    660:             next;
                    661:         }
                    662: 
                    663:         if($verbose) {
                    664:             my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
                    665:                 localtime(time());
                    666:             my $now = sprintf("%02d:%02d:%02d ", $hour, $min, $sec);
                    667:             logmsg "Fail function no: $limit at $now\r";
                    668:         }
                    669: 
                    670:         # make the memory allocation function number $limit return failure
                    671:         $ENV{'CURL_MEMLIMIT'} = $limit;
                    672: 
                    673:         # remove memdump first to be sure we get a new nice and clean one
                    674:         unlink($memdump);
                    675: 
                    676:         my $cmd = $testcmd;
                    677:         if($valgrind && !$gdbthis) {
                    678:             my @valgrindoption = getpart("verify", "valgrind");
                    679:             if((!@valgrindoption) || ($valgrindoption[0] !~ /disable/)) {
                    680:                 my $valgrindcmd = "$valgrind ";
                    681:                 $valgrindcmd .= "$valgrind_tool " if($valgrind_tool);
                    682:                 $valgrindcmd .= "--quiet --leak-check=yes ";
                    683:                 $valgrindcmd .= "--suppressions=$srcdir/valgrind.supp ";
                    684:                 # $valgrindcmd .= "--gen-suppressions=all ";
                    685:                 $valgrindcmd .= "--num-callers=16 ";
                    686:                 $valgrindcmd .= "${valgrind_logfile}=$LOGDIR/valgrind$testnum";
                    687:                 $cmd = "$valgrindcmd $testcmd";
                    688:             }
                    689:         }
                    690:         logmsg "*** Function number $limit is now set to fail ***\n" if($gdbthis);
                    691: 
                    692:         my $ret = 0;
                    693:         if($gdbthis) {
                    694:             runclient($gdbline);
                    695:         }
                    696:         else {
                    697:             $ret = runclient($cmd);
                    698:         }
                    699:         #logmsg "$_ Returned " . ($ret >> 8) . "\n";
                    700: 
                    701:         # Now clear the variable again
                    702:         delete $ENV{'CURL_MEMLIMIT'} if($ENV{'CURL_MEMLIMIT'});
                    703: 
                    704:         if(-r "core") {
                    705:             # there's core file present now!
                    706:             logmsg " core dumped\n";
                    707:             $dumped_core = 1;
                    708:             $fail = 2;
                    709:         }
                    710: 
                    711:         if($valgrind) {
                    712:             my @e = valgrindparse("$LOGDIR/valgrind$testnum");
                    713:             if(@e && $e[0]) {
                    714:                 if($automakestyle) {
                    715:                     logmsg "FAIL: torture $testnum - valgrind\n";
                    716:                 }
                    717:                 else {
                    718:                     logmsg " valgrind ERROR ";
                    719:                     logmsg @e;
                    720:                 }
                    721:                 $fail = 1;
                    722:             }
                    723:         }
                    724: 
                    725:         # verify that it returns a proper error code, doesn't leak memory
                    726:         # and doesn't core dump
                    727:         if(($ret & 255) || ($ret >> 8) >= 128) {
                    728:             logmsg " system() returned $ret\n";
                    729:             $fail=1;
                    730:         }
                    731:         else {
                    732:             my @memdata=`$memanalyze $memdump`;
                    733:             my $leak=0;
                    734:             for(@memdata) {
                    735:                 if($_ ne "") {
                    736:                     # well it could be other memory problems as well, but
                    737:                     # we call it leak for short here
                    738:                     $leak=1;
                    739:                 }
                    740:             }
                    741:             if($leak) {
                    742:                 logmsg "** MEMORY FAILURE\n";
                    743:                 logmsg @memdata;
                    744:                 logmsg `$memanalyze -l $memdump`;
                    745:                 $fail = 1;
                    746:             }
                    747:         }
                    748:         if($fail) {
                    749:             logmsg " Failed on function number $limit in test.\n",
                    750:             " invoke with \"-t$limit\" to repeat this single case.\n";
                    751:             stopservers($verbose);
                    752:             return 1;
                    753:         }
                    754:     }
                    755: 
                    756:     logmsg "torture OK\n";
                    757:     return 0;
                    758: }
                    759: 
                    760: #######################################################################
                    761: # Stop a test server along with pids which aren't in the %run hash yet.
                    762: # This also stops all servers which are relative to the given one.
                    763: #
                    764: sub stopserver {
                    765:     my ($server, $pidlist) = @_;
                    766: 
                    767:     #
                    768:     # kill sockfilter processes for pingpong relative server
                    769:     #
                    770:     if($server =~ /^(ftp|imap|pop3|smtp)s?(\d*)(-ipv6|)$/) {
                    771:         my $proto  = $1;
                    772:         my $idnum  = ($2 && ($2 > 1)) ? $2 : 1;
                    773:         my $ipvnum = ($3 && ($3 =~ /6$/)) ? 6 : 4;
                    774:         killsockfilters($proto, $ipvnum, $idnum, $verbose);
                    775:     }
                    776:     #
                    777:     # All servers relative to the given one must be stopped also
                    778:     #
                    779:     my @killservers;
                    780:     if($server =~ /^(ftp|http|imap|pop3|smtp)s((\d*)(-ipv6|-unix|))$/) {
                    781:         # given a stunnel based ssl server, also kill non-ssl underlying one
                    782:         push @killservers, "${1}${2}";
                    783:     }
                    784:     elsif($server =~ /^(ftp|http|imap|pop3|smtp)((\d*)(-ipv6|-unix|))$/) {
                    785:         # given a non-ssl server, also kill stunnel based ssl piggybacking one
                    786:         push @killservers, "${1}s${2}";
                    787:     }
                    788:     elsif($server =~ /^(socks)((\d*)(-ipv6|))$/) {
                    789:         # given a socks server, also kill ssh underlying one
                    790:         push @killservers, "ssh${2}";
                    791:     }
                    792:     elsif($server =~ /^(ssh)((\d*)(-ipv6|))$/) {
                    793:         # given a ssh server, also kill socks piggybacking one
                    794:         push @killservers, "socks${2}";
                    795:     }
                    796:     if($server eq "http") {
                    797:         # since the http2 server is a proxy that needs to know about the
                    798:         # dynamic http port it too needs to get restarted when the http server
                    799:         # is killed
                    800:         push @killservers, "http/2";
                    801:     }
                    802:     push @killservers, $server;
                    803:     #
                    804:     # kill given pids and server relative ones clearing them in %run hash
                    805:     #
                    806:     foreach my $server (@killservers) {
                    807:         if($run{$server}) {
                    808:             # we must prepend a space since $pidlist may already contain a pid
                    809:             $pidlist .= " $run{$server}";
                    810:             $run{$server} = 0;
                    811:         }
                    812:         $runcert{$server} = 0 if($runcert{$server});
                    813:     }
                    814:     killpid($verbose, $pidlist);
                    815:     #
                    816:     # cleanup server pid files
                    817:     #
                    818:     foreach my $server (@killservers) {
                    819:         my $pidfile = $serverpidfile{$server};
                    820:         my $pid = processexists($pidfile);
                    821:         if($pid > 0) {
                    822:             logmsg "Warning: $server server unexpectedly alive\n";
                    823:             killpid($verbose, $pid);
                    824:         }
                    825:         unlink($pidfile) if(-f $pidfile);
                    826:     }
                    827: }
                    828: 
                    829: #######################################################################
                    830: # Verify that the server that runs on $ip, $port is our server.  This also
                    831: # implies that we can speak with it, as there might be occasions when the
                    832: # server runs fine but we cannot talk to it ("Failed to connect to ::1: Can't
                    833: # assign requested address")
                    834: #
                    835: sub verifyhttp {
                    836:     my ($proto, $ipvnum, $idnum, $ip, $port_or_path) = @_;
                    837:     my $server = servername_id($proto, $ipvnum, $idnum);
                    838:     my $pid = 0;
                    839:     my $bonus="";
                    840:     # $port_or_path contains a path for Unix sockets, sws ignores the port
                    841:     my $port = ($ipvnum eq "unix") ? 80 : $port_or_path;
                    842: 
                    843:     my $verifyout = "$LOGDIR/".
                    844:         servername_canon($proto, $ipvnum, $idnum) .'_verify.out';
                    845:     unlink($verifyout) if(-f $verifyout);
                    846: 
                    847:     my $verifylog = "$LOGDIR/".
                    848:         servername_canon($proto, $ipvnum, $idnum) .'_verify.log';
                    849:     unlink($verifylog) if(-f $verifylog);
                    850: 
                    851:     if($proto eq "gopher") {
                    852:         # gopher is funny
                    853:         $bonus="1/";
                    854:     }
                    855: 
                    856:     my $flags = "--max-time $server_response_maxtime ";
                    857:     $flags .= "--output $verifyout ";
                    858:     $flags .= "--silent ";
                    859:     $flags .= "--verbose ";
                    860:     $flags .= "--globoff ";
                    861:     $flags .= "--unix-socket '$port_or_path' " if $ipvnum eq "unix";
                    862:     $flags .= "--insecure " if($proto eq 'https');
                    863:     $flags .= "\"$proto://$ip:$port/${bonus}verifiedserver\"";
                    864: 
                    865:     my $cmd = "$VCURL $flags 2>$verifylog";
                    866: 
                    867:     # verify if our/any server is running on this port
                    868:     logmsg "RUN: $cmd\n" if($verbose);
                    869:     my $res = runclient($cmd);
                    870: 
                    871:     $res >>= 8; # rotate the result
                    872:     if($res & 128) {
                    873:         logmsg "RUN: curl command died with a coredump\n";
                    874:         return -1;
                    875:     }
                    876: 
                    877:     if($res && $verbose) {
                    878:         logmsg "RUN: curl command returned $res\n";
                    879:         if(open(FILE, "<$verifylog")) {
                    880:             while(my $string = <FILE>) {
                    881:                 logmsg "RUN: $string" if($string !~ /^([ \t]*)$/);
                    882:             }
                    883:             close(FILE);
                    884:         }
                    885:     }
                    886: 
                    887:     my $data;
                    888:     if(open(FILE, "<$verifyout")) {
                    889:         while(my $string = <FILE>) {
                    890:             $data = $string;
                    891:             last; # only want first line
                    892:         }
                    893:         close(FILE);
                    894:     }
                    895: 
                    896:     if($data && ($data =~ /WE ROOLZ: (\d+)/)) {
                    897:         $pid = 0+$1;
                    898:     }
                    899:     elsif($res == 6) {
                    900:         # curl: (6) Couldn't resolve host '::1'
                    901:         logmsg "RUN: failed to resolve host ($proto://$ip:$port/verifiedserver)\n";
                    902:         return -1;
                    903:     }
                    904:     elsif($data || ($res && ($res != 7))) {
                    905:         logmsg "RUN: Unknown server on our $server port: $port ($res)\n";
                    906:         return -1;
                    907:     }
                    908:     return $pid;
                    909: }
                    910: 
                    911: #######################################################################
                    912: # Verify that the server that runs on $ip, $port is our server.  This also
                    913: # implies that we can speak with it, as there might be occasions when the
                    914: # server runs fine but we cannot talk to it ("Failed to connect to ::1: Can't
                    915: # assign requested address")
                    916: #
                    917: sub verifyftp {
                    918:     my ($proto, $ipvnum, $idnum, $ip, $port) = @_;
                    919:     my $server = servername_id($proto, $ipvnum, $idnum);
                    920:     my $pid = 0;
                    921:     my $time=time();
                    922:     my $extra="";
                    923: 
                    924:     my $verifylog = "$LOGDIR/".
                    925:         servername_canon($proto, $ipvnum, $idnum) .'_verify.log';
                    926:     unlink($verifylog) if(-f $verifylog);
                    927: 
                    928:     if($proto eq "ftps") {
                    929:         $extra .= "--insecure --ftp-ssl-control ";
                    930:     }
                    931: 
                    932:     my $flags = "--max-time $server_response_maxtime ";
                    933:     $flags .= "--silent ";
                    934:     $flags .= "--verbose ";
                    935:     $flags .= "--globoff ";
                    936:     $flags .= $extra;
                    937:     $flags .= "\"$proto://$ip:$port/verifiedserver\"";
                    938: 
                    939:     my $cmd = "$VCURL $flags 2>$verifylog";
                    940: 
                    941:     # check if this is our server running on this port:
                    942:     logmsg "RUN: $cmd\n" if($verbose);
                    943:     my @data = runclientoutput($cmd);
                    944: 
                    945:     my $res = $? >> 8; # rotate the result
                    946:     if($res & 128) {
                    947:         logmsg "RUN: curl command died with a coredump\n";
                    948:         return -1;
                    949:     }
                    950: 
                    951:     foreach my $line (@data) {
                    952:         if($line =~ /WE ROOLZ: (\d+)/) {
                    953:             # this is our test server with a known pid!
                    954:             $pid = 0+$1;
                    955:             last;
                    956:         }
                    957:     }
                    958:     if($pid <= 0 && @data && $data[0]) {
                    959:         # this is not a known server
                    960:         logmsg "RUN: Unknown server on our $server port: $port\n";
                    961:         return 0;
                    962:     }
                    963:     # we can/should use the time it took to verify the FTP server as a measure
                    964:     # on how fast/slow this host/FTP is.
                    965:     my $took = int(0.5+time()-$time);
                    966: 
                    967:     if($verbose) {
                    968:         logmsg "RUN: Verifying our test $server server took $took seconds\n";
                    969:     }
                    970:     $ftpchecktime = $took>=1?$took:1; # make sure it never is below 1
                    971: 
                    972:     return $pid;
                    973: }
                    974: 
                    975: #######################################################################
                    976: # Verify that the server that runs on $ip, $port is our server.  This also
                    977: # implies that we can speak with it, as there might be occasions when the
                    978: # server runs fine but we cannot talk to it ("Failed to connect to ::1: Can't
                    979: # assign requested address")
                    980: #
                    981: sub verifyrtsp {
                    982:     my ($proto, $ipvnum, $idnum, $ip, $port) = @_;
                    983:     my $server = servername_id($proto, $ipvnum, $idnum);
                    984:     my $pid = 0;
                    985: 
                    986:     my $verifyout = "$LOGDIR/".
                    987:         servername_canon($proto, $ipvnum, $idnum) .'_verify.out';
                    988:     unlink($verifyout) if(-f $verifyout);
                    989: 
                    990:     my $verifylog = "$LOGDIR/".
                    991:         servername_canon($proto, $ipvnum, $idnum) .'_verify.log';
                    992:     unlink($verifylog) if(-f $verifylog);
                    993: 
                    994:     my $flags = "--max-time $server_response_maxtime ";
                    995:     $flags .= "--output $verifyout ";
                    996:     $flags .= "--silent ";
                    997:     $flags .= "--verbose ";
                    998:     $flags .= "--globoff ";
                    999:     # currently verification is done using http
                   1000:     $flags .= "\"http://$ip:$port/verifiedserver\"";
                   1001: 
                   1002:     my $cmd = "$VCURL $flags 2>$verifylog";
                   1003: 
                   1004:     # verify if our/any server is running on this port
                   1005:     logmsg "RUN: $cmd\n" if($verbose);
                   1006:     my $res = runclient($cmd);
                   1007: 
                   1008:     $res >>= 8; # rotate the result
                   1009:     if($res & 128) {
                   1010:         logmsg "RUN: curl command died with a coredump\n";
                   1011:         return -1;
                   1012:     }
                   1013: 
                   1014:     if($res && $verbose) {
                   1015:         logmsg "RUN: curl command returned $res\n";
                   1016:         if(open(FILE, "<$verifylog")) {
                   1017:             while(my $string = <FILE>) {
                   1018:                 logmsg "RUN: $string" if($string !~ /^([ \t]*)$/);
                   1019:             }
                   1020:             close(FILE);
                   1021:         }
                   1022:     }
                   1023: 
                   1024:     my $data;
                   1025:     if(open(FILE, "<$verifyout")) {
                   1026:         while(my $string = <FILE>) {
                   1027:             $data = $string;
                   1028:             last; # only want first line
                   1029:         }
                   1030:         close(FILE);
                   1031:     }
                   1032: 
                   1033:     if($data && ($data =~ /RTSP_SERVER WE ROOLZ: (\d+)/)) {
                   1034:         $pid = 0+$1;
                   1035:     }
                   1036:     elsif($res == 6) {
                   1037:         # curl: (6) Couldn't resolve host '::1'
                   1038:         logmsg "RUN: failed to resolve host ($proto://$ip:$port/verifiedserver)\n";
                   1039:         return -1;
                   1040:     }
                   1041:     elsif($data || ($res != 7)) {
                   1042:         logmsg "RUN: Unknown server on our $server port: $port\n";
                   1043:         return -1;
                   1044:     }
                   1045:     return $pid;
                   1046: }
                   1047: 
                   1048: #######################################################################
                   1049: # Verify that the ssh server has written out its pidfile, recovering
                   1050: # the pid from the file and returning it if a process with that pid is
                   1051: # actually alive.
                   1052: #
                   1053: sub verifyssh {
                   1054:     my ($proto, $ipvnum, $idnum, $ip, $port) = @_;
                   1055:     my $server = servername_id($proto, $ipvnum, $idnum);
                   1056:     my $pidfile = server_pidfilename($proto, $ipvnum, $idnum);
                   1057:     my $pid = 0;
                   1058:     if(open(FILE, "<$pidfile")) {
                   1059:         $pid=0+<FILE>;
                   1060:         close(FILE);
                   1061:     }
                   1062:     if($pid > 0) {
                   1063:         # if we have a pid it is actually our ssh server,
                   1064:         # since runsshserver() unlinks previous pidfile
                   1065:         if(!pidexists($pid)) {
                   1066:             logmsg "RUN: SSH server has died after starting up\n";
                   1067:             checkdied($pid);
                   1068:             unlink($pidfile);
                   1069:             $pid = -1;
                   1070:         }
                   1071:     }
                   1072:     return $pid;
                   1073: }
                   1074: 
                   1075: #######################################################################
                   1076: # Verify that we can connect to the sftp server, properly authenticate
                   1077: # with generated config and key files and run a simple remote pwd.
                   1078: #
                   1079: sub verifysftp {
                   1080:     my ($proto, $ipvnum, $idnum, $ip, $port) = @_;
                   1081:     my $server = servername_id($proto, $ipvnum, $idnum);
                   1082:     my $verified = 0;
                   1083:     # Find out sftp client canonical file name
                   1084:     my $sftp = find_sftp();
                   1085:     if(!$sftp) {
                   1086:         logmsg "RUN: SFTP server cannot find $sftpexe\n";
                   1087:         return -1;
                   1088:     }
                   1089:     # Find out ssh client canonical file name
                   1090:     my $ssh = find_ssh();
                   1091:     if(!$ssh) {
                   1092:         logmsg "RUN: SFTP server cannot find $sshexe\n";
                   1093:         return -1;
                   1094:     }
                   1095:     # Connect to sftp server, authenticate and run a remote pwd
                   1096:     # command using our generated configuration and key files
                   1097:     my $cmd = "\"$sftp\" -b $sftpcmds -F $sftpconfig -S \"$ssh\" $ip > $sftplog 2>&1";
                   1098:     my $res = runclient($cmd);
                   1099:     # Search for pwd command response in log file
                   1100:     if(open(SFTPLOGFILE, "<$sftplog")) {
                   1101:         while(<SFTPLOGFILE>) {
                   1102:             if(/^Remote working directory: /) {
                   1103:                 $verified = 1;
                   1104:                 last;
                   1105:             }
                   1106:         }
                   1107:         close(SFTPLOGFILE);
                   1108:     }
                   1109:     return $verified;
                   1110: }
                   1111: 
                   1112: #######################################################################
                   1113: # Verify that the non-stunnel HTTP TLS extensions capable server that runs
                   1114: # on $ip, $port is our server.  This also implies that we can speak with it,
                   1115: # as there might be occasions when the server runs fine but we cannot talk
                   1116: # to it ("Failed to connect to ::1: Can't assign requested address")
                   1117: #
                   1118: sub verifyhttptls {
                   1119:     my ($proto, $ipvnum, $idnum, $ip, $port) = @_;
                   1120:     my $server = servername_id($proto, $ipvnum, $idnum);
                   1121:     my $pidfile = server_pidfilename($proto, $ipvnum, $idnum);
                   1122:     my $pid = 0;
                   1123: 
                   1124:     my $verifyout = "$LOGDIR/".
                   1125:         servername_canon($proto, $ipvnum, $idnum) .'_verify.out';
                   1126:     unlink($verifyout) if(-f $verifyout);
                   1127: 
                   1128:     my $verifylog = "$LOGDIR/".
                   1129:         servername_canon($proto, $ipvnum, $idnum) .'_verify.log';
                   1130:     unlink($verifylog) if(-f $verifylog);
                   1131: 
                   1132:     my $flags = "--max-time $server_response_maxtime ";
                   1133:     $flags .= "--output $verifyout ";
                   1134:     $flags .= "--verbose ";
                   1135:     $flags .= "--globoff ";
                   1136:     $flags .= "--insecure ";
                   1137:     $flags .= "--tlsauthtype SRP ";
                   1138:     $flags .= "--tlsuser jsmith ";
                   1139:     $flags .= "--tlspassword abc ";
                   1140:     $flags .= "\"https://$ip:$port/verifiedserver\"";
                   1141: 
                   1142:     my $cmd = "$VCURL $flags 2>$verifylog";
                   1143: 
                   1144:     # verify if our/any server is running on this port
                   1145:     logmsg "RUN: $cmd\n" if($verbose);
                   1146:     my $res = runclient($cmd);
                   1147: 
                   1148:     $res >>= 8; # rotate the result
                   1149:     if($res & 128) {
                   1150:         logmsg "RUN: curl command died with a coredump\n";
                   1151:         return -1;
                   1152:     }
                   1153: 
                   1154:     if($res && $verbose) {
                   1155:         logmsg "RUN: curl command returned $res\n";
                   1156:         if(open(FILE, "<$verifylog")) {
                   1157:             while(my $string = <FILE>) {
                   1158:                 logmsg "RUN: $string" if($string !~ /^([ \t]*)$/);
                   1159:             }
                   1160:             close(FILE);
                   1161:         }
                   1162:     }
                   1163: 
                   1164:     my $data;
                   1165:     if(open(FILE, "<$verifyout")) {
                   1166:         while(my $string = <FILE>) {
                   1167:             $data .= $string;
                   1168:         }
                   1169:         close(FILE);
                   1170:     }
                   1171: 
                   1172:     if($data && ($data =~ /(GNUTLS|GnuTLS)/) && open(FILE, "<$pidfile")) {
                   1173:         $pid=0+<FILE>;
                   1174:         close(FILE);
                   1175:         if($pid > 0) {
                   1176:             # if we have a pid it is actually our httptls server,
                   1177:             # since runhttptlsserver() unlinks previous pidfile
                   1178:             if(!pidexists($pid)) {
                   1179:                 logmsg "RUN: $server server has died after starting up\n";
                   1180:                 checkdied($pid);
                   1181:                 unlink($pidfile);
                   1182:                 $pid = -1;
                   1183:             }
                   1184:         }
                   1185:         return $pid;
                   1186:     }
                   1187:     elsif($res == 6) {
                   1188:         # curl: (6) Couldn't resolve host '::1'
                   1189:         logmsg "RUN: failed to resolve host (https://$ip:$port/verifiedserver)\n";
                   1190:         return -1;
                   1191:     }
                   1192:     elsif($data || ($res && ($res != 7))) {
                   1193:         logmsg "RUN: Unknown server on our $server port: $port ($res)\n";
                   1194:         return -1;
                   1195:     }
                   1196:     return $pid;
                   1197: }
                   1198: 
                   1199: #######################################################################
                   1200: # STUB for verifying socks
                   1201: #
                   1202: sub verifysocks {
                   1203:     my ($proto, $ipvnum, $idnum, $ip, $port) = @_;
                   1204:     my $server = servername_id($proto, $ipvnum, $idnum);
                   1205:     my $pidfile = server_pidfilename($proto, $ipvnum, $idnum);
                   1206:     my $pid = 0;
                   1207:     if(open(FILE, "<$pidfile")) {
                   1208:         $pid=0+<FILE>;
                   1209:         close(FILE);
                   1210:     }
                   1211:     if($pid > 0) {
                   1212:         # if we have a pid it is actually our socks server,
                   1213:         # since runsocksserver() unlinks previous pidfile
                   1214:         if(!pidexists($pid)) {
                   1215:             logmsg "RUN: SOCKS server has died after starting up\n";
                   1216:             checkdied($pid);
                   1217:             unlink($pidfile);
                   1218:             $pid = -1;
                   1219:         }
                   1220:     }
                   1221:     return $pid;
                   1222: }
                   1223: 
                   1224: #######################################################################
                   1225: # Verify that the server that runs on $ip, $port is our server.  This also
                   1226: # implies that we can speak with it, as there might be occasions when the
                   1227: # server runs fine but we cannot talk to it ("Failed to connect to ::1: Can't
                   1228: # assign requested address")
                   1229: #
                   1230: sub verifysmb {
                   1231:     my ($proto, $ipvnum, $idnum, $ip, $port) = @_;
                   1232:     my $server = servername_id($proto, $ipvnum, $idnum);
                   1233:     my $pid = 0;
                   1234:     my $time=time();
                   1235:     my $extra="";
                   1236: 
                   1237:     my $verifylog = "$LOGDIR/".
                   1238:         servername_canon($proto, $ipvnum, $idnum) .'_verify.log';
                   1239:     unlink($verifylog) if(-f $verifylog);
                   1240: 
                   1241:     my $flags = "--max-time $server_response_maxtime ";
                   1242:     $flags .= "--silent ";
                   1243:     $flags .= "--verbose ";
                   1244:     $flags .= "--globoff ";
                   1245:     $flags .= "-u 'curltest:curltest' ";
                   1246:     $flags .= $extra;
                   1247:     $flags .= "\"$proto://$ip:$port/SERVER/verifiedserver\"";
                   1248: 
                   1249:     my $cmd = "$VCURL $flags 2>$verifylog";
                   1250: 
                   1251:     # check if this is our server running on this port:
                   1252:     logmsg "RUN: $cmd\n" if($verbose);
                   1253:     my @data = runclientoutput($cmd);
                   1254: 
                   1255:     my $res = $? >> 8; # rotate the result
                   1256:     if($res & 128) {
                   1257:         logmsg "RUN: curl command died with a coredump\n";
                   1258:         return -1;
                   1259:     }
                   1260: 
                   1261:     foreach my $line (@data) {
                   1262:         if($line =~ /WE ROOLZ: (\d+)/) {
                   1263:             # this is our test server with a known pid!
                   1264:             $pid = 0+$1;
                   1265:             last;
                   1266:         }
                   1267:     }
                   1268:     if($pid <= 0 && @data && $data[0]) {
                   1269:         # this is not a known server
                   1270:         logmsg "RUN: Unknown server on our $server port: $port\n";
                   1271:         return 0;
                   1272:     }
                   1273:     # we can/should use the time it took to verify the server as a measure
                   1274:     # on how fast/slow this host is.
                   1275:     my $took = int(0.5+time()-$time);
                   1276: 
                   1277:     if($verbose) {
                   1278:         logmsg "RUN: Verifying our test $server server took $took seconds\n";
                   1279:     }
                   1280:     $ftpchecktime = $took>=1?$took:1; # make sure it never is below 1
                   1281: 
                   1282:     return $pid;
                   1283: }
                   1284: 
                   1285: #######################################################################
                   1286: # Verify that the server that runs on $ip, $port is our server.  This also
                   1287: # implies that we can speak with it, as there might be occasions when the
                   1288: # server runs fine but we cannot talk to it ("Failed to connect to ::1: Can't
                   1289: # assign requested address")
                   1290: #
                   1291: sub verifytelnet {
                   1292:     my ($proto, $ipvnum, $idnum, $ip, $port) = @_;
                   1293:     my $server = servername_id($proto, $ipvnum, $idnum);
                   1294:     my $pid = 0;
                   1295:     my $time=time();
                   1296:     my $extra="";
                   1297: 
                   1298:     my $verifylog = "$LOGDIR/".
                   1299:         servername_canon($proto, $ipvnum, $idnum) .'_verify.log';
                   1300:     unlink($verifylog) if(-f $verifylog);
                   1301: 
                   1302:     my $flags = "--max-time $server_response_maxtime ";
                   1303:     $flags .= "--silent ";
                   1304:     $flags .= "--verbose ";
                   1305:     $flags .= "--globoff ";
                   1306:     $flags .= "--upload-file - ";
                   1307:     $flags .= $extra;
                   1308:     $flags .= "\"$proto://$ip:$port\"";
                   1309: 
                   1310:     my $cmd = "echo 'verifiedserver' | $VCURL $flags 2>$verifylog";
                   1311: 
                   1312:     # check if this is our server running on this port:
                   1313:     logmsg "RUN: $cmd\n" if($verbose);
                   1314:     my @data = runclientoutput($cmd);
                   1315: 
                   1316:     my $res = $? >> 8; # rotate the result
                   1317:     if($res & 128) {
                   1318:         logmsg "RUN: curl command died with a coredump\n";
                   1319:         return -1;
                   1320:     }
                   1321: 
                   1322:     foreach my $line (@data) {
                   1323:         if($line =~ /WE ROOLZ: (\d+)/) {
                   1324:             # this is our test server with a known pid!
                   1325:             $pid = 0+$1;
                   1326:             last;
                   1327:         }
                   1328:     }
                   1329:     if($pid <= 0 && @data && $data[0]) {
                   1330:         # this is not a known server
                   1331:         logmsg "RUN: Unknown server on our $server port: $port\n";
                   1332:         return 0;
                   1333:     }
                   1334:     # we can/should use the time it took to verify the server as a measure
                   1335:     # on how fast/slow this host is.
                   1336:     my $took = int(0.5+time()-$time);
                   1337: 
                   1338:     if($verbose) {
                   1339:         logmsg "RUN: Verifying our test $server server took $took seconds\n";
                   1340:     }
                   1341: 
                   1342:     return $pid;
                   1343: }
                   1344: 
                   1345: 
                   1346: #######################################################################
                   1347: # Verify that the server that runs on $ip, $port is our server.
                   1348: # Retry over several seconds before giving up.  The ssh server in
                   1349: # particular can take a long time to start if it needs to generate
                   1350: # keys on a slow or loaded host.
                   1351: #
                   1352: # Just for convenience, test harness uses 'https' and 'httptls' literals
                   1353: # as values for 'proto' variable in order to differentiate different
                   1354: # servers. 'https' literal is used for stunnel based https test servers,
                   1355: # and 'httptls' is used for non-stunnel https test servers.
                   1356: #
                   1357: 
                   1358: my %protofunc = ('http' => \&verifyhttp,
                   1359:                  'https' => \&verifyhttp,
                   1360:                  'rtsp' => \&verifyrtsp,
                   1361:                  'ftp' => \&verifyftp,
                   1362:                  'pop3' => \&verifyftp,
                   1363:                  'imap' => \&verifyftp,
                   1364:                  'smtp' => \&verifyftp,
                   1365:                  'ftps' => \&verifyftp,
                   1366:                  'tftp' => \&verifyftp,
                   1367:                  'ssh' => \&verifyssh,
                   1368:                  'socks' => \&verifysocks,
                   1369:                  'gopher' => \&verifyhttp,
                   1370:                  'httptls' => \&verifyhttptls,
                   1371:                  'dict' => \&verifyftp,
                   1372:                  'smb' => \&verifysmb,
                   1373:                  'telnet' => \&verifytelnet);
                   1374: 
                   1375: sub verifyserver {
                   1376:     my ($proto, $ipvnum, $idnum, $ip, $port) = @_;
                   1377: 
                   1378:     my $count = 30; # try for this many seconds
                   1379:     my $pid;
                   1380: 
                   1381:     while($count--) {
                   1382:         my $fun = $protofunc{$proto};
                   1383: 
                   1384:         $pid = &$fun($proto, $ipvnum, $idnum, $ip, $port);
                   1385: 
                   1386:         if($pid > 0) {
                   1387:             last;
                   1388:         }
                   1389:         elsif($pid < 0) {
                   1390:             # a real failure, stop trying and bail out
                   1391:             return 0;
                   1392:         }
                   1393:         sleep(1);
                   1394:     }
                   1395:     return $pid;
                   1396: }
                   1397: 
                   1398: #######################################################################
                   1399: # Single shot server responsiveness test. This should only be used
                   1400: # to verify that a server present in %run hash is still functional
                   1401: #
                   1402: sub responsiveserver {
                   1403:     my ($proto, $ipvnum, $idnum, $ip, $port) = @_;
                   1404:     my $prev_verbose = $verbose;
                   1405: 
                   1406:     $verbose = 0;
                   1407:     my $fun = $protofunc{$proto};
                   1408:     my $pid = &$fun($proto, $ipvnum, $idnum, $ip, $port);
                   1409:     $verbose = $prev_verbose;
                   1410: 
                   1411:     if($pid > 0) {
                   1412:         return 1; # responsive
                   1413:     }
                   1414: 
                   1415:     my $srvrname = servername_str($proto, $ipvnum, $idnum);
                   1416:     logmsg " server precheck FAILED (unresponsive $srvrname server)\n";
                   1417:     return 0;
                   1418: }
                   1419: 
                   1420: #######################################################################
                   1421: # start the http2 server
                   1422: #
                   1423: sub runhttp2server {
                   1424:     my ($verbose, $port) = @_;
                   1425:     my $server;
                   1426:     my $srvrname;
                   1427:     my $pidfile;
                   1428:     my $logfile;
                   1429:     my $flags = "";
                   1430:     my $proto="http/2";
                   1431:     my $ipvnum = 4;
                   1432:     my $idnum = 0;
                   1433:     my $exe = "$perl $srcdir/http2-server.pl";
                   1434:     my $verbose_flag = "--verbose ";
                   1435: 
                   1436:     $server = servername_id($proto, $ipvnum, $idnum);
                   1437: 
                   1438:     $pidfile = $serverpidfile{$server};
                   1439: 
                   1440:     # don't retry if the server doesn't work
                   1441:     if ($doesntrun{$pidfile}) {
                   1442:         return (0,0);
                   1443:     }
                   1444: 
                   1445:     my $pid = processexists($pidfile);
                   1446:     if($pid > 0) {
                   1447:         stopserver($server, "$pid");
                   1448:     }
                   1449:     unlink($pidfile) if(-f $pidfile);
                   1450: 
                   1451:     $srvrname = servername_str($proto, $ipvnum, $idnum);
                   1452: 
                   1453:     $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum);
                   1454: 
                   1455:     $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" ";
                   1456:     $flags .= "--port $HTTP2PORT ";
                   1457:     $flags .= "--connect $HOSTIP:$HTTPPORT ";
                   1458:     $flags .= $verbose_flag if($debugprotocol);
                   1459: 
                   1460:     my $cmd = "$exe $flags";
                   1461:     my ($http2pid, $pid2) = startnew($cmd, $pidfile, 15, 0);
                   1462: 
                   1463:     if($http2pid <= 0 || !pidexists($http2pid)) {
                   1464:         # it is NOT alive
                   1465:         logmsg "RUN: failed to start the $srvrname server\n";
                   1466:         stopserver($server, "$pid2");
                   1467:         $doesntrun{$pidfile} = 1;
                   1468:         return (0,0);
                   1469:     }
                   1470: 
                   1471:     if($verbose) {
                   1472:         logmsg "RUN: $srvrname server is now running PID $http2pid\n";
                   1473:     }
                   1474: 
                   1475:     return ($http2pid, $pid2);
                   1476: }
                   1477: 
                   1478: #######################################################################
                   1479: # start the http server
                   1480: #
                   1481: sub runhttpserver {
                   1482:     my ($proto, $verbose, $alt, $port_or_path) = @_;
                   1483:     my $ip = $HOSTIP;
                   1484:     my $ipvnum = 4;
                   1485:     my $idnum = 1;
                   1486:     my $server;
                   1487:     my $srvrname;
                   1488:     my $pidfile;
                   1489:     my $logfile;
                   1490:     my $flags = "";
                   1491:     my $exe = "$perl $srcdir/httpserver.pl";
                   1492:     my $verbose_flag = "--verbose ";
                   1493: 
                   1494:     if($alt eq "ipv6") {
                   1495:         # if IPv6, use a different setup
                   1496:         $ipvnum = 6;
                   1497:         $ip = $HOST6IP;
                   1498:     }
                   1499:     elsif($alt eq "proxy") {
                   1500:         # basically the same, but another ID
                   1501:         $idnum = 2;
                   1502:     }
                   1503:     elsif($alt eq "unix") {
                   1504:         # IP (protocol) is mutually exclusive with Unix sockets
                   1505:         $ipvnum = "unix";
                   1506:     }
                   1507: 
                   1508:     $server = servername_id($proto, $ipvnum, $idnum);
                   1509: 
                   1510:     $pidfile = $serverpidfile{$server};
                   1511:     my $portfile = $serverportfile{$server};
                   1512: 
                   1513:     # don't retry if the server doesn't work
                   1514:     if ($doesntrun{$pidfile}) {
                   1515:         return (0,0);
                   1516:     }
                   1517: 
                   1518:     my $pid = processexists($pidfile);
                   1519:     if($pid > 0) {
                   1520:         stopserver($server, "$pid");
                   1521:     }
                   1522:     unlink($pidfile) if(-f $pidfile);
                   1523: 
                   1524:     $srvrname = servername_str($proto, $ipvnum, $idnum);
                   1525: 
                   1526:     $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum);
                   1527: 
                   1528:     $flags .= "--gopher " if($proto eq "gopher");
                   1529:     $flags .= "--connect $HOSTIP " if($alt eq "proxy");
                   1530:     $flags .= $verbose_flag if($debugprotocol);
                   1531:     $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" ";
                   1532:     $flags .= "--portfile $portfile ";
                   1533:     $flags .= "--id $idnum " if($idnum > 1);
                   1534:     if($ipvnum eq "unix") {
                   1535:         $flags .= "--unix-socket '$port_or_path' ";
                   1536:     } else {
                   1537:         $flags .= "--ipv$ipvnum --port 0 ";
                   1538:     }
                   1539:     $flags .= "--srcdir \"$srcdir\"";
                   1540: 
                   1541:     my $cmd = "$exe $flags";
                   1542:     my ($httppid, $pid2) = startnew($cmd, $pidfile, 15, 0);
                   1543: 
                   1544:     if($httppid <= 0 || !pidexists($httppid)) {
                   1545:         # it is NOT alive
                   1546:         logmsg "RUN: failed to start the $srvrname server\n";
                   1547:         stopserver($server, "$pid2");
                   1548:         displaylogs($testnumcheck);
                   1549:         $doesntrun{$pidfile} = 1;
                   1550:         return (0,0);
                   1551:     }
                   1552: 
                   1553:     # where is it?
                   1554:     my $port;
                   1555:     if(!$port_or_path) {
                   1556:         $port = $port_or_path = pidfromfile($portfile);
                   1557:     }
                   1558: 
                   1559:     # Server is up. Verify that we can speak to it.
                   1560:     my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port_or_path);
                   1561:     if(!$pid3) {
                   1562:         logmsg "RUN: $srvrname server failed verification\n";
                   1563:         # failed to talk to it properly. Kill the server and return failure
                   1564:         stopserver($server, "$httppid $pid2");
                   1565:         displaylogs($testnumcheck);
                   1566:         $doesntrun{$pidfile} = 1;
                   1567:         return (0,0);
                   1568:     }
                   1569:     $pid2 = $pid3;
                   1570: 
                   1571:     if($verbose) {
                   1572:         logmsg "RUN: $srvrname server is on PID $httppid port $port\n";
                   1573:     }
                   1574: 
                   1575:     sleep(1);
                   1576: 
                   1577:     return ($httppid, $pid2, $port);
                   1578: }
                   1579: 
                   1580: #######################################################################
                   1581: # start the https stunnel based server
                   1582: #
                   1583: sub runhttpsserver {
                   1584:     my ($verbose, $ipv6, $certfile) = @_;
                   1585:     my $proto = 'https';
                   1586:     my $ip = ($ipv6 && ($ipv6 =~ /6$/)) ? "$HOST6IP" : "$HOSTIP";
                   1587:     my $ipvnum = ($ipv6 && ($ipv6 =~ /6$/)) ? 6 : 4;
                   1588:     my $idnum = 1;
                   1589:     my $server;
                   1590:     my $srvrname;
                   1591:     my $pidfile;
                   1592:     my $logfile;
                   1593:     my $flags = "";
                   1594: 
                   1595:     if(!$stunnel) {
                   1596:         return (0,0);
                   1597:     }
                   1598: 
                   1599:     $server = servername_id($proto, $ipvnum, $idnum);
                   1600: 
                   1601:     $pidfile = $serverpidfile{$server};
                   1602: 
                   1603:     # don't retry if the server doesn't work
                   1604:     if ($doesntrun{$pidfile}) {
                   1605:         return (0,0);
                   1606:     }
                   1607: 
                   1608:     my $pid = processexists($pidfile);
                   1609:     if($pid > 0) {
                   1610:         stopserver($server, "$pid");
                   1611:     }
                   1612:     unlink($pidfile) if(-f $pidfile);
                   1613: 
                   1614:     $srvrname = servername_str($proto, $ipvnum, $idnum);
                   1615: 
                   1616:     $certfile = 'stunnel.pem' unless($certfile);
                   1617: 
                   1618:     $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum);
                   1619: 
                   1620:     $flags .= "--verbose " if($debugprotocol);
                   1621:     $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" ";
                   1622:     $flags .= "--id $idnum " if($idnum > 1);
                   1623:     $flags .= "--ipv$ipvnum --proto $proto ";
                   1624:     $flags .= "--certfile \"$certfile\" " if($certfile ne 'stunnel.pem');
                   1625:     $flags .= "--stunnel \"$stunnel\" --srcdir \"$srcdir\" ";
                   1626:     $flags .= "--connect $HTTPPORT --accept $HTTPSPORT";
                   1627: 
                   1628:     my $cmd = "$perl $srcdir/secureserver.pl $flags";
                   1629:     my ($httpspid, $pid2) = startnew($cmd, $pidfile, 15, 0);
                   1630: 
                   1631:     if($httpspid <= 0 || !pidexists($httpspid)) {
                   1632:         # it is NOT alive
                   1633:         logmsg "RUN: failed to start the $srvrname server\n";
                   1634:         stopserver($server, "$pid2");
                   1635:         displaylogs($testnumcheck);
                   1636:         $doesntrun{$pidfile} = 1;
                   1637:         return(0,0);
                   1638:     }
                   1639: 
                   1640:     # Server is up. Verify that we can speak to it.
                   1641:     my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $HTTPSPORT);
                   1642:     if(!$pid3) {
                   1643:         logmsg "RUN: $srvrname server failed verification\n";
                   1644:         # failed to talk to it properly. Kill the server and return failure
                   1645:         stopserver($server, "$httpspid $pid2");
                   1646:         displaylogs($testnumcheck);
                   1647:         $doesntrun{$pidfile} = 1;
                   1648:         return (0,0);
                   1649:     }
                   1650:     # Here pid3 is actually the pid returned by the unsecure-http server.
                   1651: 
                   1652:     $runcert{$server} = $certfile;
                   1653: 
                   1654:     if($verbose) {
                   1655:         logmsg "RUN: $srvrname server is now running PID $httpspid\n";
                   1656:     }
                   1657: 
                   1658:     sleep(1);
                   1659: 
                   1660:     return ($httpspid, $pid2);
                   1661: }
                   1662: 
                   1663: #######################################################################
                   1664: # start the non-stunnel HTTP TLS extensions capable server
                   1665: #
                   1666: sub runhttptlsserver {
                   1667:     my ($verbose, $ipv6) = @_;
                   1668:     my $proto = "httptls";
                   1669:     my $port = ($ipv6 && ($ipv6 =~ /6$/)) ? $HTTPTLS6PORT : $HTTPTLSPORT;
                   1670:     my $ip = ($ipv6 && ($ipv6 =~ /6$/)) ? "$HOST6IP" : "$HOSTIP";
                   1671:     my $ipvnum = ($ipv6 && ($ipv6 =~ /6$/)) ? 6 : 4;
                   1672:     my $idnum = 1;
                   1673:     my $server;
                   1674:     my $srvrname;
                   1675:     my $pidfile;
                   1676:     my $logfile;
                   1677:     my $flags = "";
                   1678: 
                   1679:     if(!$httptlssrv) {
                   1680:         return (0,0);
                   1681:     }
                   1682: 
                   1683:     $server = servername_id($proto, $ipvnum, $idnum);
                   1684: 
                   1685:     $pidfile = $serverpidfile{$server};
                   1686: 
                   1687:     # don't retry if the server doesn't work
                   1688:     if ($doesntrun{$pidfile}) {
                   1689:         return (0,0);
                   1690:     }
                   1691: 
                   1692:     my $pid = processexists($pidfile);
                   1693:     if($pid > 0) {
                   1694:         stopserver($server, "$pid");
                   1695:     }
                   1696:     unlink($pidfile) if(-f $pidfile);
                   1697: 
                   1698:     $srvrname = servername_str($proto, $ipvnum, $idnum);
                   1699: 
                   1700:     $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum);
                   1701: 
                   1702:     $flags .= "--http ";
                   1703:     $flags .= "--debug 1 " if($debugprotocol);
                   1704:     $flags .= "--port $port ";
                   1705:     $flags .= "--priority NORMAL:+SRP ";
                   1706:     $flags .= "--srppasswd $srcdir/certs/srp-verifier-db ";
                   1707:     $flags .= "--srppasswdconf $srcdir/certs/srp-verifier-conf";
                   1708: 
                   1709:     my $cmd = "$httptlssrv $flags > $logfile 2>&1";
                   1710:     my ($httptlspid, $pid2) = startnew($cmd, $pidfile, 10, 1); # fake pidfile
                   1711: 
                   1712:     if($httptlspid <= 0 || !pidexists($httptlspid)) {
                   1713:         # it is NOT alive
                   1714:         logmsg "RUN: failed to start the $srvrname server\n";
                   1715:         stopserver($server, "$pid2");
                   1716:         displaylogs($testnumcheck);
                   1717:         $doesntrun{$pidfile} = 1;
                   1718:         return (0,0);
                   1719:     }
                   1720: 
                   1721:     # Server is up. Verify that we can speak to it. PID is from fake pidfile
                   1722:     my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port);
                   1723:     if(!$pid3) {
                   1724:         logmsg "RUN: $srvrname server failed verification\n";
                   1725:         # failed to talk to it properly. Kill the server and return failure
                   1726:         stopserver($server, "$httptlspid $pid2");
                   1727:         displaylogs($testnumcheck);
                   1728:         $doesntrun{$pidfile} = 1;
                   1729:         return (0,0);
                   1730:     }
                   1731:     $pid2 = $pid3;
                   1732: 
                   1733:     if($verbose) {
                   1734:         logmsg "RUN: $srvrname server is now running PID $httptlspid\n";
                   1735:     }
                   1736: 
                   1737:     sleep(1);
                   1738: 
                   1739:     return ($httptlspid, $pid2);
                   1740: }
                   1741: 
                   1742: #######################################################################
                   1743: # start the pingpong server (FTP, POP3, IMAP, SMTP)
                   1744: #
                   1745: sub runpingpongserver {
                   1746:     my ($proto, $id, $verbose, $ipv6) = @_;
                   1747:     my $port;
                   1748:     my $ip = ($ipv6 && ($ipv6 =~ /6$/)) ? "$HOST6IP" : "$HOSTIP";
                   1749:     my $ipvnum = ($ipv6 && ($ipv6 =~ /6$/)) ? 6 : 4;
                   1750:     my $idnum = ($id && ($id =~ /^(\d+)$/) && ($id > 1)) ? $id : 1;
                   1751:     my $server;
                   1752:     my $srvrname;
                   1753:     my $pidfile;
                   1754:     my $logfile;
                   1755:     my $flags = "";
                   1756: 
                   1757:     $server = servername_id($proto, $ipvnum, $idnum);
                   1758: 
                   1759:     $pidfile = $serverpidfile{$server};
                   1760:     my $portfile = $serverportfile{$server};
                   1761: 
                   1762:     # don't retry if the server doesn't work
                   1763:     if ($doesntrun{$pidfile}) {
                   1764:         return (0,0);
                   1765:     }
                   1766: 
                   1767:     my $pid = processexists($pidfile);
                   1768:     if($pid > 0) {
                   1769:         stopserver($server, "$pid");
                   1770:     }
                   1771:     unlink($pidfile) if(-f $pidfile);
                   1772: 
                   1773:     $srvrname = servername_str($proto, $ipvnum, $idnum);
                   1774: 
                   1775:     $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum);
                   1776: 
                   1777:     $flags .= "--verbose " if($debugprotocol);
                   1778:     $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" ";
                   1779:     $flags .= "--portfile \"$portfile\" ";
                   1780:     $flags .= "--srcdir \"$srcdir\" --proto $proto ";
                   1781:     $flags .= "--id $idnum " if($idnum > 1);
                   1782:     $flags .= "--ipv$ipvnum --port 0 --addr \"$ip\"";
                   1783: 
                   1784:     my $cmd = "$perl $srcdir/ftpserver.pl $flags";
                   1785:     my ($ftppid, $pid2) = startnew($cmd, $pidfile, 15, 0);
                   1786: 
                   1787:     if($ftppid <= 0 || !pidexists($ftppid)) {
                   1788:         # it is NOT alive
                   1789:         logmsg "RUN: failed to start the $srvrname server\n";
                   1790:         stopserver($server, "$pid2");
                   1791:         displaylogs($testnumcheck);
                   1792:         $doesntrun{$pidfile} = 1;
                   1793:         return (0,0);
                   1794:     }
                   1795: 
                   1796:     # where is it?
                   1797:     $port = pidfromfile($portfile);
                   1798: 
                   1799:     logmsg "PINGPONG runs on port $port ($portfile)\n" if($verbose);
                   1800: 
                   1801:     # Server is up. Verify that we can speak to it.
                   1802:     my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port);
                   1803:     if(!$pid3) {
                   1804:         logmsg "RUN: $srvrname server failed verification\n";
                   1805:         # failed to talk to it properly. Kill the server and return failure
                   1806:         stopserver($server, "$ftppid $pid2");
                   1807:         displaylogs($testnumcheck);
                   1808:         $doesntrun{$pidfile} = 1;
                   1809:         return (0,0);
                   1810:     }
                   1811: 
                   1812:     $pid2 = $pid3;
                   1813: 
                   1814:     logmsg "RUN: $srvrname server is PID $ftppid port $port\n" if($verbose);
                   1815: 
                   1816:     # Assign the correct port variable!
                   1817:     if($proto eq "ftp") {
                   1818:         if($ipvnum == 6) {
                   1819:             # if IPv6, use a different setup
                   1820:             $FTP6PORT = $port;
                   1821:         }
                   1822:         elsif($idnum>1) {
                   1823:             $FTP2PORT = $port;
                   1824:         }
                   1825:         else {
                   1826:             $FTPPORT = $port;
                   1827:         }
                   1828:     }
                   1829:     elsif($proto eq "pop3") {
                   1830:         if($ipvnum == 6) {
                   1831:             $POP36PORT = $port;
                   1832:         }
                   1833:         else {
                   1834:             $POP3PORT = $port;
                   1835:         }
                   1836:     }
                   1837:     elsif($proto eq "imap") {
                   1838:         if($ipvnum == 6) {
                   1839:             $IMAP6PORT  = $port;
                   1840:         }
                   1841:         else {
                   1842:             $IMAPPORT = $port;
                   1843:         }
                   1844:     }
                   1845:     elsif($proto eq "smtp") {
                   1846:         if($ipvnum == 6) {
                   1847:             $SMTP6PORT = $port;
                   1848:         }
                   1849:         else {
                   1850:             $SMTPPORT = $port;
                   1851:         }
                   1852:     }
                   1853:     else {
                   1854:         print STDERR "Unsupported protocol $proto!!\n";
                   1855:         return 0;
                   1856:     }
                   1857: 
                   1858:     sleep(1);
                   1859: 
                   1860:     return ($pid2, $ftppid);
                   1861: }
                   1862: 
                   1863: #######################################################################
                   1864: # start the ftps server (or rather, tunnel)
                   1865: #
                   1866: sub runftpsserver {
                   1867:     my ($verbose, $ipv6, $certfile) = @_;
                   1868:     my $proto = 'ftps';
                   1869:     my $ip = ($ipv6 && ($ipv6 =~ /6$/)) ? "$HOST6IP" : "$HOSTIP";
                   1870:     my $ipvnum = ($ipv6 && ($ipv6 =~ /6$/)) ? 6 : 4;
                   1871:     my $idnum = 1;
                   1872:     my $server;
                   1873:     my $srvrname;
                   1874:     my $pidfile;
                   1875:     my $logfile;
                   1876:     my $flags = "";
                   1877: 
                   1878:     if(!$stunnel) {
                   1879:         return (0,0);
                   1880:     }
                   1881: 
                   1882:     $server = servername_id($proto, $ipvnum, $idnum);
                   1883: 
                   1884:     $pidfile = $serverpidfile{$server};
                   1885: 
                   1886:     # don't retry if the server doesn't work
                   1887:     if ($doesntrun{$pidfile}) {
                   1888:         return (0,0);
                   1889:     }
                   1890: 
                   1891:     my $pid = processexists($pidfile);
                   1892:     if($pid > 0) {
                   1893:         stopserver($server, "$pid");
                   1894:     }
                   1895:     unlink($pidfile) if(-f $pidfile);
                   1896: 
                   1897:     $srvrname = servername_str($proto, $ipvnum, $idnum);
                   1898: 
                   1899:     $certfile = 'stunnel.pem' unless($certfile);
                   1900: 
                   1901:     $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum);
                   1902: 
                   1903:     $flags .= "--verbose " if($debugprotocol);
                   1904:     $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" ";
                   1905:     $flags .= "--id $idnum " if($idnum > 1);
                   1906:     $flags .= "--ipv$ipvnum --proto $proto ";
                   1907:     $flags .= "--certfile \"$certfile\" " if($certfile ne 'stunnel.pem');
                   1908:     $flags .= "--stunnel \"$stunnel\" --srcdir \"$srcdir\" ";
                   1909:     $flags .= "--connect $FTPPORT --accept $FTPSPORT";
                   1910: 
                   1911:     my $cmd = "$perl $srcdir/secureserver.pl $flags";
                   1912:     my ($ftpspid, $pid2) = startnew($cmd, $pidfile, 15, 0);
                   1913: 
                   1914:     if($ftpspid <= 0 || !pidexists($ftpspid)) {
                   1915:         # it is NOT alive
                   1916:         logmsg "RUN: failed to start the $srvrname server\n";
                   1917:         stopserver($server, "$pid2");
                   1918:         displaylogs($testnumcheck);
                   1919:         $doesntrun{$pidfile} = 1;
                   1920:         return(0,0);
                   1921:     }
                   1922: 
                   1923:     # Server is up. Verify that we can speak to it.
                   1924:     my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $FTPSPORT);
                   1925:     if(!$pid3) {
                   1926:         logmsg "RUN: $srvrname server failed verification\n";
                   1927:         # failed to talk to it properly. Kill the server and return failure
                   1928:         stopserver($server, "$ftpspid $pid2");
                   1929:         displaylogs($testnumcheck);
                   1930:         $doesntrun{$pidfile} = 1;
                   1931:         return (0,0);
                   1932:     }
                   1933:     # Here pid3 is actually the pid returned by the unsecure-ftp server.
                   1934: 
                   1935:     $runcert{$server} = $certfile;
                   1936: 
                   1937:     if($verbose) {
                   1938:         logmsg "RUN: $srvrname server is now running PID $ftpspid\n";
                   1939:     }
                   1940: 
                   1941:     sleep(1);
                   1942: 
                   1943:     return ($ftpspid, $pid2);
                   1944: }
                   1945: 
                   1946: #######################################################################
                   1947: # start the tftp server
                   1948: #
                   1949: sub runtftpserver {
                   1950:     my ($id, $verbose, $ipv6) = @_;
                   1951:     my $ip = $HOSTIP;
                   1952:     my $proto = 'tftp';
                   1953:     my $ipvnum = 4;
                   1954:     my $idnum = ($id && ($id =~ /^(\d+)$/) && ($id > 1)) ? $id : 1;
                   1955:     my $server;
                   1956:     my $srvrname;
                   1957:     my $pidfile;
                   1958:     my $logfile;
                   1959:     my $flags = "";
                   1960: 
                   1961:     if($ipv6) {
                   1962:         # if IPv6, use a different setup
                   1963:         $ipvnum = 6;
                   1964:         $ip = $HOST6IP;
                   1965:     }
                   1966: 
                   1967:     $server = servername_id($proto, $ipvnum, $idnum);
                   1968: 
                   1969:     $pidfile = $serverpidfile{$server};
                   1970:     my $portfile = $serverportfile{$server};
                   1971: 
                   1972:     # don't retry if the server doesn't work
                   1973:     if ($doesntrun{$pidfile}) {
                   1974:         return (0,0);
                   1975:     }
                   1976: 
                   1977:     my $pid = processexists($pidfile);
                   1978:     if($pid > 0) {
                   1979:         stopserver($server, "$pid");
                   1980:     }
                   1981:     unlink($pidfile) if(-f $pidfile);
                   1982: 
                   1983:     $srvrname = servername_str($proto, $ipvnum, $idnum);
                   1984: 
                   1985:     $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum);
                   1986: 
                   1987:     $flags .= "--verbose " if($debugprotocol);
                   1988:     $flags .= "--pidfile \"$pidfile\" ".
                   1989:         "--portfile \"$portfile\" ".
                   1990:         "--logfile \"$logfile\" ";
                   1991:     $flags .= "--id $idnum " if($idnum > 1);
                   1992:     $flags .= "--ipv$ipvnum --port 0 --srcdir \"$srcdir\"";
                   1993: 
                   1994:     my $cmd = "$perl $srcdir/tftpserver.pl $flags";
                   1995:     my ($tftppid, $pid2) = startnew($cmd, $pidfile, 15, 0);
                   1996: 
                   1997:     if($tftppid <= 0 || !pidexists($tftppid)) {
                   1998:         # it is NOT alive
                   1999:         logmsg "RUN: failed to start the $srvrname server\n";
                   2000:         stopserver($server, "$pid2");
                   2001:         displaylogs($testnumcheck);
                   2002:         $doesntrun{$pidfile} = 1;
                   2003:         return (0,0);
                   2004:     }
                   2005: 
                   2006:     my $port = pidfromfile($portfile);
                   2007: 
                   2008:     # Server is up. Verify that we can speak to it.
                   2009:     my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port);
                   2010:     if(!$pid3) {
                   2011:         logmsg "RUN: $srvrname server failed verification\n";
                   2012:         # failed to talk to it properly. Kill the server and return failure
                   2013:         stopserver($server, "$tftppid $pid2");
                   2014:         displaylogs($testnumcheck);
                   2015:         $doesntrun{$pidfile} = 1;
                   2016:         return (0,0);
                   2017:     }
                   2018:     $pid2 = $pid3;
                   2019: 
                   2020:     if($verbose) {
                   2021:         logmsg "RUN: $srvrname server on PID $tftppid port $port\n";
                   2022:     }
                   2023: 
                   2024:     sleep(1);
                   2025: 
                   2026:     return ($pid2, $tftppid, $port);
                   2027: }
                   2028: 
                   2029: 
                   2030: #######################################################################
                   2031: # start the rtsp server
                   2032: #
                   2033: sub runrtspserver {
                   2034:     my ($verbose, $ipv6) = @_;
                   2035:     my $ip = $HOSTIP;
                   2036:     my $proto = 'rtsp';
                   2037:     my $ipvnum = 4;
                   2038:     my $idnum = 1;
                   2039:     my $server;
                   2040:     my $srvrname;
                   2041:     my $pidfile;
                   2042:     my $logfile;
                   2043:     my $flags = "";
                   2044: 
                   2045:     if($ipv6) {
                   2046:         # if IPv6, use a different setup
                   2047:         $ipvnum = 6;
                   2048:         $ip = $HOST6IP;
                   2049:     }
                   2050: 
                   2051:     $server = servername_id($proto, $ipvnum, $idnum);
                   2052: 
                   2053:     $pidfile = $serverpidfile{$server};
                   2054:     my $portfile = $serverportfile{$server};
                   2055: 
                   2056:     # don't retry if the server doesn't work
                   2057:     if ($doesntrun{$pidfile}) {
                   2058:         return (0,0);
                   2059:     }
                   2060: 
                   2061:     my $pid = processexists($pidfile);
                   2062:     if($pid > 0) {
                   2063:         stopserver($server, "$pid");
                   2064:     }
                   2065:     unlink($pidfile) if(-f $pidfile);
                   2066: 
                   2067:     $srvrname = servername_str($proto, $ipvnum, $idnum);
                   2068: 
                   2069:     $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum);
                   2070: 
                   2071:     $flags .= "--verbose " if($debugprotocol);
                   2072:     $flags .= "--pidfile \"$pidfile\" ".
                   2073:          "--portfile \"$portfile\" ".
                   2074:         "--logfile \"$logfile\" ";
                   2075:     $flags .= "--id $idnum " if($idnum > 1);
                   2076:     $flags .= "--ipv$ipvnum --port 0 --srcdir \"$srcdir\"";
                   2077: 
                   2078:     my $cmd = "$perl $srcdir/rtspserver.pl $flags";
                   2079:     my ($rtsppid, $pid2) = startnew($cmd, $pidfile, 15, 0);
                   2080: 
                   2081:     if($rtsppid <= 0 || !pidexists($rtsppid)) {
                   2082:         # it is NOT alive
                   2083:         logmsg "RUN: failed to start the $srvrname server\n";
                   2084:         stopserver($server, "$pid2");
                   2085:         displaylogs($testnumcheck);
                   2086:         $doesntrun{$pidfile} = 1;
                   2087:         return (0,0);
                   2088:     }
                   2089: 
                   2090:     my $port = pidfromfile($portfile);
                   2091: 
                   2092:     # Server is up. Verify that we can speak to it.
                   2093:     my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port);
                   2094:     if(!$pid3) {
                   2095:         logmsg "RUN: $srvrname server failed verification\n";
                   2096:         # failed to talk to it properly. Kill the server and return failure
                   2097:         stopserver($server, "$rtsppid $pid2");
                   2098:         displaylogs($testnumcheck);
                   2099:         $doesntrun{$pidfile} = 1;
                   2100:         return (0,0);
                   2101:     }
                   2102:     $pid2 = $pid3;
                   2103: 
                   2104:     if($verbose) {
                   2105:         logmsg "RUN: $srvrname server PID $rtsppid port $port\n";
                   2106:     }
                   2107: 
                   2108:     sleep(1);
                   2109: 
                   2110:     return ($rtsppid, $pid2, $port);
                   2111: }
                   2112: 
                   2113: 
                   2114: #######################################################################
                   2115: # Start the ssh (scp/sftp) server
                   2116: #
                   2117: sub runsshserver {
                   2118:     my ($id, $verbose, $ipv6) = @_;
                   2119:     my $ip=$HOSTIP;
                   2120:     my $port = $SSHPORT;
                   2121:     my $proto = 'ssh';
                   2122:     my $ipvnum = 4;
                   2123:     my $idnum = ($id && ($id =~ /^(\d+)$/) && ($id > 1)) ? $id : 1;
                   2124:     my $server;
                   2125:     my $srvrname;
                   2126:     my $pidfile;
                   2127:     my $logfile;
                   2128:     my $flags = "";
                   2129: 
                   2130:     $server = servername_id($proto, $ipvnum, $idnum);
                   2131: 
                   2132:     $pidfile = $serverpidfile{$server};
                   2133: 
                   2134:     # don't retry if the server doesn't work
                   2135:     if ($doesntrun{$pidfile}) {
                   2136:         return (0,0);
                   2137:     }
                   2138: 
                   2139:     my $pid = processexists($pidfile);
                   2140:     if($pid > 0) {
                   2141:         stopserver($server, "$pid");
                   2142:     }
                   2143:     unlink($pidfile) if(-f $pidfile);
                   2144: 
                   2145:     $srvrname = servername_str($proto, $ipvnum, $idnum);
                   2146: 
                   2147:     $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum);
                   2148: 
                   2149:     $flags .= "--verbose " if($verbose);
                   2150:     $flags .= "--debugprotocol " if($debugprotocol);
                   2151:     $flags .= "--pidfile \"$pidfile\" ";
                   2152:     $flags .= "--id $idnum " if($idnum > 1);
                   2153:     $flags .= "--ipv$ipvnum --addr \"$ip\" ";
                   2154:     $flags .= "--sshport $port ";
                   2155:     $flags .= "--user \"$USER\"";
                   2156: 
                   2157:     my $cmd = "$perl $srcdir/sshserver.pl $flags";
                   2158:     my ($sshpid, $pid2) = startnew($cmd, $pidfile, 60, 0);
                   2159: 
                   2160:     # on loaded systems sshserver start up can take longer than the timeout
                   2161:     # passed to startnew, when this happens startnew completes without being
                   2162:     # able to read the pidfile and consequently returns a zero pid2 above.
                   2163: 
                   2164:     if($sshpid <= 0 || !pidexists($sshpid)) {
                   2165:         # it is NOT alive
                   2166:         logmsg "RUN: failed to start the $srvrname server\n";
                   2167:         stopserver($server, "$pid2");
                   2168:         $doesntrun{$pidfile} = 1;
                   2169:         return (0,0);
                   2170:     }
                   2171: 
                   2172:     # ssh server verification allows some extra time for the server to start up
                   2173:     # and gives us the opportunity of recovering the pid from the pidfile, when
                   2174:     # this verification succeeds the recovered pid is assigned to pid2.
                   2175: 
                   2176:     my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port);
                   2177:     if(!$pid3) {
                   2178:         logmsg "RUN: $srvrname server failed verification\n";
                   2179:         # failed to fetch server pid. Kill the server and return failure
                   2180:         stopserver($server, "$sshpid $pid2");
                   2181:         $doesntrun{$pidfile} = 1;
                   2182:         return (0,0);
                   2183:     }
                   2184:     $pid2 = $pid3;
                   2185: 
                   2186:     # once it is known that the ssh server is alive, sftp server verification
                   2187:     # is performed actually connecting to it, authenticating and performing a
                   2188:     # very simple remote command.  This verification is tried only one time.
                   2189: 
                   2190:     $sshdlog = server_logfilename($LOGDIR, 'ssh', $ipvnum, $idnum);
                   2191:     $sftplog = server_logfilename($LOGDIR, 'sftp', $ipvnum, $idnum);
                   2192: 
                   2193:     if(verifysftp('sftp', $ipvnum, $idnum, $ip, $port) < 1) {
                   2194:         logmsg "RUN: SFTP server failed verification\n";
                   2195:         # failed to talk to it properly. Kill the server and return failure
                   2196:         display_sftplog();
                   2197:         display_sftpconfig();
                   2198:         display_sshdlog();
                   2199:         display_sshdconfig();
                   2200:         stopserver($server, "$sshpid $pid2");
                   2201:         $doesntrun{$pidfile} = 1;
                   2202:         return (0,0);
                   2203:     }
                   2204: 
                   2205:     my $hstpubmd5f = "curl_host_rsa_key.pub_md5";
                   2206:     if(!open(PUBMD5FILE, "<", $hstpubmd5f) ||
                   2207:        (read(PUBMD5FILE, $SSHSRVMD5, 32) != 32) ||
                   2208:        !close(PUBMD5FILE) ||
                   2209:        ($SSHSRVMD5 !~ /^[a-f0-9]{32}$/i))
                   2210:     {
                   2211:         my $msg = "Fatal: $srvrname pubkey md5 missing : \"$hstpubmd5f\" : $!";
                   2212:         logmsg "$msg\n";
                   2213:         stopservers($verbose);
                   2214:         die $msg;
                   2215:     }
                   2216: 
                   2217:     if($verbose) {
                   2218:         logmsg "RUN: $srvrname server is now running PID $pid2\n";
                   2219:     }
                   2220: 
                   2221:     return ($pid2, $sshpid);
                   2222: }
                   2223: 
                   2224: #######################################################################
                   2225: # Start the socks server
                   2226: #
                   2227: sub runmqttserver {
                   2228:     my ($id, $verbose, $ipv6) = @_;
                   2229:     my $ip=$HOSTIP;
                   2230:     my $port = $MQTTPORT;
                   2231:     my $proto = 'mqtt';
                   2232:     my $ipvnum = 4;
                   2233:     my $idnum = ($id && ($id =~ /^(\d+)$/) && ($id > 1)) ? $id : 1;
                   2234:     my $server;
                   2235:     my $srvrname;
                   2236:     my $pidfile;
                   2237:     my $portfile;
                   2238:     my $logfile;
                   2239:     my $flags = "";
                   2240: 
                   2241:     $server = servername_id($proto, $ipvnum, $idnum);
                   2242:     $pidfile = $serverpidfile{$server};
                   2243:     $portfile = $serverportfile{$server};
                   2244: 
                   2245:     # don't retry if the server doesn't work
                   2246:     if ($doesntrun{$pidfile}) {
                   2247:         return (0,0);
                   2248:     }
                   2249: 
                   2250:     my $pid = processexists($pidfile);
                   2251:     if($pid > 0) {
                   2252:         stopserver($server, "$pid");
                   2253:     }
                   2254:     unlink($pidfile) if(-f $pidfile);
                   2255: 
                   2256:     $srvrname = servername_str($proto, $ipvnum, $idnum);
                   2257: 
                   2258:     $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum);
                   2259: 
                   2260:     # start our MQTT server - on a random port!
                   2261:     my $cmd="server/mqttd".exe_ext('SRV').
                   2262:         " --port 0 ".
                   2263:         " --pidfile $pidfile".
                   2264:         " --portfile $portfile".
                   2265:         " --config $FTPDCMD";
                   2266:     my ($sockspid, $pid2) = startnew($cmd, $pidfile, 30, 0);
                   2267: 
                   2268:     if($sockspid <= 0 || !pidexists($sockspid)) {
                   2269:         # it is NOT alive
                   2270:         logmsg "RUN: failed to start the $srvrname server\n";
                   2271:         stopserver($server, "$pid2");
                   2272:         $doesntrun{$pidfile} = 1;
                   2273:         return (0,0);
                   2274:     }
                   2275: 
                   2276:     $MQTTPORT = pidfromfile($portfile);
                   2277: 
                   2278:     if($verbose) {
                   2279:         logmsg "RUN: $srvrname server is now running PID $pid2 on PORT $MQTTPORT\n";
                   2280:     }
                   2281: 
                   2282:     return ($pid2, $sockspid);
                   2283: }
                   2284: 
                   2285: #######################################################################
                   2286: # Start the socks server
                   2287: #
                   2288: sub runsocksserver {
                   2289:     my ($id, $verbose, $ipv6) = @_;
                   2290:     my $ip=$HOSTIP;
                   2291:     my $proto = 'socks';
                   2292:     my $ipvnum = 4;
                   2293:     my $idnum = ($id && ($id =~ /^(\d+)$/) && ($id > 1)) ? $id : 1;
                   2294:     my $server;
                   2295:     my $srvrname;
                   2296:     my $pidfile;
                   2297:     my $logfile;
                   2298:     my $flags = "";
                   2299: 
                   2300:     $server = servername_id($proto, $ipvnum, $idnum);
                   2301: 
                   2302:     $pidfile = $serverpidfile{$server};
                   2303:     my $portfile = $serverportfile{$server};
                   2304: 
                   2305:     # don't retry if the server doesn't work
                   2306:     if ($doesntrun{$pidfile}) {
                   2307:         return (0,0);
                   2308:     }
                   2309: 
                   2310:     my $pid = processexists($pidfile);
                   2311:     if($pid > 0) {
                   2312:         stopserver($server, "$pid");
                   2313:     }
                   2314:     unlink($pidfile) if(-f $pidfile);
                   2315: 
                   2316:     $srvrname = servername_str($proto, $ipvnum, $idnum);
                   2317: 
                   2318:     $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum);
                   2319: 
                   2320:     # start our socks server, get commands from the FTP cmd file
                   2321:     my $cmd="server/socksd".exe_ext('SRV').
                   2322:         " --port 0 ".
                   2323:         " --pidfile $pidfile".
                   2324:         " --portfile $portfile".
                   2325:         " --backend $HOSTIP".
                   2326:         " --config $FTPDCMD";
                   2327:     my ($sockspid, $pid2) = startnew($cmd, $pidfile, 30, 0);
                   2328: 
                   2329:     if($sockspid <= 0 || !pidexists($sockspid)) {
                   2330:         # it is NOT alive
                   2331:         logmsg "RUN: failed to start the $srvrname server\n";
                   2332:         stopserver($server, "$pid2");
                   2333:         $doesntrun{$pidfile} = 1;
                   2334:         return (0,0);
                   2335:     }
                   2336: 
                   2337:     my $port = pidfromfile($portfile);
                   2338: 
                   2339:     if($verbose) {
                   2340:         logmsg "RUN: $srvrname server is now running PID $pid2\n";
                   2341:     }
                   2342: 
                   2343:     return ($pid2, $sockspid, $port);
                   2344: }
                   2345: 
                   2346: #######################################################################
                   2347: # start the dict server
                   2348: #
                   2349: sub rundictserver {
                   2350:     my ($verbose, $alt, $port) = @_;
                   2351:     my $proto = "dict";
                   2352:     my $ip = $HOSTIP;
                   2353:     my $ipvnum = 4;
                   2354:     my $idnum = 1;
                   2355:     my $server;
                   2356:     my $srvrname;
                   2357:     my $pidfile;
                   2358:     my $logfile;
                   2359:     my $flags = "";
                   2360: 
                   2361:     if($alt eq "ipv6") {
                   2362:         # No IPv6
                   2363:     }
                   2364: 
                   2365:     $server = servername_id($proto, $ipvnum, $idnum);
                   2366: 
                   2367:     $pidfile = $serverpidfile{$server};
                   2368: 
                   2369:     # don't retry if the server doesn't work
                   2370:     if ($doesntrun{$pidfile}) {
                   2371:         return (0,0);
                   2372:     }
                   2373: 
                   2374:     my $pid = processexists($pidfile);
                   2375:     if($pid > 0) {
                   2376:         stopserver($server, "$pid");
                   2377:     }
                   2378:     unlink($pidfile) if(-f $pidfile);
                   2379: 
                   2380:     $srvrname = servername_str($proto, $ipvnum, $idnum);
                   2381: 
                   2382:     $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum);
                   2383: 
                   2384:     $flags .= "--verbose 1 " if($debugprotocol);
                   2385:     $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" ";
                   2386:     $flags .= "--id $idnum " if($idnum > 1);
                   2387:     $flags .= "--port $port --srcdir \"$srcdir\" ";
                   2388:     $flags .= "--host $HOSTIP";
                   2389: 
                   2390:     my $cmd = "$srcdir/dictserver.py $flags";
                   2391:     my ($dictpid, $pid2) = startnew($cmd, $pidfile, 15, 0);
                   2392: 
                   2393:     if($dictpid <= 0 || !pidexists($dictpid)) {
                   2394:         # it is NOT alive
                   2395:         logmsg "RUN: failed to start the $srvrname server\n";
                   2396:         stopserver($server, "$pid2");
                   2397:         displaylogs($testnumcheck);
                   2398:         $doesntrun{$pidfile} = 1;
                   2399:         return (0,0);
                   2400:     }
                   2401: 
                   2402:     # Server is up. Verify that we can speak to it.
                   2403:     my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port);
                   2404:     if(!$pid3) {
                   2405:         logmsg "RUN: $srvrname server failed verification\n";
                   2406:         # failed to talk to it properly. Kill the server and return failure
                   2407:         stopserver($server, "$dictpid $pid2");
                   2408:         displaylogs($testnumcheck);
                   2409:         $doesntrun{$pidfile} = 1;
                   2410:         return (0,0);
                   2411:     }
                   2412:     $pid2 = $pid3;
                   2413: 
                   2414:     if($verbose) {
                   2415:         logmsg "RUN: $srvrname server is now running PID $dictpid\n";
                   2416:     }
                   2417: 
                   2418:     sleep(1);
                   2419: 
                   2420:     return ($dictpid, $pid2);
                   2421: }
                   2422: 
                   2423: #######################################################################
                   2424: # start the SMB server
                   2425: #
                   2426: sub runsmbserver {
                   2427:     my ($verbose, $alt, $port) = @_;
                   2428:     my $proto = "smb";
                   2429:     my $ip = $HOSTIP;
                   2430:     my $ipvnum = 4;
                   2431:     my $idnum = 1;
                   2432:     my $server;
                   2433:     my $srvrname;
                   2434:     my $pidfile;
                   2435:     my $logfile;
                   2436:     my $flags = "";
                   2437: 
                   2438:     if($alt eq "ipv6") {
                   2439:         # No IPv6
                   2440:     }
                   2441: 
                   2442:     $server = servername_id($proto, $ipvnum, $idnum);
                   2443: 
                   2444:     $pidfile = $serverpidfile{$server};
                   2445: 
                   2446:     # don't retry if the server doesn't work
                   2447:     if ($doesntrun{$pidfile}) {
                   2448:         return (0,0);
                   2449:     }
                   2450: 
                   2451:     my $pid = processexists($pidfile);
                   2452:     if($pid > 0) {
                   2453:         stopserver($server, "$pid");
                   2454:     }
                   2455:     unlink($pidfile) if(-f $pidfile);
                   2456: 
                   2457:     $srvrname = servername_str($proto, $ipvnum, $idnum);
                   2458: 
                   2459:     $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum);
                   2460: 
                   2461:     $flags .= "--verbose 1 " if($debugprotocol);
                   2462:     $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" ";
                   2463:     $flags .= "--id $idnum " if($idnum > 1);
                   2464:     $flags .= "--port $port --srcdir \"$srcdir\" ";
                   2465:     $flags .= "--host $HOSTIP";
                   2466: 
                   2467:     my $cmd = "$srcdir/smbserver.py $flags";
                   2468:     my ($smbpid, $pid2) = startnew($cmd, $pidfile, 15, 0);
                   2469: 
                   2470:     if($smbpid <= 0 || !pidexists($smbpid)) {
                   2471:         # it is NOT alive
                   2472:         logmsg "RUN: failed to start the $srvrname server\n";
                   2473:         stopserver($server, "$pid2");
                   2474:         displaylogs($testnumcheck);
                   2475:         $doesntrun{$pidfile} = 1;
                   2476:         return (0,0);
                   2477:     }
                   2478: 
                   2479:     # Server is up. Verify that we can speak to it.
                   2480:     my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port);
                   2481:     if(!$pid3) {
                   2482:         logmsg "RUN: $srvrname server failed verification\n";
                   2483:         # failed to talk to it properly. Kill the server and return failure
                   2484:         stopserver($server, "$smbpid $pid2");
                   2485:         displaylogs($testnumcheck);
                   2486:         $doesntrun{$pidfile} = 1;
                   2487:         return (0,0);
                   2488:     }
                   2489:     $pid2 = $pid3;
                   2490: 
                   2491:     if($verbose) {
                   2492:         logmsg "RUN: $srvrname server is now running PID $smbpid\n";
                   2493:     }
                   2494: 
                   2495:     sleep(1);
                   2496: 
                   2497:     return ($smbpid, $pid2);
                   2498: }
                   2499: 
                   2500: #######################################################################
                   2501: # start the telnet server
                   2502: #
                   2503: sub runnegtelnetserver {
                   2504:     my ($verbose, $alt, $port) = @_;
                   2505:     my $proto = "telnet";
                   2506:     my $ip = $HOSTIP;
                   2507:     my $ipvnum = 4;
                   2508:     my $idnum = 1;
                   2509:     my $server;
                   2510:     my $srvrname;
                   2511:     my $pidfile;
                   2512:     my $logfile;
                   2513:     my $flags = "";
                   2514: 
                   2515:     if($alt eq "ipv6") {
                   2516:         # No IPv6
                   2517:     }
                   2518: 
                   2519:     $server = servername_id($proto, $ipvnum, $idnum);
                   2520: 
                   2521:     $pidfile = $serverpidfile{$server};
                   2522: 
                   2523:     # don't retry if the server doesn't work
                   2524:     if ($doesntrun{$pidfile}) {
                   2525:         return (0,0);
                   2526:     }
                   2527: 
                   2528:     my $pid = processexists($pidfile);
                   2529:     if($pid > 0) {
                   2530:         stopserver($server, "$pid");
                   2531:     }
                   2532:     unlink($pidfile) if(-f $pidfile);
                   2533: 
                   2534:     $srvrname = servername_str($proto, $ipvnum, $idnum);
                   2535: 
                   2536:     $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum);
                   2537: 
                   2538:     $flags .= "--verbose 1 " if($debugprotocol);
                   2539:     $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" ";
                   2540:     $flags .= "--id $idnum " if($idnum > 1);
                   2541:     $flags .= "--port $port --srcdir \"$srcdir\"";
                   2542: 
                   2543:     my $cmd = "$srcdir/negtelnetserver.py $flags";
                   2544:     my ($ntelpid, $pid2) = startnew($cmd, $pidfile, 15, 0);
                   2545: 
                   2546:     if($ntelpid <= 0 || !pidexists($ntelpid)) {
                   2547:         # it is NOT alive
                   2548:         logmsg "RUN: failed to start the $srvrname server\n";
                   2549:         stopserver($server, "$pid2");
                   2550:         displaylogs($testnumcheck);
                   2551:         $doesntrun{$pidfile} = 1;
                   2552:         return (0,0);
                   2553:     }
                   2554: 
                   2555:     # Server is up. Verify that we can speak to it.
                   2556:     my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port);
                   2557:     if(!$pid3) {
                   2558:         logmsg "RUN: $srvrname server failed verification\n";
                   2559:         # failed to talk to it properly. Kill the server and return failure
                   2560:         stopserver($server, "$ntelpid $pid2");
                   2561:         displaylogs($testnumcheck);
                   2562:         $doesntrun{$pidfile} = 1;
                   2563:         return (0,0);
                   2564:     }
                   2565:     $pid2 = $pid3;
                   2566: 
                   2567:     if($verbose) {
                   2568:         logmsg "RUN: $srvrname server is now running PID $ntelpid\n";
                   2569:     }
                   2570: 
                   2571:     sleep(1);
                   2572: 
                   2573:     return ($ntelpid, $pid2);
                   2574: }
                   2575: 
                   2576: 
                   2577: #######################################################################
                   2578: # Single shot http and gopher server responsiveness test. This should only
                   2579: # be used to verify that a server present in %run hash is still functional
                   2580: #
                   2581: sub responsive_http_server {
                   2582:     my ($proto, $verbose, $alt, $port_or_path) = @_;
                   2583:     my $ip = $HOSTIP;
                   2584:     my $ipvnum = 4;
                   2585:     my $idnum = 1;
                   2586: 
                   2587:     if($alt eq "ipv6") {
                   2588:         # if IPv6, use a different setup
                   2589:         $ipvnum = 6;
                   2590:         $ip = $HOST6IP;
                   2591:     }
                   2592:     elsif($alt eq "proxy") {
                   2593:         $idnum = 2;
                   2594:     }
                   2595:     elsif($alt eq "unix") {
                   2596:         # IP (protocol) is mutually exclusive with Unix sockets
                   2597:         $ipvnum = "unix";
                   2598:     }
                   2599: 
                   2600:     return &responsiveserver($proto, $ipvnum, $idnum, $ip, $port_or_path);
                   2601: }
                   2602: 
                   2603: #######################################################################
                   2604: # Single shot pingpong server responsiveness test. This should only be
                   2605: # used to verify that a server present in %run hash is still functional
                   2606: #
                   2607: sub responsive_pingpong_server {
                   2608:     my ($proto, $id, $verbose, $ipv6) = @_;
                   2609:     my $port;
                   2610:     my $ip = ($ipv6 && ($ipv6 =~ /6$/)) ? "$HOST6IP" : "$HOSTIP";
                   2611:     my $ipvnum = ($ipv6 && ($ipv6 =~ /6$/)) ? 6 : 4;
                   2612:     my $idnum = ($id && ($id =~ /^(\d+)$/) && ($id > 1)) ? $id : 1;
                   2613: 
                   2614:     if($proto eq "ftp") {
                   2615:         $port = ($idnum>1)?$FTP2PORT:$FTPPORT;
                   2616: 
                   2617:         if($ipvnum==6) {
                   2618:             # if IPv6, use a different setup
                   2619:             $port = $FTP6PORT;
                   2620:         }
                   2621:     }
                   2622:     elsif($proto eq "pop3") {
                   2623:         $port = ($ipvnum==6) ? $POP36PORT : $POP3PORT;
                   2624:     }
                   2625:     elsif($proto eq "imap") {
                   2626:         $port = ($ipvnum==6) ? $IMAP6PORT : $IMAPPORT;
                   2627:     }
                   2628:     elsif($proto eq "smtp") {
                   2629:         $port = ($ipvnum==6) ? $SMTP6PORT : $SMTPPORT;
                   2630:     }
                   2631:     else {
                   2632:         print STDERR "Unsupported protocol $proto!!\n";
                   2633:         return 0;
                   2634:     }
                   2635: 
                   2636:     return &responsiveserver($proto, $ipvnum, $idnum, $ip, $port);
                   2637: }
                   2638: 
                   2639: #######################################################################
                   2640: # Single shot rtsp server responsiveness test. This should only be
                   2641: # used to verify that a server present in %run hash is still functional
                   2642: #
                   2643: sub responsive_rtsp_server {
                   2644:     my ($verbose, $ipv6) = @_;
                   2645:     my $port = $RTSPPORT;
                   2646:     my $ip = $HOSTIP;
                   2647:     my $proto = 'rtsp';
                   2648:     my $ipvnum = 4;
                   2649:     my $idnum = 1;
                   2650: 
                   2651:     if($ipv6) {
                   2652:         # if IPv6, use a different setup
                   2653:         $ipvnum = 6;
                   2654:         $port = $RTSP6PORT;
                   2655:         $ip = $HOST6IP;
                   2656:     }
                   2657: 
                   2658:     return &responsiveserver($proto, $ipvnum, $idnum, $ip, $port);
                   2659: }
                   2660: 
                   2661: #######################################################################
                   2662: # Single shot tftp server responsiveness test. This should only be
                   2663: # used to verify that a server present in %run hash is still functional
                   2664: #
                   2665: sub responsive_tftp_server {
                   2666:     my ($id, $verbose, $ipv6) = @_;
                   2667:     my $port = $TFTPPORT;
                   2668:     my $ip = $HOSTIP;
                   2669:     my $proto = 'tftp';
                   2670:     my $ipvnum = 4;
                   2671:     my $idnum = ($id && ($id =~ /^(\d+)$/) && ($id > 1)) ? $id : 1;
                   2672: 
                   2673:     if($ipv6) {
                   2674:         # if IPv6, use a different setup
                   2675:         $ipvnum = 6;
                   2676:         $port = $TFTP6PORT;
                   2677:         $ip = $HOST6IP;
                   2678:     }
                   2679: 
                   2680:     return &responsiveserver($proto, $ipvnum, $idnum, $ip, $port);
                   2681: }
                   2682: 
                   2683: #######################################################################
                   2684: # Single shot non-stunnel HTTP TLS extensions capable server
                   2685: # responsiveness test. This should only be used to verify that a
                   2686: # server present in %run hash is still functional
                   2687: #
                   2688: sub responsive_httptls_server {
                   2689:     my ($verbose, $ipv6) = @_;
                   2690:     my $proto = "httptls";
                   2691:     my $port = ($ipv6 && ($ipv6 =~ /6$/)) ? $HTTPTLS6PORT : $HTTPTLSPORT;
                   2692:     my $ip = ($ipv6 && ($ipv6 =~ /6$/)) ? "$HOST6IP" : "$HOSTIP";
                   2693:     my $ipvnum = ($ipv6 && ($ipv6 =~ /6$/)) ? 6 : 4;
                   2694:     my $idnum = 1;
                   2695: 
                   2696:     return &responsiveserver($proto, $ipvnum, $idnum, $ip, $port);
                   2697: }
                   2698: 
                   2699: #######################################################################
                   2700: # Remove all files in the specified directory
                   2701: #
                   2702: sub cleardir {
                   2703:     my $dir = $_[0];
                   2704:     my $count;
                   2705:     my $file;
                   2706: 
                   2707:     # Get all files
                   2708:     opendir(DIR, $dir) ||
                   2709:         return 0; # can't open dir
                   2710:     while($file = readdir(DIR)) {
                   2711:         if(($file !~ /^\./)) {
                   2712:             unlink("$dir/$file");
                   2713:             $count++;
                   2714:         }
                   2715:     }
                   2716:     closedir DIR;
                   2717:     return $count;
                   2718: }
                   2719: 
                   2720: #######################################################################
                   2721: # compare test results with the expected output, we might filter off
                   2722: # some pattern that is allowed to differ, output test results
                   2723: #
                   2724: sub compare {
                   2725:     my ($testnum, $testname, $subject, $firstref, $secondref)=@_;
                   2726: 
                   2727:     my $result = compareparts($firstref, $secondref);
                   2728: 
                   2729:     if($result) {
                   2730:         # timestamp test result verification end
                   2731:         $timevrfyend{$testnum} = Time::HiRes::time();
                   2732: 
                   2733:         if(!$short) {
                   2734:             logmsg "\n $testnum: $subject FAILED:\n";
                   2735:             logmsg showdiff($LOGDIR, $firstref, $secondref);
                   2736:         }
                   2737:         elsif(!$automakestyle) {
                   2738:             logmsg "FAILED\n";
                   2739:         }
                   2740:         else {
                   2741:             # automakestyle
                   2742:             logmsg "FAIL: $testnum - $testname - $subject\n";
                   2743:         }
                   2744:     }
                   2745:     return $result;
                   2746: }
                   2747: 
                   2748: sub setupfeatures {
                   2749:     $feature{"SSL"} = $has_ssl;
                   2750:     $feature{"MultiSSL"} = $has_multissl;
                   2751:     $feature{"SSLpinning"} = $has_sslpinning;
                   2752:     $feature{"OpenSSL"} = $has_openssl;
                   2753:     $feature{"GnuTLS"} = $has_gnutls;
                   2754:     $feature{"NSS"} = $has_nss;
                   2755:     $feature{"WinSSL"} = $has_winssl;
                   2756:     $feature{"Schannel"} = $has_winssl; # alias
                   2757:     $feature{"sectransp"} = $has_darwinssl;
                   2758:     $feature{"DarwinSSL"} = $has_darwinssl; # alias
                   2759:     $feature{"ld_preload"} = ($has_ldpreload && !$debug_build);
                   2760:     $feature{"unittest"} = $debug_build;
                   2761:     $feature{"debug"} = $debug_build;
                   2762:     $feature{"TrackMemory"} = $has_memory_tracking;
                   2763:     $feature{"large_file"} = $has_largefile;
                   2764:     $feature{"idn"} = $has_idn;
                   2765:     $feature{"ipv6"} = $has_ipv6;
                   2766:     $feature{"libz"} = $has_libz;
                   2767:     $feature{"brotli"} = $has_brotli;
                   2768:     $feature{"NTLM"} = $has_ntlm;
                   2769:     $feature{"NTLM_WB"} = $has_ntlm_wb;
                   2770:     $feature{"SSPI"} = $has_sspi;
                   2771:     $feature{"GSS-API"} = $has_gssapi;
                   2772:     $feature{"Kerberos"} = $has_kerberos;
                   2773:     $feature{"SPNEGO"} = $has_spnego;
                   2774:     $feature{"getrlimit"} = $has_getrlimit;
                   2775:     $feature{"crypto"} = $has_crypto;
                   2776:     $feature{"TLS-SRP"} = $has_tls_srp;
                   2777:     $feature{"Metalink"} = $has_metalink;
                   2778:     $feature{"http/2"} = $has_http2;
                   2779:     $feature{"threaded-resolver"} = $has_threadedres;
                   2780:     $feature{"PSL"} = $has_psl;
                   2781:     $feature{"alt-svc"} = $has_altsvc;
                   2782:     $feature{"manual"} = $has_manual;
                   2783:     $feature{"unix-sockets"} = $has_unix;
                   2784:     $feature{"win32"} = $has_win32;
                   2785:     $feature{"MinGW"} = $has_mingw;
                   2786: 
                   2787:     # make each protocol an enabled "feature"
                   2788:     for my $p (@protocols) {
                   2789:         $feature{$p} = 1;
                   2790:     }
                   2791:     # 'socks' was once here but is now removed
                   2792: 
                   2793:     #
                   2794:     # strings that must match the names used in server/disabled.c
                   2795:     #
                   2796:     $feature{"cookies"} = 1;
                   2797:     $feature{"DoH"} = 1;
                   2798:     $feature{"HTTP-auth"} = 1;
                   2799:     $feature{"Mime"} = 1;
                   2800:     $feature{"netrc"} = 1;
                   2801:     $feature{"parsedate"} = 1;
                   2802:     $feature{"proxy"} = 1;
                   2803:     $feature{"shuffle-dns"} = 1;
                   2804:     $feature{"typecheck"} = 1;
                   2805:     $feature{"verbose-strings"} = 1;
                   2806: 
                   2807: }
                   2808: 
                   2809: #######################################################################
                   2810: # display information about curl and the host the test suite runs on
                   2811: #
                   2812: sub checksystem {
                   2813: 
                   2814:     unlink($memdump); # remove this if there was one left
                   2815: 
                   2816:     my $feat;
                   2817:     my $curl;
                   2818:     my $libcurl;
                   2819:     my $versretval;
                   2820:     my $versnoexec;
                   2821:     my @version=();
                   2822:     my @disabled;
                   2823:     my $dis = "";
                   2824: 
                   2825:     my $curlverout="$LOGDIR/curlverout.log";
                   2826:     my $curlvererr="$LOGDIR/curlvererr.log";
                   2827:     my $versioncmd="$CURL --version 1>$curlverout 2>$curlvererr";
                   2828: 
                   2829:     unlink($curlverout);
                   2830:     unlink($curlvererr);
                   2831: 
                   2832:     $versretval = runclient($versioncmd);
                   2833:     $versnoexec = $!;
                   2834: 
                   2835:     open(VERSOUT, "<$curlverout");
                   2836:     @version = <VERSOUT>;
                   2837:     close(VERSOUT);
                   2838: 
                   2839:     open(DISABLED, "server/disabled".exe_ext('TOOL')."|");
                   2840:     @disabled = <DISABLED>;
                   2841:     close(DISABLED);
                   2842: 
                   2843:     if($disabled[0]) {
                   2844:         map s/[\r\n]//g, @disabled;
                   2845:         $dis = join(", ", @disabled);
                   2846:     }
                   2847: 
                   2848:     $resolver="stock";
                   2849:     for(@version) {
                   2850:         chomp;
                   2851: 
                   2852:         if($_ =~ /^curl/) {
                   2853:             $curl = $_;
                   2854:             $curl =~ s/^(.*)(libcurl.*)/$1/g;
                   2855: 
                   2856:             $libcurl = $2;
                   2857:             if($curl =~ /linux|bsd|solaris/) {
                   2858:                 $has_ldpreload = 1;
                   2859:             }
                   2860:             if($curl =~ /win32|Windows|mingw(32|64)/) {
                   2861:                 # This is a Windows MinGW build or native build, we need to use
                   2862:                 # Win32-style path.
                   2863:                 $pwd = pathhelp::sys_native_current_path();
                   2864:                 $has_textaware = 1;
                   2865:                 $has_win32 = 1;
                   2866:                 $has_mingw = 1 if ($curl =~ /-pc-mingw32/);
                   2867:             }
                   2868:            if ($libcurl =~ /(winssl|schannel)/i) {
                   2869:                $has_winssl=1;
                   2870:                $has_sslpinning=1;
                   2871:            }
                   2872:            elsif ($libcurl =~ /openssl/i) {
                   2873:                $has_openssl=1;
                   2874:                $has_sslpinning=1;
                   2875:            }
                   2876:            elsif ($libcurl =~ /gnutls/i) {
                   2877:                $has_gnutls=1;
                   2878:                $has_sslpinning=1;
                   2879:            }
                   2880:            elsif ($libcurl =~ /nss/i) {
                   2881:                $has_nss=1;
                   2882:                $has_sslpinning=1;
                   2883:            }
                   2884:            elsif ($libcurl =~ /wolfssl/i) {
                   2885:                $has_wolfssl=1;
                   2886:                $has_sslpinning=1;
                   2887:            }
                   2888:            elsif ($libcurl =~ /securetransport/i) {
                   2889:                $has_darwinssl=1;
                   2890:                $has_sslpinning=1;
                   2891:            }
                   2892:            elsif ($libcurl =~ /BoringSSL/i) {
                   2893:                $has_boringssl=1;
                   2894:                $has_sslpinning=1;
                   2895:            }
                   2896:            elsif ($libcurl =~ /libressl/i) {
                   2897:                $has_libressl=1;
                   2898:                $has_sslpinning=1;
                   2899:            }
                   2900:            elsif ($libcurl =~ /mbedTLS/i) {
                   2901:                $has_mbedtls=1;
                   2902:                $has_sslpinning=1;
                   2903:            }
                   2904:            if ($libcurl =~ /ares/i) {
                   2905:                $has_cares=1;
                   2906:                $resolver="c-ares";
                   2907:            }
                   2908:            if ($libcurl =~ /mesalink/i) {
                   2909:                $has_mesalink=1;
                   2910:            }
                   2911:         }
                   2912:         elsif($_ =~ /^Protocols: (.*)/i) {
                   2913:             # these are the protocols compiled in to this libcurl
                   2914:             @protocols = split(' ', lc($1));
                   2915: 
                   2916:             # Generate a "proto-ipv6" version of each protocol to match the
                   2917:             # IPv6 <server> name and a "proto-unix" to match the variant which
                   2918:             # uses Unix domain sockets. This works even if support isn't
                   2919:             # compiled in because the <features> test will fail.
                   2920:             push @protocols, map(("$_-ipv6", "$_-unix"), @protocols);
                   2921: 
                   2922:             # 'http-proxy' is used in test cases to do CONNECT through
                   2923:             push @protocols, 'http-proxy';
                   2924: 
                   2925:             # 'none' is used in test cases to mean no server
                   2926:             push @protocols, 'none';
                   2927:         }
                   2928:         elsif($_ =~ /^Features: (.*)/i) {
                   2929:             $feat = $1;
                   2930:             if($feat =~ /TrackMemory/i) {
                   2931:                 # built with memory tracking support (--enable-curldebug)
                   2932:                 $has_memory_tracking = 1;
                   2933:             }
                   2934:             if($feat =~ /debug/i) {
                   2935:                 # curl was built with --enable-debug
                   2936:                 $debug_build = 1;
                   2937:             }
                   2938:             if($feat =~ /SSL/i) {
                   2939:                 # ssl enabled
                   2940:                 $has_ssl=1;
                   2941:             }
                   2942:             if($feat =~ /MultiSSL/i) {
                   2943:                 # multiple ssl backends available.
                   2944:                 $has_multissl=1;
                   2945:             }
                   2946:             if($feat =~ /Largefile/i) {
                   2947:                 # large file support
                   2948:                 $has_largefile=1;
                   2949:             }
                   2950:             if($feat =~ /IDN/i) {
                   2951:                 # IDN support
                   2952:                 $has_idn=1;
                   2953:             }
                   2954:             if($feat =~ /IPv6/i) {
                   2955:                 $has_ipv6 = 1;
                   2956:             }
                   2957:             if($feat =~ /UnixSockets/i) {
                   2958:                 $has_unix = 1;
                   2959:             }
                   2960:             if($feat =~ /libz/i) {
                   2961:                 $has_libz = 1;
                   2962:             }
                   2963:             if($feat =~ /brotli/i) {
                   2964:                 $has_brotli = 1;
                   2965:             }
                   2966:             if($feat =~ /NTLM/i) {
                   2967:                 # NTLM enabled
                   2968:                 $has_ntlm=1;
                   2969: 
                   2970:                 # Use this as a proxy for any cryptographic authentication
                   2971:                 $has_crypto=1;
                   2972:             }
                   2973:             if($feat =~ /NTLM_WB/i) {
                   2974:                 # NTLM delegation to winbind daemon ntlm_auth helper enabled
                   2975:                 $has_ntlm_wb=1;
                   2976:             }
                   2977:             if($feat =~ /SSPI/i) {
                   2978:                 # SSPI enabled
                   2979:                 $has_sspi=1;
                   2980:             }
                   2981:             if($feat =~ /GSS-API/i) {
                   2982:                 # GSS-API enabled
                   2983:                 $has_gssapi=1;
                   2984:             }
                   2985:             if($feat =~ /Kerberos/i) {
                   2986:                 # Kerberos enabled
                   2987:                 $has_kerberos=1;
                   2988: 
                   2989:                 # Use this as a proxy for any cryptographic authentication
                   2990:                 $has_crypto=1;
                   2991:             }
                   2992:             if($feat =~ /SPNEGO/i) {
                   2993:                 # SPNEGO enabled
                   2994:                 $has_spnego=1;
                   2995: 
                   2996:                 # Use this as a proxy for any cryptographic authentication
                   2997:                 $has_crypto=1;
                   2998:             }
                   2999:             if($feat =~ /CharConv/i) {
                   3000:                 # CharConv enabled
                   3001:                 $has_charconv=1;
                   3002:             }
                   3003:             if($feat =~ /TLS-SRP/i) {
                   3004:                 # TLS-SRP enabled
                   3005:                 $has_tls_srp=1;
                   3006:             }
                   3007:             if($feat =~ /Metalink/i) {
                   3008:                 # Metalink enabled
                   3009:                 $has_metalink=1;
                   3010:             }
                   3011:             if($feat =~ /PSL/i) {
                   3012:                 # PSL enabled
                   3013:                 $has_psl=1;
                   3014:             }
                   3015:             if($feat =~ /alt-svc/i) {
                   3016:                 # alt-svc enabled
                   3017:                 $has_altsvc=1;
                   3018:             }
                   3019:             if($feat =~ /AsynchDNS/i) {
                   3020:                 if(!$has_cares) {
                   3021:                     # this means threaded resolver
                   3022:                     $has_threadedres=1;
                   3023:                     $resolver="threaded";
                   3024:                 }
                   3025:             }
                   3026:             if($feat =~ /HTTP2/) {
                   3027:                 # http2 enabled
                   3028:                 $has_http2=1;
                   3029: 
                   3030:                 push @protocols, 'http/2';
                   3031:             }
                   3032:         }
                   3033:         #
                   3034:         # Test harness currently uses a non-stunnel server in order to
                   3035:         # run HTTP TLS-SRP tests required when curl is built with https
                   3036:         # protocol support and TLS-SRP feature enabled. For convenience
                   3037:         # 'httptls' may be included in the test harness protocols array
                   3038:         # to differentiate this from classic stunnel based 'https' test
                   3039:         # harness server.
                   3040:         #
                   3041:         if($has_tls_srp) {
                   3042:             my $add_httptls;
                   3043:             for(@protocols) {
                   3044:                 if($_ =~ /^https(-ipv6|)$/) {
                   3045:                     $add_httptls=1;
                   3046:                     last;
                   3047:                 }
                   3048:             }
                   3049:             if($add_httptls && (! grep /^httptls$/, @protocols)) {
                   3050:                 push @protocols, 'httptls';
                   3051:                 push @protocols, 'httptls-ipv6';
                   3052:             }
                   3053:         }
                   3054:     }
                   3055:     if(!$curl) {
                   3056:         logmsg "unable to get curl's version, further details are:\n";
                   3057:         logmsg "issued command: \n";
                   3058:         logmsg "$versioncmd \n";
                   3059:         if ($versretval == -1) {
                   3060:             logmsg "command failed with: \n";
                   3061:             logmsg "$versnoexec \n";
                   3062:         }
                   3063:         elsif ($versretval & 127) {
                   3064:             logmsg sprintf("command died with signal %d, and %s coredump.\n",
                   3065:                            ($versretval & 127), ($versretval & 128)?"a":"no");
                   3066:         }
                   3067:         else {
                   3068:             logmsg sprintf("command exited with value %d \n", $versretval >> 8);
                   3069:         }
                   3070:         logmsg "contents of $curlverout: \n";
                   3071:         displaylogcontent("$curlverout");
                   3072:         logmsg "contents of $curlvererr: \n";
                   3073:         displaylogcontent("$curlvererr");
                   3074:         die "couldn't get curl's version";
                   3075:     }
                   3076: 
                   3077:     if(-r "../lib/curl_config.h") {
                   3078:         open(CONF, "<../lib/curl_config.h");
                   3079:         while(<CONF>) {
                   3080:             if($_ =~ /^\#define HAVE_GETRLIMIT/) {
                   3081:                 $has_getrlimit = 1;
                   3082:             }
                   3083:         }
                   3084:         close(CONF);
                   3085:     }
                   3086: 
                   3087:     if($has_ipv6) {
                   3088:         # client has IPv6 support
                   3089: 
                   3090:         # check if the HTTP server has it!
                   3091:         my $cmd = "server/sws".exe_ext('SRV')." --version";
                   3092:         my @sws = `$cmd`;
                   3093:         if($sws[0] =~ /IPv6/) {
                   3094:             # HTTP server has IPv6 support!
                   3095:             $http_ipv6 = 1;
                   3096:             $gopher_ipv6 = 1;
                   3097:         }
                   3098: 
                   3099:         # check if the FTP server has it!
                   3100:         $cmd = "server/sockfilt".exe_ext('SRV')." --version";
                   3101:         @sws = `$cmd`;
                   3102:         if($sws[0] =~ /IPv6/) {
                   3103:             # FTP server has IPv6 support!
                   3104:             $ftp_ipv6 = 1;
                   3105:         }
                   3106:     }
                   3107: 
                   3108:     if($has_unix) {
                   3109:         # client has Unix sockets support, check whether the HTTP server has it
                   3110:         my $cmd = "server/sws".exe_ext('SRV')." --version";
                   3111:         my @sws = `$cmd`;
                   3112:         $http_unix = 1 if($sws[0] =~ /unix/);
                   3113:     }
                   3114: 
                   3115:     if(!$has_memory_tracking && $torture) {
                   3116:         die "can't run torture tests since curl was built without ".
                   3117:             "TrackMemory feature (--enable-curldebug)";
                   3118:     }
                   3119: 
                   3120:     open(M, "$CURL -M 2>&1|");
                   3121:     while(my $s = <M>) {
                   3122:         if($s =~ /built-in manual was disabled at build-time/) {
                   3123:             $has_manual = 0;
                   3124:             last;
                   3125:         }
                   3126:         $has_manual = 1;
                   3127:         last;
                   3128:     }
                   3129:     close(M);
                   3130: 
                   3131:     $has_shared = `sh $CURLCONFIG --built-shared`;
                   3132:     chomp $has_shared;
                   3133: 
                   3134:     my $hostname=join(' ', runclientoutput("hostname"));
                   3135:     my $hosttype=join(' ', runclientoutput("uname -a"));
                   3136:     my $hostos=$^O;
                   3137: 
                   3138:     logmsg ("********* System characteristics ******** \n",
                   3139:             "* $curl\n",
                   3140:             "* $libcurl\n",
                   3141:             "* Features: $feat\n",
                   3142:             "* Disabled: $dis\n",
                   3143:             "* Host: $hostname",
                   3144:             "* System: $hosttype",
                   3145:             "* OS: $hostos\n");
                   3146: 
                   3147:     if($has_memory_tracking && $has_threadedres) {
                   3148:         $has_memory_tracking = 0;
                   3149:         logmsg("*\n",
                   3150:                "*** DISABLES memory tracking when using threaded resolver\n",
                   3151:                "*\n");
                   3152:     }
                   3153: 
                   3154:     logmsg sprintf("* Servers: %s", $stunnel?"SSL ":"");
                   3155:     logmsg sprintf("%s", $http_ipv6?"HTTP-IPv6 ":"");
                   3156:     logmsg sprintf("%s", $http_unix?"HTTP-unix ":"");
                   3157:     logmsg sprintf("%s\n", $ftp_ipv6?"FTP-IPv6 ":"");
                   3158: 
                   3159:     logmsg sprintf("* Env: %s%s", $valgrind?"Valgrind ":"",
                   3160:                    $run_event_based?"event-based ":"");
                   3161:     logmsg sprintf("%s\n", $libtool?"Libtool ":"");
                   3162:     logmsg ("* Seed: $randseed\n");
                   3163:     logmsg ("* Port range: $minport-$maxport\n");
                   3164: 
                   3165:     if($verbose) {
                   3166:         logmsg "* Ports: ";
                   3167:         if($stunnel) {
                   3168:             logmsg sprintf("FTPS/%d ", $FTPSPORT);
                   3169:             logmsg sprintf("HTTPS/%d ", $HTTPSPORT);
                   3170:         }
                   3171:         logmsg sprintf("\n*   SSH/%d ", $SSHPORT);
                   3172:         if($httptlssrv) {
                   3173:             logmsg sprintf("HTTPTLS/%d ", $HTTPTLSPORT);
                   3174:             if($has_ipv6) {
                   3175:                 logmsg sprintf("HTTPTLS-IPv6/%d ", $HTTPTLS6PORT);
                   3176:             }
                   3177:             logmsg "\n";
                   3178:         }
                   3179: 
                   3180:         if($has_unix) {
                   3181:             logmsg "* Unix socket paths:\n";
                   3182:             if($http_unix) {
                   3183:                 logmsg sprintf("*   HTTP-Unix:%s\n", $HTTPUNIXPATH);
                   3184:             }
                   3185:         }
                   3186:     }
                   3187: 
                   3188:     logmsg "***************************************** \n";
                   3189: 
                   3190:     setupfeatures();
                   3191:     # toggle off the features that were disabled in the build
                   3192:     for my $d(@disabled) {
                   3193:         $feature{$d} = 0;
                   3194:     }
                   3195: }
                   3196: 
                   3197: #######################################################################
                   3198: # substitute the variable stuff into either a joined up file or
                   3199: # a command, in either case passed by reference
                   3200: #
                   3201: sub subVariables {
                   3202:     my ($thing, $prefix) = @_;
                   3203: 
                   3204:     if(!$prefix) {
                   3205:         $prefix = "%";
                   3206:     }
                   3207: 
                   3208:     # test server ports
                   3209:     $$thing =~ s/${prefix}FTP6PORT/$FTP6PORT/g;
                   3210:     $$thing =~ s/${prefix}FTP2PORT/$FTP2PORT/g;
                   3211:     $$thing =~ s/${prefix}FTPSPORT/$FTPSPORT/g;
                   3212:     $$thing =~ s/${prefix}FTPPORT/$FTPPORT/g;
                   3213:     $$thing =~ s/${prefix}GOPHER6PORT/$GOPHER6PORT/g;
                   3214:     $$thing =~ s/${prefix}GOPHERPORT/$GOPHERPORT/g;
                   3215:     $$thing =~ s/${prefix}HTTPTLS6PORT/$HTTPTLS6PORT/g;
                   3216:     $$thing =~ s/${prefix}HTTPTLSPORT/$HTTPTLSPORT/g;
                   3217:     $$thing =~ s/${prefix}HTTP6PORT/$HTTP6PORT/g;
                   3218:     $$thing =~ s/${prefix}HTTPSPORT/$HTTPSPORT/g;
                   3219:     $$thing =~ s/${prefix}HTTP2PORT/$HTTP2PORT/g;
                   3220:     $$thing =~ s/${prefix}HTTPPORT/$HTTPPORT/g;
                   3221:     $$thing =~ s/${prefix}PROXYPORT/$HTTPPROXYPORT/g;
                   3222:     $$thing =~ s/${prefix}MQTTPORT/$MQTTPORT/g;
                   3223:     $$thing =~ s/${prefix}IMAP6PORT/$IMAP6PORT/g;
                   3224:     $$thing =~ s/${prefix}IMAPPORT/$IMAPPORT/g;
                   3225:     $$thing =~ s/${prefix}POP36PORT/$POP36PORT/g;
                   3226:     $$thing =~ s/${prefix}POP3PORT/$POP3PORT/g;
                   3227:     $$thing =~ s/${prefix}RTSP6PORT/$RTSP6PORT/g;
                   3228:     $$thing =~ s/${prefix}RTSPPORT/$RTSPPORT/g;
                   3229:     $$thing =~ s/${prefix}SMTP6PORT/$SMTP6PORT/g;
                   3230:     $$thing =~ s/${prefix}SMTPPORT/$SMTPPORT/g;
                   3231:     $$thing =~ s/${prefix}SOCKSPORT/$SOCKSPORT/g;
                   3232:     $$thing =~ s/${prefix}SSHPORT/$SSHPORT/g;
                   3233:     $$thing =~ s/${prefix}TFTP6PORT/$TFTP6PORT/g;
                   3234:     $$thing =~ s/${prefix}TFTPPORT/$TFTPPORT/g;
                   3235:     $$thing =~ s/${prefix}DICTPORT/$DICTPORT/g;
                   3236:     $$thing =~ s/${prefix}SMBPORT/$SMBPORT/g;
                   3237:     $$thing =~ s/${prefix}SMBSPORT/$SMBSPORT/g;
                   3238:     $$thing =~ s/${prefix}NEGTELNETPORT/$NEGTELNETPORT/g;
                   3239:     $$thing =~ s/${prefix}NOLISTENPORT/$NOLISTENPORT/g;
                   3240: 
                   3241:     # server Unix domain socket paths
                   3242:     $$thing =~ s/${prefix}HTTPUNIXPATH/$HTTPUNIXPATH/g;
                   3243: 
                   3244:     # client IP addresses
                   3245:     $$thing =~ s/${prefix}CLIENT6IP/$CLIENT6IP/g;
                   3246:     $$thing =~ s/${prefix}CLIENTIP/$CLIENTIP/g;
                   3247: 
                   3248:     # server IP addresses
                   3249:     $$thing =~ s/${prefix}HOST6IP/$HOST6IP/g;
                   3250:     $$thing =~ s/${prefix}HOSTIP/$HOSTIP/g;
                   3251: 
                   3252:     # misc
                   3253:     $$thing =~ s/${prefix}CURL/$CURL/g;
                   3254:     $$thing =~ s/${prefix}PWD/$pwd/g;
                   3255:     $$thing =~ s/${prefix}POSIX_PWD/$posix_pwd/g;
                   3256: 
                   3257:     my $file_pwd = $pwd;
                   3258:     if($file_pwd !~ /^\//) {
                   3259:         $file_pwd = "/$file_pwd";
                   3260:     }
                   3261: 
                   3262:     $$thing =~ s/${prefix}FILE_PWD/$file_pwd/g;
                   3263:     $$thing =~ s/${prefix}SRCDIR/$srcdir/g;
                   3264:     $$thing =~ s/${prefix}USER/$USER/g;
                   3265: 
                   3266:     $$thing =~ s/${prefix}SSHSRVMD5/$SSHSRVMD5/g;
                   3267: 
                   3268:     # The purpose of FTPTIME2 and FTPTIME3 is to provide times that can be
                   3269:     # used for time-out tests and that would work on most hosts as these
                   3270:     # adjust for the startup/check time for this particular host. We needed to
                   3271:     # do this to make the test suite run better on very slow hosts.
                   3272:     my $ftp2 = $ftpchecktime * 2;
                   3273:     my $ftp3 = $ftpchecktime * 3;
                   3274: 
                   3275:     $$thing =~ s/${prefix}FTPTIME2/$ftp2/g;
                   3276:     $$thing =~ s/${prefix}FTPTIME3/$ftp3/g;
                   3277: 
                   3278:     # HTTP2
                   3279:     $$thing =~ s/${prefix}H2CVER/$h2cver/g;
                   3280: }
                   3281: 
                   3282: sub fixarray {
                   3283:     my @in = @_;
                   3284: 
                   3285:     for(@in) {
                   3286:         subVariables(\$_);
                   3287:     }
                   3288:     return @in;
                   3289: }
                   3290: 
                   3291: #######################################################################
                   3292: # Provide time stamps for single test skipped events
                   3293: #
                   3294: sub timestampskippedevents {
                   3295:     my $testnum = $_[0];
                   3296: 
                   3297:     return if((not defined($testnum)) || ($testnum < 1));
                   3298: 
                   3299:     if($timestats) {
                   3300: 
                   3301:         if($timevrfyend{$testnum}) {
                   3302:             return;
                   3303:         }
                   3304:         elsif($timesrvrlog{$testnum}) {
                   3305:             $timevrfyend{$testnum} = $timesrvrlog{$testnum};
                   3306:             return;
                   3307:         }
                   3308:         elsif($timetoolend{$testnum}) {
                   3309:             $timevrfyend{$testnum} = $timetoolend{$testnum};
                   3310:             $timesrvrlog{$testnum} = $timetoolend{$testnum};
                   3311:         }
                   3312:         elsif($timetoolini{$testnum}) {
                   3313:             $timevrfyend{$testnum} = $timetoolini{$testnum};
                   3314:             $timesrvrlog{$testnum} = $timetoolini{$testnum};
                   3315:             $timetoolend{$testnum} = $timetoolini{$testnum};
                   3316:         }
                   3317:         elsif($timesrvrend{$testnum}) {
                   3318:             $timevrfyend{$testnum} = $timesrvrend{$testnum};
                   3319:             $timesrvrlog{$testnum} = $timesrvrend{$testnum};
                   3320:             $timetoolend{$testnum} = $timesrvrend{$testnum};
                   3321:             $timetoolini{$testnum} = $timesrvrend{$testnum};
                   3322:         }
                   3323:         elsif($timesrvrini{$testnum}) {
                   3324:             $timevrfyend{$testnum} = $timesrvrini{$testnum};
                   3325:             $timesrvrlog{$testnum} = $timesrvrini{$testnum};
                   3326:             $timetoolend{$testnum} = $timesrvrini{$testnum};
                   3327:             $timetoolini{$testnum} = $timesrvrini{$testnum};
                   3328:             $timesrvrend{$testnum} = $timesrvrini{$testnum};
                   3329:         }
                   3330:         elsif($timeprepini{$testnum}) {
                   3331:             $timevrfyend{$testnum} = $timeprepini{$testnum};
                   3332:             $timesrvrlog{$testnum} = $timeprepini{$testnum};
                   3333:             $timetoolend{$testnum} = $timeprepini{$testnum};
                   3334:             $timetoolini{$testnum} = $timeprepini{$testnum};
                   3335:             $timesrvrend{$testnum} = $timeprepini{$testnum};
                   3336:             $timesrvrini{$testnum} = $timeprepini{$testnum};
                   3337:         }
                   3338:     }
                   3339: }
                   3340: 
                   3341: #######################################################################
                   3342: # Run a single specified test case
                   3343: #
                   3344: sub singletest {
                   3345:     my ($evbased, # 1 means switch on if possible (and "curl" is tested)
                   3346:                   # returns "not a test" if it can't be used for this test
                   3347:         $testnum,
                   3348:         $count,
                   3349:         $total)=@_;
                   3350: 
                   3351:     my @what;
                   3352:     my $why;
                   3353:     my $cmd;
                   3354:     my $disablevalgrind;
                   3355:     my $errorreturncode = 1; # 1 means normal error, 2 means ignored error
                   3356: 
                   3357:     # fist, remove all lingering log files
                   3358:     cleardir($LOGDIR);
                   3359: 
                   3360:     # copy test number to a global scope var, this allows
                   3361:     # testnum checking when starting test harness servers.
                   3362:     $testnumcheck = $testnum;
                   3363: 
                   3364:     # timestamp test preparation start
                   3365:     $timeprepini{$testnum} = Time::HiRes::time();
                   3366: 
                   3367:     if($disttests !~ /test$testnum\W/ ) {
                   3368:         logmsg "Warning: test$testnum not present in tests/data/Makefile.inc\n";
                   3369:     }
                   3370:     if($disabled{$testnum}) {
                   3371:         logmsg "Warning: test$testnum is explicitly disabled\n";
                   3372:     }
                   3373:     if($ignored{$testnum}) {
                   3374:         logmsg "Warning: test$testnum result is ignored\n";
                   3375:         $errorreturncode = 2;
                   3376:     }
                   3377: 
                   3378:     # load the test case file definition
                   3379:     if(loadtest("${TESTDIR}/test${testnum}")) {
                   3380:         if($verbose) {
                   3381:             # this is not a test
                   3382:             logmsg "RUN: $testnum doesn't look like a test case\n";
                   3383:         }
                   3384:         $why = "no test";
                   3385:     }
                   3386:     else {
                   3387:         @what = getpart("client", "features");
                   3388:     }
                   3389: 
                   3390:     # We require a feature to be present
                   3391:     for(@what) {
                   3392:         my $f = $_;
                   3393:         $f =~ s/\s//g;
                   3394: 
                   3395:         if($f =~ /^([^!].*)$/) {
                   3396:             if($feature{$1}) {
                   3397:                 next;
                   3398:             }
                   3399: 
                   3400:             $why = "curl lacks $1 support";
                   3401:             last;
                   3402:         }
                   3403:     }
                   3404: 
                   3405:     # We require a feature to not be present
                   3406:     if(!$why) {
                   3407:         for(@what) {
                   3408:             my $f = $_;
                   3409:             $f =~ s/\s//g;
                   3410: 
                   3411:             if($f =~ /^!(.*)$/) {
                   3412:                 if(!$feature{$1}) {
                   3413:                     next;
                   3414:                 }
                   3415:             }
                   3416:             else {
                   3417:                 next;
                   3418:             }
                   3419: 
                   3420:             $why = "curl has $1 support";
                   3421:             last;
                   3422:         }
                   3423:     }
                   3424: 
                   3425:     if(!$why) {
                   3426:         my @info_keywords = getpart("info", "keywords");
                   3427:         my $match;
                   3428:         my $k;
                   3429: 
                   3430:         # Clear the list of keywords from the last test
                   3431:         %keywords = ();
                   3432: 
                   3433:         if(!$info_keywords[0]) {
                   3434:             $why = "missing the <keywords> section!";
                   3435:         }
                   3436: 
                   3437:         for $k (@info_keywords) {
                   3438:             chomp $k;
                   3439:             if ($disabled_keywords{lc($k)}) {
                   3440:                 $why = "disabled by keyword";
                   3441:             } elsif ($enabled_keywords{lc($k)}) {
                   3442:                 $match = 1;
                   3443:             }
                   3444:             if ($ignored_keywords{lc($k)}) {
                   3445:                 logmsg "Warning: test$testnum result is ignored due to $k\n";
                   3446:                 $errorreturncode = 2;
                   3447:             }
                   3448: 
                   3449:             $keywords{$k} = 1;
                   3450:         }
                   3451: 
                   3452:         if(!$why && !$match && %enabled_keywords) {
                   3453:             $why = "disabled by missing keyword";
                   3454:         }
                   3455:     }
                   3456: 
                   3457:     # test definition may instruct to (un)set environment vars
                   3458:     # this is done this early, so that the precheck can use environment
                   3459:     # variables and still bail out fine on errors
                   3460: 
                   3461:     # restore environment variables that were modified in a previous run
                   3462:     foreach my $var (keys %oldenv) {
                   3463:         if($oldenv{$var} eq 'notset') {
                   3464:             delete $ENV{$var} if($ENV{$var});
                   3465:         }
                   3466:         else {
                   3467:             $ENV{$var} = $oldenv{$var};
                   3468:         }
                   3469:         delete $oldenv{$var};
                   3470:     }
                   3471: 
                   3472:     # get the name of the test early
                   3473:     my @testname= getpart("client", "name");
                   3474:     my $testname = $testname[0];
                   3475:     $testname =~ s/\n//g;
                   3476: 
                   3477:     # create test result in CI services
                   3478:     if(azure_check_environment() && $AZURE_RUN_ID) {
                   3479:         $AZURE_RESULT_ID = azure_create_test_result($AZURE_RUN_ID, $testnum, $testname);
                   3480:     }
                   3481:     elsif(appveyor_check_environment()) {
                   3482:         appveyor_create_test_result($testnum, $testname);
                   3483:     }
                   3484: 
                   3485:     # remove test server commands file before servers are started/verified
                   3486:     unlink($FTPDCMD) if(-f $FTPDCMD);
                   3487: 
                   3488:     # timestamp required servers verification start
                   3489:     $timesrvrini{$testnum} = Time::HiRes::time();
                   3490: 
                   3491:     if(!$why) {
                   3492:         $why = serverfortest($testnum);
                   3493:     }
                   3494: 
                   3495:     # Save a preprocessed version of the entire test file. This allows more
                   3496:     # "basic" test case readers to enjoy variable replacements.
                   3497:     my @entiretest = fulltest();
                   3498:     my $otest = "log/test$testnum";
                   3499:     open(D, ">$otest");
                   3500:     my $diff;
                   3501:     for my $s (@entiretest) {
                   3502:         my $f = $s;
                   3503:         subVariables(\$s, "%");
                   3504:         if($f ne $s) {
                   3505:             $diff++;
                   3506:         }
                   3507:         print D $s;
                   3508:     }
                   3509:     close(D);
                   3510:     # remove the separate test file again if nothing was updated to keep
                   3511:     # things simpler
                   3512:     unlink($otest) if(!$diff);
                   3513: 
                   3514:     # timestamp required servers verification end
                   3515:     $timesrvrend{$testnum} = Time::HiRes::time();
                   3516: 
                   3517:     my @setenv = getpart("client", "setenv");
                   3518:     if(@setenv) {
                   3519:         foreach my $s (@setenv) {
                   3520:             chomp $s;
                   3521:             subVariables(\$s);
                   3522:             if($s =~ /([^=]*)=(.*)/) {
                   3523:                 my ($var, $content) = ($1, $2);
                   3524:                 # remember current setting, to restore it once test runs
                   3525:                 $oldenv{$var} = ($ENV{$var})?"$ENV{$var}":'notset';
                   3526:                 # set new value
                   3527:                 if(!$content) {
                   3528:                     delete $ENV{$var} if($ENV{$var});
                   3529:                 }
                   3530:                 else {
                   3531:                     if($var =~ /^LD_PRELOAD/) {
                   3532:                         if(exe_ext('TOOL') && (exe_ext('TOOL') eq '.exe')) {
                   3533:                             # print "Skipping LD_PRELOAD due to lack of OS support\n";
                   3534:                             next;
                   3535:                         }
                   3536:                         if($debug_build || ($has_shared ne "yes")) {
                   3537:                             # print "Skipping LD_PRELOAD due to no release shared build\n";
                   3538:                             next;
                   3539:                         }
                   3540:                     }
                   3541:                     $ENV{$var} = "$content";
                   3542:                     print "setenv $var = $content\n" if($verbose);
                   3543:                 }
                   3544:             }
                   3545:         }
                   3546:     }
                   3547: 
                   3548:     if(!$why) {
                   3549:         my @precheck = getpart("client", "precheck");
                   3550:         if(@precheck) {
                   3551:             $cmd = $precheck[0];
                   3552:             chomp $cmd;
                   3553:             subVariables(\$cmd);
                   3554:             if($cmd) {
                   3555:                 my @p = split(/ /, $cmd);
                   3556:                 if($p[0] !~ /\//) {
                   3557:                     # the first word, the command, does not contain a slash so
                   3558:                     # we will scan the "improved" PATH to find the command to
                   3559:                     # be able to run it
                   3560:                     my $fullp = checktestcmd($p[0]);
                   3561: 
                   3562:                     if($fullp) {
                   3563:                         $p[0] = $fullp;
                   3564:                     }
                   3565:                     $cmd = join(" ", @p);
                   3566:                 }
                   3567: 
                   3568:                 my @o = `$cmd 2>/dev/null`;
                   3569:                 if($o[0]) {
                   3570:                     $why = $o[0];
                   3571:                     chomp $why;
                   3572:                 } elsif($?) {
                   3573:                     $why = "precheck command error";
                   3574:                 }
                   3575:                 logmsg "prechecked $cmd\n" if($verbose);
                   3576:             }
                   3577:         }
                   3578:     }
                   3579: 
                   3580:     if($why && !$listonly) {
                   3581:         # there's a problem, count it as "skipped"
                   3582:         $skipped++;
                   3583:         $skipped{$why}++;
                   3584:         $teststat[$testnum]=$why; # store reason for this test case
                   3585: 
                   3586:         if(!$short) {
                   3587:             if($skipped{$why} <= 3) {
                   3588:                 # show only the first three skips for each reason
                   3589:                 logmsg sprintf("test %04d SKIPPED: $why\n", $testnum);
                   3590:             }
                   3591:         }
                   3592: 
                   3593:         timestampskippedevents($testnum);
                   3594:         return -1;
                   3595:     }
                   3596:     logmsg sprintf("test %04d...", $testnum) if(!$automakestyle);
                   3597: 
                   3598:     my %replyattr = getpartattr("reply", "data");
                   3599:     my @reply;
                   3600:     if (partexists("reply", "datacheck")) {
                   3601:         for my $partsuffix (('', '1', '2', '3', '4')) {
                   3602:             my @replycheckpart = getpart("reply", "datacheck".$partsuffix);
                   3603:             if(@replycheckpart) {
                   3604:                 my %replycheckpartattr = getpartattr("reply", "datacheck".$partsuffix);
                   3605:                 # get the mode attribute
                   3606:                 my $filemode=$replycheckpartattr{'mode'};
                   3607:                 if($filemode && ($filemode eq "text") && $has_textaware) {
                   3608:                     # text mode when running on windows: fix line endings
                   3609:                     map s/\r\n/\n/g, @replycheckpart;
                   3610:                     map s/\n/\r\n/g, @replycheckpart;
                   3611:                 }
                   3612:                 if($replycheckpartattr{'nonewline'}) {
                   3613:                     # Yes, we must cut off the final newline from the final line
                   3614:                     # of the datacheck
                   3615:                     chomp($replycheckpart[$#replycheckpart]);
                   3616:                 }
                   3617:                 push(@reply, @replycheckpart);
                   3618:             }
                   3619:         }
                   3620:     }
                   3621:     else {
                   3622:         # check against the data section
                   3623:         @reply = getpart("reply", "data");
                   3624:         # get the mode attribute
                   3625:         my $filemode=$replyattr{'mode'};
                   3626:         if($filemode && ($filemode eq "text") && $has_textaware) {
                   3627:             # text mode when running on windows: fix line endings
                   3628:             map s/\r\n/\n/g, @reply;
                   3629:             map s/\n/\r\n/g, @reply;
                   3630:         }
                   3631:     }
                   3632:     for my $r (@reply) {
                   3633:         subVariables(\$r);
                   3634:     }
                   3635: 
                   3636:     # this is the valid protocol blurb curl should generate
                   3637:     my @protocol= fixarray ( getpart("verify", "protocol") );
                   3638: 
                   3639:     # this is the valid protocol blurb curl should generate to a proxy
                   3640:     my @proxyprot = fixarray ( getpart("verify", "proxy") );
                   3641: 
                   3642:     # redirected stdout/stderr to these files
                   3643:     $STDOUT="$LOGDIR/stdout$testnum";
                   3644:     $STDERR="$LOGDIR/stderr$testnum";
                   3645: 
                   3646:     # if this section exists, we verify that the stdout contained this:
                   3647:     my @validstdout = fixarray ( getpart("verify", "stdout") );
                   3648:     my @validstderr = fixarray ( getpart("verify", "stderr") );
                   3649: 
                   3650:     # if this section exists, we verify upload
                   3651:     my @upload = getpart("verify", "upload");
                   3652:     if(@upload) {
                   3653:       my %hash = getpartattr("verify", "upload");
                   3654:       if($hash{'nonewline'}) {
                   3655:           # cut off the final newline from the final line of the upload data
                   3656:           chomp($upload[$#upload]);
                   3657:       }
                   3658:     }
                   3659: 
                   3660:     # if this section exists, it might be FTP server instructions:
                   3661:     my @ftpservercmd = fixarray ( getpart("reply", "servercmd") );
                   3662: 
                   3663:     my $CURLOUT="$LOGDIR/curl$testnum.out"; # curl output if not stdout
                   3664: 
                   3665:     # name of the test
                   3666:     logmsg "[$testname]\n" if(!$short);
                   3667: 
                   3668:     if($listonly) {
                   3669:         timestampskippedevents($testnum);
                   3670:         return 0; # look successful
                   3671:     }
                   3672: 
                   3673:     my @codepieces = getpart("client", "tool");
                   3674: 
                   3675:     my $tool="";
                   3676:     if(@codepieces) {
                   3677:         $tool = $codepieces[0];
                   3678:         chomp $tool;
                   3679:         $tool .= exe_ext('TOOL');
                   3680:     }
                   3681: 
                   3682:     # remove server output logfile
                   3683:     unlink($SERVERIN);
                   3684:     unlink($SERVER2IN);
                   3685:     unlink($PROXYIN);
                   3686: 
                   3687:     push @ftpservercmd, "Testnum $testnum\n";
                   3688:     # write the instructions to file
                   3689:     writearray($FTPDCMD, \@ftpservercmd);
                   3690: 
                   3691:     # get the command line options to use
                   3692:     my @blaha;
                   3693:     ($cmd, @blaha)= getpart("client", "command");
                   3694: 
                   3695:     if($cmd) {
                   3696:         # make some nice replace operations
                   3697:         $cmd =~ s/\n//g; # no newlines please
                   3698:         # substitute variables in the command line
                   3699:         subVariables(\$cmd);
                   3700:     }
                   3701:     else {
                   3702:         # there was no command given, use something silly
                   3703:         $cmd="-";
                   3704:     }
                   3705:     if($has_memory_tracking) {
                   3706:         unlink($memdump);
                   3707:     }
                   3708: 
                   3709:     # create (possibly-empty) files before starting the test
                   3710:     for my $partsuffix (('', '1', '2', '3', '4')) {
                   3711:         my @inputfile=getpart("client", "file".$partsuffix);
                   3712:         my %fileattr = getpartattr("client", "file".$partsuffix);
                   3713:         my $filename=$fileattr{'name'};
                   3714:         if(@inputfile || $filename) {
                   3715:             if(!$filename) {
                   3716:                 logmsg "ERROR: section client=>file has no name attribute\n";
                   3717:                 timestampskippedevents($testnum);
                   3718:                 return -1;
                   3719:             }
                   3720:             my $fileContent = join('', @inputfile);
                   3721:             subVariables \$fileContent;
                   3722: #            logmsg "DEBUG: writing file " . $filename . "\n";
                   3723:             open(OUTFILE, ">$filename");
                   3724:             binmode OUTFILE; # for crapage systems, use binary
                   3725:             print OUTFILE $fileContent;
                   3726:             close(OUTFILE);
                   3727:         }
                   3728:     }
                   3729: 
                   3730:     my %cmdhash = getpartattr("client", "command");
                   3731: 
                   3732:     my $out="";
                   3733: 
                   3734:     if((!$cmdhash{'option'}) || ($cmdhash{'option'} !~ /no-output/)) {
                   3735:         #We may slap on --output!
                   3736:         if (!@validstdout ||
                   3737:                 ($cmdhash{'option'} && $cmdhash{'option'} =~ /force-output/)) {
                   3738:             $out=" --output $CURLOUT ";
                   3739:         }
                   3740:     }
                   3741: 
                   3742:     my $serverlogslocktimeout = $defserverlogslocktimeout;
                   3743:     if($cmdhash{'timeout'}) {
                   3744:         # test is allowed to override default server logs lock timeout
                   3745:         if($cmdhash{'timeout'} =~ /(\d+)/) {
                   3746:             $serverlogslocktimeout = $1 if($1 >= 0);
                   3747:         }
                   3748:     }
                   3749: 
                   3750:     my $postcommanddelay = $defpostcommanddelay;
                   3751:     if($cmdhash{'delay'}) {
                   3752:         # test is allowed to specify a delay after command is executed
                   3753:         if($cmdhash{'delay'} =~ /(\d+)/) {
                   3754:             $postcommanddelay = $1 if($1 > 0);
                   3755:         }
                   3756:     }
                   3757: 
                   3758:     my $CMDLINE;
                   3759:     my $cmdargs;
                   3760:     my $cmdtype = $cmdhash{'type'} || "default";
                   3761:     my $fail_due_event_based = $evbased;
                   3762:     if($cmdtype eq "perl") {
                   3763:         # run the command line prepended with "perl"
                   3764:         $cmdargs ="$cmd";
                   3765:         $CMDLINE = "$perl ";
                   3766:         $tool=$CMDLINE;
                   3767:         $disablevalgrind=1;
                   3768:     }
                   3769:     elsif($cmdtype eq "shell") {
                   3770:         # run the command line prepended with "/bin/sh"
                   3771:         $cmdargs ="$cmd";
                   3772:         $CMDLINE = "/bin/sh ";
                   3773:         $tool=$CMDLINE;
                   3774:         $disablevalgrind=1;
                   3775:     }
                   3776:     elsif(!$tool && !$keywords{"unittest"}) {
                   3777:         # run curl, add suitable command line options
                   3778:         my $inc="";
                   3779:         if((!$cmdhash{'option'}) || ($cmdhash{'option'} !~ /no-include/)) {
                   3780:             $inc = " --include";
                   3781:         }
                   3782:         $cmdargs = "$out$inc ";
                   3783: 
                   3784:         if($cmdhash{'option'} && ($cmdhash{'option'} =~ /binary-trace/)) {
                   3785:             $cmdargs .= "--trace log/trace$testnum ";
                   3786:         }
                   3787:         else {
                   3788:             $cmdargs .= "--trace-ascii log/trace$testnum ";
                   3789:         }
                   3790:         $cmdargs .= "--trace-time ";
                   3791:         if($evbased) {
                   3792:             $cmdargs .= "--test-event ";
                   3793:             $fail_due_event_based--;
                   3794:         }
                   3795:         $cmdargs .= $cmd;
                   3796:     }
                   3797:     else {
                   3798:         $cmdargs = " $cmd"; # $cmd is the command line for the test file
                   3799:         $CURLOUT = $STDOUT; # sends received data to stdout
                   3800: 
                   3801:         # Default the tool to a unit test with the same name as the test spec
                   3802:         if($keywords{"unittest"} && !$tool) {
                   3803:             $tool="unit$testnum";
                   3804:         }
                   3805: 
                   3806:         if($tool =~ /^lib/) {
                   3807:             $CMDLINE="$LIBDIR/$tool";
                   3808:         }
                   3809:         elsif($tool =~ /^unit/) {
                   3810:             $CMDLINE="$UNITDIR/$tool";
                   3811:         }
                   3812: 
                   3813:         if(! -f $CMDLINE) {
                   3814:             logmsg "The tool set in the test case for this: '$tool' does not exist\n";
                   3815:             timestampskippedevents($testnum);
                   3816:             return -1;
                   3817:         }
                   3818:         $DBGCURL=$CMDLINE;
                   3819:     }
                   3820: 
                   3821:     if($gdbthis) {
                   3822:         # gdb is incompatible with valgrind, so disable it when debugging
                   3823:         # Perhaps a better approach would be to run it under valgrind anyway
                   3824:         # with --db-attach=yes or --vgdb=yes.
                   3825:         $disablevalgrind=1;
                   3826:     }
                   3827: 
                   3828:     if($fail_due_event_based) {
                   3829:         logmsg "This test cannot run event based\n";
                   3830:         return -1;
                   3831:     }
                   3832: 
                   3833:     my @stdintest = getpart("client", "stdin");
                   3834: 
                   3835:     if(@stdintest) {
                   3836:         my $stdinfile="$LOGDIR/stdin-for-$testnum";
                   3837: 
                   3838:         my %hash = getpartattr("client", "stdin");
                   3839:         if($hash{'nonewline'}) {
                   3840:             # cut off the final newline from the final line of the stdin data
                   3841:             chomp($stdintest[$#stdintest]);
                   3842:         }
                   3843: 
                   3844:         writearray($stdinfile, \@stdintest);
                   3845: 
                   3846:         $cmdargs .= " <$stdinfile";
                   3847:     }
                   3848: 
                   3849:     if(!$tool) {
                   3850:         $CMDLINE="$CURL";
                   3851:     }
                   3852: 
                   3853:     my $usevalgrind;
                   3854:     if($valgrind && !$disablevalgrind) {
                   3855:         my @valgrindoption = getpart("verify", "valgrind");
                   3856:         if((!@valgrindoption) || ($valgrindoption[0] !~ /disable/)) {
                   3857:             $usevalgrind = 1;
                   3858:             my $valgrindcmd = "$valgrind ";
                   3859:             $valgrindcmd .= "$valgrind_tool " if($valgrind_tool);
                   3860:             $valgrindcmd .= "--quiet --leak-check=yes ";
                   3861:             $valgrindcmd .= "--suppressions=$srcdir/valgrind.supp ";
                   3862:            # $valgrindcmd .= "--gen-suppressions=all ";
                   3863:             $valgrindcmd .= "--num-callers=16 ";
                   3864:             $valgrindcmd .= "${valgrind_logfile}=$LOGDIR/valgrind$testnum";
                   3865:             $CMDLINE = "$valgrindcmd $CMDLINE";
                   3866:         }
                   3867:     }
                   3868: 
                   3869:     $CMDLINE .= "$cmdargs >$STDOUT 2>$STDERR";
                   3870: 
                   3871:     if($verbose) {
                   3872:         logmsg "$CMDLINE\n";
                   3873:     }
                   3874: 
                   3875:     open(CMDLOG, ">", "$LOGDIR/$CURLLOG");
                   3876:     print CMDLOG "$CMDLINE\n";
                   3877:     close(CMDLOG);
                   3878: 
                   3879:     unlink("core");
                   3880: 
                   3881:     my $dumped_core;
                   3882:     my $cmdres;
                   3883: 
                   3884:     if($gdbthis) {
                   3885:         my $gdbinit = "$TESTDIR/gdbinit$testnum";
                   3886:         open(GDBCMD, ">$LOGDIR/gdbcmd");
                   3887:         print GDBCMD "set args $cmdargs\n";
                   3888:         print GDBCMD "show args\n";
                   3889:         print GDBCMD "source $gdbinit\n" if -e $gdbinit;
                   3890:         close(GDBCMD);
                   3891:     }
                   3892: 
                   3893:     # timestamp starting of test command
                   3894:     $timetoolini{$testnum} = Time::HiRes::time();
                   3895: 
                   3896:     # run the command line we built
                   3897:     if ($torture) {
                   3898:         $cmdres = torture($CMDLINE,
                   3899:                           $testnum,
                   3900:                           "$gdb --directory libtest $DBGCURL -x $LOGDIR/gdbcmd");
                   3901:     }
                   3902:     elsif($gdbthis) {
                   3903:         my $GDBW = ($gdbxwin) ? "-w" : "";
                   3904:         runclient("$gdb --directory libtest $DBGCURL $GDBW -x $LOGDIR/gdbcmd");
                   3905:         $cmdres=0; # makes it always continue after a debugged run
                   3906:     }
                   3907:     else {
                   3908:         $cmdres = runclient("$CMDLINE");
                   3909:         my $signal_num  = $cmdres & 127;
                   3910:         $dumped_core = $cmdres & 128;
                   3911: 
                   3912:         if(!$anyway && ($signal_num || $dumped_core)) {
                   3913:             $cmdres = 1000;
                   3914:         }
                   3915:         else {
                   3916:             $cmdres >>= 8;
                   3917:             $cmdres = (2000 + $signal_num) if($signal_num && !$cmdres);
                   3918:         }
                   3919:     }
                   3920: 
                   3921:     # timestamp finishing of test command
                   3922:     $timetoolend{$testnum} = Time::HiRes::time();
                   3923: 
                   3924:     if(!$dumped_core) {
                   3925:         if(-r "core") {
                   3926:             # there's core file present now!
                   3927:             $dumped_core = 1;
                   3928:         }
                   3929:     }
                   3930: 
                   3931:     if($dumped_core) {
                   3932:         logmsg "core dumped\n";
                   3933:         if(0 && $gdb) {
                   3934:             logmsg "running gdb for post-mortem analysis:\n";
                   3935:             open(GDBCMD, ">$LOGDIR/gdbcmd2");
                   3936:             print GDBCMD "bt\n";
                   3937:             close(GDBCMD);
                   3938:             runclient("$gdb --directory libtest -x $LOGDIR/gdbcmd2 -batch $DBGCURL core ");
                   3939:      #       unlink("$LOGDIR/gdbcmd2");
                   3940:         }
                   3941:     }
                   3942: 
                   3943:     # If a server logs advisor read lock file exists, it is an indication
                   3944:     # that the server has not yet finished writing out all its log files,
                   3945:     # including server request log files used for protocol verification.
                   3946:     # So, if the lock file exists the script waits here a certain amount
                   3947:     # of time until the server removes it, or the given time expires.
                   3948: 
                   3949:     if($serverlogslocktimeout) {
                   3950:         my $lockretry = $serverlogslocktimeout * 20;
                   3951:         while((-f $SERVERLOGS_LOCK) && $lockretry--) {
                   3952:             portable_sleep(0.05);
                   3953:         }
                   3954:         if(($lockretry < 0) &&
                   3955:            ($serverlogslocktimeout >= $defserverlogslocktimeout)) {
                   3956:             logmsg "Warning: server logs lock timeout ",
                   3957:                    "($serverlogslocktimeout seconds) expired\n";
                   3958:         }
                   3959:     }
                   3960: 
                   3961:     # Test harness ssh server does not have this synchronization mechanism,
                   3962:     # this implies that some ssh server based tests might need a small delay
                   3963:     # once that the client command has run to avoid false test failures.
                   3964:     #
                   3965:     # gnutls-serv also lacks this synchronization mechanism, so gnutls-serv
                   3966:     # based tests might need a small delay once that the client command has
                   3967:     # run to avoid false test failures.
                   3968: 
                   3969:     portable_sleep($postcommanddelay) if($postcommanddelay);
                   3970: 
                   3971:     # timestamp removal of server logs advisor read lock
                   3972:     $timesrvrlog{$testnum} = Time::HiRes::time();
                   3973: 
                   3974:     # test definition might instruct to stop some servers
                   3975:     # stop also all servers relative to the given one
                   3976: 
                   3977:     my @killtestservers = getpart("client", "killserver");
                   3978:     if(@killtestservers) {
                   3979:         foreach my $server (@killtestservers) {
                   3980:             chomp $server;
                   3981:             stopserver($server);
                   3982:         }
                   3983:     }
                   3984: 
                   3985:     # run the postcheck command
                   3986:     my @postcheck= getpart("client", "postcheck");
                   3987:     if(@postcheck) {
                   3988:         $cmd = join("", @postcheck);
                   3989:         chomp $cmd;
                   3990:         subVariables \$cmd;
                   3991:         if($cmd) {
                   3992:             logmsg "postcheck $cmd\n" if($verbose);
                   3993:             my $rc = runclient("$cmd");
                   3994:             # Must run the postcheck command in torture mode in order
                   3995:             # to clean up, but the result can't be relied upon.
                   3996:             if($rc != 0 && !$torture) {
                   3997:                 logmsg " postcheck FAILED\n";
                   3998:                 # timestamp test result verification end
                   3999:                 $timevrfyend{$testnum} = Time::HiRes::time();
                   4000:                 return $errorreturncode;
                   4001:             }
                   4002:         }
                   4003:     }
                   4004: 
                   4005:     # restore environment variables that were modified
                   4006:     if(%oldenv) {
                   4007:         foreach my $var (keys %oldenv) {
                   4008:             if($oldenv{$var} eq 'notset') {
                   4009:                 delete $ENV{$var} if($ENV{$var});
                   4010:             }
                   4011:             else {
                   4012:                 $ENV{$var} = "$oldenv{$var}";
                   4013:             }
                   4014:         }
                   4015:     }
                   4016: 
                   4017:     # Skip all the verification on torture tests
                   4018:     if ($torture) {
                   4019:         # timestamp test result verification end
                   4020:         $timevrfyend{$testnum} = Time::HiRes::time();
                   4021:         return $cmdres;
                   4022:     }
                   4023: 
                   4024:     my @err = getpart("verify", "errorcode");
                   4025:     my $errorcode = $err[0] || "0";
                   4026:     my $ok="";
                   4027:     my $res;
                   4028:     chomp $errorcode;
                   4029:     if (@validstdout) {
                   4030:         # verify redirected stdout
                   4031:         my @actual = loadarray($STDOUT);
                   4032: 
                   4033:         # what parts to cut off from stdout
                   4034:         my @stripfile = getpart("verify", "stripfile");
                   4035: 
                   4036:         foreach my $strip (@stripfile) {
                   4037:             chomp $strip;
                   4038:             my @newgen;
                   4039:             for(@actual) {
                   4040:                 eval $strip;
                   4041:                 if($_) {
                   4042:                     push @newgen, $_;
                   4043:                 }
                   4044:             }
                   4045:             # this is to get rid of array entries that vanished (zero
                   4046:             # length) because of replacements
                   4047:             @actual = @newgen;
                   4048:         }
                   4049: 
                   4050:         # variable-replace in the stdout we have from the test case file
                   4051:         @validstdout = fixarray(@validstdout);
                   4052: 
                   4053:         # get all attributes
                   4054:         my %hash = getpartattr("verify", "stdout");
                   4055: 
                   4056:         # get the mode attribute
                   4057:         my $filemode=$hash{'mode'};
                   4058:         if($filemode && ($filemode eq "text") && $has_textaware) {
                   4059:             # text mode when running on windows: fix line endings
                   4060:             map s/\r\n/\n/g, @validstdout;
                   4061:             map s/\n/\r\n/g, @validstdout;
                   4062:         }
                   4063: 
                   4064:         if($hash{'nonewline'}) {
                   4065:             # Yes, we must cut off the final newline from the final line
                   4066:             # of the protocol data
                   4067:             chomp($validstdout[$#validstdout]);
                   4068:         }
                   4069: 
                   4070:         $res = compare($testnum, $testname, "stdout", \@actual, \@validstdout);
                   4071:         if($res) {
                   4072:             return $errorreturncode;
                   4073:         }
                   4074:         $ok .= "s";
                   4075:     }
                   4076:     else {
                   4077:         $ok .= "-"; # stdout not checked
                   4078:     }
                   4079: 
                   4080:     if (@validstderr) {
                   4081:         # verify redirected stderr
                   4082:         my @actual = loadarray($STDERR);
                   4083: 
                   4084:         # what parts to cut off from stderr
                   4085:         my @stripfile = getpart("verify", "stripfile");
                   4086: 
                   4087:         foreach my $strip (@stripfile) {
                   4088:             chomp $strip;
                   4089:             my @newgen;
                   4090:             for(@actual) {
                   4091:                 eval $strip;
                   4092:                 if($_) {
                   4093:                     push @newgen, $_;
                   4094:                 }
                   4095:             }
                   4096:             # this is to get rid of array entries that vanished (zero
                   4097:             # length) because of replacements
                   4098:             @actual = @newgen;
                   4099:         }
                   4100: 
                   4101:         # variable-replace in the stderr we have from the test case file
                   4102:         @validstderr = fixarray(@validstderr);
                   4103: 
                   4104:         # get all attributes
                   4105:         my %hash = getpartattr("verify", "stderr");
                   4106: 
                   4107:         # get the mode attribute
                   4108:         my $filemode=$hash{'mode'};
                   4109:         if($filemode && ($filemode eq "text") && $has_textaware) {
                   4110:             # text mode when running on windows: fix line endings
                   4111:             map s/\r\n/\n/g, @validstderr;
                   4112:             map s/\n/\r\n/g, @validstderr;
                   4113:         }
                   4114: 
                   4115:         if($hash{'nonewline'}) {
                   4116:             # Yes, we must cut off the final newline from the final line
                   4117:             # of the protocol data
                   4118:             chomp($validstderr[$#validstderr]);
                   4119:         }
                   4120: 
                   4121:         $res = compare($testnum, $testname, "stderr", \@actual, \@validstderr);
                   4122:         if($res) {
                   4123:             return $errorreturncode;
                   4124:         }
                   4125:         $ok .= "r";
                   4126:     }
                   4127:     else {
                   4128:         $ok .= "-"; # stderr not checked
                   4129:     }
                   4130: 
                   4131:     if(@protocol) {
                   4132:         # Verify the sent request
                   4133:         my @out = loadarray($SERVERIN);
                   4134: 
                   4135:         # what to cut off from the live protocol sent by curl
                   4136:         my @strip = getpart("verify", "strip");
                   4137: 
                   4138:         my @protstrip=@protocol;
                   4139: 
                   4140:         # check if there's any attributes on the verify/protocol section
                   4141:         my %hash = getpartattr("verify", "protocol");
                   4142: 
                   4143:         if($hash{'nonewline'}) {
                   4144:             # Yes, we must cut off the final newline from the final line
                   4145:             # of the protocol data
                   4146:             chomp($protstrip[$#protstrip]);
                   4147:         }
                   4148: 
                   4149:         for(@strip) {
                   4150:             # strip off all lines that match the patterns from both arrays
                   4151:             chomp $_;
                   4152:             @out = striparray( $_, \@out);
                   4153:             @protstrip= striparray( $_, \@protstrip);
                   4154:         }
                   4155: 
                   4156:         # what parts to cut off from the protocol
                   4157:         my @strippart = getpart("verify", "strippart");
                   4158:         my $strip;
                   4159:         @strippart = fixarray(@strippart);
                   4160:         for $strip (@strippart) {
                   4161:             chomp $strip;
                   4162:             for(@out) {
                   4163:                 eval $strip;
                   4164:             }
                   4165:         }
                   4166: 
                   4167:         if((!$out[0] || ($out[0] eq "")) && $protstrip[0]) {
                   4168:             logmsg "\n $testnum: protocol FAILED!\n".
                   4169:                 " There was no content at all in the file $SERVERIN.\n".
                   4170:                 " Server glitch? Total curl failure? Returned: $cmdres\n";
                   4171:             return $errorreturncode;
                   4172:         }
                   4173: 
                   4174:         $res = compare($testnum, $testname, "protocol", \@out, \@protstrip);
                   4175:         if($res) {
                   4176:             return $errorreturncode;
                   4177:         }
                   4178: 
                   4179:         $ok .= "p";
                   4180: 
                   4181:     }
                   4182:     else {
                   4183:         $ok .= "-"; # protocol not checked
                   4184:     }
                   4185: 
                   4186:     if(!$replyattr{'nocheck'} && (@reply || $replyattr{'sendzero'})) {
                   4187:         # verify the received data
                   4188:         my @out = loadarray($CURLOUT);
                   4189:         $res = compare($testnum, $testname, "data", \@out, \@reply);
                   4190:         if ($res) {
                   4191:             return $errorreturncode;
                   4192:         }
                   4193:         $ok .= "d";
                   4194:     }
                   4195:     else {
                   4196:         $ok .= "-"; # data not checked
                   4197:     }
                   4198: 
                   4199:     if(@upload) {
                   4200:         # verify uploaded data
                   4201:         my @out = loadarray("$LOGDIR/upload.$testnum");
                   4202: 
                   4203:         # what parts to cut off from the upload
                   4204:         my @strippart = getpart("verify", "strippart");
                   4205:         my $strip;
                   4206:         for $strip (@strippart) {
                   4207:             chomp $strip;
                   4208:             for(@out) {
                   4209:                 eval $strip;
                   4210:             }
                   4211:         }
                   4212: 
                   4213:         $res = compare($testnum, $testname, "upload", \@out, \@upload);
                   4214:         if ($res) {
                   4215:             return $errorreturncode;
                   4216:         }
                   4217:         $ok .= "u";
                   4218:     }
                   4219:     else {
                   4220:         $ok .= "-"; # upload not checked
                   4221:     }
                   4222: 
                   4223:     if(@proxyprot) {
                   4224:         # Verify the sent proxy request
                   4225:         my @out = loadarray($PROXYIN);
                   4226: 
                   4227:         # what to cut off from the live protocol sent by curl, we use the
                   4228:         # same rules as for <protocol>
                   4229:         my @strip = getpart("verify", "strip");
                   4230: 
                   4231:         my @protstrip=@proxyprot;
                   4232: 
                   4233:         # check if there's any attributes on the verify/protocol section
                   4234:         my %hash = getpartattr("verify", "proxy");
                   4235: 
                   4236:         if($hash{'nonewline'}) {
                   4237:             # Yes, we must cut off the final newline from the final line
                   4238:             # of the protocol data
                   4239:             chomp($protstrip[$#protstrip]);
                   4240:         }
                   4241: 
                   4242:         for(@strip) {
                   4243:             # strip off all lines that match the patterns from both arrays
                   4244:             chomp $_;
                   4245:             @out = striparray( $_, \@out);
                   4246:             @protstrip= striparray( $_, \@protstrip);
                   4247:         }
                   4248: 
                   4249:         # what parts to cut off from the protocol
                   4250:         my @strippart = getpart("verify", "strippart");
                   4251:         my $strip;
                   4252:         for $strip (@strippart) {
                   4253:             chomp $strip;
                   4254:             for(@out) {
                   4255:                 eval $strip;
                   4256:             }
                   4257:         }
                   4258: 
                   4259:         $res = compare($testnum, $testname, "proxy", \@out, \@protstrip);
                   4260:         if($res) {
                   4261:             return $errorreturncode;
                   4262:         }
                   4263: 
                   4264:         $ok .= "P";
                   4265: 
                   4266:     }
                   4267:     else {
                   4268:         $ok .= "-"; # protocol not checked
                   4269:     }
                   4270: 
                   4271:     my $outputok;
                   4272:     for my $partsuffix (('', '1', '2', '3', '4')) {
                   4273:         my @outfile=getpart("verify", "file".$partsuffix);
                   4274:         if(@outfile || partexists("verify", "file".$partsuffix) ) {
                   4275:             # we're supposed to verify a dynamically generated file!
                   4276:             my %hash = getpartattr("verify", "file".$partsuffix);
                   4277: 
                   4278:             my $filename=$hash{'name'};
                   4279:             if(!$filename) {
                   4280:                 logmsg "ERROR: section verify=>file$partsuffix ".
                   4281:                        "has no name attribute\n";
                   4282:                 stopservers($verbose);
                   4283:                 # timestamp test result verification end
                   4284:                 $timevrfyend{$testnum} = Time::HiRes::time();
                   4285:                 return -1;
                   4286:             }
                   4287:             my @generated=loadarray($filename);
                   4288: 
                   4289:             # what parts to cut off from the file
                   4290:             my @stripfile = getpart("verify", "stripfile".$partsuffix);
                   4291: 
                   4292:             my $filemode=$hash{'mode'};
                   4293:             if($filemode && ($filemode eq "text") && $has_textaware) {
                   4294:                 # text mode when running on windows: fix line endings
                   4295:                 map s/\r\n/\n/g, @outfile;
                   4296:                 map s/\n/\r\n/g, @outfile;
                   4297:             }
                   4298: 
                   4299:             my $strip;
                   4300:             for $strip (@stripfile) {
                   4301:                 chomp $strip;
                   4302:                 my @newgen;
                   4303:                 for(@generated) {
                   4304:                     eval $strip;
                   4305:                     if($_) {
                   4306:                         push @newgen, $_;
                   4307:                     }
                   4308:                 }
                   4309:                 # this is to get rid of array entries that vanished (zero
                   4310:                 # length) because of replacements
                   4311:                 @generated = @newgen;
                   4312:             }
                   4313: 
                   4314:             @outfile = fixarray(@outfile);
                   4315: 
                   4316:             $res = compare($testnum, $testname, "output ($filename)",
                   4317:                            \@generated, \@outfile);
                   4318:             if($res) {
                   4319:                 return $errorreturncode;
                   4320:             }
                   4321: 
                   4322:             $outputok = 1; # output checked
                   4323:         }
                   4324:     }
                   4325:     $ok .= ($outputok) ? "o" : "-"; # output checked or not
                   4326: 
                   4327:     # accept multiple comma-separated error codes
                   4328:     my @splerr = split(/ *, */, $errorcode);
                   4329:     my $errok;
                   4330:     foreach my $e (@splerr) {
                   4331:         if($e == $cmdres) {
                   4332:             # a fine error code
                   4333:             $errok = 1;
                   4334:             last;
                   4335:         }
                   4336:     }
                   4337: 
                   4338:     if($errok) {
                   4339:         $ok .= "e";
                   4340:     }
                   4341:     else {
                   4342:         if(!$short) {
                   4343:             logmsg sprintf("\n%s returned $cmdres, when expecting %s\n",
                   4344:                            (!$tool)?"curl":$tool, $errorcode);
                   4345:         }
                   4346:         logmsg " exit FAILED\n";
                   4347:         # timestamp test result verification end
                   4348:         $timevrfyend{$testnum} = Time::HiRes::time();
                   4349:         return $errorreturncode;
                   4350:     }
                   4351: 
                   4352:     if($has_memory_tracking) {
                   4353:         if(! -f $memdump) {
                   4354:             logmsg "\n** ALERT! memory tracking with no output file?\n"
                   4355:                 if(!$cmdtype eq "perl");
                   4356:         }
                   4357:         else {
                   4358:             my @memdata=`$memanalyze $memdump`;
                   4359:             my $leak=0;
                   4360:             for(@memdata) {
                   4361:                 if($_ ne "") {
                   4362:                     # well it could be other memory problems as well, but
                   4363:                     # we call it leak for short here
                   4364:                     $leak=1;
                   4365:                 }
                   4366:             }
                   4367:             if($leak) {
                   4368:                 logmsg "\n** MEMORY FAILURE\n";
                   4369:                 logmsg @memdata;
                   4370:                 # timestamp test result verification end
                   4371:                 $timevrfyend{$testnum} = Time::HiRes::time();
                   4372:                 return $errorreturncode;
                   4373:             }
                   4374:             else {
                   4375:                 $ok .= "m";
                   4376:             }
                   4377:         }
                   4378:     }
                   4379:     else {
                   4380:         $ok .= "-"; # memory not checked
                   4381:     }
                   4382: 
                   4383:     if($valgrind) {
                   4384:         if($usevalgrind) {
                   4385:             unless(opendir(DIR, "$LOGDIR")) {
                   4386:                 logmsg "ERROR: unable to read $LOGDIR\n";
                   4387:                 # timestamp test result verification end
                   4388:                 $timevrfyend{$testnum} = Time::HiRes::time();
                   4389:                 return $errorreturncode;
                   4390:             }
                   4391:             my @files = readdir(DIR);
                   4392:             closedir(DIR);
                   4393:             my $vgfile;
                   4394:             foreach my $file (@files) {
                   4395:                 if($file =~ /^valgrind$testnum(\..*|)$/) {
                   4396:                     $vgfile = $file;
                   4397:                     last;
                   4398:                 }
                   4399:             }
                   4400:             if(!$vgfile) {
                   4401:                 logmsg "ERROR: valgrind log file missing for test $testnum\n";
                   4402:                 # timestamp test result verification end
                   4403:                 $timevrfyend{$testnum} = Time::HiRes::time();
                   4404:                 return $errorreturncode;
                   4405:             }
                   4406:             my @e = valgrindparse("$LOGDIR/$vgfile");
                   4407:             if(@e && $e[0]) {
                   4408:                 if($automakestyle) {
                   4409:                     logmsg "FAIL: $testnum - $testname - valgrind\n";
                   4410:                 }
                   4411:                 else {
                   4412:                     logmsg " valgrind ERROR ";
                   4413:                     logmsg @e;
                   4414:                 }
                   4415:                 # timestamp test result verification end
                   4416:                 $timevrfyend{$testnum} = Time::HiRes::time();
                   4417:                 return $errorreturncode;
                   4418:             }
                   4419:             $ok .= "v";
                   4420:         }
                   4421:         else {
                   4422:             if($verbose && !$disablevalgrind) {
                   4423:                 logmsg " valgrind SKIPPED\n";
                   4424:             }
                   4425:             $ok .= "-"; # skipped
                   4426:         }
                   4427:     }
                   4428:     else {
                   4429:         $ok .= "-"; # valgrind not checked
                   4430:     }
                   4431:     # add 'E' for event-based
                   4432:     $ok .= $evbased ? "E" : "-";
                   4433: 
                   4434:     logmsg "$ok " if(!$short);
                   4435: 
                   4436:     # timestamp test result verification end
                   4437:     $timevrfyend{$testnum} = Time::HiRes::time();
                   4438: 
                   4439:     my $sofar= time()-$start;
                   4440:     my $esttotal = $sofar/$count * $total;
                   4441:     my $estleft = $esttotal - $sofar;
                   4442:     my $left=sprintf("remaining: %02d:%02d",
                   4443:                      $estleft/60,
                   4444:                      $estleft%60);
                   4445:     my $took = $timevrfyend{$testnum} - $timeprepini{$testnum};
                   4446:     my $duration = sprintf("duration: %02d:%02d",
                   4447:                            $sofar/60, $sofar%60);
                   4448:     if(!$automakestyle) {
                   4449:         logmsg sprintf("OK (%-3d out of %-3d, %s, took %.1fs, %s)\n",
                   4450:                        $count, $total, $left, $took, $duration);
                   4451:     }
                   4452:     else {
                   4453:         logmsg "PASS: $testnum - $testname\n";
                   4454:     }
                   4455: 
                   4456:     if($errorreturncode==2) {
                   4457:         logmsg "Warning: test$testnum result is ignored, but passed!\n";
                   4458:     }
                   4459: 
                   4460:     return 0;
                   4461: }
                   4462: 
                   4463: #######################################################################
                   4464: # Stop all running test servers
                   4465: #
                   4466: sub stopservers {
                   4467:     my $verbose = $_[0];
                   4468:     #
                   4469:     # kill sockfilter processes for all pingpong servers
                   4470:     #
                   4471:     killallsockfilters($verbose);
                   4472:     #
                   4473:     # kill all server pids from %run hash clearing them
                   4474:     #
                   4475:     my $pidlist;
                   4476:     foreach my $server (keys %run) {
                   4477:         if($run{$server}) {
                   4478:             if($verbose) {
                   4479:                 my $prev = 0;
                   4480:                 my $pids = $run{$server};
                   4481:                 foreach my $pid (split(' ', $pids)) {
                   4482:                     if($pid != $prev) {
                   4483:                         logmsg sprintf("* kill pid for %s => %d\n",
                   4484:                             $server, $pid);
                   4485:                         $prev = $pid;
                   4486:                     }
                   4487:                 }
                   4488:             }
                   4489:             $pidlist .= "$run{$server} ";
                   4490:             $run{$server} = 0;
                   4491:         }
                   4492:         $runcert{$server} = 0 if($runcert{$server});
                   4493:     }
                   4494:     killpid($verbose, $pidlist);
                   4495:     #
                   4496:     # cleanup all server pid files
                   4497:     #
                   4498:     foreach my $server (keys %serverpidfile) {
                   4499:         my $pidfile = $serverpidfile{$server};
                   4500:         my $pid = processexists($pidfile);
                   4501:         if($pid > 0) {
                   4502:             logmsg "Warning: $server server unexpectedly alive\n";
                   4503:             killpid($verbose, $pid);
                   4504:         }
                   4505:         unlink($pidfile) if(-f $pidfile);
                   4506:     }
                   4507: }
                   4508: 
                   4509: #######################################################################
                   4510: # startservers() starts all the named servers
                   4511: #
                   4512: # Returns: string with error reason or blank for success
                   4513: #
                   4514: sub startservers {
                   4515:     my @what = @_;
                   4516:     my ($pid, $pid2);
                   4517:     for(@what) {
                   4518:         my (@whatlist) = split(/\s+/,$_);
                   4519:         my $what = lc($whatlist[0]);
                   4520:         $what =~ s/[^a-z0-9\/-]//g;
                   4521: 
                   4522:         my $certfile;
                   4523:         if($what =~ /^(ftp|http|imap|pop3|smtp)s((\d*)(-ipv6|-unix|))$/) {
                   4524:             $certfile = ($whatlist[1]) ? $whatlist[1] : 'stunnel.pem';
                   4525:         }
                   4526: 
                   4527:         if(($what eq "pop3") ||
                   4528:            ($what eq "ftp") ||
                   4529:            ($what eq "imap") ||
                   4530:            ($what eq "smtp")) {
                   4531:             if($torture && $run{$what} &&
                   4532:                !responsive_pingpong_server($what, "", $verbose)) {
                   4533:                 stopserver($what);
                   4534:             }
                   4535:             if(!$run{$what}) {
                   4536:                 ($pid, $pid2) = runpingpongserver($what, "", $verbose);
                   4537:                 if($pid <= 0) {
                   4538:                     return "failed starting ". uc($what) ." server";
                   4539:                 }
                   4540:                 printf ("* pid $what => %d %d\n", $pid, $pid2) if($verbose);
                   4541:                 $run{$what}="$pid $pid2";
                   4542:             }
                   4543:         }
                   4544:         elsif($what eq "ftp2") {
                   4545:             if($torture && $run{'ftp2'} &&
                   4546:                !responsive_pingpong_server("ftp", "2", $verbose)) {
                   4547:                 stopserver('ftp2');
                   4548:             }
                   4549:             if(!$run{'ftp2'}) {
                   4550:                 ($pid, $pid2) = runpingpongserver("ftp", "2", $verbose);
                   4551:                 if($pid <= 0) {
                   4552:                     return "failed starting FTP2 server";
                   4553:                 }
                   4554:                 printf ("* pid ftp2 => %d %d\n", $pid, $pid2) if($verbose);
                   4555:                 $run{'ftp2'}="$pid $pid2";
                   4556:             }
                   4557:         }
                   4558:         elsif($what eq "ftp-ipv6") {
                   4559:             if($torture && $run{'ftp-ipv6'} &&
                   4560:                !responsive_pingpong_server("ftp", "", $verbose, "ipv6")) {
                   4561:                 stopserver('ftp-ipv6');
                   4562:             }
                   4563:             if(!$run{'ftp-ipv6'}) {
                   4564:                 ($pid, $pid2) = runpingpongserver("ftp", "", $verbose, "ipv6");
                   4565:                 if($pid <= 0) {
                   4566:                     return "failed starting FTP-IPv6 server";
                   4567:                 }
                   4568:                 logmsg sprintf("* pid ftp-ipv6 => %d %d\n", $pid,
                   4569:                        $pid2) if($verbose);
                   4570:                 $run{'ftp-ipv6'}="$pid $pid2";
                   4571:             }
                   4572:         }
                   4573:         elsif($what eq "gopher") {
                   4574:             if($torture && $run{'gopher'} &&
                   4575:                !responsive_http_server("gopher", $verbose, 0, $GOPHERPORT)) {
                   4576:                 stopserver('gopher');
                   4577:             }
                   4578:             if(!$run{'gopher'}) {
                   4579:                 ($pid, $pid2, $GOPHERPORT) =
                   4580:                     runhttpserver("gopher", $verbose, 0);
                   4581:                 if($pid <= 0) {
                   4582:                     return "failed starting GOPHER server";
                   4583:                 }
                   4584:                 logmsg sprintf ("* pid gopher => %d %d\n", $pid, $pid2)
                   4585:                     if($verbose);
                   4586:                 $run{'gopher'}="$pid $pid2";
                   4587:             }
                   4588:         }
                   4589:         elsif($what eq "gopher-ipv6") {
                   4590:             if($torture && $run{'gopher-ipv6'} &&
                   4591:                !responsive_http_server("gopher", $verbose, "ipv6",
                   4592:                                        $GOPHER6PORT)) {
                   4593:                 stopserver('gopher-ipv6');
                   4594:             }
                   4595:             if(!$run{'gopher-ipv6'}) {
                   4596:                 ($pid, $pid2, $GOPHER6PORT) =
                   4597:                     runhttpserver("gopher", $verbose, "ipv6");
                   4598:                 if($pid <= 0) {
                   4599:                     return "failed starting GOPHER-IPv6 server";
                   4600:                 }
                   4601:                 logmsg sprintf("* pid gopher-ipv6 => %d %d\n", $pid,
                   4602:                                $pid2) if($verbose);
                   4603:                 $run{'gopher-ipv6'}="$pid $pid2";
                   4604:             }
                   4605:         }
                   4606:         elsif($what eq "http/2") {
                   4607:             if(!$run{'http/2'}) {
                   4608:                 ($pid, $pid2) = runhttp2server($verbose, $HTTP2PORT);
                   4609:                 if($pid <= 0) {
                   4610:                     return "failed starting HTTP/2 server";
                   4611:                 }
                   4612:                 logmsg sprintf ("* pid http/2 => %d %d\n", $pid, $pid2)
                   4613:                     if($verbose);
                   4614:                 $run{'http/2'}="$pid $pid2";
                   4615:             }
                   4616:         }
                   4617:         elsif($what eq "http") {
                   4618:             if($torture && $run{'http'} &&
                   4619:                !responsive_http_server("http", $verbose, 0, $HTTPPORT)) {
                   4620:                 stopserver('http');
                   4621:             }
                   4622:             if(!$run{'http'}) {
                   4623:                 ($pid, $pid2, $HTTPPORT) =
                   4624:                     runhttpserver("http", $verbose, 0);
                   4625:                 if($pid <= 0) {
                   4626:                     return "failed starting HTTP server";
                   4627:                 }
                   4628:                 logmsg sprintf ("* pid http => %d %d\n", $pid, $pid2)
                   4629:                     if($verbose);
                   4630:                 $run{'http'}="$pid $pid2";
                   4631:             }
                   4632:         }
                   4633:         elsif($what eq "http-proxy") {
                   4634:             if($torture && $run{'http-proxy'} &&
                   4635:                !responsive_http_server("http", $verbose, "proxy",
                   4636:                                        $HTTPPROXYPORT)) {
                   4637:                 stopserver('http-proxy');
                   4638:             }
                   4639:             if(!$run{'http-proxy'}) {
                   4640:                 ($pid, $pid2, $HTTPPROXYPORT) =
                   4641:                     runhttpserver("http", $verbose, "proxy");
                   4642:                 if($pid <= 0) {
                   4643:                     return "failed starting HTTP-proxy server";
                   4644:                 }
                   4645:                 logmsg sprintf ("* pid http-proxy => %d %d\n", $pid, $pid2)
                   4646:                     if($verbose);
                   4647:                 $run{'http-proxy'}="$pid $pid2";
                   4648:             }
                   4649:         }
                   4650:         elsif($what eq "http-ipv6") {
                   4651:             if($torture && $run{'http-ipv6'} &&
                   4652:                !responsive_http_server("http", $verbose, "ipv6", $HTTP6PORT)) {
                   4653:                 stopserver('http-ipv6');
                   4654:             }
                   4655:             if(!$run{'http-ipv6'}) {
                   4656:                 ($pid, $pid2, $HTTP6PORT) =
                   4657:                     runhttpserver("http", $verbose, "ipv6");
                   4658:                 if($pid <= 0) {
                   4659:                     return "failed starting HTTP-IPv6 server";
                   4660:                 }
                   4661:                 logmsg sprintf("* pid http-ipv6 => %d %d\n", $pid, $pid2)
                   4662:                     if($verbose);
                   4663:                 $run{'http-ipv6'}="$pid $pid2";
                   4664:             }
                   4665:         }
                   4666:         elsif($what eq "rtsp") {
                   4667:             if($torture && $run{'rtsp'} &&
                   4668:                !responsive_rtsp_server($verbose)) {
                   4669:                 stopserver('rtsp');
                   4670:             }
                   4671:             if(!$run{'rtsp'}) {
                   4672:                 ($pid, $pid2, $RTSPPORT) = runrtspserver($verbose);
                   4673:                 if($pid <= 0) {
                   4674:                     return "failed starting RTSP server";
                   4675:                 }
                   4676:                 printf ("* pid rtsp => %d %d\n", $pid, $pid2) if($verbose);
                   4677:                 $run{'rtsp'}="$pid $pid2";
                   4678:             }
                   4679:         }
                   4680:         elsif($what eq "rtsp-ipv6") {
                   4681:             if($torture && $run{'rtsp-ipv6'} &&
                   4682:                !responsive_rtsp_server($verbose, "ipv6")) {
                   4683:                 stopserver('rtsp-ipv6');
                   4684:             }
                   4685:             if(!$run{'rtsp-ipv6'}) {
                   4686:                 ($pid, $pid2, $RTSP6PORT) = runrtspserver($verbose, "ipv6");
                   4687:                 if($pid <= 0) {
                   4688:                     return "failed starting RTSP-IPv6 server";
                   4689:                 }
                   4690:                 logmsg sprintf("* pid rtsp-ipv6 => %d %d\n", $pid, $pid2)
                   4691:                     if($verbose);
                   4692:                 $run{'rtsp-ipv6'}="$pid $pid2";
                   4693:             }
                   4694:         }
                   4695:         elsif($what eq "ftps") {
                   4696:             if(!$stunnel) {
                   4697:                 # we can't run ftps tests without stunnel
                   4698:                 return "no stunnel";
                   4699:             }
                   4700:             if($runcert{'ftps'} && ($runcert{'ftps'} ne $certfile)) {
                   4701:                 # stop server when running and using a different cert
                   4702:                 stopserver('ftps');
                   4703:             }
                   4704:             if($torture && $run{'ftp'} &&
                   4705:                !responsive_pingpong_server("ftp", "", $verbose)) {
                   4706:                 stopserver('ftp');
                   4707:             }
                   4708:             if(!$run{'ftp'}) {
                   4709:                 ($pid, $pid2) = runpingpongserver("ftp", "", $verbose);
                   4710:                 if($pid <= 0) {
                   4711:                     return "failed starting FTP server";
                   4712:                 }
                   4713:                 printf ("* pid ftp => %d %d\n", $pid, $pid2) if($verbose);
                   4714:                 $run{'ftp'}="$pid $pid2";
                   4715:             }
                   4716:             if(!$run{'ftps'}) {
                   4717:                 ($pid, $pid2) = runftpsserver($verbose, "", $certfile);
                   4718:                 if($pid <= 0) {
                   4719:                     return "failed starting FTPS server (stunnel)";
                   4720:                 }
                   4721:                 logmsg sprintf("* pid ftps => %d %d\n", $pid, $pid2)
                   4722:                     if($verbose);
                   4723:                 $run{'ftps'}="$pid $pid2";
                   4724:             }
                   4725:         }
                   4726:         elsif($what eq "file") {
                   4727:             # we support it but have no server!
                   4728:         }
                   4729:         elsif($what eq "https") {
                   4730:             if(!$stunnel) {
                   4731:                 # we can't run https tests without stunnel
                   4732:                 return "no stunnel";
                   4733:             }
                   4734:             if($runcert{'https'} && ($runcert{'https'} ne $certfile)) {
                   4735:                 # stop server when running and using a different cert
                   4736:                 stopserver('https');
                   4737:             }
                   4738:             if($torture && $run{'http'} &&
                   4739:                !responsive_http_server("http", $verbose, 0, $HTTPPORT)) {
                   4740:                 stopserver('http');
                   4741:             }
                   4742:             if(!$run{'http'}) {
                   4743:                 ($pid, $pid2, $HTTPPORT) =
                   4744:                     runhttpserver("http", $verbose, 0);
                   4745:                 if($pid <= 0) {
                   4746:                     return "failed starting HTTP server";
                   4747:                 }
                   4748:                 printf ("* pid http => %d %d\n", $pid, $pid2) if($verbose);
                   4749:                 $run{'http'}="$pid $pid2";
                   4750:             }
                   4751:             if(!$run{'https'}) {
                   4752:                 ($pid, $pid2) = runhttpsserver($verbose, "", $certfile);
                   4753:                 if($pid <= 0) {
                   4754:                     return "failed starting HTTPS server (stunnel)";
                   4755:                 }
                   4756:                 logmsg sprintf("* pid https => %d %d\n", $pid, $pid2)
                   4757:                     if($verbose);
                   4758:                 $run{'https'}="$pid $pid2";
                   4759:             }
                   4760:         }
                   4761:         elsif($what eq "httptls") {
                   4762:             if(!$httptlssrv) {
                   4763:                 # for now, we can't run http TLS-EXT tests without gnutls-serv
                   4764:                 return "no gnutls-serv";
                   4765:             }
                   4766:             if($torture && $run{'httptls'} &&
                   4767:                !responsive_httptls_server($verbose, "IPv4")) {
                   4768:                 stopserver('httptls');
                   4769:             }
                   4770:             if(!$run{'httptls'}) {
                   4771:                 ($pid, $pid2) = runhttptlsserver($verbose, "IPv4");
                   4772:                 if($pid <= 0) {
                   4773:                     return "failed starting HTTPTLS server (gnutls-serv)";
                   4774:                 }
                   4775:                 logmsg sprintf("* pid httptls => %d %d\n", $pid, $pid2)
                   4776:                     if($verbose);
                   4777:                 $run{'httptls'}="$pid $pid2";
                   4778:             }
                   4779:         }
                   4780:         elsif($what eq "httptls-ipv6") {
                   4781:             if(!$httptlssrv) {
                   4782:                 # for now, we can't run http TLS-EXT tests without gnutls-serv
                   4783:                 return "no gnutls-serv";
                   4784:             }
                   4785:             if($torture && $run{'httptls-ipv6'} &&
                   4786:                !responsive_httptls_server($verbose, "ipv6")) {
                   4787:                 stopserver('httptls-ipv6');
                   4788:             }
                   4789:             if(!$run{'httptls-ipv6'}) {
                   4790:                 ($pid, $pid2) = runhttptlsserver($verbose, "ipv6");
                   4791:                 if($pid <= 0) {
                   4792:                     return "failed starting HTTPTLS-IPv6 server (gnutls-serv)";
                   4793:                 }
                   4794:                 logmsg sprintf("* pid httptls-ipv6 => %d %d\n", $pid, $pid2)
                   4795:                     if($verbose);
                   4796:                 $run{'httptls-ipv6'}="$pid $pid2";
                   4797:             }
                   4798:         }
                   4799:         elsif($what eq "tftp") {
                   4800:             if($torture && $run{'tftp'} &&
                   4801:                !responsive_tftp_server("", $verbose)) {
                   4802:                 stopserver('tftp');
                   4803:             }
                   4804:             if(!$run{'tftp'}) {
                   4805:                 ($pid, $pid2, $TFTPPORT) =
                   4806:                     runtftpserver("", $verbose);
                   4807:                 if($pid <= 0) {
                   4808:                     return "failed starting TFTP server";
                   4809:                 }
                   4810:                 printf ("* pid tftp => %d %d\n", $pid, $pid2) if($verbose);
                   4811:                 $run{'tftp'}="$pid $pid2";
                   4812:             }
                   4813:         }
                   4814:         elsif($what eq "tftp-ipv6") {
                   4815:             if($torture && $run{'tftp-ipv6'} &&
                   4816:                !responsive_tftp_server("", $verbose, "ipv6")) {
                   4817:                 stopserver('tftp-ipv6');
                   4818:             }
                   4819:             if(!$run{'tftp-ipv6'}) {
                   4820:                 ($pid, $pid2, $TFTP6PORT) =
                   4821:                     runtftpserver("", $verbose, "ipv6");
                   4822:                 if($pid <= 0) {
                   4823:                     return "failed starting TFTP-IPv6 server";
                   4824:                 }
                   4825:                 printf("* pid tftp-ipv6 => %d %d\n", $pid, $pid2) if($verbose);
                   4826:                 $run{'tftp-ipv6'}="$pid $pid2";
                   4827:             }
                   4828:         }
                   4829:         elsif($what eq "sftp" || $what eq "scp") {
                   4830:             if(!$run{'ssh'}) {
                   4831:                 ($pid, $pid2) = runsshserver("", $verbose);
                   4832:                 if($pid <= 0) {
                   4833:                     return "failed starting SSH server";
                   4834:                 }
                   4835:                 printf ("* pid ssh => %d %d\n", $pid, $pid2) if($verbose);
                   4836:                 $run{'ssh'}="$pid $pid2";
                   4837:             }
                   4838:         }
                   4839:         elsif($what eq "socks4" || $what eq "socks5" ) {
                   4840:             if(!$run{'socks'}) {
                   4841:                 ($pid, $pid2, $SOCKSPORT) = runsocksserver("", $verbose);
                   4842:                 if($pid <= 0) {
                   4843:                     return "failed starting socks server";
                   4844:                 }
                   4845:                 printf ("* pid socks => %d %d\n", $pid, $pid2) if($verbose);
                   4846:                 $run{'socks'}="$pid $pid2";
                   4847:             }
                   4848:         }
                   4849:         elsif($what eq "mqtt" ) {
                   4850:             if(!$run{'mqtt'}) {
                   4851:                 ($pid, $pid2) = runmqttserver("", $verbose);
                   4852:                 if($pid <= 0) {
                   4853:                     return "failed starting mqtt server";
                   4854:                 }
                   4855:                 printf ("* pid mqtt => %d %d\n", $pid, $pid2) if($verbose);
                   4856:                 $run{'mqtt'}="$pid $pid2";
                   4857:             }
                   4858:         }
                   4859:         elsif($what eq "http-unix") {
                   4860:             if($torture && $run{'http-unix'} &&
                   4861:                !responsive_http_server("http", $verbose, "unix", $HTTPUNIXPATH)) {
                   4862:                 stopserver('http-unix');
                   4863:             }
                   4864:             if(!$run{'http-unix'}) {
                   4865:                 my $unused;
                   4866:                 ($pid, $pid2, $unused) =
                   4867:                     runhttpserver("http", $verbose, "unix", $HTTPUNIXPATH);
                   4868:                 if($pid <= 0) {
                   4869:                     return "failed starting HTTP-unix server";
                   4870:                 }
                   4871:                 logmsg sprintf("* pid http-unix => %d %d\n", $pid, $pid2)
                   4872:                     if($verbose);
                   4873:                 $run{'http-unix'}="$pid $pid2";
                   4874:             }
                   4875:         }
                   4876:         elsif($what eq "dict") {
                   4877:             if(!$run{'dict'}) {
                   4878:                 ($pid, $pid2) = rundictserver($verbose, "", $DICTPORT);
                   4879:                 if($pid <= 0) {
                   4880:                     return "failed starting DICT server";
                   4881:                 }
                   4882:                 logmsg sprintf ("* pid DICT => %d %d\n", $pid, $pid2)
                   4883:                     if($verbose);
                   4884:                 $run{'dict'}="$pid $pid2";
                   4885:             }
                   4886:         }
                   4887:         elsif($what eq "smb") {
                   4888:             if(!$run{'smb'}) {
                   4889:                 ($pid, $pid2) = runsmbserver($verbose, "", $SMBPORT);
                   4890:                 if($pid <= 0) {
                   4891:                     return "failed starting SMB server";
                   4892:                 }
                   4893:                 logmsg sprintf ("* pid SMB => %d %d\n", $pid, $pid2)
                   4894:                     if($verbose);
                   4895:                 $run{'dict'}="$pid $pid2";
                   4896:             }
                   4897:         }
                   4898:         elsif($what eq "telnet") {
                   4899:             if(!$run{'telnet'}) {
                   4900:                 ($pid, $pid2) = runnegtelnetserver($verbose,
                   4901:                                                    "",
                   4902:                                                    $NEGTELNETPORT);
                   4903:                 if($pid <= 0) {
                   4904:                     return "failed starting neg TELNET server";
                   4905:                 }
                   4906:                 logmsg sprintf ("* pid neg TELNET => %d %d\n", $pid, $pid2)
                   4907:                     if($verbose);
                   4908:                 $run{'dict'}="$pid $pid2";
                   4909:             }
                   4910:         }
                   4911:         elsif($what eq "none") {
                   4912:             logmsg "* starts no server\n" if ($verbose);
                   4913:         }
                   4914:         else {
                   4915:             warn "we don't support a server for $what";
                   4916:             return "no server for $what";
                   4917:         }
                   4918:     }
                   4919:     return 0;
                   4920: }
                   4921: 
                   4922: ##############################################################################
                   4923: # This function makes sure the right set of server is running for the
                   4924: # specified test case. This is a useful design when we run single tests as not
                   4925: # all servers need to run then!
                   4926: #
                   4927: # Returns: a string, blank if everything is fine or a reason why it failed
                   4928: #
                   4929: sub serverfortest {
                   4930:     my ($testnum)=@_;
                   4931: 
                   4932:     my @what = getpart("client", "server");
                   4933: 
                   4934:     if(!$what[0]) {
                   4935:         warn "Test case $testnum has no server(s) specified";
                   4936:         return "no server specified";
                   4937:     }
                   4938: 
                   4939:     for(my $i = scalar(@what) - 1; $i >= 0; $i--) {
                   4940:         my $srvrline = $what[$i];
                   4941:         chomp $srvrline if($srvrline);
                   4942:         if($srvrline =~ /^(\S+)((\s*)(.*))/) {
                   4943:             my $server = "${1}";
                   4944:             my $lnrest = "${2}";
                   4945:             my $tlsext;
                   4946:             if($server =~ /^(httptls)(\+)(ext|srp)(\d*)(-ipv6|)$/) {
                   4947:                 $server = "${1}${4}${5}";
                   4948:                 $tlsext = uc("TLS-${3}");
                   4949:             }
                   4950:             if(! grep /^\Q$server\E$/, @protocols) {
                   4951:                 if(substr($server,0,5) ne "socks") {
                   4952:                     if($tlsext) {
                   4953:                         return "curl lacks $tlsext support";
                   4954:                     }
                   4955:                     else {
                   4956:                         return "curl lacks $server server support";
                   4957:                     }
                   4958:                 }
                   4959:             }
                   4960:             $what[$i] = "$server$lnrest" if($tlsext);
                   4961:         }
                   4962:     }
                   4963: 
                   4964:     return &startservers(@what);
                   4965: }
                   4966: 
                   4967: #######################################################################
                   4968: # runtimestats displays test-suite run time statistics
                   4969: #
                   4970: sub runtimestats {
                   4971:     my $lasttest = $_[0];
                   4972: 
                   4973:     return if(not $timestats);
                   4974: 
                   4975:     logmsg "\nTest suite total running time breakdown per task...\n\n";
                   4976: 
                   4977:     my @timesrvr;
                   4978:     my @timeprep;
                   4979:     my @timetool;
                   4980:     my @timelock;
                   4981:     my @timevrfy;
                   4982:     my @timetest;
                   4983:     my $timesrvrtot = 0.0;
                   4984:     my $timepreptot = 0.0;
                   4985:     my $timetooltot = 0.0;
                   4986:     my $timelocktot = 0.0;
                   4987:     my $timevrfytot = 0.0;
                   4988:     my $timetesttot = 0.0;
                   4989:     my $counter;
                   4990: 
                   4991:     for my $testnum (1 .. $lasttest) {
                   4992:         if($timesrvrini{$testnum}) {
                   4993:             $timesrvrtot += $timesrvrend{$testnum} - $timesrvrini{$testnum};
                   4994:             $timepreptot +=
                   4995:                 (($timetoolini{$testnum} - $timeprepini{$testnum}) -
                   4996:                  ($timesrvrend{$testnum} - $timesrvrini{$testnum}));
                   4997:             $timetooltot += $timetoolend{$testnum} - $timetoolini{$testnum};
                   4998:             $timelocktot += $timesrvrlog{$testnum} - $timetoolend{$testnum};
                   4999:             $timevrfytot += $timevrfyend{$testnum} - $timesrvrlog{$testnum};
                   5000:             $timetesttot += $timevrfyend{$testnum} - $timeprepini{$testnum};
                   5001:             push @timesrvr, sprintf("%06.3f  %04d",
                   5002:                 $timesrvrend{$testnum} - $timesrvrini{$testnum}, $testnum);
                   5003:             push @timeprep, sprintf("%06.3f  %04d",
                   5004:                 ($timetoolini{$testnum} - $timeprepini{$testnum}) -
                   5005:                 ($timesrvrend{$testnum} - $timesrvrini{$testnum}), $testnum);
                   5006:             push @timetool, sprintf("%06.3f  %04d",
                   5007:                 $timetoolend{$testnum} - $timetoolini{$testnum}, $testnum);
                   5008:             push @timelock, sprintf("%06.3f  %04d",
                   5009:                 $timesrvrlog{$testnum} - $timetoolend{$testnum}, $testnum);
                   5010:             push @timevrfy, sprintf("%06.3f  %04d",
                   5011:                 $timevrfyend{$testnum} - $timesrvrlog{$testnum}, $testnum);
                   5012:             push @timetest, sprintf("%06.3f  %04d",
                   5013:                 $timevrfyend{$testnum} - $timeprepini{$testnum}, $testnum);
                   5014:         }
                   5015:     }
                   5016: 
                   5017:     {
                   5018:         no warnings 'numeric';
                   5019:         @timesrvr = sort { $b <=> $a } @timesrvr;
                   5020:         @timeprep = sort { $b <=> $a } @timeprep;
                   5021:         @timetool = sort { $b <=> $a } @timetool;
                   5022:         @timelock = sort { $b <=> $a } @timelock;
                   5023:         @timevrfy = sort { $b <=> $a } @timevrfy;
                   5024:         @timetest = sort { $b <=> $a } @timetest;
                   5025:     }
                   5026: 
                   5027:     logmsg "Spent ". sprintf("%08.3f ", $timesrvrtot) .
                   5028:            "seconds starting and verifying test harness servers.\n";
                   5029:     logmsg "Spent ". sprintf("%08.3f ", $timepreptot) .
                   5030:            "seconds reading definitions and doing test preparations.\n";
                   5031:     logmsg "Spent ". sprintf("%08.3f ", $timetooltot) .
                   5032:            "seconds actually running test tools.\n";
                   5033:     logmsg "Spent ". sprintf("%08.3f ", $timelocktot) .
                   5034:            "seconds awaiting server logs lock removal.\n";
                   5035:     logmsg "Spent ". sprintf("%08.3f ", $timevrfytot) .
                   5036:            "seconds verifying test results.\n";
                   5037:     logmsg "Spent ". sprintf("%08.3f ", $timetesttot) .
                   5038:            "seconds doing all of the above.\n";
                   5039: 
                   5040:     $counter = 25;
                   5041:     logmsg "\nTest server starting and verification time per test ".
                   5042:         sprintf("(%s)...\n\n", (not $fullstats)?"top $counter":"full");
                   5043:     logmsg "-time-  test\n";
                   5044:     logmsg "------  ----\n";
                   5045:     foreach my $txt (@timesrvr) {
                   5046:         last if((not $fullstats) && (not $counter--));
                   5047:         logmsg "$txt\n";
                   5048:     }
                   5049: 
                   5050:     $counter = 10;
                   5051:     logmsg "\nTest definition reading and preparation time per test ".
                   5052:         sprintf("(%s)...\n\n", (not $fullstats)?"top $counter":"full");
                   5053:     logmsg "-time-  test\n";
                   5054:     logmsg "------  ----\n";
                   5055:     foreach my $txt (@timeprep) {
                   5056:         last if((not $fullstats) && (not $counter--));
                   5057:         logmsg "$txt\n";
                   5058:     }
                   5059: 
                   5060:     $counter = 25;
                   5061:     logmsg "\nTest tool execution time per test ".
                   5062:         sprintf("(%s)...\n\n", (not $fullstats)?"top $counter":"full");
                   5063:     logmsg "-time-  test\n";
                   5064:     logmsg "------  ----\n";
                   5065:     foreach my $txt (@timetool) {
                   5066:         last if((not $fullstats) && (not $counter--));
                   5067:         logmsg "$txt\n";
                   5068:     }
                   5069: 
                   5070:     $counter = 15;
                   5071:     logmsg "\nTest server logs lock removal time per test ".
                   5072:         sprintf("(%s)...\n\n", (not $fullstats)?"top $counter":"full");
                   5073:     logmsg "-time-  test\n";
                   5074:     logmsg "------  ----\n";
                   5075:     foreach my $txt (@timelock) {
                   5076:         last if((not $fullstats) && (not $counter--));
                   5077:         logmsg "$txt\n";
                   5078:     }
                   5079: 
                   5080:     $counter = 10;
                   5081:     logmsg "\nTest results verification time per test ".
                   5082:         sprintf("(%s)...\n\n", (not $fullstats)?"top $counter":"full");
                   5083:     logmsg "-time-  test\n";
                   5084:     logmsg "------  ----\n";
                   5085:     foreach my $txt (@timevrfy) {
                   5086:         last if((not $fullstats) && (not $counter--));
                   5087:         logmsg "$txt\n";
                   5088:     }
                   5089: 
                   5090:     $counter = 50;
                   5091:     logmsg "\nTotal time per test ".
                   5092:         sprintf("(%s)...\n\n", (not $fullstats)?"top $counter":"full");
                   5093:     logmsg "-time-  test\n";
                   5094:     logmsg "------  ----\n";
                   5095:     foreach my $txt (@timetest) {
                   5096:         last if((not $fullstats) && (not $counter--));
                   5097:         logmsg "$txt\n";
                   5098:     }
                   5099: 
                   5100:     logmsg "\n";
                   5101: }
                   5102: 
                   5103: # globally disabled tests
                   5104: disabledtests("$TESTDIR/DISABLED");
                   5105: 
                   5106: # locally disabled tests, ignored by git etc
                   5107: disabledtests("$TESTDIR/DISABLED.local");
                   5108: 
                   5109: #######################################################################
                   5110: # Check options to this test program
                   5111: #
                   5112: 
                   5113: my $number=0;
                   5114: my $fromnum=-1;
                   5115: my @testthis;
                   5116: while(@ARGV) {
                   5117:     if ($ARGV[0] eq "-v") {
                   5118:         # verbose output
                   5119:         $verbose=1;
                   5120:     }
                   5121:     elsif($ARGV[0] =~ /^-b(.*)/) {
                   5122:         my $portno=$1;
                   5123:         if($portno =~ s/(\d+)$//) {
                   5124:             $base = int $1;
                   5125:         }
                   5126:     }
                   5127:     elsif ($ARGV[0] eq "-c") {
                   5128:         # use this path to curl instead of default
                   5129:         $DBGCURL=$CURL="\"$ARGV[1]\"";
                   5130:         shift @ARGV;
                   5131:     }
                   5132:     elsif ($ARGV[0] eq "-vc") {
                   5133:         # use this path to a curl used to verify servers
                   5134: 
                   5135:         # Particularly useful when you introduce a crashing bug somewhere in
                   5136:         # the development version as then it won't be able to run any tests
                   5137:         # since it can't verify the servers!
                   5138: 
                   5139:         $VCURL="\"$ARGV[1]\"";
                   5140:         shift @ARGV;
                   5141:     }
                   5142:     elsif ($ARGV[0] eq "-d") {
                   5143:         # have the servers display protocol output
                   5144:         $debugprotocol=1;
                   5145:     }
                   5146:     elsif($ARGV[0] eq "-e") {
                   5147:         # run the tests cases event based if possible
                   5148:         $run_event_based=1;
                   5149:     }
                   5150:     elsif ($ARGV[0] eq "-g") {
                   5151:         # run this test with gdb
                   5152:         $gdbthis=1;
                   5153:     }
                   5154:     elsif ($ARGV[0] eq "-gw") {
                   5155:         # run this test with windowed gdb
                   5156:         $gdbthis=1;
                   5157:         $gdbxwin=1;
                   5158:     }
                   5159:     elsif($ARGV[0] eq "-s") {
                   5160:         # short output
                   5161:         $short=1;
                   5162:     }
                   5163:     elsif($ARGV[0] eq "-am") {
                   5164:         # automake-style output
                   5165:         $short=1;
                   5166:         $automakestyle=1;
                   5167:     }
                   5168:     elsif($ARGV[0] eq "-n") {
                   5169:         # no valgrind
                   5170:         undef $valgrind;
                   5171:     }
                   5172:     elsif ($ARGV[0] eq "-R") {
                   5173:         # execute in scrambled order
                   5174:         $scrambleorder=1;
                   5175:     }
                   5176:     elsif($ARGV[0] =~ /^-t(.*)/) {
                   5177:         # torture
                   5178:         $torture=1;
                   5179:         my $xtra = $1;
                   5180: 
                   5181:         if($xtra =~ s/(\d+)$//) {
                   5182:             $tortalloc = $1;
                   5183:         }
                   5184:     }
                   5185:     elsif($ARGV[0] =~ /--shallow=(\d+)/) {
                   5186:         # Fail no more than this amount per tests when running
                   5187:         # torture.
                   5188:         my ($num)=($1);
                   5189:         $shallow=$num;
                   5190:     }
                   5191:     elsif($ARGV[0] =~ /--repeat=(\d+)/) {
                   5192:         # Repeat-run the given tests this many times
                   5193:         $repeat = $1;
                   5194:     }
                   5195:     elsif($ARGV[0] =~ /--seed=(\d+)/) {
                   5196:         # Set a fixed random seed (used for -R and --shallow)
                   5197:         $randseed = $1;
                   5198:     }
                   5199:     elsif($ARGV[0] eq "-a") {
                   5200:         # continue anyway, even if a test fail
                   5201:         $anyway=1;
                   5202:     }
                   5203:     elsif($ARGV[0] eq "-p") {
                   5204:         $postmortem=1;
                   5205:     }
                   5206:     elsif($ARGV[0] eq "-l") {
                   5207:         # lists the test case names only
                   5208:         $listonly=1;
                   5209:     }
                   5210:     elsif($ARGV[0] eq "-k") {
                   5211:         # keep stdout and stderr files after tests
                   5212:         $keepoutfiles=1;
                   5213:     }
                   5214:     elsif($ARGV[0] eq "-r") {
                   5215:         # run time statistics needs Time::HiRes
                   5216:         if($Time::HiRes::VERSION) {
                   5217:             keys(%timeprepini) = 1000;
                   5218:             keys(%timesrvrini) = 1000;
                   5219:             keys(%timesrvrend) = 1000;
                   5220:             keys(%timetoolini) = 1000;
                   5221:             keys(%timetoolend) = 1000;
                   5222:             keys(%timesrvrlog) = 1000;
                   5223:             keys(%timevrfyend) = 1000;
                   5224:             $timestats=1;
                   5225:             $fullstats=0;
                   5226:         }
                   5227:     }
                   5228:     elsif($ARGV[0] eq "-rf") {
                   5229:         # run time statistics needs Time::HiRes
                   5230:         if($Time::HiRes::VERSION) {
                   5231:             keys(%timeprepini) = 1000;
                   5232:             keys(%timesrvrini) = 1000;
                   5233:             keys(%timesrvrend) = 1000;
                   5234:             keys(%timetoolini) = 1000;
                   5235:             keys(%timetoolend) = 1000;
                   5236:             keys(%timesrvrlog) = 1000;
                   5237:             keys(%timevrfyend) = 1000;
                   5238:             $timestats=1;
                   5239:             $fullstats=1;
                   5240:         }
                   5241:     }
                   5242:     elsif(($ARGV[0] eq "-h") || ($ARGV[0] eq "--help")) {
                   5243:         # show help text
                   5244:         print <<EOHELP
                   5245: Usage: runtests.pl [options] [test selection(s)]
                   5246:   -a       continue even if a test fails
                   5247:   -am      automake style output PASS/FAIL: [number] [name]
                   5248:   -bN      use base port number N for test servers (default $base)
                   5249:   -c path  use this curl executable
                   5250:   -d       display server debug info
                   5251:   -e       event-based execution
                   5252:   -g       run the test case with gdb
                   5253:   -gw      run the test case with gdb as a windowed application
                   5254:   -h       this help text
                   5255:   -k       keep stdout and stderr files present after tests
                   5256:   -l       list all test case names/descriptions
                   5257:   -n       no valgrind
                   5258:   -p       print log file contents when a test fails
                   5259:   -R       scrambled order (uses the random seed, see --seed)
                   5260:   -r       run time statistics
                   5261:   -rf      full run time statistics
                   5262:   -s       short output
                   5263:   --seed=[num] set the random seed to a fixed number
                   5264:   --shallow=[num] randomly makes the torture tests "thinner"
                   5265:   -t[N]    torture (simulate function failures); N means fail Nth function
                   5266:   -v       verbose output
                   5267:   -vc path use this curl only to verify the existing servers
                   5268:   [num]    like "5 6 9" or " 5 to 22 " to run those tests only
                   5269:   [!num]   like "!5 !6 !9" to disable those tests
                   5270:   [~num]   like "~5 ~6 ~9" to ignore the result of those tests
                   5271:   [keyword] like "IPv6" to select only tests containing the key word
                   5272:   [!keyword] like "!cookies" to disable any tests containing the key word
                   5273:   [~keyword] like "~cookies" to ignore results of tests containing key word
                   5274: EOHELP
                   5275:     ;
                   5276:         exit;
                   5277:     }
                   5278:     elsif($ARGV[0] =~ /^(\d+)/) {
                   5279:         $number = $1;
                   5280:         if($fromnum >= 0) {
                   5281:             for my $n ($fromnum .. $number) {
                   5282:                 if($disabled{$n}) {
                   5283:                     # skip disabled test cases
                   5284:                     my $why = "configured as DISABLED";
                   5285:                     $skipped++;
                   5286:                     $skipped{$why}++;
                   5287:                     $teststat[$n]=$why; # store reason for this test case
                   5288:                 }
                   5289:                 else {
                   5290:                     push @testthis, $n;
                   5291:                 }
                   5292:             }
                   5293:             $fromnum = -1;
                   5294:         }
                   5295:         else {
                   5296:             push @testthis, $1;
                   5297:         }
                   5298:     }
                   5299:     elsif($ARGV[0] =~ /^to$/i) {
                   5300:         $fromnum = $number+1;
                   5301:     }
                   5302:     elsif($ARGV[0] =~ /^!(\d+)/) {
                   5303:         $fromnum = -1;
                   5304:         $disabled{$1}=$1;
                   5305:     }
                   5306:     elsif($ARGV[0] =~ /^~(\d+)/) {
                   5307:         $fromnum = -1;
                   5308:         $ignored{$1}=$1;
                   5309:     }
                   5310:     elsif($ARGV[0] =~ /^!(.+)/) {
                   5311:         $disabled_keywords{lc($1)}=$1;
                   5312:     }
                   5313:     elsif($ARGV[0] =~ /^~(.+)/) {
                   5314:         $ignored_keywords{lc($1)}=$1;
                   5315:     }
                   5316:     elsif($ARGV[0] =~ /^([-[{a-zA-Z].*)/) {
                   5317:         $enabled_keywords{lc($1)}=$1;
                   5318:     }
                   5319:     else {
                   5320:         print "Unknown option: $ARGV[0]\n";
                   5321:         exit;
                   5322:     }
                   5323:     shift @ARGV;
                   5324: }
                   5325: 
                   5326: if(!$randseed) {
                   5327:     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
                   5328:         localtime(time);
                   5329:     # seed of the month. December 2019 becomes 201912
                   5330:     $randseed = ($year+1900)*100 + $mon+1;
                   5331:     open(C, "$CURL --version 2>/dev/null|");
                   5332:     my @c = <C>;
                   5333:     close(C);
                   5334:     # use the first line of output and get the md5 out of it
                   5335:     my $str = md5($c[0]);
                   5336:     $randseed += unpack('S', $str);  # unsigned 16 bit value
                   5337: }
                   5338: srand $randseed;
                   5339: 
                   5340: if(@testthis && ($testthis[0] ne "")) {
                   5341:     $TESTCASES=join(" ", @testthis);
                   5342: }
                   5343: 
                   5344: if($valgrind) {
                   5345:     # we have found valgrind on the host, use it
                   5346: 
                   5347:     # verify that we can invoke it fine
                   5348:     my $code = runclient("valgrind >/dev/null 2>&1");
                   5349: 
                   5350:     if(($code>>8) != 1) {
                   5351:         #logmsg "Valgrind failure, disable it\n";
                   5352:         undef $valgrind;
                   5353:     } else {
                   5354: 
                   5355:         # since valgrind 2.1.x, '--tool' option is mandatory
                   5356:         # use it, if it is supported by the version installed on the system
                   5357:         runclient("valgrind --help 2>&1 | grep -- --tool > /dev/null 2>&1");
                   5358:         if (($? >> 8)==0) {
                   5359:             $valgrind_tool="--tool=memcheck";
                   5360:         }
                   5361:         open(C, "<$CURL");
                   5362:         my $l = <C>;
                   5363:         if($l =~ /^\#\!/) {
                   5364:             # A shell script. This is typically when built with libtool,
                   5365:             $valgrind="../libtool --mode=execute $valgrind";
                   5366:         }
                   5367:         close(C);
                   5368: 
                   5369:         # valgrind 3 renamed the --logfile option to --log-file!!!
                   5370:         my $ver=join(' ', runclientoutput("valgrind --version"));
                   5371:         # cut off all but digits and dots
                   5372:         $ver =~ s/[^0-9.]//g;
                   5373: 
                   5374:         if($ver =~ /^(\d+)/) {
                   5375:             $ver = $1;
                   5376:             if($ver >= 3) {
                   5377:                 $valgrind_logfile="--log-file";
                   5378:             }
                   5379:         }
                   5380:     }
                   5381: }
                   5382: 
                   5383: if ($gdbthis) {
                   5384:     # open the executable curl and read the first 4 bytes of it
                   5385:     open(CHECK, "<$CURL");
                   5386:     my $c;
                   5387:     sysread CHECK, $c, 4;
                   5388:     close(CHECK);
                   5389:     if($c eq "#! /") {
                   5390:         # A shell script. This is typically when built with libtool,
                   5391:         $libtool = 1;
                   5392:         $gdb = "../libtool --mode=execute gdb";
                   5393:     }
                   5394: }
                   5395: 
                   5396: $minport         = $base; # original base port number
                   5397: $HTTPSPORT       = $base++; # HTTPS (stunnel) server port
                   5398: $FTPSPORT        = $base++; # FTPS (stunnel) server port
                   5399: $SSHPORT         = $base++; # SSH (SCP/SFTP) port
                   5400: $HTTPTLSPORT     = $base++; # HTTP TLS (non-stunnel) server port
                   5401: $HTTPTLS6PORT    = $base++; # HTTP TLS (non-stunnel) IPv6 server port
                   5402: $HTTP2PORT       = $base++; # HTTP/2 port
                   5403: $DICTPORT        = $base++; # DICT port
                   5404: $SMBPORT         = $base++; # SMB port
                   5405: $SMBSPORT        = $base++; # SMBS port
                   5406: $NEGTELNETPORT   = $base++; # TELNET port with negotiation
                   5407: $HTTPUNIXPATH    = "http$$.sock"; # HTTP server Unix domain socket path
                   5408: 
                   5409: $maxport         = $base-1; # updated base port number
                   5410: 
                   5411: #######################################################################
                   5412: # clear and create logging directory:
                   5413: #
                   5414: 
                   5415: cleardir($LOGDIR);
                   5416: mkdir($LOGDIR, 0777);
                   5417: 
                   5418: #######################################################################
                   5419: # initialize some variables
                   5420: #
                   5421: 
                   5422: get_disttests();
                   5423: init_serverpidfile_hash();
                   5424: 
                   5425: #######################################################################
                   5426: # Output curl version and host info being tested
                   5427: #
                   5428: 
                   5429: if(!$listonly) {
                   5430:     checksystem();
                   5431: }
                   5432: 
                   5433: #######################################################################
                   5434: # Fetch all disabled tests, if there are any
                   5435: #
                   5436: 
                   5437: sub disabledtests {
                   5438:     my ($file) = @_;
                   5439: 
                   5440:     if(open(D, "<$file")) {
                   5441:         while(<D>) {
                   5442:             if(/^ *\#/) {
                   5443:                 # allow comments
                   5444:                 next;
                   5445:             }
                   5446:             if($_ =~ /(\d+)/) {
                   5447:                 my ($n) = $1;
                   5448:                 $disabled{$n}=$n; # disable this test number
                   5449:                 if(! -f "$srcdir/data/test$n") {
                   5450:                     print STDERR "WARNING! Non-exiting test $n in DISABLED!\n";
                   5451:                     # fail hard to make user notice
                   5452:                     exit 1;
                   5453:                 }
                   5454:             }
                   5455:         }
                   5456:         close(D);
                   5457:     }
                   5458: }
                   5459: 
                   5460: #######################################################################
                   5461: # If 'all' tests are requested, find out all test numbers
                   5462: #
                   5463: 
                   5464: if ( $TESTCASES eq "all") {
                   5465:     # Get all commands and find out their test numbers
                   5466:     opendir(DIR, $TESTDIR) || die "can't opendir $TESTDIR: $!";
                   5467:     my @cmds = grep { /^test([0-9]+)$/ && -f "$TESTDIR/$_" } readdir(DIR);
                   5468:     closedir(DIR);
                   5469: 
                   5470:     $TESTCASES=""; # start with no test cases
                   5471: 
                   5472:     # cut off everything but the digits
                   5473:     for(@cmds) {
                   5474:         $_ =~ s/[a-z\/\.]*//g;
                   5475:     }
                   5476:     # sort the numbers from low to high
                   5477:     foreach my $n (sort { $a <=> $b } @cmds) {
                   5478:         if($disabled{$n}) {
                   5479:             # skip disabled test cases
                   5480:             my $why = "configured as DISABLED";
                   5481:             $skipped++;
                   5482:             $skipped{$why}++;
                   5483:             $teststat[$n]=$why; # store reason for this test case
                   5484:             next;
                   5485:         }
                   5486:         $TESTCASES .= " $n";
                   5487:     }
                   5488: }
                   5489: else {
                   5490:     my $verified="";
                   5491:     map {
                   5492:         if (-e "$TESTDIR/test$_") {
                   5493:             $verified.="$_ ";
                   5494:         }
                   5495:     } split(" ", $TESTCASES);
                   5496:     if($verified eq "") {
                   5497:         print "No existing test cases were specified\n";
                   5498:         exit;
                   5499:     }
                   5500:     $TESTCASES = $verified;
                   5501: }
                   5502: if($repeat) {
                   5503:     my $s;
                   5504:     for(1 .. $repeat) {
                   5505:         $s .= $TESTCASES;
                   5506:     }
                   5507:     $TESTCASES = $s;
                   5508: }
                   5509: 
                   5510: if($scrambleorder) {
                   5511:     # scramble the order of the test cases
                   5512:     my @rand;
                   5513:     while($TESTCASES) {
                   5514:         my @all = split(/ +/, $TESTCASES);
                   5515:         if(!$all[0]) {
                   5516:             # if the first is blank, shift away it
                   5517:             shift @all;
                   5518:         }
                   5519:         my $r = rand @all;
                   5520:         push @rand, $all[$r];
                   5521:         $all[$r]="";
                   5522:         $TESTCASES = join(" ", @all);
                   5523:     }
                   5524:     $TESTCASES = join(" ", @rand);
                   5525: }
                   5526: 
                   5527: # Display the contents of the given file.  Line endings are canonicalized
                   5528: # and excessively long files are elided
                   5529: sub displaylogcontent {
                   5530:     my ($file)=@_;
                   5531:     if(open(SINGLE, "<$file")) {
                   5532:         my $linecount = 0;
                   5533:         my $truncate;
                   5534:         my @tail;
                   5535:         while(my $string = <SINGLE>) {
                   5536:             $string =~ s/\r\n/\n/g;
                   5537:             $string =~ s/[\r\f\032]/\n/g;
                   5538:             $string .= "\n" unless ($string =~ /\n$/);
                   5539:             $string =~ tr/\n//;
                   5540:             for my $line (split("\n", $string)) {
                   5541:                 $line =~ s/\s*\!$//;
                   5542:                 if ($truncate) {
                   5543:                     push @tail, " $line\n";
                   5544:                 } else {
                   5545:                     logmsg " $line\n";
                   5546:                 }
                   5547:                 $linecount++;
                   5548:                 $truncate = $linecount > 1000;
                   5549:             }
                   5550:         }
                   5551:         if(@tail) {
                   5552:             my $tailshow = 200;
                   5553:             my $tailskip = 0;
                   5554:             my $tailtotal = scalar @tail;
                   5555:             if($tailtotal > $tailshow) {
                   5556:                 $tailskip = $tailtotal - $tailshow;
                   5557:                 logmsg "=== File too long: $tailskip lines omitted here\n";
                   5558:             }
                   5559:             for($tailskip .. $tailtotal-1) {
                   5560:                 logmsg "$tail[$_]";
                   5561:             }
                   5562:         }
                   5563:         close(SINGLE);
                   5564:     }
                   5565: }
                   5566: 
                   5567: sub displaylogs {
                   5568:     my ($testnum)=@_;
                   5569:     opendir(DIR, "$LOGDIR") ||
                   5570:         die "can't open dir: $!";
                   5571:     my @logs = readdir(DIR);
                   5572:     closedir(DIR);
                   5573: 
                   5574:     logmsg "== Contents of files in the $LOGDIR/ dir after test $testnum\n";
                   5575:     foreach my $log (sort @logs) {
                   5576:         if($log =~ /\.(\.|)$/) {
                   5577:             next; # skip "." and ".."
                   5578:         }
                   5579:         if($log =~ /^\.nfs/) {
                   5580:             next; # skip ".nfs"
                   5581:         }
                   5582:         if(($log eq "memdump") || ($log eq "core")) {
                   5583:             next; # skip "memdump" and  "core"
                   5584:         }
                   5585:         if((-d "$LOGDIR/$log") || (! -s "$LOGDIR/$log")) {
                   5586:             next; # skip directory and empty files
                   5587:         }
                   5588:         if(($log =~ /^stdout\d+/) && ($log !~ /^stdout$testnum/)) {
                   5589:             next; # skip stdoutNnn of other tests
                   5590:         }
                   5591:         if(($log =~ /^stderr\d+/) && ($log !~ /^stderr$testnum/)) {
                   5592:             next; # skip stderrNnn of other tests
                   5593:         }
                   5594:         if(($log =~ /^upload\d+/) && ($log !~ /^upload$testnum/)) {
                   5595:             next; # skip uploadNnn of other tests
                   5596:         }
                   5597:         if(($log =~ /^curl\d+\.out/) && ($log !~ /^curl$testnum\.out/)) {
                   5598:             next; # skip curlNnn.out of other tests
                   5599:         }
                   5600:         if(($log =~ /^test\d+\.txt/) && ($log !~ /^test$testnum\.txt/)) {
                   5601:             next; # skip testNnn.txt of other tests
                   5602:         }
                   5603:         if(($log =~ /^file\d+\.txt/) && ($log !~ /^file$testnum\.txt/)) {
                   5604:             next; # skip fileNnn.txt of other tests
                   5605:         }
                   5606:         if(($log =~ /^netrc\d+/) && ($log !~ /^netrc$testnum/)) {
                   5607:             next; # skip netrcNnn of other tests
                   5608:         }
                   5609:         if(($log =~ /^trace\d+/) && ($log !~ /^trace$testnum/)) {
                   5610:             next; # skip traceNnn of other tests
                   5611:         }
                   5612:         if(($log =~ /^valgrind\d+/) && ($log !~ /^valgrind$testnum(\..*|)$/)) {
                   5613:             next; # skip valgrindNnn of other tests
                   5614:         }
                   5615:         if(($log =~ /^test$testnum$/)) {
                   5616:             next; # skip test$testnum since it can be very big
                   5617:         }
                   5618:         logmsg "=== Start of file $log\n";
                   5619:         displaylogcontent("$LOGDIR/$log");
                   5620:         logmsg "=== End of file $log\n";
                   5621:     }
                   5622: }
                   5623: 
                   5624: #######################################################################
                   5625: # Setup Azure Pipelines Test Run (if running in Azure DevOps)
                   5626: #
                   5627: 
                   5628: if(azure_check_environment()) {
                   5629:     $AZURE_RUN_ID = azure_create_test_run();
                   5630:     logmsg "Azure Run ID: $AZURE_RUN_ID\n" if ($verbose);
                   5631: }
                   5632: 
                   5633: #######################################################################
                   5634: # The main test-loop
                   5635: #
                   5636: 
                   5637: my $failed;
                   5638: my $testnum;
                   5639: my $ok=0;
                   5640: my $ign=0;
                   5641: my $total=0;
                   5642: my $lasttest=0;
                   5643: my @at = split(" ", $TESTCASES);
                   5644: my $count=0;
                   5645: 
                   5646: $start = time();
                   5647: 
                   5648: foreach $testnum (@at) {
                   5649: 
                   5650:     $lasttest = $testnum if($testnum > $lasttest);
                   5651:     $count++;
                   5652: 
                   5653:     my $error = singletest($run_event_based, $testnum, $count, scalar(@at));
                   5654: 
                   5655:     # update test result in CI services
                   5656:     if(azure_check_environment() && $AZURE_RUN_ID && $AZURE_RESULT_ID) {
                   5657:         $AZURE_RESULT_ID = azure_update_test_result($AZURE_RUN_ID, $AZURE_RESULT_ID, $testnum, $error,
                   5658:                                                     $timeprepini{$testnum}, $timevrfyend{$testnum});
                   5659:     }
                   5660:     elsif(appveyor_check_environment()) {
                   5661:         appveyor_update_test_result($testnum, $error, $timeprepini{$testnum}, $timevrfyend{$testnum});
                   5662:     }
                   5663: 
                   5664:     if($error < 0) {
                   5665:         # not a test we can run
                   5666:         next;
                   5667:     }
                   5668: 
                   5669:     $total++; # number of tests we've run
                   5670: 
                   5671:     if($error>0) {
                   5672:         if($error==2) {
                   5673:             # ignored test failures are wrapped in ()
                   5674:             $failed.= "($testnum) ";
                   5675:         }
                   5676:         else {
                   5677:             $failed.= "$testnum ";
                   5678:         }
                   5679:         if($postmortem) {
                   5680:             # display all files in log/ in a nice way
                   5681:             displaylogs($testnum);
                   5682:         }
                   5683:         if($error==2) {
                   5684:             $ign++; # ignored test result counter
                   5685:         }
                   5686:         elsif(!$anyway) {
                   5687:             # a test failed, abort
                   5688:             logmsg "\n - abort tests\n";
                   5689:             last;
                   5690:         }
                   5691:     }
                   5692:     elsif(!$error) {
                   5693:         $ok++; # successful test counter
                   5694:     }
                   5695: 
                   5696:     # loop for next test
                   5697: }
                   5698: 
                   5699: my $sofar = time() - $start;
                   5700: 
                   5701: #######################################################################
                   5702: # Finish Azure Pipelines Test Run (if running in Azure DevOps)
                   5703: #
                   5704: 
                   5705: if(azure_check_environment() && $AZURE_RUN_ID) {
                   5706:     $AZURE_RUN_ID = azure_update_test_run($AZURE_RUN_ID);
                   5707: }
                   5708: 
                   5709: # Tests done, stop the servers
                   5710: stopservers($verbose);
                   5711: 
                   5712: my $all = $total + $skipped;
                   5713: 
                   5714: runtimestats($lasttest);
                   5715: 
                   5716: if($total) {
                   5717:     logmsg sprintf("TESTDONE: $ok tests out of $total reported OK: %d%%\n",
                   5718:                    $ok/$total*100);
                   5719: 
                   5720:     if($ok != $total) {
                   5721:         logmsg "TESTFAIL: These test cases failed: $failed\n";
                   5722:     }
                   5723: }
                   5724: else {
                   5725:     logmsg "TESTFAIL: No tests were performed\n";
                   5726: }
                   5727: 
                   5728: if($all) {
                   5729:     logmsg "TESTDONE: $all tests were considered during ".
                   5730:         sprintf("%.0f", $sofar) ." seconds.\n";
                   5731: }
                   5732: 
                   5733: if($skipped && !$short) {
                   5734:     my $s=0;
                   5735:     logmsg "TESTINFO: $skipped tests were skipped due to these restraints:\n";
                   5736: 
                   5737:     for(keys %skipped) {
                   5738:         my $r = $_;
                   5739:         printf "TESTINFO: \"%s\" %d times (", $r, $skipped{$_};
                   5740: 
                   5741:         # now show all test case numbers that had this reason for being
                   5742:         # skipped
                   5743:         my $c=0;
                   5744:         my $max = 9;
                   5745:         for(0 .. scalar @teststat) {
                   5746:             my $t = $_;
                   5747:             if($teststat[$_] && ($teststat[$_] eq $r)) {
                   5748:                 if($c < $max) {
                   5749:                     logmsg ", " if($c);
                   5750:                     logmsg $_;
                   5751:                 }
                   5752:                 $c++;
                   5753:             }
                   5754:         }
                   5755:         if($c > $max) {
                   5756:             logmsg " and ".($c-$max)." more";
                   5757:         }
                   5758:         logmsg ")\n";
                   5759:     }
                   5760: }
                   5761: 
                   5762: if($total && (($ok+$ign) != $total)) {
                   5763:     exit 1;
                   5764: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>