Author: Vasily Zorin (maintainer@daemon.io)
Inheritance: use trait PHPDaemon\Traits\ClassWatchdog, use trait PHPDaemon\Traits\StaticObjectWatchdog, use trait PHPDaemon\Traits\EventLoopContainer
 /**
  * Constructor.
  * @return void
  */
 public function init()
 {
     if (!isset($this->attrs->server['FR_PATH'])) {
         $this->status(404);
         $this->finish();
         return;
     }
     $job = new \PHPDaemon\Core\ComplexJob(function ($job) {
         $this->wakeup();
     });
     $this->job = $job;
     $this->sleep(5, true);
     $this->attrs->server['FR_PATH'] = \PHPDaemon\FS\FileSystem::sanitizePath($this->attrs->server['FR_PATH']);
     $job('stat', function ($name, $job) {
         /** @var \PHPDaemon\Core\ComplexJob $job */
         \PHPDaemon\FS\FileSystem::stat($this->attrs->server['FR_PATH'], function ($path, $stat) use($job) {
             if ($stat === -1) {
                 $this->fileNotFound();
                 $job->setResult('stat', false);
                 return;
             }
             if ($stat['type'] === 'd') {
                 if (!\PHPDaemon\FS\FileSystem::$supported) {
                     $this->file(rtrim($path, '/') . '/index.html');
                 } else {
                     $job('readdir', function ($name, $job) use($path) {
                         /** @var \PHPDaemon\Core\ComplexJob $job */
                         \PHPDaemon\FS\FileSystem::readdir(rtrim($path, '/'), function ($path, $dir) use($job) {
                             $found = false;
                             if (is_array($dir)) {
                                 foreach ($dir['dents'] as $file) {
                                     if ($file['type'] === \EIO_DT_REG) {
                                         // is file
                                         if (in_array($file['name'], $this->appInstance->indexFiles)) {
                                             $this->file($path . '/' . $file['name']);
                                             $found = true;
                                             break;
                                         }
                                     }
                                 }
                             }
                             if (!$found) {
                                 if (isset($this->attrs->server['FR_AUTOINDEX']) && $this->attrs->server['FR_AUTOINDEX']) {
                                     $this->autoindex($path, $dir);
                                 } else {
                                     $this->fileNotFound();
                                 }
                             }
                             $job->setResult('readdir');
                         }, \EIO_READDIR_STAT_ORDER | \EIO_READDIR_DENTS);
                     });
                 }
             } elseif ($stat['type'] === 'f') {
                 $this->file($path);
             }
             $job->setResult('stat', $stat);
         });
     });
     $job();
 }
Example #2
0
 protected function prepareAsync()
 {
     EventLoop::init();
     Daemon::initSettings();
     FileSystem::init();
     FileSystem::initEvent();
 }
Example #3
0
 public function init()
 {
     $req = $this;
     $this->sleep(1, true);
     \PHPDaemon\FS\FileSystem::readfile('/etc/filesystems', function ($file, $data) use($req) {
         $req->fileData = $data;
         $req->wakeup();
     });
 }
Example #4
0
 /**
  * Called when worker is going to update configuration
  * @return void
  */
 public function onConfigUpdated()
 {
     parent::onConfigUpdated();
     if (Daemon::$process instanceof \PHPDaemon\Thread\Worker) {
         $pool = $this;
         FileSystem::readfile($this->config->file->value, function ($file, $data) use($pool) {
             $pool->policyData = $data;
             $pool->enable();
         });
     }
 }
Example #5
0
 /**
  * Manager constructor.
  * @param $path
  */
 public function __construct($path, $threadsNum)
 {
     $this->threadsNum = $threadsNum;
     $this->path = $path;
     $this->queue = new StackCallbacks();
     $this->reloadCheckTimer = setTimeout(function ($ev) {
         FileSystem::stat($this->path, function ($path, $stat) {
             if (!$stat) {
                 $this->stop();
                 $this->free();
             }
             if ($this->reloadCheckLastModified >= $stat['mtime']) {
                 return;
             }
             $this->reloadCheckLastModified = $stat['mtime'];
             $this->stop();
             $this->start();
         });
         $ev->timeout(static::RELOAD_CHECK_INTERVAL);
     }, 1);
 }
