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

Dear brothers,

I have a script run by FreeRadius (using their Apache-like perl_mod system, called rlm_perl) that executes a function when an Access-Request RADIUS packet is received.

The function determines if the authentication is correct or not, and returns the approriate response to the daemon. It must also send a notification. I have these implemented as e-mail messages (using Mail::Sendmail), but I cannot wait for the email to be sent (network delays, etc...).

The problem is that when I fork the notification, I cannot wait() for it: if I allow it to end, it will return a reply of its own to the FreeRadius, which is translated in more than one reply packet to the client; if I exit the child, it remains as a zombie freeradius process until the server is reinit...

I have tried to implement this setup with Proc::Fork, vanilla fork() and even threads (although these cannot work, because the function is executed in a kind of CGI fashion), but I always get these problems...

So, can anyone tell me if it's possible to fork the notification so it doesn't let zombies behind, and does not forces me to wait for it to be done?

As a last resort, I will have to take the notification to a different process that is watching a log file or something, but that complicates things a bit, and it's yet another process to dogwatch...

Thanks!

PS- updated: I have tested it with $SIG{CHLD} = 'IGNORE'; and am playing with all the different possibilities of perlipc(1), but it's a bit discouraging... Thanks!

--
our $Perl6 is Fantastic;

Replies are listed 'Best First'.
Re: Zombie-less forking inside a daemon?
by Moron (Curate) on Jun 13, 2006 at 11:31 UTC
    It depends on what you mean by "wait". A POSIX subprocess will autozombify if the stack frame from which perl called it is unwound without waiting - it seems to me that the fork itself should wait for the mail subprocess to prevent that being the zombie - waiting for the fork that invokes the mail should not be the issue here:
    use POSIX ":sys_wait_h"; ... # important: called within fork sub Send { my $message = shift; my $pid = open my $wh, '| mail ...'; print $wh $message; close $wh; waitpid $pid, 0; }
    So in my expected scenario the above fork "waits" but is really only waiting for the mail process to close the pipe rather than prematurely unwind the current stack frame for subroutine Send. See the perlipc documentation section for the full and very gory details.

    -M

    Free your mind

Re: Zombie-less forking inside a daemon?
by crouchingpenguin (Priest) on Jun 13, 2006 at 13:57 UTC
    You want to use the double fork method that orphans your process to be reclaimed by init (PID 1). Within your child, fork again and die immediately. The original process (grandparent) then waits for the new parent while the grandchild goes off to do notifications.

    cp
    ----
    "Never be afraid to try something new. Remember, amateurs built the ark. Professionals built the Titanic."
Re: Zombie-less forking inside a daemon?
by dsheroh (Monsignor) on Jun 13, 2006 at 15:09 UTC
    Have you considered putting a wait() into a SIGCHILD handler? I would expect the wait() to then only fire when a child has died, so it should return immediately.

    (I have done the sort of thing you're asking about and I think that's how I avoided zombies, but I'm not currently able to access that source to verify my methods.)