Created
June 26, 2013 16:41
-
-
Save kenee/5869076 to your computer and use it in GitHub Desktop.
double fork
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
PHP forked daemon | |
Standalone PHP binary must be compiled with --enable-sockets and --enable-pcntl | |
Dave M. -2002 | |
Online Services USA | |
*/ | |
define(DEBUG,true); | |
require dirname(__FILE__)."/../../config/config.php"; | |
$todo = $_SERVER['argv'][1]; | |
$daemon = new svhost_daemon; | |
if ( $todo == 'start' ){ | |
$daemon->start(); | |
} | |
if ( $todo == 'stop' ){ | |
$daemon->stop(); | |
} | |
if ( $todo == 'restart' ){ | |
$daemon->stop(); | |
$daemon->start(); | |
} | |
if ( $todo == 'status' ){ | |
$daemon->status(); | |
} | |
if ( $todo == '' or !isset($todo) ){ | |
echo "usage: php daemon (start|stop|restart|status)\n"; | |
} | |
class svhost_daemon{ | |
private $pid_file; | |
private $sv_log_file; | |
private $underpriv_uid; | |
private $underpriv_gid; | |
private $port; | |
private $address; | |
function __construct() { | |
error_reporting (4); | |
set_time_limit (0); | |
ob_implicit_flush (); | |
$this->pid_file = DATA_DIR.'/svhost.pid'; | |
$this->sv_log_file = DATA_DIR."/logs/svhost.log"; | |
$this->underpriv_uid = '99'; // uid 99 == user nobody, at least on my system. | |
$this->underpriv_gid = '99'; | |
$this->port = '10000'; | |
$this->address = '127.0.0.1'; // 0 binds to all addresses, may not work on fbsd | |
//pcntl_signal( SIGCHLD, array('this','sig_handler') ); | |
//pcntl_signal( SIGTERM, array('this','sig_handler') ); | |
//pcntl_signal( SIGINT, array('this','sig_handler') ); | |
pcntl_signal(SIGCHLD, SIG_IGN); | |
} | |
function __destruct(){ | |
if(!file_exists($this->pid_file)) { | |
return; | |
} | |
if(posix_getpid() == $this->pid) { | |
unlink($this->pid_file); | |
} | |
} | |
function interact($connection) { | |
$cid=getmypid(); | |
$msg = "\nWelcome to the PHP Execute Server. \n" . | |
"To quit, type 'quit'. To shut down the server type 'shutdown'.\n"; | |
socket_write($connection, $msg, strlen($msg)); | |
while ( true ){ | |
if (!is_resource($connection)){ | |
posix_kill($cid, SIGTERM); | |
exit; | |
} | |
if (false === ($buf = socket_read($connection, 2048))) { | |
next; | |
} | |
if ( substr($buf,0,4) == 'quit' ) { | |
$talkback = "bye\n"; | |
socket_write($connection, $talkback, strlen($talkback)); | |
$this->sv_log ('Client Disconnect'); | |
posix_kill($cid, SIGTERM); | |
exit; | |
} elseif ( substr($buf,0,4) == 'exec' ) { | |
$cmd = trim(substr($buf,5)); | |
$cmd = escapeshellcmd($cmd); | |
$cmd = $cmd.' 2>&1 '; | |
$this->sv_log( "exec $cmd" ); | |
$ret = @shell_exec ($cmd); | |
if ( $ret == '' or !isset($ret)){ | |
$ret = "$cmd exec failed"; | |
} | |
$talkback = $ret."\n"; | |
if (DEBUG){ | |
$this->sv_log( $ret ); | |
} | |
socket_write($connection, $talkback, strlen($talkback)); | |
}else{ | |
$talkback = "Unknown command: " . str_replace("\r\n", '\r\n', $buf) ."\n"; | |
socket_write($connection, $talkback, strlen($talkback)); | |
} | |
$buf = ''; | |
} | |
} | |
function start() { | |
if (($this->sock = socket_create (AF_INET, SOCK_STREAM, 0)) < 0) { | |
$this->sv_log("socket_create() failed: reason: " . socket_strerror ($this->sock) ); | |
} | |
if (($ret = socket_bind ($this->sock, $this->address, $this->port)) < 0) { | |
$this->sv_log( "socket_bind() failed: reason: " . socket_strerror ($ret) ); | |
} | |
if (($ret = socket_listen ($this->sock, 0)) < 0) { | |
$this->sv_log( "socket_listen() failed: reason: " . socket_strerror ($ret) ); | |
} | |
#change_identity($underpriv_uid,$underpriv_gid); | |
$this->sv_log("Server ready. Waiting for connections....."); | |
$fh = $this->open_pid_file($this->pid_file); | |
$pid = $this->become_daemon(); | |
fputs($fh,$pid); | |
fclose($fh); | |
while(true ) { | |
if (($connection = socket_accept($this->sock)) < 0) { | |
next; | |
} | |
if( ($child = pcntl_fork()) == -1 ) { | |
$this->sv_log("Could not fork!!"); | |
$this->sv_log("Dying..."); | |
exit; | |
} | |
elseif($child == 0) { | |
$this->interact($connection); | |
socket_close($this->sock); | |
exit; | |
}else{ | |
pcntl_wait($status,1); | |
} | |
socket_close($connection); | |
} | |
} | |
function stop(){ | |
if(!file_exists($this->pid_file)) { | |
$this->sv_log("PID file ".$this->pid_file." not found"); | |
exit; | |
} | |
$fp = fopen($this->pid_file,"r"); | |
$pid = fgets($fp,1024); | |
if(!posix_kill($pid,9)) { | |
$this->sv_log("can not kill PID: $pid"); | |
exit; | |
} | |
$this->sv_log("server process $pid stoped"); | |
if(!unlink($this->pid_file)) { | |
$this->sv_log("Cannot unlink PID file ".$this->pid_file); | |
exit; | |
} | |
} | |
function status(){ | |
} | |
function sig_handler($signo) { | |
switch($signo) { | |
case SIGTERM: | |
// handle shutdown tasks | |
exit; | |
break; | |
case SIGHUP: | |
// handle restart tasks | |
break; | |
case SIGUSR1: | |
$this->sv_log( "Caught SIGUSR1..."); | |
break; | |
case SIGCHLD: | |
while( pcntl_waitpid(-1,$status,WNOHANG)>0 ) { | |
} | |
break; | |
case SIGINT: | |
exit; | |
default: | |
// not implemented yet... | |
break; | |
} | |
} | |
function sv_log($msg){ | |
$sv_log = date("Y-m-d H:i:s")." ".$msg."\r\n"; | |
error_log($sv_log,3,$this->sv_log_file); | |
} | |
function become_daemon() { | |
$child = pcntl_fork(); | |
if($child) { | |
exit; // kill parent | |
} | |
posix_setsid(); // become session leader | |
chdir("/"); | |
umask(0); // clear umask | |
return posix_getpid(); | |
} | |
function open_pid_file($file) { | |
if(file_exists($file)) { | |
$fp = fopen($file,"r"); | |
$pid = fgets($fp,1024); | |
fclose($fp); | |
if(posix_kill($pid,0)) { | |
$this->sv_log("Server already running with PID: $pid"); | |
exit; | |
} | |
$this->sv_log("Removing PID file for defunct server process $pid"); | |
if(!unlink($file)) { | |
$this->sv_log("Cannot unlink PID file $file"); | |
exit; | |
} | |
} | |
if($fp = fopen($file,"w")) { | |
return $fp; | |
} else { | |
$this->sv_log( "Unable to open PID file $file for writing..." ); | |
exit; | |
} | |
} | |
function change_identity($uid,$gid) { | |
if(!posix_setgid($gid)) { | |
$this->sv_log("Unable to setgid to $gid!"); | |
unlink($this->pid_file); | |
exit; | |
} | |
if(!posix_setuid($uid)) { | |
$this->sv_log("Unable to setuid to $uid!"); | |
unlink($this->pid_file); | |
exit; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment