######
#
#   EASY-SERV.PL
#       Copyright : Software Research Associates, Inc. 1990
#	Written by Hiroshi Sakoh (sakoh@sra.co.jp) on 11-01-90
#	Please distribute widely, but leave my name here.
#

require "sys/fcntl.ph";
require "easy-ipc.pl";
#
# &register_serv($name, $port)
#
# Registers a service port.
#
sub register_serv {
    &defserver($_[0], $_[1]);
    fcntl($_[0], &F_SETFL, &FNDELAY)         || die "fcntl: $!\n";
    $_eserv_generic{$_[0]} = $_[0]; # define generic socket
    $_eserv_sockets{$_[0]} = $_[0];
}
#
# &register_client($name, $host, $port)
#
# Registers a client port.
#
sub register_client {
    &defclient($_[0], $_[1], $_[2]);
    fcntl($_[0], &F_SETFL, &FNDELAY)         || die "fcntl: $!\n";
    $_eclient_sockets{$_[0]} = $_[0];
}

#
# &run_serv()
#
# Wait for a request, dispatch it.
# Sends back a reply to the requester.
#
sub run_serv {

    local($bytestoread, $packet, $actualread, $request, $reply);
    local($bytestowrite, $actualwrite);
    local($try);
    local($MAXTRY) = 1000;

    for (;;) {

	@avails = &selectsock(keys(_eserv_sockets)); # wait for a request

	nextavail: for(@avails) {
	    if (defined($_eserv_generic{$_})) { # got a request for connection
		&acceptsock($_eserv_newsock, $_);
		$_eserv_sockets{$_eserv_newsock} = $_eserv_newsock;
	    } else {
		if (!eof($_)) { # got an usual request
		    chop($bytestoread = <$_>);
			# The first packet should contain bytes to be read.
		    for ( $request = "" ; $bytestoread > 0 ;
				$bytestoread -= $actualread) {
			for ($actualread = $try = 0;
			     ($actualread == 0) && ($try < $MAXTRY); $try++) {
			    $actualread = read($_, $packet, $bytestoread);
			}
			if ($actualread == 0) {
			    print STDERR "Unexpected EOF\n";
			    close($_);
			    delete $_eserv_sockets{$_};
			    next nextavail;
			}
			$request .= $packet;
		    }
		    $reply = &serv_body($request, $_);
		    # I'd really like to use syswrite() below to
		    # avoid to be blocked. But it doesn't work. Why??????
		    print $_ length($reply) . "\n";
		    for ($bytestowrite = length($reply)
			; $bytestowrite > 0 ; $bytestowrite -= 1024) {
			print $_  substr($reply, 0, 1024);
			$reply = substr($reply, 1024);
		    }
		} else {	# got an eof message
		    close($_);
		    delete $_eserv_sockets{$_};
		}
	    }
	}
    }
}

#
# &send_request($socket, $request)
#
# Sends a request to a server, waits a reply from the server
# and returns it.
#
sub send_request {
    local($sock, $request) = @_;
    local($reply, $packet, $bytestoread, $actualread);
    local($bytestowrite);
    local($try);
    local($MAXTRY) = 1000;

    # I'd really like to use syswrite() below to
    # avoid to be blocked. But it doesn't work. Why??????
    print $_ length($request) . "\n";		# write length of data
    for ($bytestowrite = length($request)	# write data packets
	; $bytestowrite > 0 ; $bytestowrite -= 1024) {
	print $sock substr($request, 0, 1024);
	$reply = substr($request, 1024);
    }

    chop($bytestoread = <$sock>);
	# The first packet should contain bytes to read.
    for ( $reply = "" ; $bytestoread > 0 ; $bytestoread -= $actualread) {
	for ($actualread = $try = 0;
	     ($actualread == 0) && ($try < $MAXTRY); $try++) {
	    $actualread = read($_, $packet, $bytestoread);
	}
	if ($actualread == 0) {
	    print STDERR "Unexpected EOF\n";
	    close($sock);
	    return "";
	}
	$reply .= $packet;
    }
    $reply;
}

#
# &cleanup_serv()
#
# Closes down all server sockets and exits.
#
sub cleanup_serv {
    for(keys(_eserv_sockets)) {
	close($_);
    }
    exit;
}

1;
