Source for file nanoserv.php
Documentation is available at nanoserv.php
* nanoserv - a sockets daemon toolkit for PHP 5.1+
* Copyright (C) 2004-2010 Vincent Negrier aka. sIX <six at aegis-corp.org>
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* nanoserv current version number
define("NS_VERSION", "2.1.1-dev");
parent::__construct($errmsg, $errno);
public function __construct($errmsg, $errno, $addr, NS_Listener $listener = NULL) {
public function __construct($errmsg, $errno, $addr, NS_Handler $handler = NULL) {
* Maximum number of bytes read by Read()
* Internal Socket unique ID
* Socket stream descriptor
* Is the socket connected ?
* Is the socket waiting to be connected ?
* Is the socket waiting for ssl/tls handshake ?
* Is the socket blocked ?
* Should we block reading from this socket ?
* @var NS_Connection_Handler
* Static instance counter
public function __construct($fd = false, $crypto_type = false) {
return stream_context_get_options($this->fd);
* Set a stream context option
public function Set_Option($wrapper, $opt, $val) {
* Sets wether the socket is blocking or not
* Flag the socket so that the main loop won't read from it even if data is available.
* This can be used to implement flow control when proxying data between two asymetric connections for example.
* @return bool the previous status
* Set the stream write buffer (PHP defaults to 8192 bytes)
* @param int $buffer_size
* Enable or disable ssl/tls crypto on the socket
public function Setup() {
* Read data from the socket and return it
* @param int $length maximum read length
return fread($this->fd, self::DEFAULT_READ_LENGTH);
* Read data from a non connected socket and return it
* @param string &$addr contains the message sender address upon return
* @param int $len maximum read length
public function Read_From(&$addr, $len = 16384) {
* Write data to the socket
* write returns the number of bytes written to the socket
public function Write($data) {
if (isset ($data[$nb])) $this->blocked = true;
* Write data to a non connected socket
* @param string $to in the form of "<ip_address>:<port>"
* Write data from stream to socket
* returns the number of bytes read from the stream and written to the socket
* @param resource $stream
* @param int $len maximum length (bytes) to read/write
* Query end of stream status
public function Close() {
* Listen address (format is 'proto://addr:port')
* Real listen address (format is 'proto://addr:port')
* NS_Server_Socket constructor
if (($proto === "udp") || ($proto === "unix")) {
$this->real_address = $addr;
$this->real_address = "tcp:" . strtok("");
if ($proto !== "tcp") switch ($proto) {
case "ssl": $this->crypto_type = STREAM_CRYPTO_METHOD_SSLv23_SERVER; break;
case "tls": $this->crypto_type = STREAM_CRYPTO_METHOD_TLS_SERVER; break;
case "sslv2": $this->crypto_type = STREAM_CRYPTO_METHOD_SSLv2_SERVER; break;
case "sslv3": $this->crypto_type = STREAM_CRYPTO_METHOD_SSLv3_SERVER; break;
* Start listening and accepting connetions
public function Listen($bind_only = false) {
$errno = $errstr = false;
$this->fd = @stream_socket_server($this->real_address, $errno, $errstr, STREAM_SERVER_BIND | ($bind_only ? 0 : STREAM_SERVER_LISTEN), $this->context);
if ($this->fd === false) {
throw new NS_Server_Exception("cannot listen to {$this->real_address}: { $errstr}", $errno, $this->real_address);
public function Accept() {
return @stream_socket_accept($this->fd, 0);
class NS_Client_Socket extends NS_Socket {
* Connect timeout (seconds)
const CONNECT_TIMEOUT = 10;
* Peer address (format is 'proto://addr:port')
* Connect timeout (timestamp)
* NS_Client_Socket constructor
public function __construct($addr) {
$proto = strtolower(strtok($addr, ":"));
if (($proto === "udp") || ($proto === "unix")) {
$this->real_address = $addr;
$this->real_address = "tcp:" . $s;
if ($proto != "tcp") switch ($proto) {
case "ssl": $this->crypto_type = STREAM_CRYPTO_METHOD_SSLv23_CLIENT; break;
case "tls": $this->crypto_type = STREAM_CRYPTO_METHOD_TLS_CLIENT; break;
case "sslv2": $this->crypto_type = STREAM_CRYPTO_METHOD_SSLv2_CLIENT; break;
case "sslv3": $this->crypto_type = STREAM_CRYPTO_METHOD_SSLv3_CLIENT; break;
* Connect to the peer address
* @param int $timeout connection timeout in seconds
public function Connect($timeout = false) {
$errno = $errstr = false;
if ($this->fd === false) {
throw new <a href="../nanoserv/Core/NS_Client_Exception.html">NS_Client_Exception</a>("cannot connect to { $this->real_address}: { $errstr}", $errno, $this->real_address);
if ($timeout === false) $timeout = self::CONNECT_TIMEOUT;
$this->connect_timeout = microtime(true) + $timeout;
class NS_IPC_Socket extends NS_Socket {
* Maximum size of inter process communication packets
const IPC_MAX_PACKET_SIZE = 1048576;
* pid number of the remote forked process
public function __construct($fd, $pid=false) {
parent::__construct($fd);
* Read data from IPC socket
return fread($this->fd, self::IPC_MAX_PACKET_SIZE);
* Creates a pair of connected, indistinguishable pipes
* Returns an array of two NS_IPC_Socket objects
static public function Pair($domain = STREAM_PF_UNIX, $type = STREAM_SOCK_DGRAM, $proto = 0) {
list($s1, $s2) = stream_socket_pair($domain, $type, $proto);
return array(new NS_IPC_Socket($s1), new NS_IPC_Socket($s2));
* Ask the master process for object data
* @param bool $need_response
public function Ask_Master($request, $need_response = true) {
$this->Write(serialize($request));
if (!$need_response) return;
if (@stream_select($rfd, $dfd, $dfd, 600)) return unserialize($this->Read());
* Do not instanciate NS_Timer but use the Nanoserv::New_Timer() method instead
* System time for timer activation
* @see Nanoserv::New_Timer()
public function __construct($time, $callback) {
$this->microtime = $time;
$this->callback = $callback;
* Timers are activated by default, and Activate should only be used after a call do Deactivate()
* @see NS_Timer::Deactivate()
public function Activate() {
public function Deactivate() {
interface NS_I_Write_Buffer {
* Setup a new write buffer
* @param NS_Socket $socket
public function __construct(NS_Socket $socket, $data, $callback = false);
* Get availability of data
public function Waiting_Data();
* Write data to socket and advance buffer pointer
public function Write($length = NULL);
* Write buffer base class
abstract class NS_Write_Buffer {
protected $callback = false;
* NS_Write_Buffer constructor
* @param NS_Socket $socket
public function __construct(NS_Socket $socket, $data, $callback = false) {
$this->callback = $callback;
* NS_Write_Buffer destructor
public function __destruct() {
if ($this->callback) call_user_func($this->callback, $this->Waiting_Data());
* Static write buffer class
class NS_Static_Write_Buffer extends NS_Write_Buffer implements NS_I_Write_Buffer {
* Get availability of data
public function Waiting_Data() {
return isset($this->data[$this->pointer]);
* Write data to socket and advance buffer pointer
public function Write($length = 16384) {
$this->pointer += $this->socket->Write(substr($this->data, $this->pointer, $length));
* Stream write buffer class
class NS_Stream_Write_Buffer extends NS_Write_Buffer implements NS_I_Write_Buffer {
* Get availability of data from stream
public function Waiting_Data() {
return !@feof($this->data);
* Read data from stream and write it to socket
public function Write($length = 16384) {
return $this->socket->Write_From_Stream($this->data, $length);
abstract class NS_Handler {
* Set a stream context option
public function Set_Option($wrapper, $opt, $val) {
return $this->socket->Set_Option($wrapper, $opt, $val);
* Datagram listener / handler class
abstract class NS_Datagram_Handler extends NS_Handler {
* Is the listener active ?
* NS_Datagram_Handler constructor
* @param string $handler_classname
* @param mixed $handler_options
public function __construct($addr) {
$this->socket = new NS_Server_Socket($addr);
public function Activate() {
if ($ret = $this->socket->Listen(true)) $this->active = true;
} catch (NS_Server_Exception $e) {
throw new NS_Server_Exception($e->getMessage(), $e->getCode(), $e->addr, $this);
* Deactivate the listener
public function Deactivate($close_socket = true) {
* Send data over the connection
* @param string $to in the form of "<ip_address>:<port>"
public function Write($to, $data) {
return $this->socket->Write_To($to, $data);
* Event called on data reception
public function on_Read($from, $data) {
* NS_Datagram_Handler destructor
public function __destruct() {
* Connection handler class
abstract class NS_Connection_Handler extends NS_Handler {
* Cause of connection failure
const FAIL_CONNREFUSED = 1;
* Send data over the connection
* @return NS_Static_Write_Buffer
public function Write($data, $callback=false) {
return Nanoserv::New_Static_Write_Buffer($this->socket, $data, $callback);
* Send open stream over the connection
* @param resource $stream
* @return NS_Stream_Write_Buffer
public function Write_Stream($stream, $callback=false) {
return Nanoserv::New_Stream_Write_Buffer($this->socket, $stream, $callback);
* @param int $timeout timeout in seconds
public function Connect($timeout=false) {
$this->socket->Connect($timeout);
} catch (NS_Client_Exception $e) {
Nanoserv::Free_Connection($this);
throw new NS_Client_Exception($e->getMessage(), $e->getCode(), $e->addr, $this);
public function Disconnect() {
Nanoserv::Free_Connection($this);
* Event called on received connection
public function on_Accept() {
* Event called on established connection
public function on_Connect() {
* Event called on failed connection
* @param int $failcode see NS_Connection_Handler::FAIL_* constants
public function on_Connect_Fail($failcode) {
* Event called on disconnection
public function on_Disconnect() {
* Event called on data reception
public function on_Read($data) {
* Event called before forking
public function on_Fork_Prepare() {
* Event called after forking, both on master and child processes
public function on_Fork_Done() {
* Name of the handler class
* @see NS_Connetion_Handler
public $handler_classname;
* this is passed as the first constructor parameter of each spawned connection handlers
* Is the listener active ?
* If set the listener will fork() a new process for each accepted connection
* NS_Listener constructor
* @param string $handler_classname
* @param mixed $handler_options
public function __construct($addr, $handler_classname, $handler_options=false, $forking=false) {
$this->socket = new NS_Server_Socket($addr);
$this->handler_classname = $handler_classname;
$this->handler_options = $handler_options;
$this->forking = ($forking && is_callable("pcntl_fork"));
* Set a stream context option
public function Set_Option($wrapper, $opt, $val) {
return $this->socket->Set_Option($wrapper, $opt, $val);
* Sets wether the listener should fork() a new process for each accepted connection
public function Set_Forking($forking=true) {
if ($forking && !is_callable("pcntl_fork")) return false;
$this->forking = $forking;
public function Activate() {
if ($ret = $this->socket->Listen()) $this->active = true;
} catch (<a href="../nanoserv/Core/NS_Server_Exception.html">NS_Server_Exception</a> $e) {
throw new <a href="../nanoserv/Core/NS_Server_Exception.html">NS_Server_Exception</a>($e->getMessage(), $e->getCode(), $e->addr, $this);
* Deactivate the listener
public function Deactivate() {
* Shared object class for inter-process communications
class <a href="../nanoserv/Core/NS_Shared_Object.html">NS_Shared_Object</a> {
static public $caller_pid;
* shared object unique identifier
* static instance counter
static public $shared_count = 0;
* NS_Shared_Object constructor
* If $o is omited, a new StdClass object will be created and wrapped
public function __construct($o=false) {
if ($o === false) $o = new StdClass();
$this->_oid = ++self::$shared_count;
public function __get($k) {
if (Nanoserv::$child_process) {
return Nanoserv::$master_pipe->Ask_Master(array("oid" => $this->_oid, "action" => "G", "var" => $k));
return $this->wrapped->$k;
public function __set($k, $v) {
if (<a href="../nanoserv/Core/Nanoserv.html">Nanoserv</a>::$child_process) {
Nanoserv::$master_pipe->Ask_Master(array("oid" => $this->_oid, "action" => "S", "var" => $k, "val" => $v), false);
public function __call($m, $a) {
if (<a href="../nanoserv/Core/Nanoserv.html">Nanoserv</a>::$child_process) {
return Nanoserv::$master_pipe->Ask_Master(array("oid" => $this->_oid, "action" => "C", "func" => $m, "args" => $a));
return call_user_func_array(array($this->wrapped, $m), $a);
* Server / multiplexer class
* nanoserv current version number
static private $listeners = array();
static private $write_buffers = array();
static private $connections = array();
* Active datagram handlers
static private $dgram_handlers = array();
static private $shared_objects = array();
static private $forked_pipes = array();
static private $timers = array();
static private $timers_updated = false;
* Number of active connection handler processes
* Maximum number of active children before incoming connections get delayed
* Are we master or child process ?
* Forked server handled connection
* @var NS_Connection_Handler
static private $forked_connection;
* Forked server pipe to the master process
* Class Nanoserv should not be instanciated but used statically
private function __construct() {
* Register a new listener
* For consistency New_Listener() will also wrap Nanoserv::New_Datagram_Handler() if the given addr is of type "udp"
* @param string $handler_classname
* @param mixed $handler_options
* @see NS_Datagram_Handler
static public function New_Listener($addr, $handler_classname, $handler_options=false) {
$l = self::New_Datagram_Handler($addr, $handler_classname);
$l = new <a href="../nanoserv/Core/NS_Listener.html">NS_Listener</a>($addr, $handler_classname, $handler_options);
* Deactivate and free a previously registered listener
* For consistency Free_Listener() will also wrap Nanoserv::Free_Datagram_Handler() if the given object is an instance of NS_Datagram_Handler
* @see NS_Datagram_Handler
if ($l instanceof NS_Listener) {
foreach (self::$listeners as $k => $v) if ($v === $l) {
unset(self::$listeners[$k]);
} else if ($l instanceof <a href="../nanoserv/Core/NS_Datagram_Handler.html">NS_Datagram_Handler</a>) {
return self::Free_Datagram_Handler($l);
* Register a new static write buffer
* This method is used by NS_Connection_Handler::Write() and should not be
* called unless you really know what you are doing
* @param NS_Socket $socket
* @return NS_Static_Write_Buffer
* @see NS_Connection_Handler::Write()
$wb = new <a href="../nanoserv/Core/NS_Static_Write_Buffer.html">NS_Static_Write_Buffer</a>($socket, $data, $callback);
if ($wb->Waiting_Data()) {
self::$write_buffers[$socket->id][] = $wb;
* Register a new static write buffer
* This method is used by NS_Connection_Handler::Write_Stream() and should not be
* called unless you really know what you are doing
* @param NS_Socket $socket
* @param resource $stream
* @return NS_Stream_Write_Buffer
* @see NS_Connection_Handler::Write_Stream()
$wb = new NS_Stream_Write_Buffer($socket, $data, $callback);
if ($wb->Waiting_Data()) {
self::$write_buffers[$socket->id][] = $wb;
* Free a registered write buffer
* @param int $sid socket id
unset(self::$write_buffers[$sid]);
* Register a new outgoing connection
* @param string $handler_classname
* @param mixed $handler_options
* @return NS_Connection_Handler
* @see NS_Connection_Handler
static public function New_Connection($addr, $handler_classname, $handler_options=false) {
$sck = new NS_Client_Socket($addr);
$h = new $handler_classname($handler_options);
self::$connections[$sck->id] = $h;
* Free an allocated connection
* @param NS_Connection_Handler $h
unset(self::$connections[$so->id]);
self::Free_Write_Buffers($so->id);
$so->pending_connect = $so->pending_crypto = $so->connected = false;
if (self::$child_process && (self::$forked_connection === $h)) exit();
* Register a new datagram (udp) handler
* @param string $handler_classname
* @return NS_Datagram_Handler
* @see NS_Datagram_Handler
$h = new $handler_classname($addr);
self::$dgram_handlers[$h->socket->id] = $h;
* Deactivate and free a datagram handler
* @param NS_Datagram_Handler $h
unset(self::$dgram_handlers[$h->socket->id]);
* Register a new shared object
* shared objects allow forked processes to use objects stored on the master process
* if $o is ommited, a new StdClass empty object is created
* @return NS_Shared_Object
$shr = new <a href="../nanoserv/Core/NS_Shared_Object.html">NS_Shared_Object</a>($o);
self::$shared_objects[$shr->_oid] = $shr;
* @param NS_Shared_Object $o
unset(self::$shared_objects[$o->_oid]);
* Register a new timer callback
* @param float $delay specified in seconds
* @param mixed $callback may be "function" or array($obj, "method")
static public function New_Timer($delay, $callback) {
$t = new NS_Timer(microtime(true) + $delay, $callback);
self::$timers_updated = true;
* Clear all existing timers
* @return int number of timers cleared
$ret = count(self::$timers);
* Get all registered NS_Connection_Handler objects
* Note: connections created by fork()ing listeners can not be retreived this way
* @param bool $include_pending_connect
foreach (self::$connections as $c) if ($c->socket->connected || $include_pending_connect) $ret[] = $c;
* Get all registered NS_Listener objects
* @param bool $include_inactive
foreach (self::$listeners as $l) if ($l->active || $include_inactive) $ret[] = $l;
* Get all registered NS_Timer objects
* @param bool $include_inactive
static public function Get_Timers($include_inactive=false) {
foreach (self::$timers as $t) if ($t->active || $include_inactive) $ret[] = $t;
* Set the maximum number of allowed children processes before delaying incoming connections
* Note: this setting only affect and applies to forking listeners
self::$max_forked_processes = $i;
* Flush all write buffers
while (self::$write_buffers) {
* Fork and setup IPC sockets
* @return int the pid of the created process, 0 if child process
static public function Fork() {
if ($has_shared = (<a href="../nanoserv/Core/NS_Shared_Object.html">NS_Shared_Object</a>::$shared_count > 0)) {
list($s1, $s2) = NS_IPC_Socket::Pair();
self::$child_process = true;
self::$master_pipe = $s2;
++self::$nb_forked_processes;
self::$forked_pipes[$pid] = $s1;
* The <var>$time</var> parameter can have different meanings:
* <li>int or float > 0 : the main loop will run once and will wait for activity for a maximum of <var>$time</var> seconds</li>
* <li>0 : the main loop will run once and will not wait for activity when polling, only handling waiting packets and timers</li>
* <li>int or float < 0 : the main loop will run for -<var>$time</var> seconds exactly, whatever may happen</li>
* <li>NULL : the main loop will run forever</li>
* @param float $time how much time should we run, if omited nanoserv will enter an endless loop
* @param array $user_streams if specified, user streams will be polled along with internal streams
* @return array the user streams with pending data
static public function Run($time = NULL, array $user_streams = NULL) {
$exit_mt = microtime(true) - $time;
if (self::$timers_updated) {
usort(self::$timers, function(NS_Timer $a, NS_Timer $b) { return $a->microtime > $b->microtime; });
self::$timers_updated = false;
if (self::$timers) foreach (self::$timers as $k => $tmr) {
if ($tmr->microtime > $t) {
} else if ($tmr->active) {
unset(self::$timers[$k]);
if (self::$timers_updated) {
usort(self::$timers, function(NS_Timer $a, NS_Timer $b) { return $a->microtime > $b->microtime; });
foreach (self::$timers as $tmr) {
if ($tmr->microtime > $t) {
self::$timers_updated = false;
// Write buffers to non blocked sockets
foreach (self::$write_buffers as $write_buffers) {
if (!$write_buffers || $write_buffers[0]->socket->blocked || !$write_buffers[0]->socket->connected) continue;
foreach ($write_buffers as $wb) {
while ($wb->Waiting_Data() && !$wb->socket->blocked) {
if (!$wb->Waiting_Data()) {
if (!self::$write_buffers[$wb->socket->id]) self::Free_Write_Buffers($wb->socket->id);
$handler = $so = $write_buffers = $l = $c = $wbs = $wb = $data = $so = NULL;
$fd_lookup_r = $fd_lookup_w = $rfd = $wfd = $efd = array();
foreach (self::$listeners as $l) if (($l->active) && ((!$l->forking) || (self::$nb_forked_processes <= self::$max_forked_processes))) {
$fd_lookup_r[(int)$fd] = $l;
$next_conn_timeout_mt = NULL;
foreach (self::$connections as $c) {
if ($so->pending_crypto) {
$cr = $so->Enable_Crypto();
} else if ($cr === false) {
$c->on_Connect_Fail(<a href="../nanoserv/Core/NS_Connection_Handler.html">NS_Connection_Handler</a>::FAIL_CRYPTO);
self::Free_Connection($c);
$fd_lookup_r[(int)$fd] = $c;
} else if ($so->connected) {
$fd_lookup_r[(int)$fd] = $c;
} else if ($so->connect_timeout < $t) {
$c->on_Connect_Fail(<a href="../nanoserv/Core/NS_Connection_Handler.html">NS_Connection_Handler</a>::FAIL_TIMEOUT);
self::Free_Connection($c);
} else if ($so->pending_connect) {
$fd_lookup_w[(int)$fd] = $c;
if (!$next_conn_timeout_mt || ($sc->connect_timeout < $next_conn_timeout_mt)) {
$next_conn_timeout_mt = $sc->connect_timeout;
if (self::$dgram_handlers) foreach (self::$dgram_handlers as $l) if ($l->active) {
$fd_lookup_r[(int)$fd] = $l;
foreach (self::$write_buffers as $wbs) if ($wbs[0]->socket->blocked) {
$fd = $wbs[0]->socket->fd;
$fd_lookup_w[(int)$fd] = self::$connections[$wbs[0]->socket->id];
if (self::$forked_pipes) foreach (self::$forked_pipes as $fp) {
$fd_lookup_r[(int)$fd] = $fp;
if (isset($user_streams)) {
foreach ((array)$user_streams[0] as $tmp_r) $rfd[] = $tmp_r;
foreach ((array)$user_streams[1] as $tmp_w) $wfd[] = $tmp_w;
$wait_mds = array($poll_max_wait);
if (isset($next_timer_md)) $wait_mds[] = $next_timer_md;
if (isset($exit_mt)) $wait_mds[] = $exit_mt - $t;
if (isset($next_conn_timeout_mt)) $wait_mds[] = $next_conn_timeout_mt - $t;
$wait_md = min($wait_mds);
$tv_usec = ($wait_md - $tv_sec) * 1000000;
if (($rfd || $wfd) && (@stream_select($rfd, $wfd, $efd, $tv_sec, $tv_usec))) {
foreach ($rfd as $act_rfd) {
$handler = $fd_lookup_r[(int)$act_rfd];
if ($handler instanceof <a href="../nanoserv/Core/NS_Connection_Handler.html">NS_Connection_Handler</a>) {
if ($so->pending_crypto) {
$cr = $so->Enable_Crypto();
} else if ($cr === false) {
$handler->on_Connect_Fail(<a href="../nanoserv/Core/NS_Connection_Handler.html">NS_Connection_Handler</a>::FAIL_CRYPTO);
self::Free_Connection($handler);
} else if (!$so->connected) {
if (($data === "") || ($data === false)) {
$handler->on_Disconnect();
self::Free_Connection($handler);
$handler->on_Read($data);
} else if ($handler instanceof <a href="../nanoserv/Core/NS_Datagram_Handler.html">NS_Datagram_Handler</a>) {
$data = $so->Read_From($from);
$handler->on_Read($from, $data);
} else if ($handler instanceof <a href="../nanoserv/Core/NS_Listener.html">NS_Listener</a>) {
while ($fd = $so->Accept()) {
// New connection accepted
$sck = new <a href="../nanoserv/Core/NS_Socket.html">NS_Socket</a>($fd, $so->crypto_type);
$hnd = new $handler->handler_classname($handler->handler_options);
if (self::Fork() === 0) {
self::$write_buffers = self::$listeners = array();
self::$connections = array($sck->id => $hnd);
self::$forked_connection = $hnd;
$handler = $hnd = $sck = $l = $c = $wbs = $wb = $fd_lookup_r = $fd_lookup_w = false;
if (self::$nb_forked_processes >= self::$max_forked_processes) break;
self::$connections[$sck->id] = $hnd;
} else if ($handler instanceof <a href="../nanoserv/Core/NS_IPC_Socket.html">NS_IPC_Socket</a>) {
while ($ipcm = $handler->Read()) {
if ((!$ipcq = unserialize($ipcm)) || (!is_object($o = self::$shared_objects[$ipcq["oid"]]))) continue;
switch ($ipcq["action"]) {
$handler->Write(serialize($o->$ipcq["var"]));
$o->$ipcq["var"] = $ipcq["val"];
<a href="../nanoserv/Core/NS_Shared_Object.html">NS_Shared_Object</a>::$caller_pid = $handler->pid;
$o = $ipcq = $ipcm = NULL;
} else if (!isset($handler)) {
foreach ($wfd as $act_wfd) {
$handler = $fd_lookup_w[$act_wfd];
} else if ($so->connected) {
// Unblock buffered write
$handler->on_Disconnect();
self::Free_Connection($handler);
} else if ($so->pending_connect) {
$handler->on_Connect_Fail(<a href="../nanoserv/Core/NS_Connection_Handler.html">NS_Connection_Handler</a>::FAIL_CONNREFUSED);
self::Free_Connection($handler);
$so->pending_connect = false;
if (self::$nb_forked_processes && !self::$child_process) while ((($pid = pcntl_wait($tmp, WNOHANG)) > 0) && self::$nb_forked_processes--) unset(self::$forked_pipes[$pid]);
} else if (isset($exit_mt)) {
|