######
#
#   EASY-SERV.PL
#       Copyright : Software Research Associates, Inc. 1990
#       Written by Hiroshi Sakoh ([email protected]) 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;