Forking a daemonic Socket listener from a CGI script - browser times out

Discussion in 'Perl Misc' started by Clyde Ingram, Dec 12, 2003.

  1. Clyde Ingram

    Clyde Ingram Guest

    I have 2 separate Perl programs:

    1. Socket server - which listens for a connection request from a socket
    client, writes some data records, and exits.

    2. CGI program - which sends a Java applet to the browser (Navigator 4.6).
    The applet requests a socket connection to the "Socket server", reads
    records, and displays them.

    All works well if the "Socket server" and "CGI program" run as separate
    processes - the browser requests and gets the applet from the "CGI server";
    the applet starts, connects with the "Socket server", reads the data records
    from it, and displays the records..

    However, I combine them into one CGI program, which forks a child process to
    performs the long-running "Socket server" function, the HTML document sent
    by the "CGI server" does not complete loading in the browser.

    At least, not until a 5 minute timeout. Then the applet runs, and
    successfully connects to the "Socket server" and reads and displays the
    data. The indicates on screen that an error occurred. The server weblog
    records a timeout error.

    I have tried various tricks from the books on detaching the "Socket server"
    (child) process from the "CGI program" (parent) process, but cannot fix this
    "daemonic" problem in document loading.

    For example, the child process:

    - calls POSIX::setsid
    - closes and re-opens some of its file handles

    Can any helpful person suggest what I have missed here, please?

    Here is my web server log - spot the 5 minute delay before the "Socket
    server" writes out its data.
    This is followed by the complete CGI program - a bit long, I know, but the
    "fork" call is in the main code.
    (Because this posting is so long, I am not posting the Java applet - yet. I
    think it is not the problem, since it works fine with the original separate
    2 Perl server programs.)

    Ta,
    Clyde

    +++++++++++++++++++++++++++ web server log
    12:45:08: Process 22587 forking
    12:45:08: Parent: closing STDIN - unwanted
    12:45:08: Parent: writing HTML page including socket client applet,
    instructing to use port 4444
    12:45:08: Child: closing STDIN - unwanted
    12:45:08: Child: closing STDOUT - unwanted
    12:45:08: \ main::write_html_page_incl_socket_client_applet( 4444 )
    12:45:08: Parent: generate HTML document
    12:45:08: Child: Creating and listening on socket for tcp port 4444
    12:45:08: Child: shutting down read stream of socket - unwanted
    12:45:08: Child: Wait for incoming socket client connection request
    12:45:08:
    12:45:08: Parent: prepared this HTML document:
    12:45:08:
    12:45:08: Content-Type: text/html; charset=ISO-8859-1

    12:45:08:

    12:45:08: <?xml version="1.0" encoding="utf-8"?>
    12:45:08: <!DOCTYPE html
    12:45:08: PUBLIC "-//W3C//DTD XHTML Basic 1.0//EN"
    12:45:08: "http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd">
    12:45:08: <html xmlns="http://www.w3.org/1999/xhtml"
    lang="en-US"><head><title>Applet running a Socket Client</title>
    12:45:08: </head><body>
    12:45:08: <h3>
    12:45:08: Applet running a Socket Client
    12:45:08: </h3>
    12:45:08: <applet width="100%" code="MonitorAdrLoaderApplet.class"
    name="MonitorAdrLoaderApplet" height="100%" codebase="http://web/admin-ui/">
    12:45:08: <param value="host.domain" name="serverhostname"> <param
    value="4444" name="serverport"> <param value="33" name="appletrows"> <param
    value="77" name="appletcols"> <param value="12" name="appletfontsize">
    <param value="Courier" name="appletfontname"> <param value="."
    name="socketeofmarker">
    12:45:08: </applet>
    12:45:08: </body></html>
    12:45:08:
    12:45:08:
    12:45:08: Parent: sending HTML document to browser:
    12:45:08:
    12:45:08: / main::write_html_page_incl_socket_client_applet( )
    12:45:08: Parent: closing STDOUT - unwanted
    12:45:08: Parent: closing STDERR - unwanted
    12:45:08: Parent 22587: exiting
    [12/Dec/2003:12:50:08] failure ( 8561): for host 127.0.0.1 trying to GET
    /admin-ui/test_socket_applet.cgi, cgi_send reports: error occurred while
    sending script output (IO timeout error)
    [12/Dec/2003:12:50:08] warning ( 8561): for host 127.0.0.1 trying to GET
    /admin-ui/MonitorAdrLoaderApplet.class.sec, send-file reports: can't find
    /opt/jocs/website/admin/MonitorAdrLoaderApplet.class.sec (No such file or
    directory)
    12:50:09: Child: Flush socket client file handle, and write records out to
    it
    12:50:09: Child: -> Homer: D'oh
    12:50:09: Child: -> Marge: A deer
    12:50:09: Child: -> Lisa: A female deer
    12:50:09: Child: ->
    12:50:09: Child: -> Bart: Hello. I'm Bart Simpson.
    12:50:09: Child: -> Bart: Who the hell are you?
    12:50:09: Child: ->
    12:50:09: Child: -> Homer: Mmmmm
    12:50:09: Child: -> Homer: 64
    12:50:09: Child: -> Homer: slices
    12:50:09: Child: -> Homer: of
    12:50:09: Child: -> Homer: American
    12:50:09: Child: -> Homer: Cheese
    12:50:09: Child: ->
    12:50:09: Child: -> Homer: Sacrilicious!
    12:50:09: Child: ->
    12:50:09: Child: -> Homer: Yummie, yummie, yummie -- I've got love in my
    tummy, and I think I'm loving you. D'oh, d'oh, d'oh!!
    12:50:09: Child: ->
    12:50:09: Child: -> Homer: Mmmmm, chocolate!
    12:50:09: Child: -> .
    12:50:09: Child: Closing socket for tcp port 4444
    12:50:09: Child: Exiting

    +++++++++++++++++++++++++++ CGI program

    #!/bin/perl -wT

    $ENV{'PATH'} = '/bin:/usr/bin';
    $ENV{'SHELL'} = '/bin/sh' if ( exists $ENV{'SHELL'} );
    delete @ENV{ 'IFS', 'CDPATH', 'ENV', 'BASH_ENV' };

    print STDERR join ( "\n", @INC ) . "\n";

    use strict;
    use POSIX; # For dup() and setsid() functions
    use English;
    use IO::Socket;

    $OUTPUT_AUTOFLUSH++;

    use constant HOSTNAME => scalar 'host.domain';
    use constant SERVER_PORT => scalar '4444';
    use constant PROTOCOL => scalar 'tcp';
    use constant APPLET_ROWS => scalar '33';
    use constant APPLET_COLS => scalar '77';
    use constant APPLET_FONTSIZE => scalar '12';
    use constant APPLET_FONTNAME => scalar 'Courier';
    use constant EOF_MARKER => scalar '.';

    BEGIN {
    use CGI
    qw/ -oldstyle_urls :standard :html3 :form :cgi cgi_error $POST_MAX
    $DISABLE_UPLOAD :netscape /;

    $CGI::pOST_MAX = 2 * 1024 * 1024;
    $CGI::DISABLE_UPLOAD = 1;
    use CGI::Carp qw( fatalsToBrowser carpout );

    my $server_error_log_file =
    '/opt/netscape/suitespot/https/logs/errors';

    open( LOG, ">>$server_error_log_file" )
    or die "$server_error_log_file: unable to append to log file:
    $ERRNO\n";
    carpout(*LOG);

    use CGI::pretty qw ( :html3 );
    }

    local $SIG{'CHLD'} = 'IGNORE';

    my $identity = 'Process';
    my $child_pid;

    my @socket_data = <DATA>;
    chomp @socket_data;

    warn("$identity $PID forking\n");

    if ( $child_pid = fork() ) { # Parent

    $identity = 'Parent';

    # warn( "$identity: closing server socket - unwanted\n" );
    # close( $server_socket );
    warn("$identity: closing STDIN - unwanted\n");
    close(STDIN);
    open( *STDIN, "+< /dev/null" )
    or die "$identity failed to close STDIN: $ERRNO";

    warn(
    "$identity: writing HTML page including socket client applet,
    instructing to use port "
    . +SERVER_PORT . "\n" );

    write_html_page_incl_socket_client_applet( +SERVER_PORT )
    or die "Failed to write HTML page with socket client applet: $ERRNO";

    warn("$identity: closing STDOUT - unwanted\n");
    warn("$identity: closing STDERR - unwanted\n");

    warn("$identity $PID: exiting\n");

    close(STDOUT);
    close(STDERR);
    open( *STDOUT, "+< /dev/null" )
    or die "$identity failed to close STDOUT: $ERRNO";
    open( *STDERR, "+< /dev/null" )
    or die "$identity failed to close STDERR: $ERRNO";

    exit(1);
    }
    else { # Child

    $identity = 'Child';

    local $SIG{'PIPE'} = 'IGNORE';

    local $SIG{'INT'} = $SIG{'TERM'} = $SIG{'HUP'} = sub {

    warn( "Signal handler: $identity got INT or TERM or HUP signal"
    . ( $CHILD_ERROR >> 8 ) . "\n" );
    exit(0);
    };

    warn("$identity: closing STDIN - unwanted\n");
    warn("$identity: closing STDOUT - unwanted\n");

    # warn( "$identity: closing STDERR - unwanted\n" );
    close(STDIN);
    close(STDOUT);

    # close( STDERR );
    open( *STDIN, "+< /dev/null" )
    or die "$identity failed to close STDIN: $ERRNO";
    open( *STDOUT, "+< /dev/null" )
    or die "$identity failed to close STDOUT: $ERRNO";

    # open( *STDERR, "+< /dev/null" ) or die "$identity failed to close
    STDERR: $ERRNO";

    # Dissociate from the parent and stop being part of the process
    # group we had been a member of

    POSIX::setsid()
    or die "Cannot start a new session: $ERRNO";

    # Listen for a socket connection request from the Java applet
    listen_and_write_to_socket()
    or die "Failed to listen for service socket: $ERRNO";

    exit(1);
    }

    exit(1);

    #-----------------------------------------------------------------------

    sub write_html_page_incl_socket_client_applet {

    trace_in( ( caller(0) )[3], @_ );

    my ($server_port_nr) = @_;

    warn("$identity: generate HTML document\n");

    my $html_document =
    header()
    . start_html( -Title => 'Applet running a Socket Client' )
    . h3('Applet running a Socket Client')
    Clyde Ingram, Dec 12, 2003
    #1
    1. Advertising

  2. >>>>> "Clyde" == Clyde Ingram <> writes:

    Clyde> I have tried various tricks from the books on detaching the "Socket server"
    Clyde> (child) process from the "CGI program" (parent) process, but cannot fix this
    Clyde> "daemonic" problem in document loading.

    Read the stuff I've repeated in at least three or four of my
    columns (of the 198 I've done so far). Google for:

    site:stonehenge.com cgi fork

    That should point you in the right direction.

    print "Just another Perl hacker,"
    --
    Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
    <> <URL:http://www.stonehenge.com/merlyn/>
    Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
    See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!
    Randal L. Schwartz, Dec 12, 2003
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ed
    Replies:
    0
    Views:
    687
  2. Robin Munn

    Re: Bug help: CGI forking

    Robin Munn, Aug 1, 2003, in forum: Python
    Replies:
    0
    Views:
    545
    Robin Munn
    Aug 1, 2003
  3. John L. Stephens

    Multiprocessing.Process Daemonic Behavior

    John L. Stephens, Mar 16, 2011, in forum: Python
    Replies:
    0
    Views:
    274
    John L. Stephens
    Mar 16, 2011
  4. Rob Young

    forking and ending a CGI process

    Rob Young, Aug 11, 2003, in forum: Perl Misc
    Replies:
    1
    Views:
    123
    Gregory Toomey
    Aug 11, 2003
  5. kath
    Replies:
    4
    Views:
    585
    J. Gleixner
    Apr 9, 2007
Loading...

Share This Page