Example #6
0
 /**
  * Shutdown this worker
  * @param boolean Hard? If hard, we shouldn't wait for graceful shutdown of the running applications.
  * @return boolean|null Ready?
  */
 protected function shutdown($hard = false)
 {
     $error = error_get_last();
     if ($error) {
         if ($error['type'] === E_ERROR) {
             Daemon::log('W#' . $this->pid . ' crashed by error \'' . $error['message'] . '\' at ' . $error['file'] . ':' . $error['line']);
         }
     }
     if (Daemon::$config->logevents->value) {
         $this->log('event shutdown(' . ($hard ? 'HARD' : '') . ') invoked.');
     }
     if (Daemon::$config->throwexceptiononshutdown->value) {
         throw new \Exception('event shutdown');
     }
     @ob_flush();
     if ($this->terminated === true) {
         if ($hard) {
             exit(0);
         }
         return;
     }
     $this->terminated = true;
     if ($hard) {
         $this->setState(Daemon::WSTATE_SHUTDOWN);
         exit(0);
     }
     $this->reloadReady = $this->appInstancesReloadReady();
     if ($this->reload && $this->graceful) {
         $this->reloadReady = $this->reloadReady && microtime(TRUE) > $this->reloadTime;
     }
     if (Daemon::$config->logevents->value) {
         $this->log('reloadReady = ' . Debug::dump($this->reloadReady));
     }
     Timer::remove('breakMainLoopCheck');
     Timer::add(function ($event) {
         $self = Daemon::$process;
         $self->reloadReady = $self->appInstancesReloadReady();
         if ($self->reload === TRUE) {
             $self->reloadReady = $self->reloadReady && microtime(TRUE) > $self->reloadTime;
         }
         if (!$self->reloadReady) {
             $event->timeout();
         } else {
             $self->eventBase->exit();
         }
     }, 1000000.0, 'checkReloadReady');
     while (!$this->reloadReady) {
         $this->eventBase->loop();
     }
     FileSystem::waitAllEvents();
     // ensure that all I/O events completed before suicide
     exit(0);
     // R.I.P.
 }
Example #7
0
 /**
  * Returns string of pseudo random bytes
  * @param  integer  $len  Length of desired string
  * @param  callable $cb   Callback
  * @param  integer  $pri  Priority of EIO operation
  * @param  boolean  $hang If true, we shall use /dev/random instead of /dev/urandom and it may cause a delay
  * @return integer
  */
 public static function randomBytes($len, $cb, $pri = 0, $hang = false)
 {
     FileSystem::open('/dev/' . ($hang ? '' : 'u') . 'random', 'r', function ($file) use($len, $cb, $pri) {
         if (!$file) {
             call_user_func($cb, false);
             return;
         }
         $file->read($len, 0, function ($file, $data) use($cb) {
             call_user_func($cb, $data);
         }, $pri);
     }, null, $pri);
 }
Example #8
0
 /**
  * Start new session
  * @param  callable $cb Callback
  * @return void
  */
 protected function sessionStartNew($cb = null)
 {
     FileSystem::tempnam(session_save_path(), $this->sessionPrefix, function ($fp) use($cb) {
         if (!$fp) {
             call_user_func($cb, false);
             return;
         }
         $this->sessionFp = $fp;
         $this->sessionId = substr(basename($fp->path), strlen($this->sessionPrefix));
         $this->setcookie(ini_get('session.name'), $this->sessionId, ini_get('session.cookie_lifetime'), ini_get('session.cookie_path'), ini_get('session.cookie_domain'), ini_get('session.cookie_secure'), ini_get('session.cookie_httponly'));
         call_user_func($cb, true);
     });
 }
