Copyright (c) 2009-2012, Abhinav Singh . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Abhinav Singh nor the names of his contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
示例#1
0
文件: jaxl_fsm.php 项目: jaxl/JAXL
 public function __call($event, $args)
 {
     if ($this->state) {
         // call state method
         JAXLLogger::debug(sprintf("calling state handler '%s' for incoming event '%s'", is_array($this->state) ? $this->state[1] : $this->state, $event));
         if (is_callable($this->state)) {
             $call = $this->state;
         } else {
             $call = method_exists($this, $this->state) ? array(&$this, $this->state) : $this->state;
         }
         $r = call_user_func($call, $event, $args);
         // 4 cases of possible return value
         if (is_callable($r)) {
             $this->state = $r;
         } elseif (is_array($r) && count($r) == 2) {
             list($this->state, $ret) = $r;
         } elseif (is_array($r) && count($r) == 1) {
             $this->state = $r[0];
         } elseif (is_string($r)) {
             $this->state = $r;
         } else {
             $this->handle_invalid_state($r);
         }
         JAXLLogger::debug("current state '" . (is_array($this->state) ? $this->state[1] : $this->state) . "'");
         // return case
         if (!is_callable($r) && is_array($r) && count($r) == 2) {
             return $ret;
         }
     } else {
         JAXLLogger::debug("invalid state found, nothing called for event " . $event . "");
     }
 }
示例#2
0
文件: xep_0114.php 项目: jaxl/JAXL
 public function logged_out($stanza)
 {
     if ($stanza->name == "error" && $stanza->ns == XMPP::NS_XMPP) {
         $reason = $stanza->children[0]->name;
         $this->jaxl->handle_auth_failure($reason);
         $this->jaxl->send_end_stream();
         return array("logged_out", 0);
     } else {
         JAXLLogger::debug("uncatched stanza received in logged_out");
     }
 }
示例#3
0
 public function dispatch($request)
 {
     foreach ($this->rules as $rule) {
         //JAXLLogger::debug("matching $request->path with pattern $rule->pattern");
         if (($matches = $rule->match($request->path, $request->method)) !== false) {
             JAXLLogger::debug("matching rule found, dispatching");
             $params = array($request);
             // TODO: a bad way to restrict on 'pk', fix me for generalization
             if (isset($matches['pk'])) {
                 $params[] = $matches['pk'];
             }
             call_user_func_array($rule->cb, $params);
             return true;
         }
     }
     return false;
 }
示例#4
0
 public static function shutdown_handler()
 {
     try {
         JAXLLogger::debug("got shutdown handler");
         if (null !== ($error = error_get_last())) {
             throw new JAXLException($error['message'], $error['type'], $error['file'], $error['line']);
         }
     } catch (Exception $e) {
         JAXLLogger::debug("shutdown handler catched with exception " . json_encode($e));
     }
 }
示例#5
0
 public function done($event, $data)
 {
     JAXLLogger::warning("got unhandled event {$event} with data {$data['0']}");
     return array('done', false);
 }
示例#6
0
 * notice, this list of conditions and the following disclaimer in
 * the documentation and/or other materials provided with the
 * distribution.
 *
 * * Neither the name of Abhinav Singh nor the names of his
 * contributors may be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 */
