######
#
#   EASY-IPC.PL
#       Copyright : Software Research Associates, Inc. 1990
#       Written by Hiroshi Sakoh ([email protected]) on 10-25-90
#       Please distribute widely, but leave my name here.
#

require "sys/socket.ph";
#
# &defserver(SOCKET, $port);
#
# Returns a server socket ready for acceptsock()
#
sub defserver { # arg0 == socket, arg1 == port
   local($this, $oldfh);
   local($port) = $_[1];
   local($name, $aliases, $proto);
   local($sockaddr_t) = 'S n a4 x8';

   ($name, $aliases, $port, $proto) = getservbyname($port, "tcp")
                                       unless $port =~ /^\d+$/;
   socket($_[0], &PF_INET, &SOCK_STREAM, 0) || die "socket: $!\n";
   $this = pack($sockaddr_t, &PF_INET, $port, "\0\0\0\0");
   bind($_[0], $this) || die "bind: $!\n";
   listen($_[0], 5);
   $oldfh = select($_[0]) ; $| = 1; select($oldfh);
}

#
# &defclient(SOCKET, $host, $port)
#
# Returns a connected client socket.
#
sub defclient { # arg0 == socket, arg1 == host, arg2 == port
   local($that, $thataddr, $oldfh);
   local($port) = $_[2];
   local($name, $aliases, $proto);
   local($sockaddr_t) = 'S n a4 x8';

   ($name, $aliases, $port, $proto) = getservbyname($port, "tcp")
                                       unless $port =~ /^\d+$/;
   if ($_[1] =~ /^\d+\.\d+\.\d+\.\d+$/) {
       $thataddr = &inet_addr($_[1]);
   } else {
       ($name, $aliases, $type, $len, $thataddr) = gethostbyname($_[1]);
   }
   $that = pack($sockaddr_t, &PF_INET, $port, $thataddr);
   socket($_[0], &PF_INET, &SOCK_STREAM, 0) || die "socket: $!\n";
   connect($_[0], $that)                    || die "connect: $!\n";
   $oldfh = select($_[0]) ; $| = 1; select($oldfh);
}

$__EIPCSno__ = 'a';
#
# &acceptsock($newsock, $serversock)
#
# Returns a bind socket which is derived from a generic server socket
#
sub acceptsock {
   local($addr);
   local($oldfh);

   $_[0] = $_[1] . ".." . $__EIPCSno__ ++; # make it unique
   $addr = accept($_[0], $_[1]) || die "accept: $!\n";
   $oldfh = select($_[0]) ; $| = 1; select($oldfh);
   $addr;
}

#
# &selectsock(@sockets)
#
# Returns available sockets for read (blocks)
#
sub selectsock {
   &selectsock_with_timeout(undef, @_);
}

#
# &selectsock_non_block(@sockets)
#
# Returns available sockets for read (doesn't block)
#
sub selectsock_non_block {
   &selectsock_with_timeout(0, @_);
}

#
# &selectsock_with_timeout($timeout, @sockets)
#
# Returns available sockets for read (with timeout)
#
sub selectsock_with_timeout {
   local($nfound, $timeleft);
   local($rin, $rout, $win, $wout, $eout, $ein);
   local($timeout) = shift;

   $rin = &setsockbits(@_);
   ($nfound, $timeleft) = select($rout=$rin, $wout=$win, $eout=$ein, $timeout);

   grep(vec($rout,fileno($_),1),@_);
}

#
# &setsockbits(@sockets)
#
# Returns a bitvector corresponding to sockets list
#
sub setsockbits{
   local(@fhs) = @_;
   local($bits);
   for (@fhs) {
       vec($bits, fileno($_), 1) = 1;
   }
   $bits;
}

#
# &inet_addr($addr)
#
# Converts an internet dot notation (##.##.##.##) to an internet address
#
sub inet_addr {
   pack("C4", split(/\./, $_[0]));
}

1;