Example #9
0
 /**
  * Shutdown thread
  * @param boolean - Hard? If hard, we shouldn't wait for graceful shutdown of the running applications.
  * @return boolean|null - Ready?
  */
 public function shutdown($hard = false)
 {
     $error = error_get_last();
     if ($error) {
         if ($error['type'] === E_ERROR) {
             $this->log('crashed by error \'' . $error['message'] . '\' at ' . $error['file'] . ':' . $error['line']);
         }
     }
     if (Daemon::$config->logevents->value) {
         $this->log('event shutdown(' . ($hard ? 'HARD' : '') . ') invoked.');
     }
     if (Daemon::$config->throwexceptiononshutdown->value) {
         throw new \Exception('event shutdown');
     }
     @ob_flush();
     if ($this->terminated === true) {
         if ($hard) {
             exit(0);
         }
         return;
     }
     $this->terminated = true;
     if ($hard) {
         exit(0);
     }
     FileSystem::waitAllEvents();
     // ensure that all I/O events completed before suicide
     posix_kill(posix_getppid(), SIGCHLD);
     // praying to Master
     exit(0);
     // R.I.P.
 }
Example #10
0
 /**
  * Applies config
  * @return void
  */
 public function applyConfig()
 {
     parent::applyConfig();
     $pool = $this;
     if (!isset($this->preloading)) {
         $this->preloading = new ComplexJob();
     }
     $job = $this->preloading;
     $job->addJob('resolvfile', function ($jobname, $job) use($pool) {
         FileSystem::readfile($pool->config->resolvfile->value, function ($file, $data) use($pool, $job, $jobname) {
             if ($file) {
                 foreach (explode("\n", $data) as $line) {
                     $line = trim($line);
                     if ($line !== '' && $line[0] !== '#' && preg_match('~nameserver ([^\\r\\n;]+)~i', $line, $m)) {
                         $pool->nameServers[] = $m[1];
                     }
                 }
             }
             $job->setResult($jobname);
         });
     });
     $job->addJob('hostsfile', function ($jobname, $job) use($pool) {
         FileSystem::readfile($pool->config->hostsfile->value, function ($file, $data) use($pool, $job, $jobname) {
             if ($file) {
                 preg_match_all('~^(\\S+)\\s+([^\\r\\n]+)\\s*~m', $data, $m, PREG_SET_ORDER);
                 $pool->hosts = [];
                 foreach ($m as $h) {
                     $hosts = preg_split('~\\s+~', $h[2]);
                     $ip = $h[1];
                     foreach ($hosts as $host) {
                         $host = rtrim($host, '.') . '.';
                         $pool->hosts[$host][] = $ip;
                     }
                 }
             }
             $job->setResult($jobname);
         });
     });
     $job();
 }
Example #11
0
 /**
  * Called after request finish
  * @param  callable $cb Callback
  * @return void
  */
 protected function postFinishHandler($cb = null)
 {
     if (!$this->headers_sent) {
         $this->out('');
     }
     $this->sendfp = null;
     if (isset($this->attrs->files)) {
         foreach ($this->attrs->files as $f) {
             if (isset($f['tmp_name'])) {
                 FileSystem::unlink($f['tmp_name']);
             }
         }
     }
     if (isset($this->attrs->session)) {
         $this->sessionCommit($cb);
     } else {
         $cb === null || $cb();
     }
 }