if ($argc < 2) {
    echo "Usage: {$argv['0']} url\n";
    exit;
}
require_once 'jaxl.php';
JAXLLogger::$level = JAXL_DEBUG;
require_once JAXL_CWD . '/http/http_client.php';
$request = new HTTPClient($argv[1]);
$request->start();
示例#7
0
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 */
require dirname(__FILE__) . '/_bootstrap.php';
// configure logger
JAXLLogger::$level = JAXLLogger::INFO;
// print usage notice and parse addr/port parameters if passed
JAXLLogger::cliLog("Usage: {$argv['0']} port (default: 9699)", JAXLLogger::NOTICE);
$port = $argc == 2 ? $argv[1] : 9699;
// initialize http server
$http = new HTTPServer($port);
// catch all incoming requests here
function on_request($request)
{
    $body = json_encode($request);
    $request->ok($body, array('Content-Type' => 'application/json'));
}
// start http server
$http->start('on_request');
示例#8
0
function on_auth_failure_callback($reason)
{
    global $client;
    $client->send_end_stream();
    JAXLLogger::info("got on_auth_failure cb with reason {$reason}");
}
示例#9
0
function delete_event($request, $pk)
{
    JAXLLogger::info("got event delete request for {$pk}");
    $request->close();
}
示例#10
0
 public function on_client_write_ready($client)
 {
     $client_id = (int) $client;
     JAXLLogger::debug("client#{$client_id} is write ready");
     try {
         // send in chunks
         $total = $this->clients[$client_id]['obuffer'];
         $written = @fwrite($client, substr($total, 0, $this->send_chunk_size));
         if ($written === false) {
             // fwrite failed
             JAXLLogger::warning("====> fwrite failed");
             $this->clients[$client_id]['obuffer'] = $total;
         } elseif ($written == strlen($total) || $written == $this->send_chunk_size) {
             // full chunk written
             //JAXLLogger::debug("full chunk written");
             $this->clients[$client_id]['obuffer'] = substr($total, $this->send_chunk_size);
         } else {
             // partial chunk written
             //JAXLLogger::debug("partial chunk $written written");
             $this->clients[$client_id]['obuffer'] = substr($total, $written);
         }
         // if no more stuff to write, remove write handler
         if (strlen($this->clients[$client_id]['obuffer']) === 0) {
             $this->del_write_cb($client_id);
             // if scheduled for close and not closed do it and clean up
             if ($this->clients[$client_id]['close'] && !$this->clients[$client_id]['closed']) {
                 if (is_resource($client)) {
                     fclose($client);
                 }
                 $this->clients[$client_id]['closed'] = true;
                 unset($this->clients[$client_id]);
                 JAXLLogger::debug("closed client#" . $client_id);
             }
         }
     } catch (JAXLException $e) {
         JAXLLogger::debug("====> got fwrite exception");
     }
 }
示例#11
0
 protected function handle_start_tag($parser, $name, array $attrs)
 {
     $name = $this->explode($name);
     //echo "start of tag ".$name[1]." with ns ".$name[0].PHP_EOL;
     // replace ns with prefix
     foreach ($attrs as $key => $v) {
         $k = $this->explode($key);
         // no ns specified
         if ($k[0] == null) {
             $attrs[$k[1]] = $v;
         } elseif ($k[0] == XMPP::NS_XML) {
             // xml ns
             unset($attrs[$key]);
             $attrs['xml:' . $k[1]] = $v;
         } else {
             JAXLLogger::error("==================> unhandled ns prefix on attribute");
             // remove attribute else will cause error with bad stanza format
             // report to developer if above error message is ever encountered
             unset($attrs[$key]);
         }
     }
     if ($this->depth <= 0) {
         $this->depth = 0;
         $this->ns = $name[1];
         if ($this->start_cb) {
             $stanza = new JAXLXml($name[1], $name[0], $attrs);
             call_user_func($this->start_cb, $stanza);
         }
     } else {
         if (!$this->stanza) {
             $stanza = new JAXLXml($name[1], $name[0], $attrs);
             $this->stanza =& $stanza;
         } else {
             $this->stanza->c($name[1], $name[0], $attrs);
         }
     }
     ++$this->depth;
 }
示例#12
0
 public function on_write_ready($fd)
 {
     //JAXLLogger::debug("on write ready called");
     $total = strlen($this->obuffer);
     $bytes = @fwrite($fd, $this->obuffer);
     $this->send_bytes += $bytes;
     JAXLLogger::debug("sent " . $bytes . "/" . $this->send_bytes . " of data");
     JAXLLogger::debug(substr($this->obuffer, 0, $bytes));
     $this->obuffer = substr($this->obuffer, $bytes, $total - $bytes);
     // unwatch for write if obuffer is empty
     if (strlen($this->obuffer) === 0) {
         JAXLLoop::unwatch($fd, array('write' => true));
         $this->writing = false;
     }
     //JAXLLogger::debug("current obuffer size: ".strlen($this->obuffer)."");
 }
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 */
if ($argc < 2) {
    echo "Usage: {$argv['0']} /path/to/server.sock\n";
    exit;
}
require_once 'jaxl.php';
JAXLLogger::$level = JAXL_INFO;
$server = null;
function on_request($client, $raw)
{
    global $server;
    $server->send($client, $raw);
    _info("got client callback " . $raw);
}
@unlink($argv[1]);
$server = new JAXLSocketServer('unix://' . $argv[1], 'on_request');
JAXLLoop::run();
echo "done\n";
示例#14
0
文件: xmpp_stream.php 项目: jaxl/JAXL
 public function logged_out($event, $args)
 {
     switch ($event) {
         case "end_cb":
             $this->trans->disconnect();
             return "disconnected";
             break;
         case "end_stream":
             return "disconnected";
             break;
         case "disconnect":
             $this->trans->disconnect();
             return "disconnected";
             break;
         case "connect":
             return $this->do_connect($args);
             break;
         default:
             // exit for any other event in logged_out state
             JAXLLogger::debug("uncatched {$event}");
             return $this->handle_other($event, $args);
             //return array("logged_out", 0);
             break;
     }
 }
示例#15
0
文件: pipes.php 项目: jaxl/JAXL
function read_event_callback($data)
{
    global $pipe;
    JAXLLogger::info("read " . trim($data) . " from pipe");
}
示例#16
0
文件: jaxl_clock.php 项目: jaxl/JAXL
 public function __destruct()
 {
     JAXLLogger::info("shutting down clock server...");
 }
示例#17
0
 protected function send_response($code, array $headers = array(), $body = null)
 {
     // send out response line
     $this->send_line($code);
     // set content length of body exists and is not already set
     if ($body && !isset($headers['Content-Length'])) {
         $headers['Content-Length'] = strlen($body);
     }
     // send out headers
     $this->send_headers($code, $headers);
     // send body
     // prefixed with an empty line
     JAXLLogger::debug("sending out HTTP_CRLF prefixed body");
     if ($body) {
         $this->send_body(HTTPServer::HTTP_CRLF . $body);
     }
 }
示例#18
0
function on_disconnect($client)
{
    JAXLLogger::info("got on_disconnect cb");
}
示例#19
0
function on_request($client, $raw)
{
    global $server;
    $server->send($client, $raw);
    JAXLLogger::info("got client callback " . $raw);
}
示例#20
0
文件: jaxl.php 项目: jaxl/JAXL
 public function handle_other($event, $args)
 {
     $stanza = isset($args[0]) ? $args[0] : null;
     $stanza = new XMPPStanza($stanza);
     $ev = 'on_' . $stanza->name . '_stanza';
     if ($this->ev->exists($ev)) {
         return $this->ev->emit($ev, array($stanza));
     } else {
         JAXLLogger::warning("event '" . $event . "' catched in handle_other with stanza name " . $stanza->name);
     }
 }
