#!/usr/bin/perl -w

# findport - find a server running at an unknown TCP port

# Copyright (C) 1996 by John J. Chew, III <jjchew@math.utoronto.ca>

chop($gHostname = `hostname`);
unshift(@INC, "$ENV{HOME}/local/$gHostname/lib/perl", "$ENV{HOME}/lib/perl");
require 'getopts.pl';
require 'sys/socket.ph';

sub Usage {
  die "Usage: $0 [-m] [-O] [-q] host [start-port]\n".
    "-m  allow multiple matches\n".
    "-O  try `obvious' ports\n".
    "-q  be quiet\n".
    "";
  }

&Getopts('mOq') || &Usage;
$#ARGV < $[ && &Usage;
$#ARGV > $[ + 1 && &Usage;
$#ARGV > $[ && $opt_O && &Usage;

($serverhostname, $serverportname) = @ARGV;
$serverportname = 7777 unless defined $serverportname;

@gObvious = (
  # popular port numbers for MOOs
  7777, 8888, 6666, 6969, 1234, 1701, 4444, 2112, 2499, 4000, 8000, 9595,
  1138, 1359, 1709, 1848, 1961, 1975, 1996, 2000, 2001, 2029, 2345, 3000,
  3175, 4201, 4242, 5000, 5678, 6464, 7000, 7007, 7200, 7700, 7878, 8080,
  8889, 9000, 9020, 9030, 9040, 9999, 3434,

  # other `obvious' numbers
  1111, 1112, 1113, 1996, 1997, 1998, 1999, 2222, 2223, 2224, 3001, 3333,
  3334, 3335, 3456, 4001, 4445, 4446, 4567, 5001, 5556, 5557, 6000, 6001,
  6667, 6668, 6789, 7001, 7778, 7779, 7890, 8001, 9001,
  );
  
sub die { die $_[0] unless $opt_q; exit 1; }

sub lint { $opt_m; }

$sockaddr_t = 'S n a4 x8';

($name, $aliases, $protocol) = getprotobyname('tcp');
socket(S, &PF_INET, &SOCK_STREAM, $protocol) || &die("socket() failed: $!");

(($name, $aliases, $type, $length, $clientaddress) 
  = gethostbyname($gHostname))
  || &die("gethostbyname($gHostname) failed: $!");
$clientname = pack($sockaddr_t, &AF_INET,     0, $clientaddress);
bind(S, $clientname) || &die("bind() failed: $!");

(($name, $aliases, $port) = getservbyname($serverportname, 'tcp'))
  || ($port = $serverportname);
(($name, $aliases, $type, $length, $serveraddress) 
  = gethostbyname($serverhostname))
  || &die("gethostbyname($ARGV[0]) failed: $!");

$| = 1;
$port = shift @gObvious if $opt_O;
while (1) {
  $servername = pack($sockaddr_t, &AF_INET, $port, $serveraddress);
  print "$port" unless $opt_q;
  if (connect(S, $servername)) {
    print "\n\a" unless $opt_q;
    print "$port is active.\n";
    exit 0 unless $opt_m;
    }
  else { 
    print " ";
    $opt_O ? (($port = shift @gObvious) || exit) : $port++;
    close(S);
    socket(S, &PF_INET, &SOCK_STREAM, $protocol) || &die("socket() failed: $!");
    bind(S, $clientname) || &die("bind() failed: $!");
    }
  }
