# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# NAME                                                                #
#   HTTPcon - make HTTP connection.                                   #
#                                                                     #
# SYNOPSIS                                                            #
#   $stat = &HTTPcon(*F,'fubar.com:1234');                            #
#                                                                     #
# DESCRIIPTION                                                        #
#   This  accepts a URL's host:port portion, and attempts to make the #
#   connection.  If successful, we return 1 with F open  to  the  TCP #
#   socket.   If  we fail, we return 0, and F may or may not be open. #
#   (Maybe we should close it.)                                       #
#                                                                     #
# TIMEOUTS                                                            #
#   I've added a timeout kludge:  If $HTTPtimeout is nonzero, we will #
#   exit after that many seconds. This is drastic, but it seems to be #
#   the only solution to the hung-connect problem.   This  is  mostly #
#   used  in webcat, which is used as a subprocess by other programs. #
#   If you call "webcat -T15 ...", it will exit after 15  seconds  if #
#   the connection can't be made, and you can go about your business. #
#                                                                     #
# AUTHOR                                                              #
#   <a href="mailto:jc@trillian.mit.edu">John Chambers</a>            #
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
$HTTPcontime = time;
$HTTPcons = 0;	# Count of connections.
$HTTPalrm = 0;	# Alarm needs to be handled.

sub HTTPcon {
	local(*HTTPsock,$hp) = @_;
	local($a,$b,$c,$d);
	local(@addrs,$host,$port,$savsig,$t,$this,$that,$This,$That);
	$HTTPtimeout = 30 unless defined $HTTPtimeout;
	$W3trace     =  0 unless defined $W3trace;
	if (($host,$port) = ($hp =~ m"^(.*):(\d+)$")) {
		print V "HTTPcon: host=\"$host\" port=\"$port\"\n" if $V>5;
	} else {
		$host = $hp;
		$port = 80;
		print V "HTTPcon: host=\"$host\" port=$port.\n" if $V>5;
	}
	$AF_INET = 2;
	$SOCK_STREAM = 1;
	$sockaddr = 'S n a4 x8';
	($name,$aliases,$proto) = getprotobyname('tcp');
	($name,$aliases,$port) = getservbyname($port,'tcp')
		unless $port =~ /^\d+$/;
	$thisaddr = "\0\0\0\0";
	print "<!--HTTPcon: Get address for \"$host\" -->\n" if $W3trace;
	($name,$aliases,$type,$len,@addrs) = gethostbyname($host);
	if (!@addrs) {
		$errmsg = "No address for \"$host\"";
		return 0;
	}
	$thataddr = $addrs[0];
	$this = pack($sockaddr, $AF_INET, 0, $thisaddr);
	$that = pack($sockaddr, $AF_INET, $port, $thataddr);
	($a,$b,$c,$d) = unpack('C4',$thisaddr);
	$This = "$a.$b.$c.$d:0";
	($a,$b,$c,$d) = unpack('C4',$thataddr);
	$That = "$a.$b.$c.$d:$port";
	if (socket(HTTPsock,$AF_INET,$SOCK_STREAM,$proto)) {
		print V "HTTPcon: Got socket.\n" if $V>5;
	} else {
		print V "HTTPcon: Can't get socket ($!)\n" if $V>0;
		$exitstat = $!;
		return 0;
	}
	if (bind(HTTPsock,$this)) {
		$t = time - $HTTPcontime;
		print V "HTTPcon: Bind to \"$This\" succeeded in $t sec.\n" if $V>5;
	} else {
		$t = time - $HTTPcontime;
		print V "HTTPcon: Bind to \"$This\" failed in $t sec ($!)\n" if $V>2;
		$exitstat = $!;
		return 0;
	}
	++$HTTPcons;
	$HTTPcontime = time;
	if ($HTTPtimeout > 0) {
		alarm $HTTPtimeout;
		$savsig = $SIG{ALRM};
		$SIG{ALRM} = 'HTTPalarm';
		print V "HTTPcon: Set alarm after $HTTPtimeout sec.\n" if $V>3;
	}
	print "<!--HTTPcon: Connecting to \"$That\" -->\n" if $W3trace;
	print "HTTPcon: Connecting to \"$That\"\n" if $V>5;
	if (connect(HTTPsock,$that)) {
		$t = time - $HTTPcontime;
		print V "HTTPcon: Connect $HTTPcons to \"$That\" succeeded in $t sec.\n" if $V>5;
		print "<!--HTTPcon: Connected to \"$That\" -->\n" if $W3trace;
		if ($HTTPtimeout > 0) {
			alarm 0;
			$SIG{ALRM} = $savsig;
			print V "HTTPcon: Set alarm 0.\n" if $V>5;
		}
	} else {
		$t = time - $HTTPcontime;
		print "<!--HTTPcon: Can't connect to \"$That\" in $t sec. ($!)" if $W3trace;
		print V "HTTPcon: Connect $HTTPcons to \"$That\" failed ($!) after $t sec.\n" if $V>2;
		$exitstat = $!;
		if ($HTTPtimeout > 0) {
			alarm 0;
			$SIG{ALRM} = $savsig;
			print V "HTTPcon: Set alarm 0.\n" if $V>5;
		}
		return 0;
	}
	if ($HTTPalrm) {
		close HTTPsock;
		alarm 0;
		$SIG{ALRM} = $savsig;
		print V "HTTPcon: Set alarm 0.\n" if $V>5;
	} else {
		select(HTTPsock); $| = 1; select(STDOUT);
	}
	return 1;
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
sub HTTPalarm {
	my $t = time - $HTTPcontime;
	print "<!--HTTPcon: ALARM after $t sec -->\n" if $W3trace;
#	exit -1;
	$errmsg = 'timeout';
}

1;