示例#21
0
function on_disconnect_callback()
{
    JAXLLogger::info("got on_disconnect cb");
}
示例#22
0
function on_disconnect_callback()
{
    global $form;
    JAXLLogger::info("registration " . ($form['type'] == 'result' ? 'succeeded' : 'failed'));
}
示例#23
0
 public function __construct($config)
 {
     // env
     $this->cfg = $config;
     $strict = isset($this->cfg['strict']) ? $this->cfg['strict'] : TRUE;
     if ($strict) {
         $this->add_exception_handlers();
     }
     $this->mode = PHP_SAPI;
     $this->local_ip = gethostbyname(php_uname('n'));
     $this->pid = getmypid();
     // initialize core modules
     $this->ev = new JAXLEvent();
     // jid object
     $jid = @$this->cfg['jid'] ? new XMPPJid($this->cfg['jid']) : null;
     // handle signals
     if (extension_loaded('pcntl')) {
         pcntl_signal(SIGHUP, array($this, 'signal_handler'));
         pcntl_signal(SIGINT, array($this, 'signal_handler'));
         pcntl_signal(SIGTERM, array($this, 'signal_handler'));
     }
     // create .jaxl directory in JAXL_CWD
     // for our /tmp, /run and /log folders
     // overwrite these using jaxl config array
     $this->priv_dir = @$this->cfg['priv_dir'] ? $this->cfg['priv_dir'] : JAXL_CWD . "/.jaxl";
     $this->tmp_dir = $this->priv_dir . "/tmp";
     $this->pid_dir = $this->priv_dir . "/run";
     $this->log_dir = $this->priv_dir . "/log";
     $this->sock_dir = $this->priv_dir . "/sock";
     if (!is_dir($this->priv_dir)) {
         mkdir($this->priv_dir);
     }
     if (!is_dir($this->tmp_dir)) {
         mkdir($this->tmp_dir);
     }
     if (!is_dir($this->pid_dir)) {
         mkdir($this->pid_dir);
     }
     if (!is_dir($this->log_dir)) {
         mkdir($this->log_dir);
     }
     if (!is_dir($this->sock_dir)) {
         mkdir($this->sock_dir);
     }
     // setup logger
     if (isset($this->cfg['log_path'])) {
         JAXLLogger::$path = $this->cfg['log_path'];
     }
     //else JAXLLogger::$path = $this->log_dir."/jaxl.log";
     if (isset($this->cfg['log_level'])) {
         JAXLLogger::$level = $this->log_level = $this->cfg['log_level'];
     } else {
         JAXLLogger::$level = $this->log_level;
     }
     // touch pid file
     if ($this->mode == "cli") {
         touch($this->get_pid_file_path());
         _info("created pid file " . $this->get_pid_file_path());
     }
     // include mandatory xmpp xeps
     // service discovery and entity caps
     // are recommended for every xmpp entity
     $this->require_xep(array('0030', '0115'));
     // do dns lookup, update $cfg['host'] and $cfg['port'] if not already specified
     $host = @$this->cfg['host'];
     $port = @$this->cfg['port'];
     if (!$host && !$port && $jid) {
         // this dns lookup is blocking
         _info("dns srv lookup for " . $jid->domain);
         list($host, $port) = JAXLUtil::get_dns_srv($jid->domain);
     }
     $this->cfg['host'] = $host;
     $this->cfg['port'] = $port;
     // choose appropriate transport
     // if 'bosh_url' cfg is defined include 0206
     if (@$this->cfg['bosh_url']) {
         _debug("including bosh xep");
         $this->require_xep('0206');
         $transport = $this->xeps['0206'];
     } else {
         list($host, $port) = JAXLUtil::get_dns_srv($jid->domain);
         $stream_context = @$this->cfg['stream_context'];
         $transport = new JAXLSocketClient($stream_context);
     }
     // initialize xmpp stream with configured transport
     parent::__construct($transport, $jid, @$this->cfg['pass'], @$this->cfg['resource'] ? 'jaxl#' . $this->cfg['resource'] : 'jaxl#' . md5(time()), @$this->cfg['force_tls']);
 }
示例#24
0
文件: jaxl_sock5.php 项目: jaxl/JAXL
 public function on_response($raw)
 {
     JAXLLogger::debug($raw);
 }
示例#25
0
文件: xmpp_rest.php 项目: jaxl/JAXL
function on_auth_success_callback()
{
    global $xmpp;
    JAXLLogger::info("got on_auth_success cb, jid " . $xmpp->full_jid->to_string());
}
示例#26
0
文件: xep_0206.php 项目: jaxl/JAXL
 public function disconnect()
 {
     JAXLLogger::debug("disconnecting");
 }
