tests: move pingpong server to dynamic listening port

FTP, IMAP, POP3, SMTP and their IPv6 versions are now all on dynamic
ports

Test 842-845 are unfortunately a bit hard to move over to this concept
right now and require "default port" still...
diff --git a/tests/ftpserver.pl b/tests/ftpserver.pl
index 718920f..92420ea 100755
--- a/tests/ftpserver.pl
+++ b/tests/ftpserver.pl
@@ -96,6 +96,7 @@
 # global vars used for file names
 #
 my $pidfile;            # server pid file name
+my $portfile=".ftpserver.port"; # server port file name
 my $logfile;            # server log file name
 my $mainsockf_pidfile;  # pid file for primary connection sockfilt process
 my $mainsockf_logfile;  # log file for primary connection sockfilt process
@@ -191,6 +192,7 @@
     # For now, simply mimic old behavior.
     killsockfilters($proto, $ipvnum, $idnum, $verbose);
     unlink($pidfile);
+    unlink($portfile);
     if($serverlogslocked) {
         $serverlogslocked = 0;
         clear_advisor_read_lock($SERVERLOGS_LOCK);
@@ -390,6 +392,7 @@
                "line $lcaller. $srvrname server, sysread error: $!\n";
         killsockfilters($proto, $ipvnum, $idnum, $verbose);
         unlink($pidfile);
+        unlink($portfile);
         if($serverlogslocked) {
             $serverlogslocked = 0;
             clear_advisor_read_lock($SERVERLOGS_LOCK);
@@ -404,6 +407,7 @@
                "line $lcaller. $srvrname server, read zero\n";
         killsockfilters($proto, $ipvnum, $idnum, $verbose);
         unlink($pidfile);
+        unlink($portfile);
         if($serverlogslocked) {
             $serverlogslocked = 0;
             clear_advisor_read_lock($SERVERLOGS_LOCK);
@@ -418,6 +422,7 @@
     my $mainsockfcmd = "./server/sockfilt".exe_ext('SRV')." " .
         "--ipv$ipvnum --port $port " .
         "--pidfile \"$mainsockf_pidfile\" " .
+        "--portfile \"$portfile\" " .
         "--logfile \"$mainsockf_logfile\"";
     $sfpid = open2(*SFREAD, *SFWRITE, $mainsockfcmd);
 
@@ -431,6 +436,7 @@
         logmsg "Failed sockfilt command: $mainsockfcmd\n";
         killsockfilters($proto, $ipvnum, $idnum, $verbose);
         unlink($pidfile);
+        unlink($portfile);
         if($serverlogslocked) {
             $serverlogslocked = 0;
             clear_advisor_read_lock($SERVERLOGS_LOCK);
@@ -2900,6 +2906,7 @@
 # --id        # server instance number
 # --proto     # server protocol
 # --pidfile   # server pid file
+# --portfile  # server port file
 # --logfile   # server log file
 # --ipv4      # server IP version 4
 # --ipv6      # server IP version 6
@@ -2937,6 +2944,12 @@
             shift @ARGV;
         }
     }
+    elsif($ARGV[0] eq '--portfile') {
+        if($ARGV[1]) {
+            $portfile = $ARGV[1];
+            shift @ARGV;
+        }
+    }
     elsif($ARGV[0] eq '--logfile') {
         if($ARGV[1]) {
             $logfile = $ARGV[1];
@@ -2952,8 +2965,8 @@
         $listenaddr = '::1' if($listenaddr eq '127.0.0.1');
     }
     elsif($ARGV[0] eq '--port') {
-        if($ARGV[1] && ($ARGV[1] =~ /^(\d+)$/)) {
-            $port = $1 if($1 > 1024);
+        if($ARGV[1] =~ /^(\d+)$/) {
+            $port = $1;
             shift @ARGV;
         }
     }
@@ -3013,6 +3026,15 @@
 
 startsf();
 
+# actual port
+if($portfile && !$port) {
+    my $aport;
+    open(P, "<$portfile");
+    $aport = <P>;
+    close(P);
+    $port = 0 + $aport;
+}
+
 logmsg sprintf("%s server listens on port IPv${ipvnum}/${port}\n", uc($proto));
 
 open(PID, ">$pidfile");
@@ -3021,7 +3043,6 @@
 
 logmsg("logged pid $$ in $pidfile\n");
 
-
 while(1) {
 
     # kill previous data connection sockfilt when alive
diff --git a/tests/runtests.pl b/tests/runtests.pl
index 2feb5ae..d853a4a 100755
--- a/tests/runtests.pl
+++ b/tests/runtests.pl
@@ -124,7 +124,7 @@
 my $minport;     # minimum used port number
 my $maxport;     # maximum used port number
 
-my $MQTTPORT;            # MQTT server port
+my $MQTTPORT="[not running]"; # MQTT server port
 my $HTTPPORT;            # HTTP server port
 my $HTTP6PORT;           # HTTP IPv6 server port
 my $HTTPSPORT;           # HTTPS (stunnel) server port
@@ -1744,31 +1744,10 @@
     my $logfile;
     my $flags = "";
 
-    if($proto eq "ftp") {
-        $port = ($idnum>1)?$FTP2PORT:$FTPPORT;
-
-        if($ipvnum==6) {
-            # if IPv6, use a different setup
-            $port = $FTP6PORT;
-        }
-    }
-    elsif($proto eq "pop3") {
-        $port = ($ipvnum==6) ? $POP36PORT : $POP3PORT;
-    }
-    elsif($proto eq "imap") {
-        $port = ($ipvnum==6) ? $IMAP6PORT : $IMAPPORT;
-    }
-    elsif($proto eq "smtp") {
-        $port = ($ipvnum==6) ? $SMTP6PORT : $SMTPPORT;
-    }
-    else {
-        print STDERR "Unsupported protocol $proto!!\n";
-        return 0;
-    }
-
     $server = servername_id($proto, $ipvnum, $idnum);
 
     $pidfile = $serverpidfile{$server};
+    my $portfile = $serverportfile{$server};
 
     # don't retry if the server doesn't work
     if ($doesntrun{$pidfile}) {
@@ -1787,9 +1766,10 @@
 
     $flags .= "--verbose " if($debugprotocol);
     $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" ";
+    $flags .= "--portfile \"$portfile\" ";
     $flags .= "--srcdir \"$srcdir\" --proto $proto ";
     $flags .= "--id $idnum " if($idnum > 1);
-    $flags .= "--ipv$ipvnum --port $port --addr \"$ip\"";
+    $flags .= "--ipv$ipvnum --port 0 --addr \"$ip\"";
 
     my $cmd = "$perl $srcdir/ftpserver.pl $flags";
     my ($ftppid, $pid2) = startnew($cmd, $pidfile, 15, 0);
@@ -1803,6 +1783,11 @@
         return (0,0);
     }
 
+    # where is it?
+    $port = pidfromfile($portfile);
+
+    logmsg "PINGPONG runs on port $port ($portfile)\n" if($verbose);
+
     # Server is up. Verify that we can speak to it.
     my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port);
     if(!$pid3) {
@@ -1816,8 +1801,48 @@
 
     $pid2 = $pid3;
 
-    if($verbose) {
-        logmsg "RUN: $srvrname server is now running PID $ftppid\n";
+    logmsg "RUN: $srvrname server is PID $ftppid port $port\n" if($verbose);
+
+    # Assign the correct port variable!
+    if($proto eq "ftp") {
+        if($ipvnum == 6) {
+            # if IPv6, use a different setup
+            $FTP6PORT = $port;
+        }
+        elsif($idnum>1) {
+            $FTP2PORT = $port;
+        }
+        else {
+            $FTPPORT = $port;
+        }
+    }
+    elsif($proto eq "pop3") {
+        if($ipvnum == 6) {
+            $POP36PORT = $port;
+        }
+        else {
+            $POP3PORT = $port;
+        }
+    }
+    elsif($proto eq "imap") {
+        if($ipvnum == 6) {
+            $IMAP6PORT  = $port;
+        }
+        else {
+            $IMAPPORT = $port;
+        }
+    }
+    elsif($proto eq "smtp") {
+        if($ipvnum == 6) {
+            $SMTP6PORT = $port;
+        }
+        else {
+            $SMTPPORT = $port;
+        }
+    }
+    else {
+        print STDERR "Unsupported protocol $proto!!\n";
+        return 0;
     }
 
     sleep(1);
@@ -3120,35 +3145,22 @@
 
     if($verbose) {
         logmsg "* Ports: ";
-        logmsg sprintf("FTP/%d ", $FTPPORT);
-        logmsg sprintf("FTP2/%d ", $FTP2PORT);
         logmsg sprintf("RTSP/%d ", $RTSPPORT);
         if($stunnel) {
             logmsg sprintf("FTPS/%d ", $FTPSPORT);
             logmsg sprintf("HTTPS/%d ", $HTTPSPORT);
         }
-        logmsg sprintf("\n*   TFTP/%d ", $TFTPPORT);
+        logmsg sprintf("TFTP/%d ", $TFTPPORT);
         if($http_ipv6) {
             logmsg sprintf("RTSP-IPv6/%d ", $RTSP6PORT);
         }
-        if($ftp_ipv6) {
-            logmsg sprintf("FTP-IPv6/%d ", $FTP6PORT);
-        }
         if($tftp_ipv6) {
             logmsg sprintf("TFTP-IPv6/%d ", $TFTP6PORT);
         }
         logmsg sprintf("\n*   SSH/%d ", $SSHPORT);
         logmsg sprintf("SOCKS/%d ", $SOCKSPORT);
-        logmsg sprintf("POP3/%d ", $POP3PORT);
-        logmsg sprintf("IMAP/%d ", $IMAPPORT);
-        logmsg sprintf("SMTP/%d\n", $SMTPPORT);
-        if($ftp_ipv6) {
-            logmsg sprintf("*   POP3-IPv6/%d ", $POP36PORT);
-            logmsg sprintf("IMAP-IPv6/%d ", $IMAP6PORT);
-            logmsg sprintf("SMTP-IPv6/%d\n", $SMTP6PORT);
-        }
         if($httptlssrv) {
-            logmsg sprintf("*   HTTPTLS/%d ", $HTTPTLSPORT);
+            logmsg sprintf("HTTPTLS/%d ", $HTTPTLSPORT);
             if($has_ipv6) {
                 logmsg sprintf("HTTPTLS-IPv6/%d ", $HTTPTLS6PORT);
             }
@@ -3527,7 +3539,7 @@
         if(@precheck) {
             $cmd = $precheck[0];
             chomp $cmd;
-            subVariables \$cmd;
+            subVariables(\$cmd);
             if($cmd) {
                 my @p = split(/ /, $cmd);
                 if($p[0] !~ /\//) {
@@ -3674,7 +3686,7 @@
         # make some nice replace operations
         $cmd =~ s/\n//g; # no newlines please
         # substitute variables in the command line
-        subVariables \$cmd;
+        subVariables(\$cmd);
     }
     else {
         # there was no command given, use something silly
@@ -5428,22 +5440,12 @@
 }
 
 $minport         = $base; # original base port number
-
 $HTTPSPORT       = $base++; # HTTPS (stunnel) server port
-$FTPPORT         = $base++; # FTP server port
 $FTPSPORT        = $base++; # FTPS (stunnel) server port
-$FTP2PORT        = $base++; # FTP server 2 port
-$FTP6PORT        = $base++; # FTP IPv6 port
 $TFTPPORT        = $base++; # TFTP (UDP) port
 $TFTP6PORT       = $base++; # TFTP IPv6 (UDP) port
 $SSHPORT         = $base++; # SSH (SCP/SFTP) port
 $SOCKSPORT       = $base++; # SOCKS port
-$POP3PORT        = $base++; # POP3 server port
-$POP36PORT       = $base++; # POP3 IPv6 server port
-$IMAPPORT        = $base++; # IMAP server port
-$IMAP6PORT       = $base++; # IMAP IPv6 server port
-$SMTPPORT        = $base++; # SMTP server port
-$SMTP6PORT       = $base++; # SMTP IPv6 server port
 $RTSPPORT        = $base++; # RTSP server port
 $RTSP6PORT       = $base++; # RTSP IPv6 server port
 $HTTPTLSPORT     = $base++; # HTTP TLS (non-stunnel) server port
diff --git a/tests/server/sockfilt.c b/tests/server/sockfilt.c
index 82bc7b8..84c72f9 100644
--- a/tests/server/sockfilt.c
+++ b/tests/server/sockfilt.c
@@ -1304,6 +1304,7 @@
   curl_socket_t msgsock = CURL_SOCKET_BAD;
   int wrotepidfile = 0;
   const char *pidname = ".sockfilt.pid";
+  const char *portfile = NULL; /* none by default */
   bool juggle_again;
   int rc;
   int error;
@@ -1331,6 +1332,11 @@
       if(argc>arg)
         pidname = argv[arg++];
     }
+    else if(!strcmp("--portfile", argv[arg])) {
+      arg++;
+      if(argc > arg)
+        portfile = argv[arg++];
+    }
     else if(!strcmp("--logfile", argv[arg])) {
       arg++;
       if(argc>arg)
@@ -1360,12 +1366,6 @@
       if(argc>arg) {
         char *endptr;
         unsigned long ulnum = strtoul(argv[arg], &endptr, 10);
-        if((endptr != argv[arg] + strlen(argv[arg])) ||
-           ((ulnum != 0UL) && ((ulnum < 1025UL) || (ulnum > 65535UL)))) {
-          fprintf(stderr, "sockfilt: invalid --port argument (%s)\n",
-                  argv[arg]);
-          return 0;
-        }
         port = curlx_ultous(ulnum);
         arg++;
       }
@@ -1501,6 +1501,13 @@
     write_stdout("FAIL\n", 5);
     goto sockfilt_cleanup;
   }
+  if(portfile) {
+    wrotepidfile = write_portfile(portfile, port);
+    if(!wrotepidfile) {
+      write_stdout("FAIL\n", 5);
+      goto sockfilt_cleanup;
+    }
+  }
 
   do {
     juggle_again = juggle(&msgsock, sock, &mode);