1#*************************************************************************** 2# _ _ ____ _ 3# Project ___| | | | _ \| | 4# / __| | | | |_) | | 5# | (__| |_| | _ <| |___ 6# \___|\___/|_| \_\_____| 7# 8# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9# 10# This software is licensed as described in the file COPYING, which 11# you should have received as part of this distribution. The terms 12# are also available at https://curl.se/docs/copyright.html. 13# 14# You may opt to use, copy, modify, merge, publish, distribute and/or sell 15# copies of the Software, and permit persons to whom the Software is 16# furnished to do so, under the terms of the COPYING file. 17# 18# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19# KIND, either express or implied. 20# 21# SPDX-License-Identifier: curl 22# 23#*************************************************************************** 24 25# This perl module contains functions useful in writing test servers. 26 27package serverhelp; 28 29use strict; 30use warnings; 31 32BEGIN { 33 use base qw(Exporter); 34 35 our @EXPORT_OK = qw( 36 logmsg 37 $logfile 38 serverfactors 39 servername_id 40 servername_str 41 servername_canon 42 server_pidfilename 43 server_portfilename 44 server_logfilename 45 server_cmdfilename 46 server_inputfilename 47 server_outputfilename 48 mainsockf_pidfilename 49 mainsockf_logfilename 50 datasockf_pidfilename 51 datasockf_logfilename 52 ); 53 54 # sub second timestamping needs Time::HiRes 55 eval { 56 no warnings "all"; 57 require Time::HiRes; 58 import Time::HiRes qw( gettimeofday ); 59 } 60} 61 62 63our $logfile; # server log file name, for logmsg 64 65#*************************************************************************** 66# Just for convenience, test harness uses 'https' and 'httptls' literals as 67# values for 'proto' variable in order to differentiate different servers. 68# 'https' literal is used for stunnel based https test servers, and 'httptls' 69# is used for non-stunnel https test servers. 70 71#********************************************************************** 72# logmsg is general message logging subroutine for our test servers. 73# 74sub logmsg { 75 my $now; 76 # sub second timestamping needs Time::HiRes 77 if($Time::HiRes::VERSION) { 78 my ($seconds, $usec) = gettimeofday(); 79 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = 80 localtime($seconds); 81 $now = sprintf("%02d:%02d:%02d.%06d ", $hour, $min, $sec, $usec); 82 } 83 else { 84 my $seconds = time(); 85 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = 86 localtime($seconds); 87 $now = sprintf("%02d:%02d:%02d ", $hour, $min, $sec); 88 } 89 # we see warnings on Windows run that $logfile is used uninitialized 90 # TODO: not found yet where this comes from 91 $logfile = "serverhelp_uninitialized.log" if(!$logfile); 92 if(open(my $logfilefh, ">>", "$logfile")) { 93 print $logfilefh $now; 94 print $logfilefh @_; 95 close($logfilefh); 96 } 97} 98 99 100#*************************************************************************** 101# Return server characterization factors given a server id string. 102# 103sub serverfactors { 104 my $server = $_[0]; 105 my $proto; 106 my $ipvnum; 107 my $idnum; 108 109 if($server =~ 110 /^((ftp|http|imap|pop3|smtp|http-pipe)s?)(\d*)(-ipv6|)$/) { 111 $proto = $1; 112 $idnum = ($3 && ($3 > 1)) ? $3 : 1; 113 $ipvnum = ($4 && ($4 =~ /6$/)) ? 6 : 4; 114 } 115 elsif($server =~ 116 /^(tftp|sftp|socks|ssh|rtsp|gopher|httptls)(\d*)(-ipv6|)$/) { 117 $proto = $1; 118 $idnum = ($2 && ($2 > 1)) ? $2 : 1; 119 $ipvnum = ($3 && ($3 =~ /6$/)) ? 6 : 4; 120 } 121 else { 122 die "invalid server id: '$server'" 123 } 124 return($proto, $ipvnum, $idnum); 125} 126 127 128#*************************************************************************** 129# Return server name string formatted for presentation purposes 130# 131sub servername_str { 132 my ($proto, $ipver, $idnum) = @_; 133 134 $proto = uc($proto) if($proto); 135 die "unsupported protocol: '$proto'" unless($proto && 136 ($proto =~ /^(((FTP|HTTP|HTTP\/2|HTTP\/3|IMAP|POP3|GOPHER|SMTP|HTTP-PIPE)S?)|(TFTP|SFTP|SOCKS|SSH|RTSP|HTTPTLS|DICT|SMB|SMBS|TELNET|MQTT))$/)); 137 138 $ipver = (not $ipver) ? 'ipv4' : lc($ipver); 139 die "unsupported IP version: '$ipver'" unless($ipver && 140 ($ipver =~ /^(4|6|ipv4|ipv6|-ipv4|-ipv6|unix)$/)); 141 $ipver = ($ipver =~ /6$/) ? '-IPv6' : (($ipver =~ /unix$/) ? '-unix' : ''); 142 143 $idnum = 1 if(not $idnum); 144 die "unsupported ID number: '$idnum'" unless($idnum && 145 ($idnum =~ /^(\d+)$/)); 146 $idnum = '' if($idnum <= 1); 147 148 return "${proto}${idnum}${ipver}"; 149} 150 151 152#*************************************************************************** 153# Return server name string formatted for identification purposes 154# 155sub servername_id { 156 my ($proto, $ipver, $idnum) = @_; 157 return lc(servername_str($proto, $ipver, $idnum)); 158} 159 160 161#*************************************************************************** 162# Return server name string formatted for file name purposes 163# 164sub servername_canon { 165 my ($proto, $ipver, $idnum) = @_; 166 my $string = lc(servername_str($proto, $ipver, $idnum)); 167 $string =~ tr/-/_/; 168 $string =~ s/\//_v/; 169 return $string; 170} 171 172 173#*************************************************************************** 174# Return file name for server pid file. 175# 176sub server_pidfilename { 177 my ($piddir, $proto, $ipver, $idnum) = @_; 178 my $trailer = '_server.pid'; 179 return "${piddir}/". servername_canon($proto, $ipver, $idnum) ."$trailer"; 180} 181 182#*************************************************************************** 183# Return file name for server port file. 184# 185sub server_portfilename { 186 my ($piddir, $proto, $ipver, $idnum) = @_; 187 my $trailer = '_server.port'; 188 return "${piddir}/". servername_canon($proto, $ipver, $idnum) ."$trailer"; 189} 190 191 192#*************************************************************************** 193# Return file name for server log file. 194# 195sub server_logfilename { 196 my ($logdir, $proto, $ipver, $idnum) = @_; 197 my $trailer = '_server.log'; 198 $trailer = '_stunnel.log' if(lc($proto) =~ /^(ftp|http|imap|pop3|smtp)s$/); 199 return "${logdir}/". servername_canon($proto, $ipver, $idnum) ."$trailer"; 200} 201 202 203#*************************************************************************** 204# Return file name for server commands file. 205# 206sub server_cmdfilename { 207 my ($logdir, $proto, $ipver, $idnum) = @_; 208 my $trailer = '_server.cmd'; 209 return "${logdir}/". servername_canon($proto, $ipver, $idnum) ."$trailer"; 210} 211 212 213#*************************************************************************** 214# Return file name for server input file. 215# 216sub server_inputfilename { 217 my ($logdir, $proto, $ipver, $idnum) = @_; 218 my $trailer = '_server.input'; 219 return "${logdir}/". servername_canon($proto, $ipver, $idnum) ."$trailer"; 220} 221 222 223#*************************************************************************** 224# Return file name for server output file. 225# 226sub server_outputfilename { 227 my ($logdir, $proto, $ipver, $idnum) = @_; 228 my $trailer = '_server.output'; 229 return "${logdir}/". servername_canon($proto, $ipver, $idnum) ."$trailer"; 230} 231 232 233#*************************************************************************** 234# Return file name for main or primary sockfilter pid file. 235# 236sub mainsockf_pidfilename { 237 my ($piddir, $proto, $ipver, $idnum) = @_; 238 die "unsupported protocol: '$proto'" unless($proto && 239 (lc($proto) =~ /^(ftp|imap|pop3|smtp)s?$/)); 240 my $trailer = (lc($proto) =~ /^ftps?$/) ? '_sockctrl.pid':'_sockfilt.pid'; 241 return "${piddir}/". servername_canon($proto, $ipver, $idnum) ."$trailer"; 242} 243 244 245#*************************************************************************** 246# Return file name for main or primary sockfilter log file. 247# 248sub mainsockf_logfilename { 249 my ($logdir, $proto, $ipver, $idnum) = @_; 250 die "unsupported protocol: '$proto'" unless($proto && 251 (lc($proto) =~ /^(ftp|imap|pop3|smtp)s?$/)); 252 my $trailer = (lc($proto) =~ /^ftps?$/) ? '_sockctrl.log':'_sockfilt.log'; 253 return "${logdir}/". servername_canon($proto, $ipver, $idnum) ."$trailer"; 254} 255 256 257#*************************************************************************** 258# Return file name for data or secondary sockfilter pid file. 259# 260sub datasockf_pidfilename { 261 my ($piddir, $proto, $ipver, $idnum) = @_; 262 die "unsupported protocol: '$proto'" unless($proto && 263 (lc($proto) =~ /^ftps?$/)); 264 my $trailer = '_sockdata.pid'; 265 return "${piddir}/". servername_canon($proto, $ipver, $idnum) ."$trailer"; 266} 267 268 269#*************************************************************************** 270# Return file name for data or secondary sockfilter log file. 271# 272sub datasockf_logfilename { 273 my ($logdir, $proto, $ipver, $idnum) = @_; 274 die "unsupported protocol: '$proto'" unless($proto && 275 (lc($proto) =~ /^ftps?$/)); 276 my $trailer = '_sockdata.log'; 277 return "${logdir}/". servername_canon($proto, $ipver, $idnum) ."$trailer"; 278} 279 280 281#*************************************************************************** 282# End of library 2831; 284