#!/afs/athena/contrib/perl/perl

require "sys/socket.ph";

package zsend;

sub zascii {
	local($retval,$data) = ("",$_[0]);
	while (length($data)>=4) {
	        $retval .= " " if ($retval);
		($c1,$c2,$c3,$c4,$data) = unpack("C4a*",$data);
		$retval .= sprintf("0x%02X%02X%02X%02X",$c1,$c2,$c3,$c4);
	}

	if ($data) {
		$retval .= " " if ($retval);
		$retval .= "0x";
		while ($data) {
			($c1,$data) = unpack("Ca*",$data);
			$retval .= sprintf("%02X",$c1);
		}
	}

	return($retval);
}

sub zlong {
	return(&zascii(pack("N",$_[0]))."\0");
}

sub thechop {
	local($foo) = $_[0];
	chop($foo);
	return($foo);
}

sub main'zpacket {
	local($uid, $class, $inst, $opcode, $sender, $recip, $default, $msg)
		= @_;
	local($packet);

	if (! $uid) {
	    if (@zhmaddr && $zhmaddr[0] != 127) {
		$localaddr = pack("C4",@zhmaddr) if (! $localaddr);
	    } else {
		$localaddr = ((gethostbyname(&thechop(`hostname`)))[4])
				if (! $localaddr);
	    }
	    $uidinc = 0 if ($oldtime != time);
	    $uidinc++;
	    $uid = pack("a4 N N",$localaddr,$oldtime=time,$uidinc);
	}

	$packet .= "ZEPH0.2\0";
	$packet .= &zlong(17);
	$packet .= &zlong(0);			# UNSAFE
	$packet .= &zascii($uid)."\0";
	$packet .= &zascii(pack("n",0))."\0";	# no response port
	$packet .= &zlong(0);			# no auth
	$packet .= &zlong(0);			# authlen = 0
	$packet .= "\0";			# no authdata
	$packet .= $class."\0";
	$packet .= $inst."\0";
	$packet .= $opcode."\0";
	$packet .= $sender."\0";
	$packet .= $recip."\0";
	$packet .= $default."\0";
	$packet .= &zlong(0);			# no checksum
	$packet .= "\0";			# no fragmentation
	$packet .= &zascii($uid)."\0";
	$packet .= $msg;
}

sub zinit {
	local($saddr,$port,$sin,$sock,$fd);

 	$port = (getservbyname("zephyr-hm","udp"))[2] ||
	    die "servbyname: $!\n";

	if (@zhmaddr == 0) {
	    @zhmaddr = (127,0,0,1);
	}

	$zhmsrc = pack("S n C4 x8",&main'AF_INET,0,127,0,0,1);
	$zhm = pack("S n C4 x8",&main'AF_INET,$port,@zhmaddr);

	socket(ZHM, &main'AF_INET, &main'SOCK_DGRAM, 0) || die "socket: $!";

	bind(ZHM, $zhmsrc);

	$fd = select(ZHM); $| = 1;   # set nonbufferred
	select($fd);
}

sub main'zsend {
	&zinit if (! defined($zhm));

	send(ZHM,$_[0],0,$zhm) || die "$! sending packet\n";
}