示例#27
0
function _colorize($msg, $verbosity)
{
    error_log(JAXLLogger::colorize($msg, $verbosity));
}
示例#28
0
文件: http_server.php 项目: jaxl/JAXL
 public function on_request($sock, $raw)
 {
     JAXLLogger::debug("on_request for client#{$sock}");
     $request = $this->requests[$sock];
     // 'wait_for_body' state is reached when ever
     // application calls recv_body() method
     // on received $request object
     if ($request->state() == 'wait_for_body') {
         $request->body($raw);
     } else {
         // break on crlf
         $lines = explode(HTTP_CRLF, $raw);
         // parse request line
         if ($request->state() == 'wait_for_request_line') {
             list($method, $resource, $version) = explode(" ", $lines[0]);
             $request->line($method, $resource, $version);
             unset($lines[0]);
             JAXLLogger::info($request->ip . " " . $request->method . " " . $request->resource . " " . $request->version);
         }
         // parse headers
         foreach ($lines as $line) {
             $line_parts = explode(":", $line);
             if (count($line_parts) > 1) {
                 if (strlen($line_parts[0]) > 0) {
                     $k = $line_parts[0];
                     unset($line_parts[0]);
                     $v = implode(":", $line_parts);
                     $request->set_header($k, $v);
                 }
             } elseif (strlen(trim($line_parts[0])) == 0) {
                 $request->empty_line();
             } else {
                 // if exploded line array size is 1
                 // and there is something in $line_parts[0]
                 // must be request body
                 $request->body($line);
             }
         }
     }
     // if request has reached 'headers_received' state?
     if ($request->state() == 'headers_received') {
         // dispatch to any matching rule found
         JAXLLogger::debug("delegating to dispatcher for further routing");
         $dispatched = $this->dispatcher->dispatch($request);
         // if no dispatch rule matched call generic callback
         if (!$dispatched && $this->cb) {
             JAXLLogger::debug("no dispatch rule matched, sending to generic callback");
             call_user_func($this->cb, $request);
         } elseif (!$dispatched) {
             // elseif not dispatched and not generic callbacked
             // send 404 not_found
             // TODO: send 404 if no callback is registered for this request
             JAXLLogger::debug("dropping request since no matching dispatch rule or generic callback was specified");
             $request->not_found('404 Not Found');
         }
     } else {
         // if state is not 'headers_received'
         // reactivate client socket for read event
         $this->server->read($sock);
     }
 }
示例#29
0
文件: jaxlctl.php 项目: jaxl/JAXL
 public static function printHelp()
 {
     global $exe;
     JAXLLogger::cliLog("Usage: {$exe} command [options...]" . PHP_EOL, JAXLLogger::INFO);
     JAXLLogger::cliLog("Commands:", JAXLLogger::NOTICE);
     JAXLLogger::cliLog("    help      This help text", JAXLLogger::DEBUG);
     JAXLLogger::cliLog("    debug     Attach a debug console to a running JAXL daemon", JAXLLogger::DEBUG);
     JAXLLogger::cliLog("    shell     Open up Jaxl shell emulator", JAXLLogger::DEBUG);
     echo PHP_EOL;
 }
示例#30
0
文件: jaxl_loop.php 项目: jaxl/JAXL
 public static function select()
 {
     $read = self::$read_fds;
     $write = self::$write_fds;
     $except = null;
     $changed = @stream_select($read, $write, $except, self::$secs, self::$usecs);
     if ($changed === false) {
         JAXLLogger::error("error in the event loop, shutting down...");
         /*foreach (self::$read_fds as $fd) {
                   if (is_resource($fd)) {
                           print_r(stream_get_meta_data($fd));
                   }
           }*/
         exit;
     } elseif ($changed > 0) {
         // read callback
         foreach ($read as $r) {
             $fdid = array_search($r, self::$read_fds);
             if (isset(self::$read_fds[$fdid])) {
                 call_user_func(self::$read_cbs[$fdid], self::$read_fds[$fdid]);
             }
         }
         // write callback
         foreach ($write as $w) {
             $fdid = array_search($w, self::$write_fds);
             if (isset(self::$write_fds[$fdid])) {
                 call_user_func(self::$write_cbs[$fdid], self::$write_fds[$fdid]);
             }
         }
         self::$clock->tick();
     } elseif ($changed === 0) {
         //JAXLLogger::debug("nothing changed while selecting for read");
         self::$clock->tick(self::$secs * pow(10, 6) + self::$usecs);
     }
 }