guilherme.e.j has asked for the wisdom of the Perl Monks concerning the following question:

Hello all, I'm doing a perl daemon that runs commands in a server. A client connects in a specific port and send any command. It works fine, but when I run a "/etc/init.d/asterisk start", for example, the service is started normally, but when I close the daemon, the service started goes down too. I already use POE module, but I didn't have sucess. Any idea??

daemon.pl:
use IO::Socket; use Net::hostent; # for OO version of gethostbyaddr use POE; $PORT = 5039; # pick something not in use $sock = IO::Socket::INET->new( Proto => 'tcp', LocalPort => $PORT, Listen => 1, Reuse => 1); die "can't setup server" unless $sock; print "[Server $0 accepting clients]\n"; $command = $sock->accept(); while (1) { while (<$command>) { POE::Session->create( inline_states => { _start => sub { qx(/etc/init.d/asteris +k start); } }, ); $poe_kernel->run(); } sleep(1); }
Thanks

Replies are listed 'Best First'.
Re: Perl daemon that runs another daemon
by Old_Gray_Bear (Bishop) on Nov 01, 2006 at 20:51 UTC
    The Perl Cookbook has a recipe titled "17.15 Writing a Multitasking Server with POE". It says that you want to use the POE::Component::Server::TCP module to build the server framework. Then you supply call-back routines and the framework handles the messiness.

    I haven't tried this myself; when I've needed daemons, I just use fork() and cleanup the environment (interrupts, STD files, etc) to suit (Recipe 17.17, a couple of pages later).

    ----
    I Go Back to Sleep, Now.

    OGB

Re: Perl daemon that runs another daemon
by Fletch (Bishop) on Nov 01, 2006 at 20:33 UTC

    Oy, where to start . . .

    qx// runs the command you specify synchronously, capturing the output. Presumably /etc/init.d/asterisk will fork off some other daemon and then exit. Since there's nothing else likely to be keeping the POE session alive after the start state routines it'll exit, and . . .

    Know what? Forget that code. My brane is throbbing just from attempting to divine its intent. Start from scratch and describe what you're attempting to do. Don't presume any mechanism or particular modules for implementations. Step back and outline what the frell you're attempting to do. Then someone might be able to help.

      I would like to do a daemon that listen in a specific port. This daemon will run commands come from client machines. I will develop a web application that will permit actions like start and stop, of several services (apache,mysql,asterisk...), so the application will connect in this daemon to run commands (/etc/init.d/mysql stop, for examplo). I dont know if it is clear...
      Thanks
Re: Perl daemon that runs another daemon
by andyford (Curate) on Nov 01, 2006 at 22:35 UTC
    Ignore this post if you're just doing this for fun or if you're requirements are more complex than what you've described, but....

    Just from reading your requirements, I'd say that your daemon is already probably running on your server: sshd!
    Read the following aloud to yourself:

    I would like to do a daemon that listen in a specific port. This daemon will run commands come from client machines. I will develop a web application that will permit actions like start and stop, of several services (apache,mysql,asterisk...), so the application will connect in this daemon to run commands (/etc/init.d/mysql stop, for examplo)
    Your description is exactly that of someone doing ssh <host> <command>. Of course in your case the someone will be your "web application".

    If you hate security, passwords, and keys and all that then do telnet instead.

    andyford
    or non-Perl: Andy Ford

Re: Perl daemon that runs another daemon
by cLive ;-) (Prior) on Nov 01, 2006 at 21:01 UTC
    I have no clue, but there's a similar issue with running stuff from an ssh shell and logging out. I guess the equivalent would be amending the asterisk command to:
    qx(/etc/init.d/asterisk start </dev/null>/dev/null 2>&1 &)
    Or is my stab in the dark way too wide?
Re: Perl daemon that runs another daemon
by wjw (Priest) on Nov 01, 2006 at 22:27 UTC
    This sounds a great deal like what WebMin does. It is written in Perl (last I checked at any rate) and allows one to start and stop services from a remote web page. You might want to see how it is that they went about doing this. Webmin is open source and rock solid. Check it out here -> Webmin. Hope that might give you some alternatives if not exactly the answer you are looking for...

    ...the majority is always wrong, and always the last to know about it...

Re: Perl daemon that runs another daemon
by shmem (Chancellor) on Nov 02, 2006 at 11:49 UTC
    At the beginning of a daemon, there's a fork to detach from the controlling terminal. Then you should daemonize your process properly:
    • chdir to /
    • close all your file descriptors (and reopen them as neccesary, e.g. STDOUT and STDERR to a log file)
    • fork again to be able to change the process group, and adopted by init
    • call setsid() (see POSIX) to start a new session, i.e. to become a process group leader
    • set up signal handlers as approriate for your daemon

    Of course the processes from which you have forked must exit immediately after the fork.

    Your daemon should now be safe. See the section Complete Dissociation of Child from Parent in perlipc.

    Your

    _start => sub { qx(/etc/init.d/asterisk start); }

    subroutine should do that, and finally exec /etc/init.d/asterisk start after checking whether it is running already.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: Perl daemon that runs another daemon
by Argel (Prior) on Nov 02, 2006 at 21:40 UTC
    Here's what I like to use:
    use IO::Socket; use POSIX qw(WNOHANG setsid); sub daemonize { $SIG{CHLD} = 'IGNORE'; # Configure to autoreap zombies die "Can't fork" unless defined ( my $child = fork ); # FORK +<<<<<<<<<<<< CORE::exit(0) if $child; # Parent exits setsid(); # Become session leader open( STDIN, "</dev/null" ); # Detach STDIN from shell open( STDOUT, ">/dev/null" ); # Detach STDOUT from shell open( STDERR, ">&STDOUT" ); # Detach STDERR from shell chdir '/tmp'; # Change working directory umask(0); # Reset umask $ENV{PATH} = '/bin:/sbin:/usr/sbin'; # Reset PATH }

    WARNING: Verify your system supports autoreaping of zombies!!!!!

    You can read more in these threads: 547974, 201937, 539098.