Example #12
0
 /**
  * Initialize SSL/TLS context
  * @return void
  */
 protected function initSecureContext()
 {
     if (!\EventUtil::sslRandPoll()) {
         Daemon::$process->log(get_class($this->pool) . ': EventUtil::sslRandPoll failed');
         $this->erroneous = true;
         return;
     }
     if (!FileSystem::checkFileReadable($this->certfile) || !FileSystem::checkFileReadable($this->pkfile)) {
         Daemon::log('Couldn\'t read ' . $this->certfile . ' or ' . $this->pkfile . ' file.  To generate a key' . PHP_EOL . 'and self-signed certificate, run' . PHP_EOL . '  openssl genrsa -out ' . escapeshellarg($this->pkfile) . ' 2048' . PHP_EOL . '  openssl req -new -key ' . escapeshellarg($this->pkfile) . '  -out cert.req' . PHP_EOL . '  openssl x509 -req -days 365 -in cert.req -signkey ' . escapeshellarg($this->pkfile) . '  -out ' . escapeshellarg($this->certfile));
         return;
     }
     $params = [\EventSslContext::OPT_LOCAL_CERT => $this->certfile, \EventSslContext::OPT_LOCAL_PK => $this->pkfile, \EventSslContext::OPT_VERIFY_PEER => $this->verifypeer, \EventSslContext::OPT_ALLOW_SELF_SIGNED => $this->allowselfsigned];
     if ($this->passphrase !== null) {
         $params[\EventSslContext::OPT_PASSPHRASE] = $this->passphrase;
     }
     if ($this->verifydepth !== null) {
         $params[\EventSslContext::OPT_VERIFY_DEPTH] = $this->verifydepth;
     }
     if ($this->cafile !== null) {
         $params[\EventSslContext::OPT_CA_FILE] = $this->cafile;
     }
     if ($this->tls === true) {
         $method = \EventSslContext::TLS_SERVER_METHOD;
     } elseif ($this->tls === 'v11') {
         $method = \EventSslContext::TLSv11_SERVER_METHOD;
     } elseif ($this->tls === 'v12') {
         $method = \EventSslContext::TLSv12_SERVER_METHOD;
     } elseif ($this->ssl === 'v3' || $this->ssl === true || $this->ssl === '1') {
         $method = \EventSslContext::SSLv3_SERVER_METHOD;
     } elseif ($this->ssl === 'v2') {
         $method = \EventSslContext::SSLv2_SERVER_METHOD;
     } elseif ($this->ssl === 'v23') {
         $method = \EventSslContext::SSLv23_SERVER_METHOD;
     } elseif ($this->ssl) {
         Daemon::log(get_class($this) . ': unrecognized SSL version \'' . $this->ssl . '\'');
         return;
     } else {
         return;
     }
     $this->ctx = new \EventSslContext($method, $params);
 }
Example #13
0
 /**
  * Stat() non-cached
  * @param  callable $cb Callback
  * @param  integer $pri Priority
  * @return resource|boolean
  */
 public function statRefresh($cb, $pri = EIO_PRI_DEFAULT)
 {
     $cb = CallbackWrapper::forceWrap($cb);
     if (!$this->fd || $this->fd === -1) {
         if ($cb) {
             $cb($this, false);
         }
         return false;
     }
     if (!FileSystem::$supported) {
         $cb($this, FileSystem::statPrepare(fstat($this->fd)));
         return true;
     }
     return eio_fstat($this->fd, $pri, function ($file, $stat) use($cb) {
         $stat = FileSystem::statPrepare($stat);
         $file->stat = $stat;
         $cb($file, $stat);
     }, $this);
 }
Example #14
0
 /**
  * Returns string of pseudo random bytes
  * @param  integer $len Length of desired string
  * @param  callable $cb Callback
  * @param  integer $pri Priority of EIO operation
  * @param  boolean $hang If true, we shall use /dev/random instead of /dev/urandom and it may cause a delay
  * @return integer
  */
 public static function randomBytes($len, $cb, $pri = 0, $hang = false)
 {
     $cb = CallbackWrapper::wrap($cb);
     FileSystem::open('/dev/' . ($hang ? '' : 'u') . 'random', 'r', function ($file) use($len, $cb, $pri) {
         if (!$file) {
             $cb(false);
             return;
         }
         $file->read($len, 0, function ($file, $data) use($cb) {
             $cb($data);
         }, $pri);
     }, null, $pri);
 }
Example #15
0
 /**
  * Applies config
  * @return void
  */
 public function applyConfig()
 {
     parent::applyConfig();
     $pool = $this;
     if (!isset($this->preloading)) {
         $this->preloading = new ComplexJob();
     }
     $job = $this->preloading;
     $job->addJob('resolvfile', function ($jobname, $job) use($pool) {
         FileSystem::readfile($pool->config->resolvfile->value, function ($file, $data) use($pool, $job, $jobname) {
             if ($file) {
                 preg_match_all('~nameserver ([^\\r\\n;]+)~', $data, $m);
                 foreach ($m[1] as $s) {
                     $pool->addServer('udp://' . $s);
                     //$pool->addServer('tcp://' . $s);
                 }
             }
             $job->setResult($jobname);
         });
     });
     $job->addJob('hostsfile', function ($jobname, $job) use($pool) {
         FileSystem::readfile($pool->config->hostsfile->value, function ($file, $data) use($pool, $job, $jobname) {
             if ($file) {
                 preg_match_all('~^(\\S+)\\s+([^\\r\\n]+)\\s*~m', $data, $m, PREG_SET_ORDER);
                 $pool->hosts = [];
                 foreach ($m as $h) {
                     $hosts = preg_split('~\\s+~', $h[2]);
                     $ip = $h[1];
                     foreach ($hosts as $host) {
                         $host = rtrim($host, '.') . '.';
                         $pool->hosts[$host] = $ip;
                     }
                 }
             }
             $job->setResult($jobname);
         });
     });
     $job();
 }
