#! /usr/bin/perl # # nuttscp/nuttrcp v2.1 # # Copyright(c) 2008-2010 Bill Fink. All rights reserved. # # nuttscp/nuttrcp is free, opensource software. You can # redistribute it and/or modify it under the terms of Version 2 # of the GNU General Public License (GPL), as published by the # GNU Project (http://www.gnu.org). A copy of the license can # also be found in the LICENSE file. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # copy files to/from remote host using nuttcp # # Usage: nuttscp or nuttscp -h prints this usage info # Usage: nuttscp -V reports nuttscp version # Usage: nuttscp [options] infile [user@]host[/datahost]:outfile # or: nuttscp [options] [user@]host[/datahost]:infile outfile # options: -w window default=unspecified # -N num_streams default=1 # -P ctlport default=5100 # -p dataport default=5101 (5001 nuttcp < 6.2.8) # -l buflen default=64KB # -n numbuf default=unlimited # -T timeout default=none # -i interval default=no interval reports # -I identifier default=no identifier # -R rate_limit default=unlimited # -M mss default=unspecified # -x extra_option default=unspecified # -b brief_option default=standard brief output # -f default=remote nuttcp server # -F default=nuttcp flip off # -4 default=auto IPv4/IPv6 # -6 default=auto IPv4/IPv6 # -v default=no verbose nuttcp # -z default=no zero copy # --copy-dir default=copy file # --verbose default=not verbose # --compressed default=not compressed # --one-file-system default=stay on local fs # --remote-shell shell default=same as local # --remote-nuttcp path default=nuttcp # --datahost host default=same as ssh/rsh host # --ssh-id identity default=unspecified # --ssh-port port default=22 # --debug default=debugging off # --noexec default=off # --clobber default=noclobber # --noclobber default=noclobber # # infile may be a pipe: "command |" # outfile may be a pipe: "| command" # # Run nuttscp/nuttrcp with no arguments to get a usage statement # # If invoked as nuttrcp will use rsh instead of ssh to start # remote oneshot nuttcp server # # Developed by Bill Fink, billfink@mindspring.com # # 2.1, Bill Fink, 26-Jan-10 # Updated Copyright notice # Add nuttcp "-x" extras option # Add nuttcp "-b" brief option # Add "-z" zero copy option # Allow "host+addr_stride" format for multilink aggregation # Resolve $myipaddr to $myhostname for "-f" multilink aggregation # Don't give "File exists" error for /dev/null # 2.0, Bill Fink, 23-Aug-09 # Not doing correct check for using nuttrcp # Add "-f" option to use local nuttcp server (remote client) # Fix incorrect error checking affecting piped get case # Add nuttcp "-I" identifier option # 1.7, Bill Fink, 31-Jul-09 # Say "something went wrong" if can't execute remote nuttcp # Add comment that bash syntax is required for perl "system" exec # Support "nuttscp file remote:" for regular file & empty outfile # 1.6, Bill Fink, 30-Jul-09 # Add undocumented "-i" nuttcp interval option # Add "--remote-nuttcp" option to set remote nuttcp path # Add "--ssh-id"/"--ssh-port" options to set ssh identity and port # Update usage to reflect new nuttcp default data port of 5101 # 1.5, Bill Fink, 24-Mar-09 # Allow separate ssh/rsh and nuttcp data channels # (using "--datahost" option or ctlhost/datahost syntax) # Added "-v" option for nuttcp verbose output # 1.4, Bill Fink, 26-Aug-08 # Change required nuttcp version to non-beta 6.1.1 # 1.3, Bill Fink, 20-Aug-08 # Allow infile and outfile to be pipes # Add "--copy-dir" option to copy directories # Add "--verbose" option to verbosely copy directories # Add "--compressed" option to copy directories with compression # Add "--one-file-system" option to copy directories on local fs # Add "-V" option to get nuttscp version # Add "-h" option to print usage info # Only add "-f-beta" to nuttcp command if using beta version # Added GPL license notice # 1.2.1, Bill Fink, 16-Aug-08 # Style changes to make it more like UNIX C code # 1.2, Bill Fink, 16-Aug-08 # Handle copying file to a directory # Extend "--clobber" and "--noclobber" to remote files # Added "-4" and "-6" options to force using IPv4 or IPv6 # 1.1, Bill Fink, 14-Aug-08 # Check for required nuttcp version of at least 6.0.6 # Added "--remote-shell" parameter to specify remote user shell # Added "-n" option to specify numbuf (or numbytes) # Allow user@host: syntax like scp/rcp # Added "-F" option to flip direction of data connection open # Added check for ssh/rsh command failure (rsh always returns 0) # Added "--debug" and "--noexec" options for debugging # Gracefully handle problems with local file # Added "--clobber" and "--noclobber options" # Added ChangeLog and other boilerplate # 1.0, Bill Fink, 13-Aug-08 # Initial version (modeled after scp/rcp) use Socket qw( SOCK_DGRAM SOCK_STREAM PF_INET AF_INET ); $nuttscp_vers = "2.1"; # default noclobber setting (change if desired) $def_noclobber = 1; # default control port for nuttcp to use (change if desired) $def_ctlport = 5100; # Minimum required nuttcp version $vers_min = 60101; $vers_min_str = "6.1.1"; # Note: If invoked as nuttrcp will use rsh instead of ssh # to start remote oneshot nuttcp server $rsh = "ssh"; # local nuttcp command $lnuttcp = "nuttcp"; $nuttcp_vers = `$lnuttcp -V`; if ($nuttcp_vers =~ /beta/) { $lnuttcp .= " -f-beta"; } # remote nuttcp command $rnuttcp = "nuttcp"; # remote user shell - set if different than local user shell # e.g. if local shell is tcsh but remote is bash set to "bash" $rshell = ""; # build local command to execute in $lcmd $lcmd = ""; # build remote command to execute in $rcmd $rcmd = ""; # build client args for client nuttcp command $clientargs = ""; # default parameter settings $window = "0"; $num_streams = 1; $ctlport = $def_ctlport; $dataport = 5101; $buflen = 65536; $numbuf = 0; $timeout = 0; $interval = 0; $ratelimit = 0; $mss = 0; $xopt = ""; $briefopt = ""; $zerocopy = 0; $debug = 0; $noexec = 0; $noclobber = $def_noclobber; $flip = 0; $af = AF_INET; $copy_dir = 0; $intaropts = "cf"; $outtaropts = "xpf"; $one_fs = 0; $datahost = ""; if ($0 =~ "nuttrcp") { $rsh = "rsh"; } $nuttcp_vers =~ s/^nuttcp-v?//; $nuttcp_vers =~ s/-.*$//; ($vers_major, $vers_minor, $vers_delta) = split(/\./, $nuttcp_vers); $nuttcp_vers = 10000*$vers_major + 100*$vers_minor + $vers_delta; if ($nuttcp_vers < $vers_min) { print "Error: nuttscp/nuttrcp needs at least version $vers_min_str " . "of nuttcp\n"; print " make sure remote version of nuttcp is also at least " . "$vers_min_str\n"; exit( 1 ); } while (@ARGV[0] =~ /^-/) { PARSE_PTIONS: { if (@ARGV[0] eq "-w") { shift; $window = @ARGV[0]; $clientargs .= " -w $window"; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "-N") { shift; $num_streams = @ARGV[0]; $clientargs .= " -N $num_streams"; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "-P") { shift; $ctlport = @ARGV[0]; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "-p") { shift; $dataport = @ARGV[0]; $clientargs .= " -p $dataport"; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "-l") { shift; $buflen = @ARGV[0]; $clientargs .= " -l $buflen"; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "-n") { shift; $numbuf = @ARGV[0]; $clientargs .= " -n $numbuf"; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "-T") { shift; $timeout = @ARGV[0]; $clientargs .= " -T $timeout"; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "-i") { shift; $interval = @ARGV[0]; $clientargs .= " -i $interval"; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "-I") { shift; $identifier = @ARGV[0]; $clientargs .= " -I '$identifier'"; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "-R") { shift; $rate_limit = @ARGV[0]; $clientargs .= " -R $rate_limit"; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "-M") { shift; $mss = @ARGV[0]; $clientargs .= " -M $mss"; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "-x") { shift; $xopt = @ARGV[0]; $clientargs .= " -x$xopt"; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "-b") { shift; $briefopt = @ARGV[0]; $clientargs .= " -b$briefopt"; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "-f") { shift; $flip = 1; last PARSE_PTIONS; } if (@ARGV[0] eq "-F") { shift; $clientargs .= " -F"; last PARSE_PTIONS; } if (@ARGV[0] eq "-4") { shift; $af = AF_INET; $clientargs .= " -4"; last PARSE_PTIONS; } if (@ARGV[0] eq "-6") { shift; $af = AF_INET6; $clientargs .= " -6"; last PARSE_PTIONS; } if (@ARGV[0] eq "-v") { shift; $clientargs .= " -v"; last PARSE_PTIONS; } if (@ARGV[0] eq "-z") { shift; if (`uname` !~ /[Ll]inux/) { print "Warning: zero copy not supported on " . `uname`; } $zerocopy = 1; last PARSE_PTIONS; } if (@ARGV[0] eq "-V") { print "nuttscp-$nuttscp_vers\n"; exit( 0 ); } if (@ARGV[0] eq "-h") { &usage(); exit( 0 ); } if (@ARGV[0] eq "--copy-dir") { shift; $copy_dir = 1; last PARSE_PTIONS; } if (@ARGV[0] eq "--verbose") { shift; $outtaropts .= "v"; last PARSE_PTIONS; } if (@ARGV[0] eq "--compressed") { shift; $intaropts .= "z"; $outtaropts .= "z"; last PARSE_PTIONS; } if (@ARGV[0] eq "--one-file-system") { shift; $one_fs = 1; last PARSE_PTIONS; } if (@ARGV[0] eq "--remote-shell") { shift; $rshell = @ARGV[0]; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "--remote-nuttcp") { shift; $rnuttcp = @ARGV[0]; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "--datahost") { shift; $datahost = @ARGV[0]; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "--ssh-id") { shift; $rsh = "$rsh -i @ARGV[0]"; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "--ssh-port") { shift; $rsh = "$rsh -p @ARGV[0]"; shift; last PARSE_PTIONS; } if (@ARGV[0] eq "--debug") { shift; $debug = 1; last PARSE_PTIONS; } if (@ARGV[0] eq "--noexec") { shift; $noexec = 1; last PARSE_PTIONS; } if (@ARGV[0] eq "--clobber") { shift; $noclobber = 0; last PARSE_PTIONS; } if (@ARGV[0] eq "--noclobber") { shift; $noclobber = 1; last PARSE_PTIONS; } print "$0: unknown option: \"@ARGV[0]\"\n"; print "$0: unknown option: \"@ARGV[0]\"\n"; &usage(); exit( 1 ); } } if ($flip) { if ($zerocopy) { $lcmd = "$lnuttcp -1 -sz"; } else { $lcmd = "$lnuttcp -1 -s"; } } else { if ($zerocopy) { $lcmd = "$lnuttcp -sz$clientargs"; } else { $lcmd = "$lnuttcp -s$clientargs"; } } if ($flip) { if ($zerocopy) { $rcmd = "$rnuttcp -sz$clientargs"; } else { $rcmd = "$rnuttcp -s$clientargs"; } } else { if ($zerocopy) { $rcmd = "$rnuttcp -1 -sz"; } else { $rcmd = "$rnuttcp -1 -s"; } } $lcmd .= " -P $ctlport"; $rcmd .= " -P $ctlport"; $intaropts .= " -"; $outtaropts .= " -"; if ($one_fs) { $intaropts .= " --one-file-system"; } if ($#ARGV != 1) { &usage(); if ($#ARGV >= 0) { exit( 1 ); } exit( 0 ); } if (($rshell =~ /csh/) || ($rshell eq "") && ($ENV{'SHELL'} =~ /csh/)) { $rshell = "csh"; } else { $rshell = "bash"; } $inspec = @ARGV[0]; $outspec = @ARGV[1]; $cmd = "$rsh"; $ipipe = 0; $opipe = 0; if ($inspec =~ /:/) { if ($outspec =~ /:/) { &usage(); exit( 1 ); } ($inhost, $infile) = split(":", $inspec); ($inruser, $inrhost) = split("@", $inhost); if ($inrhost ne "") { $inhost = $inrhost; $cmd .= " -l $inruser"; } if ($datahost eq "") { ($ctlhost, $datahost) = split("/", $inhost); $inhost = $ctlhost; if ($datahost eq "") { $datahost = $inhost; } } if ($inhost =~ /\+/) { $inhost = substr( $inhost, 0, index( $inhost, "+" ) ); } if ($infile eq "") { print "No input file specified\n"; exit( 1 ); } if ($infile =~ /^\s*\|/) { print "Error: empty remote input pipe " . "(or pipe on wrong side)\n"; exit( 1 ); } if ($infile =~ /^(.*)\s*\|\s*$/) { $ipipe = 1; $ipipe_cmd = $1; if ($flip) { $rcmd .= " -a"; } else { $lcmd .= " -a"; } } elsif ($copy_dir) { $ipipe = 1; if ($rshell eq "csh") { $ipipe_cmd = "( chdir $infile ; "; } else { $ipipe_cmd = "( set -e ; cd $infile ; "; } $ipipe_cmd .= "tar $intaropts . )"; if ($flip) { $rcmd .= " -a"; } else { $lcmd .= " -a"; } } if ($flip) { ($datadest, $ipad_stride) = split(/\+/, $datahost); $myipaddr = &getmyiptodest( $datadest, $dataport ); ($myhostname) = gethostbyaddr( $myipaddr, $af ); if (($num_streams =~ /m/) && ($myhostname ne "")) { $rcmd .= " $myhostname"; } else { ($myipaddr1, $myipaddr2, $myipaddr3, $myipaddr4) = unpack( "C4", $myipaddr ); $rcmd .= " $myipaddr1.$myipaddr2.$myipaddr3.$myipaddr4"; } if ($ipad_stride ne "") { $rcmd .= "+" . $ipad_stride; } } if ($outspec =~ /\|\s*$/) { print "Error: empty local output pipe " . "(or pipe on wrong side)\n"; exit( 1 ); } if ($outspec =~ /^\s*\|\s*(.*)$/) { $opipe = 1; $opipe_cmd = $1; } else { if ($copy_dir) { if ((-d $outspec) || !(-e $outspec)) { $opipe = 1; $opipe_cmd = "( mkdir -p $outspec ; set -e ; " . "cd $outspec ; tar $outtaropts )"; } else { print "$outspec: not a directory\n"; exit( 1 ); } } elsif (-d $outspec) { $intail = substr( $infile, rindex( $infile, "/" ) + 1 ); if (($intail eq "") || ($intail eq ".") || ($intail eq "..")) { print "$infile: not a regular file\n"; exit( 1 ); } if ($outspec !~ /\/$/) { $outspec .= "/"; } $outspec .= "$intail"; } if (-e $outspec) { if (($noclobber) && ($outspec ne "/dev/null")) { print "$outspec: File exists.\n"; exit( 1 ); } elsif (! -w $outspec) { print "$outspec: Permission denied\n"; exit( 1 ); } } } $cmd .= " $inhost '"; if (!$copy_dir && !$ipipe) { if ($rshell eq "csh") { $cmd .= "if (-d $infile) echo $infile: " . "not a regular file ; "; $cmd .= "if (-d $infile) kill -HUP \$\$ ; "; } else { $cmd .= "if [ -d $infile ]; then " . "echo $infile: not a regular file ; " . "exit 1 ; fi ; "; } } if ($ipipe) { $cmd .= "$ipipe_cmd | $rcmd "; } else { $cmd .= "$rcmd < $infile "; } if ($rshell eq "csh") { if ($flip) { $cmd .= "' "; } else { $cmd .= ">& /dev/null' "; } } else { if ($flip) { $cmd .= "' "; } else { $cmd .= "> /dev/null 2>&1' "; } } if ($ipipe) { if ($flip) { $cmd .= "; "; } else { $cmd .= "& "; } } else { $cmd .= "; "; } # following must be bash syntax since executed by perl via system $cmd .= "if [ \$? -ne 0 ]; then echo nuttscp: something went wrong; "; $cmd .= "exit; fi ; "; if (!$flip) { $lcmd .= " -r $datahost"; } if ($opipe) { if ($flip) { $lcmd .= " | $opipe_cmd &"; } else { $lcmd .= " | $opipe_cmd"; } } else { $lcmd .= " > $outspec"; } } elsif ($outspec =~ /:/) { ($outhost, $outfile) = split(":", $outspec); ($outruser, $outrhost) = split("@", $outhost); if ($inspec =~ /^\s*\|/) { print "Error: empty local input pipe (or pipe on wrong side)\n"; exit( 1 ); } if ($inspec =~ /^(.*)\s*\|\s*$/) { $ipipe = 1; $ipipe_cmd = $1; if ($zerocopy) { print "$inspec: not a regular file: " . "zero copy not possible\n"; $zerocopy = 0; } } else { if (! -e $inspec) { print "$inspec: No such file or directory\n"; exit( 1 ); } if (! -r $inspec) { print "$inspec: Permission denied\n"; exit( 1 ); } if (-d $inspec) { if ($copy_dir) { $ipipe = 1; $ipipe_cmd = "( set -e ; cd $inspec ; " . "tar $intaropts . )"; } else { print "$inspec: not a regular file\n"; exit( 1 ); } } else { if ($copy_dir) { print "$inspec: not a directory\n"; exit( 1 ); } elsif ((-f $inspec) && ($outfile eq "")) { $outfile = substr( $inspec, rindex( $inspec, "/" ) + 1 ); } } if ($zerocopy && (! -f $inspec)) { print "$inspec: not a regular file: " . "zero copy not possible\n"; $zerocopy = 0; } } if ($outrhost ne "") { $outhost = $outrhost; $cmd .= " -l $outruser"; } if ($datahost eq "") { ($ctlhost, $datahost) = split("/", $outhost); $outhost = $ctlhost; if ($datahost eq "") { $datahost = $outhost; } } if ($outhost =~ /\+/) { $outhost = substr( $outhost, 0, index( $outhost, "+" ) ); } if ($outfile eq "") { print "No output directory specified\n"; exit( 1 ); } if ($outfile =~ /\|\s*$/) { print "Error: empty remote output pipe " . "(or pipe on wrong side)\n"; exit( 1 ); } if ($outfile =~ /^\s*\|\s*(.*)$/) { $opipe = 1; $opipe_cmd = $1; if ($flip) { $rcmd .= " -a"; } else { $lcmd .= " -a"; } } else { if ($copy_dir) { $opipe = 1; if ($rshell eq "csh") { $opipe_cmd .= "( chdir $outfile ; "; } else { $opipe_cmd .= "( cd $outfile ; "; } $opipe_cmd .= "tar $outtaropts )"; if ($flip) { $rcmd .= " -a"; } else { $lcmd .= " -a"; } } else { $intail = substr( $inspec, rindex( $inspec, "/" ) + 1 ); if ($outfile eq "") { $outfile = $intail; } elsif ($outfile =~ /\/$/) { $outfile .= "$intail"; } elsif (($outfile =~ /\/\.$/) || ($outfile =~ /\/\.\.$/) || ($outfile eq ".") || ($outfile eq "..")) { $outfile .= "/$intail"; } } } if ($flip) { ($datadest, $ipad_stride) = split(/\+/, $datahost); $myipaddr = &getmyiptodest( $datadest, $dataport ); ($myhostname) = gethostbyaddr( $myipaddr, $af ); if (($num_streams =~ /m/) && ($myhostname ne "")) { $rcmd .= " -r $myhostname"; } else { ($myipaddr1, $myipaddr2, $myipaddr3, $myipaddr4) = unpack( "C4", $myipaddr ); $rcmd .= " -r"; $rcmd .= " $myipaddr1.$myipaddr2.$myipaddr3.$myipaddr4"; } if ($ipad_stride ne "") { $rcmd .= "+" . $ipad_stride; } } $cmd .= " $outhost '"; if ($rshell eq "csh") { if ($noclobber) { $cmd .= "set noclobber ; "; } else { $cmd .= "unset noclobber ; "; } } else { if ($noclobber) { $cmd .= "set -o noclobber ; "; } else { $cmd .= "set +o noclobber ; "; } } if ($copy_dir) { if ($rshell ne "csh") { $cmd .= "set -e ; "; } if ($noclobber) { $cmd .= "mkdir $outfile ; "; } else { $cmd .= "mkdir -p $outfile ; "; } if ($rshell eq "csh") { $cmd .= "if (\$?) kill -HUP \$\$ ; "; } } $cmd .= "$rcmd < /dev/null "; if ($rshell eq "csh") { if ($opipe) { if ($flip) { $cmd .= "| $opipe_cmd' ; "; } else { $cmd .= "|& $opipe_cmd' & "; } } else { if ($flip) { $cmd .= "> $outfile' ; "; } else { $cmd .= ">& $outfile' ; "; } } } else { if ($opipe) { if ($flip) { $cmd .= "| $opipe_cmd' ; "; } else { $cmd .= "| $opipe_cmd 2>&1' & "; } } else { if ($flip) { $cmd .= "> $outfile' ; "; } else { $cmd .= "> $outfile 2>&1' ; "; } } } # following must be bash syntax since executed by perl via system if (!$flip) { $cmd .= "if [ \$? -ne 0 ]; "; $cmd .= "then echo nuttscp: something went wrong; "; $cmd .= "exit; fi ; "; } if ($ipipe) { if ($flip) { $lcmd = "$ipipe_cmd | $lcmd &"; } else { $cmd .= "$ipipe_cmd | "; } } # following must be bash syntax since executed by perl via system if ($flip) { $cmd .= "if [ \$? -ne 0 ]; "; $cmd .= "then echo nuttscp: something went wrong; "; $cmd .= "exit; fi ; "; } if (!$flip) { $lcmd .= " $datahost"; } if (!$ipipe) { $lcmd .= " < $inspec"; } } else { &usage(); exit( 1 ); } if (!$flip) { $cmd .= "$lcmd"; } if ($debug) { if ($flip) { print "$lcmd ; "; } print "$cmd\n"; } if (!$noexec) { if ($flip) { system "$lcmd"; } if ($? == 0) { if ($flip) { # check for error from executing remote command $error = 0; open( CMD, "$cmd < /dev/null 2>&1 |" ); while () { print; if (/something went wrong/) { $error = 1; } } close( CMD ); if ($error) { # probably left the local nuttcp server # running so stop it by connecting to the # control port and then closing it $hungnuttcp = &stoplocalserver( $ctlport ); exit( 1 ); } if ($rsh eq "rsh") { # rsh is weird and can't check its output # for errors so just unconditionally try # to stop the local nuttcp server in case # it was left hanging around $hungnuttcp = &stoplocalserver( $ctlport ); if ($hungnuttcp) { exit( 1 ); } else { exit( 0 ); } } } else { system "$cmd"; } } else { print "Error: couldn't start local nuttcp server\n"; exit( 1 ); } } exit( 0 ); sub getmyiptodest { local( $dsthost, $dstport ) = @_; local( $myaddr ); ($fqdn) = gethostbyname( $dsthost ); ($fqdn2, $aliases, $addrtype, $addrlen, @dstaddr) = gethostbyname( $fqdn ); if ($#dstaddr < 0) { print "Error: bad hostname or IP address $dsthost\n"; exit( 1 ); } ($protoname, $aliases, $proto) = getprotobyname( "udp" ); if (!socket( S, PF_INET, SOCK_DGRAM, $proto)) { print "Error: couldn't create socket\n"; exit( 1 ); } $wildcard[0] = 0; $wildcard[1] = 0; $wildcard[2] = 0; $wildcard[3] = 0; $sockaddr = "S n a4 x8"; $me = pack( $sockaddr, AF_INET, 0, $wildcard ); $dst = pack( $sockaddr, AF_INET, $dstport, $dstaddr[0] ); if (!bind( S, $me )) { print "Error: couldn't bind\n"; close( S ); exit( 1 ); } if (!connect( S, $dst )) { print "Error: couldn't connect to $dsthost port $dstport\n"; close( S ); exit( 1 ); } $mysockaddr = getsockname( S ); ($family, $myport, $myaddr) = unpack( $sockaddr, $mysockaddr ); close( S ); return $myaddr; } sub stoplocalserver { local( $serverport ) = @_; local( $connected ); # stop a local nuttcp server by connecting to its # control port on 127.0.0.1 and then closing it # no error messages should be output since local # nuttcp server may have already exited $connected = 0; ($protoname, $aliases, $proto) = getprotobyname( "tcp" ); if (!socket( S, PF_INET, SOCK_STREAM, $proto)) { #print "Error: couldn't create socket\n"; return $connected; } $wildcard[0] = 0; $wildcard[1] = 0; $wildcard[2] = 0; $wildcard[3] = 0; $localhost[0] = 127; $localhost[1] = 0; $localhost[2] = 0; $localhost[3] = 1; $sockaddr = "S n a4 x8"; $me = pack( $sockaddr, AF_INET, 0, $wildcard ); $dst = pack( $sockaddr, AF_INET, $serverport, $localhost ); if (!bind( S, $me )) { #print "Error: couldn't bind\n"; close( S ); return $connected; } if (!connect( S, $dst )) { #print "Error: couldn't connect to 127.0.0.1 " # . "port $serverport\n"; close( S ); return $connected; } $connected = 1; close( S ); return $connected; } sub usage { print "Usage: nuttscp or nuttscp -h prints this usage info\n"; print "Usage: nuttscp -V reports nuttscp version\n"; print "Usage: $0 [options] infile [user@]host[/datahost]:outfile\n"; print " or: $0 [options] [user@]host[/datahost]:infile outfile\n"; print " options: -w window default=unspecified\n"; print " -N num_streams default=1\n"; print " -P ctlport default=5100\n"; print " -p dataport default=5101 (5001 on" . " nuttcp < 6.2.8)\n"; print " -l buflen default=64KB\n"; print " -n numbuf default=unlimited\n"; print " -T timeout default=none\n"; # problem with interval retrans info so leave undocumented for now # print " -i interval default=no interval" # . " reports\n"; print " -I identifier default=" . "no identifier\n"; print " -R rate_limit default=unlimited\n"; print " -M mss default=unspecified\n"; print " -x extra_option default=unspecified\n"; print " -b brief_option default=standard" . " brief output\n"; print " -f default=remote" . " nuttcp server\n"; print " -F default=" . "nuttcp flip off\n"; print " -4 default=" . "auto IPv4/IPv6\n"; print " -6 default=" . "auto IPv4/IPv6\n"; print " -v default=" . "no verbose nuttcp\n"; if (`uname` =~ /[Ll]inux/) { print " -z default=no zero copy\n"; } print " --copy-dir default=copy file\n"; print " --verbose default=not verbose\n"; print " --compressed default=" . "not compressed\n"; print " --one-file-system default=" . "stay on local fs\n"; print " --remote-shell shell default=" . "same as local\n"; print " --remote-nuttcp path default=nuttcp\n"; print " --datahost host default=same as " . "ssh/rsh host\n"; print " --ssh-id identity default=unspecified\n"; print " --ssh-port port default=22\n"; if ($def_noclobber) { print " --clobber default=" . "noclobber\n"; } else { print " --noclobber default=" . "clobber\n"; } print "\n"; print " infile may be a pipe: \"command |\"\n"; print " outfile may be a pipe: \"| command\"\n"; }