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

So... I have a fast-cgi like daemon written in perl... when a call comes in I do the following:

*STDIN = $c; # $c is child socket select $c; open(STDOUT,">&=".fileno($c));
the problem I am coming across, however, is the old closing and opening STDOUT changing the file descriptor of STDOUT. When this happens child processes can't see STDOUT.

I believe this is what is causing my problems, but I can't figure out how to ensure that I always open fileno 1. Is there a way to do it?

                - Ant
                - Some of my best work - (1 2 3)

Replies are listed 'Best First'.
Re: STDOUT changing descritpors
by Zaxo (Archbishop) on Sep 01, 2004 at 20:21 UTC

    No, not without closing whatever handle has descriptor 1, then opening STDOUT - checking fileno to see if you got what you wanted.

    There is no rule that says STDIN, STDOUT, STDERR are fileno 0, 1, 2. That's just their conventional default values. Closings and openings scramble the fileno values. It is an error to assume anything about those values.

    A child process will never have its live inherited file handles changed by their modification in the parent. The parent handles have been duplicated by fork. The child's copies are still associated with the original file whatever the parent may do to modify its own.

    After Compline,
    Zaxo

Re: STDOUT changing descritpors (open, no =)
by tye (Sage) on Sep 02, 2004 at 15:49 UTC
    *STDIN = $c; # $c is child socket

    Well, no wonder you have problems. Using symbol table globs to copy around file handles is usually a pretty bad idea, in my experience.

    I can't figure out how to ensure that I always open fileno 1

    open covers this. You close fileno 1 and then immediately reopen STDOUT and Perl even goes to a little extra effort to make sure fileno 1 is what you get (and this is documented). But ">&=" doesn't "open" any file descriptors, it causes a file handle to be associated with an already-open file descriptor. You want ">&" instead (which dup()s a file descriptor).

    There is even an example of how to redirect STDOUT and STDERR (and then restore them) in the open documentation. To do STDIN andn STDOUT and not worry about restoring them, you should use something like:

    open( STDIN, "<&".fileno($c) ) # also closes old STDIN or die "Can't redirect STDIN from socket: $!\n"; open( STDOUT, ">&".fi­leno($c) ) # also closes old STDOUT or die "Can't redirect STDOUT to socket: $!\n";

    - tye        

      Excellent... that seems to fix the STDOUT problem... but when I do that for STDIN it does not seem to work.
      open(STDIN,"<&".fileno($c)) or die; print STDERR "STDIN: ",<STDIN>; print STDERR "\$c: ",<$c>;
      gives me:
      20040902 14:15:45 STDIN: 20040902 14:15:45 $c: fcl_userid=d4ants&fcl_password=hidden&referer=& +fcl_login_submit=Login
      very strange. This I can deal with.. the STDOUT was the more important thing, STDIN would just be a nice thing to get working.

      I had manged to get it working using POSIX::dup2 and POSIX::close... but this seems much nicer :)

      Thanks!

                      - Ant
                      - Some of my best work - (1 2 3)