Example #16
0
 /**
  * Process HTTP headers
  * @return boolean Success
  */
 protected function httpProcessHeaders()
 {
     $this->req->attrs->paramsDone = true;
     if (isset($this->req->attrs->server['HTTP_CONNECTION']) && preg_match('~(?:^|\\W)Upgrade(?:\\W|$)~i', $this->req->attrs->server['HTTP_CONNECTION']) && isset($this->req->attrs->server['HTTP_UPGRADE']) && strtolower($this->req->attrs->server['HTTP_UPGRADE']) === 'websocket') {
         if ($this->pool->WS) {
             $this->pool->WS->inheritFromRequest($this->req, $this);
         }
         return false;
     }
     $this->req = Daemon::$appResolver->getRequest($this->req, $this, isset($this->pool->config->responder->value) ? $this->pool->config->responder->value : null);
     if ($this->req instanceof \stdClass) {
         $this->endRequest($this->req, 0, 0);
         return false;
     } else {
         if ($this->pool->config->sendfile->value && (!$this->pool->config->sendfileonlybycommand->value || isset($this->req->attrs->server['USE_SENDFILE'])) && !isset($this->req->attrs->server['DONT_USE_SENDFILE'])) {
             $req = $this->req;
             FileSystem::tempnam($this->pool->config->sendfiledir->value, $this->pool->config->sendfileprefix->value, function ($fn) use($req) {
                 FileSystem::open($fn, 'wb', function ($file) use($req) {
                     $req->sendfp = $file;
                 });
                 $req->header('X-Sendfile: ' . $fn);
             });
         }
         $this->req->callInit();
     }
     return true;
 }
