vasu has asked for the wisdom of the Perl Monks concerning the following question:

Hi perl gurus, I have a setup wherein a perl script is configured as a service inetd.conf (i.e., the perl script is spawned when I make a telnet/tcp connection to the corresponding tcp port defined in inetd.conf). The perl script in turn starts up remsh onto a different host
open(RCMD, "remsh $h -l $u $script |") || die $!; while (<RCMD>) { print $_; }
So, the intent is that a user or application makes a connection to the inetd port (for example, telnet localhost 9876), inetd spawns the perl script, which in turn runs remsh. The perl script has cleanup sub-routine setup for TERM, HUP, QUIT, PIPE signals. The setup works ok except that when the calling telnet/tcp process exits, the perl script is not getting any signal or any indication that the calling process has exited. The only time we get an indication that the calling process has exited is when the remsh returns some data to be written to STDOUT, at which time a SIGPIPE is signalled. I checked inetd code to see if it monitors the active socket; inetd just passes the control of the active socket essentially to the perl script (using dup2 and execv). An immediate indication I get that the calling process has exited is that the child remsh process either exits (HP-UX) or becomes defunct (Tru64) - This happens when I dont use the -n option for remsh. To cut a long story short, do you have any pointers on how I can detect that the calling process has exited ? Any different ways in which I can call remsh ? Also, is it possible for the perl process to check if the stdout has been closed without writing any data to the stdout ?

Replies are listed 'Best First'.
Re: inetd spawned perl problem
by chip (Curate) on May 09, 2003 at 15:43 UTC
    You should start by checking the return value of print - it will return false eventually when it tries to flush an output buffer and the socket it's writing to is closed. You may also want to set $| so that output is sent immediately and closure is detected immediately.

        -- Chip Salzenberg, Free-Floating Agent of Chaos

Re: inetd spawned perl problem
by Thelonius (Priest) on May 09, 2003 at 16:11 UTC
    I am presuming that the commands you are running via remsh are _not_ trying to read STDIN. If they did, they would detect EOF when the remote process ended (or otherwise closed the socket), so they should exit normally.

    Assuming this is the case, you should have a process use select() or IO::Select::can_read to monitor the socket. Without knowing which O/S and version of Perl you are running this on, I can't promise this will work, but my suggestion would be to try this:

    Right before you do the open(RCMD,...), fork(). Have the parent do a can_read on STDIN. Have it be prepared to receive SIGCHLD. The child just runs the code that you give above, then exits().
    If the can_read() returns before the SIGCHLD, then the socket has closed (assuming you are not expecting more data!) and you can kill the child process.
      Hi, Thank you very much for your message. I'm using perl 5.005_03 on HP-UX 10.20 and 5.8.0 on Tru64 v5. I think that i've not explained the exact problem.
      The connection sequence would be as shown:
      • client uses telnet to make connection to inetd port (eg 9876)
      • inetd spawns my perl process and disassociates itself from the active socket created. My perl process does not explicitly open a socket; all it's doing is writing to stdout, which in turn will be written on the socket back to the client.
      • My perl process runs remsh and writes whatever data is returned by remsh.

      At this point, I close the client that calls the telnet. If I start remsh w/o the -n option, then the spawned child remsh process becomes defunct (most probably b'cos the parent remsh process does not do a wait()). If I start remsh with the -n option, then there does not appear to be any signals processed (additionally remsh inherently ignores TERM, INT and QUIT).
      So, at this point, I have my perl script still running along with the remsh processes. The script will exit along with the remsh processes only when there is some data returned from remsh and SIGPIPE is received.
      Is there any other way I can check for the closure of the socket from my perl script (given the fact that I dont have a file handle on the socket) ? Also, any other way I can check for the closure of STDOUT ? I cant write arbitrary data out to STDOUT as the script writes to another set of processes that parse the data and expect the data to be in a certain format and those processes cannot be modified easily.
      Thanks again!
        Here is my interpretation of what you describe:

        A client process "C" connects to port 9876.
        Inetd accepts the connection, forks, then execs() your perl program "P".
        Your perl program starts a remsh process "S" which connects to a remote host and process "R".

        The process P is running this code:

        open(RCMD, "remsh $h -l $u $script |") || die $!; while (<RCMD>) { print $_; }

        I think what you are asking is how your Perl program P can detect if the client C exits (or otherwises closes the socket connection). Right now it may wait a long time on <RCMD> and not give an error until the "print $_".

        If this is a correct understanding, then what I suggested above should work. The STDIN and STDOUT of your Perl process P are both connected to the socket connection that "C" connected to and inetd accepted. A call to select() or can_read() should detect when that socket connection is closed.