######
#
#   EASY-IPC.PL
#       Copyright : Software Research Associates, Inc. 1990
#	Written by Hiroshi Sakoh (sakoh@sra.co.jp) 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;