Example #17
0
 /**
  * Actions on early startup.
  * @param string Optional. Config file path.
  * @return void
  */
 public static function init($configFile = null)
 {
     if (!version_compare(PHP_VERSION, '5.4.0', '>=')) {
         Daemon::log('PHP >= 5.4.0 required.');
         return;
     }
     //run without composer
     if (!function_exists('setTimeout')) {
         require 'PHPDaemon/Utils/func.php';
     }
     Daemon::initSettings();
     FileSystem::init();
     Daemon::$runName = basename($_SERVER['argv'][0]);
     $error = FALSE;
     $argv = $_SERVER['argv'];
     $runmode = isset($argv[1]) ? str_replace('-', '', $argv[1]) : '';
     $args = Bootstrap::getArgs($argv);
     if (!isset(self::$params[$runmode]) && !in_array($runmode, self::$commands)) {
         if ('' !== $runmode) {
             echo 'Unrecognized command: ' . $runmode . "\n";
         }
         self::printUsage();
         exit;
     } elseif ('help' === $runmode) {
         self::printHelp();
         exit;
     }
     $n = null;
     if ('log' === $runmode) {
         if (isset($args['n'])) {
             $n = $args['n'];
             unset($args['n']);
         } else {
             $n = 20;
         }
     }
     if (isset($configFile)) {
         Daemon::$config->configfile->setHumanValue($configFile);
     }
     if (isset($args['configfile'])) {
         Daemon::$config->configfile->setHumanValue($args['configfile']);
     }
     if (!Daemon::$config->loadCmdLineArgs($args)) {
         $error = true;
     }
     if (!Daemon::loadConfig(Daemon::$config->configfile->value)) {
         $error = true;
     }
     if ('log' === $runmode) {
         passthru('tail -n ' . $n . ' -f ' . escapeshellarg(Daemon::$config->logstorage->value));
         exit;
     }
     if (extension_loaded('apc') && ini_get('apc.enabled')) {
         Daemon::log('Detected pecl-apc extension enabled. Usage of bytecode caching (APC/eAccelerator/xcache/...)  makes no sense at all in case of using phpDaemon \'cause phpDaemon includes files just in time itself.');
     }
     if (isset(Daemon::$config->locale->value) && Daemon::$config->locale->value !== '') {
         setlocale(LC_ALL, array_map('trim', explode(',', Daemon::$config->locale->value)));
     }
     if (Daemon::$config->autoreimport->value && !is_callable('runkit_import')) {
         Daemon::log('[WARN] runkit extension not found. You should install it or disable --auto-reimport. Non-critical error.');
     }
     if (!is_callable('posix_kill')) {
         Daemon::log('[EMERG] Posix not found. You should compile PHP without \'--disable-posix\'.');
         $error = true;
     }
     if (!is_callable('pcntl_signal')) {
         Daemon::log('[EMERG] PCNTL not found. You should compile PHP with \'--enable-pcntl\'.');
         $error = true;
     }
     if (extension_loaded('libevent')) {
         Daemon::log('[EMERG] libevent extension found. You have to remove libevent.so extension.');
         $error = true;
     }
     $eventVer = '1.6.1';
     $eventVerType = 'stable';
     if (!Daemon::loadModuleIfAbsent('event', $eventVer . '-' . $eventVerType)) {
         Daemon::log('[EMERG] event extension >= ' . $eventVer . ' not found (or OUTDATED). You have to install it. `pecl install http://pecl.php.net/get/event`');
         $error = true;
     }
     if (!is_callable('socket_create')) {
         Daemon::log('[EMERG] Sockets extension not found. You should compile PHP with \'--enable-sockets\'.');
         $error = true;
     }
     if (!is_callable('shmop_open')) {
         Daemon::log('[EMERG] Shmop extension not found. You should compile PHP with \'--enable-shmop\'.');
         $error = true;
     }
     if (!isset(Daemon::$config->user)) {
         Daemon::log('[EMERG] You must set \'user\' parameter.');
         $error = true;
     }
     if (!isset(Daemon::$config->path)) {
         Daemon::log('[EMERG] You must set \'path\' parameter (path to your application resolver).');
         $error = true;
     }
     if (!file_exists(Daemon::$config->pidfile->value)) {
         if (!touch(Daemon::$config->pidfile->value)) {
             Daemon::log('[EMERG] Couldn\'t create pid-file \'' . Daemon::$config->pidfile->value . '\'.');
             $error = true;
         }
         Bootstrap::$pid = 0;
     } elseif (!is_file(Daemon::$config->pidfile->value)) {
         Daemon::log('Pid-file \'' . Daemon::$config->pidfile->value . '\' must be a regular file.');
         Bootstrap::$pid = FALSE;
         $error = true;
     } elseif (!is_writable(Daemon::$config->pidfile->value)) {
         Daemon::log('Pid-file \'' . Daemon::$config->pidfile->value . '\' must be writable.');
         $error = true;
     } elseif (!is_readable(Daemon::$config->pidfile->value)) {
         Daemon::log('Pid-file \'' . Daemon::$config->pidfile->value . '\' must be readable.');
         Bootstrap::$pid = FALSE;
         $error = true;
     } else {
         Bootstrap::$pid = (int) file_get_contents(Daemon::$config->pidfile->value);
     }
     if (Daemon::$config->chroot->value !== '/') {
         if (posix_getuid() != 0) {
             Daemon::log('You must have the root privileges to change root.');
             $error = true;
         }
     }
     $pathList = preg_split('~\\s*;\\s*~', Daemon::$config->path->value);
     $found = false;
     foreach ($pathList as $path) {
         if (@is_file($path)) {
             Daemon::$appResolverPath = $path;
             $found = true;
             break;
         }
     }
     if (!$found) {
         Daemon::log('Your application resolver \'' . Daemon::$config->path->value . '\' is not available (config directive \'path\').');
         $error = true;
     }
     Daemon::$appResolver = (require Daemon::$appResolverPath);
     if (isset(Daemon::$config->group->value) && is_callable('posix_getgid')) {
         if (($sg = posix_getgrnam(Daemon::$config->group->value)) === FALSE) {
             Daemon::log('Unexisting group \'' . Daemon::$config->group->value . '\'. You have to replace config-variable \'group\' with existing group-name.');
             $error = true;
         } elseif ($sg['gid'] != posix_getgid() && posix_getuid() != 0) {
             Daemon::log('You must have the root privileges to change group.');
             $error = true;
         }
     }
     if (isset(Daemon::$config->user->value) && is_callable('posix_getuid')) {
         if (($su = posix_getpwnam(Daemon::$config->user->value)) === FALSE) {
             Daemon::log('Unexisting user \'' . Daemon::$config->user->value . '\', user not found. You have to replace config-variable \'user\' with existing username.');
             $error = true;
         } elseif ($su['uid'] != posix_getuid() && posix_getuid() != 0) {
             Daemon::log('You must have the root privileges to change user.');
             $error = true;
         }
     }
     if (isset(Daemon::$config->minspareworkers->value) && Daemon::$config->minspareworkers->value > 0 && isset(Daemon::$config->maxspareworkers->value) && Daemon::$config->maxspareworkers->value > 0) {
         if (Daemon::$config->minspareworkers->value > Daemon::$config->maxspareworkers->value) {
             Daemon::log('\'minspareworkers\' cannot be greater than \'maxspareworkers\'.');
             $error = true;
         }
     }
     if (isset(Daemon::$config->addincludepath->value)) {
         ini_set('include_path', ini_get('include_path') . ':' . implode(':', Daemon::$config->addincludepath->value));
     }
     if (isset(Daemon::$config->minworkers->value) && isset(Daemon::$config->maxworkers->value)) {
         if (Daemon::$config->minworkers->value > Daemon::$config->maxworkers->value) {
             Daemon::$config->minworkers->value = Daemon::$config->maxworkers->value;
         }
     }
     if ($runmode === 'start') {
         if ($error === FALSE) {
             Bootstrap::start();
         } else {
             exit(6);
         }
     } elseif ($runmode === 'runworker') {
         if ($error === FALSE) {
             Bootstrap::runworker();
         } else {
             exit(6);
         }
     } elseif ($runmode === 'status' || $runmode === 'fullstatus') {
         $status = Bootstrap::$pid && Thread\Generic::ifExistsByPid(Bootstrap::$pid);
         echo '[STATUS] phpDaemon ' . Daemon::$version . ' is ' . ($status ? 'running' : 'NOT running') . ' (' . Daemon::$config->pidfile->value . ").\n";
         if ($status && $runmode === 'fullstatus') {
             echo 'Uptime: ' . DateTime::diffAsText(filemtime(Daemon::$config->pidfile->value), time()) . "\n";
             Daemon::$shm_wstate = new ShmEntity(Daemon::$config->pidfile->value, Daemon::SHM_WSTATE_SIZE, 'wstate');
             $stat = Daemon::getStateOfWorkers();
             echo "State of workers:\n";
             echo "\tTotal: " . $stat['alive'] . "\n";
             echo "\tIdle: " . $stat['idle'] . "\n";
             echo "\tBusy: " . $stat['busy'] . "\n";
             echo "\tShutdown: " . $stat['shutdown'] . "\n";
             echo "\tPre-init: " . $stat['preinit'] . "\n";
             echo "\tInit: " . $stat['init'] . "\n";
         }
         echo "\n";
     } elseif ($runmode === 'update') {
         if (!Bootstrap::$pid || !posix_kill(Bootstrap::$pid, SIGHUP)) {
             echo '[UPDATE] ERROR. It seems that phpDaemon is not running' . (Bootstrap::$pid ? ' (PID ' . Bootstrap::$pid . ')' : '') . ".\n";
         }
     } elseif ($runmode === 'reopenlog') {
         if (!Bootstrap::$pid || !posix_kill(Bootstrap::$pid, SIGUSR1)) {
             echo '[REOPEN-LOG] ERROR. It seems that phpDaemon is not running' . (Bootstrap::$pid ? ' (PID ' . Bootstrap::$pid . ')' : '') . ".\n";
         }
     } elseif ($runmode === 'reload') {
         if (!Bootstrap::$pid || !posix_kill(Bootstrap::$pid, SIGUSR2)) {
             echo '[RELOAD] ERROR. It seems that phpDaemon is not running' . (Bootstrap::$pid ? ' (PID ' . Bootstrap::$pid . ')' : '') . ".\n";
         }
     } elseif ($runmode === 'restart') {
         if ($error === FALSE) {
             Bootstrap::stop(2);
             Bootstrap::start();
         }
     } elseif ($runmode === 'hardrestart') {
         Bootstrap::stop(3);
         Bootstrap::start();
     } elseif ($runmode === 'ipcpath') {
         $i = Daemon::$appResolver->getInstanceByAppName('\\PHPDaemon\\IPCManager\\IPCManager');
         echo $i->getSocketUrl() . PHP_EOL;
     } elseif ($runmode === 'configtest') {
         $term = new Terminal();
         $term->enableColor();
         echo "\n";
         $rows = [];
         $rows[] = ['parameter' => 'PARAMETER', 'value' => 'VALUE', '_color' => '37', '_bold' => true];
         foreach (Daemon::$config as $name => $entry) {
             if (!$entry instanceof Generic) {
                 continue;
             }
             $row = ['parameter' => $name, 'value' => var_export($entry->humanValue, true)];
             if ($entry->defaultValue != $entry->humanValue) {
                 $row['value'] .= ' (' . var_export($entry->defaultValue, true) . ')';
             }
             $rows[] = $row;
         }
         $term->drawtable($rows);
         echo "\n";
     } elseif ($runmode === 'stop') {
         Bootstrap::stop();
     } elseif ($runmode === 'gracefulstop') {
         Bootstrap::stop(4);
     } elseif ($runmode === 'hardstop') {
         echo '[HARDSTOP] Sending SIGINT to ' . Bootstrap::$pid . '... ';
         $ok = Bootstrap::$pid && posix_kill(Bootstrap::$pid, SIGINT);
         echo $ok ? 'OK.' : 'ERROR. It seems that phpDaemon is not running.';
         if ($ok) {
             $i = 0;
             while ($r = Thread\Generic::ifExistsByPid(Bootstrap::$pid)) {
                 usleep(500000);
                 if ($i === 9) {
                     echo "\nphpDaemon master-process hasn't finished. Sending SIGKILL... ";
                     posix_kill(Bootstrap::$pid, SIGKILL);
                     sleep(0.2);
                     if (!Thread\Generic::ifExistsByPid(Bootstrap::$pid)) {
                         echo " Oh, his blood is on my hands :'(";
                     } else {
                         echo "ERROR: Process alive. Permissions?";
                     }
                     break;
                 }
                 ++$i;
             }
         }
         echo "\n";
     }
 }
 /**
  * Open logs.
  * @return void
  */
 public static function openLogs()
 {
     if (Daemon::$config->logging->value) {
         Daemon::$logpointer = fopen(Daemon::$config->logstorage->value, 'a');
         if (isset(Daemon::$config->group->value)) {
             chgrp(Daemon::$config->logstorage->value, Daemon::$config->group->value);
             // @TODO: rewrite to async I/O
         }
         if (isset(Daemon::$config->user->value)) {
             chown(Daemon::$config->logstorage->value, Daemon::$config->user->value);
             // @TODO: rewrite to async I/O
         }
         if (Daemon::$process instanceof Thread\Worker && FileSystem::$supported) {
             FileSystem::open(Daemon::$config->logstorage->value, 'a!', function ($file) {
                 Daemon::$logpointerAsync = $file;
                 if (!$file) {
                     return;
                 }
             });
         }
     } else {
         Daemon::$logpointer = null;
         Daemon::$logpointerAsync = null;
     }
 }
Example #19
0
 /**
  * Obtain exclusive temporary file
  * @param  string   $dir    Directory
  * @param  string   $prefix Prefix
  * @param  callable $cb     Callback (File)
  * @return resource
  */
 public static function tempnam($dir, $prefix, $cb)
 {
     $cb = CallbackWrapper::forceWrap($cb);
     if (!FileSystem::$supported) {
         FileSystem::open(tempnam($dir, $prefix), 'w!', $cb);
     }
     $tries = 0;
     static::tempnamHandler($dir, $prefix, $cb, $tries);
 }