/** * Called when new data received * @param string New data * @return void */ public function stdin($buf) { Daemon::log(Debug::exportBytes($buf)); while ($c = array_pop($this->callbacks)) { list($cb, $st) = $c; $cb(microtime(true) - $st); } }
/** * Called when new data received * @param string New data * @return void */ public function stdin($buf) { $this->buf .= $buf; while (($l = $this->gets()) !== FALSE) { $e = explode(' ', rtrim($l, "\r\n")); if ($e[0] === 'RUN') { if (isset($this->appInstance->jobs[$e[1]])) { call_user_func($this->appInstance->jobs[$e[1]][0], $e[0], $e[1], $this->appInstance); } } elseif ($e[0] === 'DONE') { if (isset($this->appInstance->jobs[$e[1]][1])) { call_user_func($this->appInstance->jobs[$e[1]][1], $e[0], $e[1], $this->appInstance); } } elseif ($e[0] === 'FAILED') { if (isset($this->appInstance->jobs[$e[1]][2])) { call_user_func($this->appInstance->jobs[$e[1]][2], $e[0], $e[1], $this->appInstance); } } if ($this->appInstance->config->protologging->value) { Daemon::log('Lock client <-- Lock server: ' . Debug::exportBytes(implode(' ', $e)) . "\n"); } } }
public static function getLV(&$p, $l = 1, $nul = false, $lrev = false) { $s = self::b2i(binarySubstr($p, 0, $l), !!$lrev); //Daemon::log('s = '.$s. ' -- '.Debug::exportBytes(binarySubstr($p,0,$l), true)); $p = binarySubstr($p, $l); if ($s == 0) { return ''; } $r = ''; if (strlen($p) < $s) { echo "getLV error: buf length (" . strlen($p) . "): " . Debug::exportBytes($p) . ", must be >= string length (" . $s . ")\n"; } elseif ($nul) { if ($p[$s - 1] != "") { echo "getLV error: Wrong end of NUL-string (" . Debug::exportBytes($p[$s - 1]) . "), len " . $s . "\n"; } else { $d = $s - 1; if ($d < 0) { $d = 0; } $r = binarySubstr($p, 0, $d); $p = binarySubstr($p, $s); } } else { $r = binarySubstr($p, 0, $s); $p = binarySubstr($p, $s); } return $r; }
/** * Read data from the connection's buffer * @param integer Connection's ID * @param integer Max. number of bytes to read * @return string Readed data */ public function read($connId, $n) { if (!isset($this->buf[$connId])) { return FALSE; } if (isset($this->readEvents[$connId])) { if (Daemon::$useSockets) { $read = socket_read(Daemon::$process->pool[$connId], $n); if ($read === FALSE) { $no = socket_last_error(Daemon::$process->pool[$connId]); if ($no !== 11) { // Resource temporarily unavailable Daemon::log(get_class($this) . '::' . __METHOD__ . ': connId = ' . $connId . '. Socket error. (' . $no . '): ' . socket_strerror($no)); $this->onFailureEvent($connId, array()); } } } else { $read = fread(Daemon::$process->pool[$connId], $n); } } else { $read = event_buffer_read($this->buf[$connId], $n); } if ($read === '' || $read === NULL || $read === FALSE) { if (Daemon::$config->logreads->value) { Daemon::log('read(' . $connId . ',' . $n . ') interrupted.'); } unset(Daemon::$process->readPoolState[$connId]); return FALSE; } if (Daemon::$config->logreads->value) { Daemon::log('read(' . $connId . ',' . $n . ',[' . gettype($read) . '-' . ($read === FALSE ? 'false' : strlen($read)) . ':' . Debug::exportBytes($read) . ']).'); } return $read; }
/** * Constructor * @return void */ public function __construct($file, $config, $included = FALSE) { $cfg = $this; $cfg->file = $file; $cfg->result = $config; $cfg->revision = ++Daemon_Config::$lastRevision; $cfg->data = file_get_contents($file); if (substr($cfg->data, 0, 2) === '#!') { if (!is_executable($file)) { $this->raiseError('Shebang (#!) detected in the first line, but file hasn\'t +x mode.'); return; } $cfg->data = shell_exec($file); } $cfg->data = str_replace("\r", '', $cfg->data); $cfg->len = strlen($cfg->data); $cfg->state[] = array(self::T_ALL, $cfg->result); $cfg->tokens = array(self::T_COMMENT => function ($cfg, $c) { if ($c === "\n") { array_pop($cfg->state); } }, self::T_STRING => function ($cfg, $q) { $str = ''; ++$cfg->p; for (; $cfg->p < $cfg->len; ++$cfg->p) { $c = $cfg->getCurrentChar(); if ($c === $q) { ++$cfg->p; break; } elseif ($c === '\\') { if ($cfg->getNextChar() === $q) { $str .= $q; ++$cfg->p; } else { $str .= $c; } } else { $str .= $c; } } if ($cfg->p >= $cfg->len) { $cfg->raiseError('Unexpected End-Of-File.'); } return $str; }, self::T_ALL => function ($cfg, $c) { if (ctype_space($c)) { } elseif ($c === '#') { $cfg->state[] = array(Daemon_ConfigParser::T_COMMENT); } elseif ($c === '}') { if (sizeof($cfg->state) > 1) { $cfg->purgeScope($cfg->getCurrentScope()); array_pop($cfg->state); } else { $cfg->raiseError('Unexpected \'}\''); } } elseif (ctype_alnum($c)) { $elements = array(''); $elTypes = array(NULL); $i = 0; $tokenType = 0; for (; $cfg->p < $cfg->len; ++$cfg->p) { $c = $cfg->getCurrentChar(); if (ctype_space($c) || $c === '=') { if ($elTypes[$i] !== NULL) { ++$i; $elTypes[$i] = NULL; } } elseif ($c === '"' || $c === '\'') { if ($elTypes[$i] != NULL) { $cfg->raiseError('Unexpected T_STRING.'); } $string = call_user_func($cfg->tokens[Daemon_ConfigParser::T_STRING], $cfg, $c); --$cfg->p; if ($elTypes[$i] === NULL) { $elements[$i] = $string; $elTypes[$i] = Daemon_ConfigParser::T_STRING; } } elseif ($c === '}') { $cfg->raiseError('Unexpected \'}\' instead of \';\' or \'{\''); } elseif ($c === ';') { $tokenType = Daemon_ConfigParser::T_VAR; break; } elseif ($c === '{') { $tokenType = Daemon_ConfigParser::T_BLOCK; break; } else { if ($elTypes[$i] === Daemon_ConfigParser::T_STRING) { $cfg->raiseError('Unexpected T_CVALUE.'); } else { if (!isset($elements[$i])) { $elements[$i] = ''; } $elements[$i] .= $c; $elTypes[$i] = Daemon_ConfigParser::T_CVALUE; } } } foreach ($elTypes as $k => $v) { if (Daemon_ConfigParser::T_CVALUE === $v) { if (ctype_digit($elements[$k])) { $elements[$k] = (int) $elements[$k]; } elseif (is_numeric($elements[$k])) { $elements[$k] = (double) $elements[$k]; } else { $l = strtolower($elements[$k]); if ($l === 'true' || $l === 'on') { $elements[$k] = true; } elseif ($l === 'false' || $l === 'off') { $elements[$k] = false; } elseif ($l === 'null') { $elements[$k] = null; } } } } if ($tokenType === 0) { $cfg->raiseError('Expected \';\' or \'{\''); } elseif ($tokenType === Daemon_ConfigParser::T_VAR) { $name = str_replace('-', '', strtolower($elements[0])); $scope = $cfg->getCurrentScope(); if ($name === 'include') { $path = $elements[1]; if (substr($path, 0, 1) !== '/') { $path = 'conf/' . $path; } $files = glob($path); if ($files) { foreach ($files as $fn) { $parser = new Daemon_ConfigParser($fn, $scope, true); } } } elseif (substr(strtolower($elements[0]), 0, 4) === 'mod-') { $cfg->raiseError('Variable started with \'mod-\'. This style is deprecated. You should replace it with block.'); } elseif (isset($scope->{$name})) { if ($scope->{$name}->source != 'cmdline') { if (!isset($elements[1])) { $elements[1] = true; $elTypes[1] = Daemon_ConfigParser::T_CVALUE; } if ($elTypes[1] === Daemon_ConfigParser::T_CVALUE && is_string($elements[1])) { $scope->{$name}->setHumanValue($elements[1]); } else { $scope->{$name}->setValue($elements[1]); } $scope->{$name}->source = 'config'; $scope->{$name}->revision = $cfg->revision; } } elseif (sizeof($cfg->state) > 1) { $scope->{$name} = new Daemon_ConfigEntry(); $scope->{$name}->source = 'config'; $scope->{$name}->revision = $cfg->revision; if (!isset($elements[1])) { $elements[1] = true; $elTypes[1] = Daemon_ConfigParser::T_CVALUE; } $scope->{$name}->setValue($elements[1]); $scope->{$name}->setValueType($elTypes[1]); } else { $cfg->raiseError('Unrecognized parameter \'' . $name . '\''); } } elseif ($tokenType === Daemon_ConfigParser::T_BLOCK) { $scope = $cfg->getCurrentScope(); $sectionName = implode('-', $elements); $sectionName = strtr($sectionName, '-. ', ':::'); if (!isset($scope->{$sectionName})) { $scope->{$sectionName} = new Daemon_ConfigSection(); } $scope->{$sectionName}->source = 'config'; $scope->{$sectionName}->revision = $cfg->revision; $cfg->state[] = array(Daemon_ConfigParser::T_ALL, $scope->{$sectionName}); } } else { $cfg->raiseError('Unexpected char \'' . Debug::exportBytes($c) . '\''); } }); for (; $cfg->p < $cfg->len; ++$cfg->p) { $c = $cfg->getCurrentChar(); $e = end($this->state); $cfg->token($e[0], $c); } if (!$included) { $this->purgeScope($this->result); } }
/** * Called when new data received. * @param string New data. * @return void */ public function stdin($buf) { $this->buf .= $buf; while (($l = $this->gets()) !== FALSE) { $l = rtrim($l, "\r\n"); $e = explode(' ', $l, 2); if ($e[0] === 'acquire') { $this->writeln($this->acquireLock($e[1]) . ' ' . $e[1]); } elseif ($e[0] === 'acquireWait') { $this->writeln($this->acquireLock($e[1], TRUE) . ' ' . $e[1]); } elseif ($e[0] === 'done') { $this->done($e[1], 'DONE'); } elseif ($e[0] === 'failed') { $this->done($e[1], 'FAILED'); } elseif ($e[0] === 'quit') { $this->finish(); } elseif ($e[0] !== '') { $this->writeln('PROTOCOL_ERROR'); } if ($this->pool->config->protologging->value) { Daemon::log('Lock client --> Lock server: ' . Debug::exportBytes(implode(' ', $e)) . "\n"); } } if (strpos($this->buf, "ÿôÿý") !== FALSE || strpos($this->buf, "ÿì") !== FALSE) { $this->finish(); } }
public function onEvBufReadEvent($evBuf, $arg) { $connId = $arg[0]; Debug::netEvent(get_class($this) . '::' . __METHOD__ . '(' . $connId . ') invoked. '); $this->updateLastContact($connId); $data = ''; while (true) { $read = event_buffer_read($evBuf, $this->readPacketSize); if ($read === '' || $read === NULL || $read === false) { break; } $data .= $read; } if ($data) { Debug::netEvent(get_class($this) . '::' . __METHOD__ . '(' . $connId . ') stdin(' . Utils::convertSize(strlen($data)) . ') start... '); Debug::stdin('Server --> Get Client Data: ' . Debug::exportBytes($data)); $this->connSocketSessionPool[$connId]->stdin($data); Debug::netEvent(get_class($this) . '::' . __METHOD__ . '(' . $connId . ') stdin(' . Utils::convertSize(strlen($data)) . ') end. '); } }
/** * Called when new data received * @param string New data * @return void */ public function stdin($buf) { $this->buf .= $buf; if ($this->appInstance->config->protologging->value) { Daemon::log('Server --> Client: ' . Debug::exportBytes($buf) . "\n\n"); } start: $this->buflen = strlen($this->buf); if ($this->buflen < 5) { // Not enough data buffered yet return; } $type = binarySubstr($this->buf, 0, 1); list(, $length) = unpack('N', binarySubstr($this->buf, 1, 4)); $length -= 4; if ($this->buflen < 5 + $length) { // Not enough data buffered yet return; } $packet = binarySubstr($this->buf, 5, $length); $this->buf = binarySubstr($this->buf, 5 + $length); if ($type === 'R') { // Authentication request list(, $authType) = unpack('N', $packet); if ($authType === 0) { // Successful if ($this->appInstance->config->protologging->value) { Daemon::log(__CLASS__ . ': auth. ok.'); } $this->cstate = 4; // Auth. ok foreach ($this->onConnected as $cb) { call_user_func($cb, $this, TRUE); } } elseif ($authType === 2) { // KerberosV5 Daemon::log(__CLASS__ . ': Unsupported authentication method: KerberosV5.'); $this->cstate = 3; // Auth. error $this->finish(); // Unsupported, finish } elseif ($authType === 3) { // Cleartext $this->sendPacket('p', $this->password); // Password Message $this->cstate = 2; // Auth. packet sent } elseif ($authType === 4) { // Crypt $salt = binarySubstr($packet, 4, 2); $this->sendPacket('p', crypt($this->password, $salt)); // Password Message $this->cstate = 2; // Auth. packet sent } elseif ($authType === 5) { // MD5 $salt = binarySubstr($packet, 4, 4); $this->sendPacket('p', 'md5' . md5(md5($this->password . $this->user) . $salt)); // Password Message $this->cstate = 2; // Auth. packet sent } elseif ($authType === 6) { // SCM Daemon::log(__CLASS__ . ': Unsupported authentication method: SCM.'); $this->cstate = 3; // Auth. error $this->finish(); // Unsupported, finish } elseif ($authType == 9) { // GSS Daemon::log(__CLASS__ . ': Unsupported authentication method: GSS.'); $this->cstate = 3; // Auth. error $this->finish(); // Unsupported, finish } } elseif ($type === 'T') { // Row Description list(, $numfields) = unpack('n', binarySubstr($packet, 0, 2)); $p = 2; for ($i = 0; $i < $numfields; ++$i) { list($name) = $this->decodeNULstrings($packet, 1, $p); $field = unpack('NtableOID/nattrNo/NdataType/ndataTypeSize/NtypeMod/nformat', binarySubstr($packet, $p, 18)); $p += 18; $field['name'] = $name; $this->resultFields[] = $field; } } elseif ($type === 'D') { // Data Row list(, $numfields) = unpack('n', binarySubstr($packet, 0, 2)); $p = 2; $row = array(); for ($i = 0; $i < $numfields; ++$i) { list(, $length) = unpack('N', binarySubstr($packet, $p, 4)); $p += 4; if ($length === 4294967295.0) { // hack $length = -1; } if ($length === -1) { $value = NULL; } else { $value = binarySubstr($packet, $p, $length); $p += $length; } $row[$this->resultFields[$i]['name']] = $value; } $this->resultRows[] = $row; } elseif ($type === 'G' || $type === 'H') { // Copy in response // The backend is ready to copy data from the frontend to a table; see Section 45.2.5. if ($this->appInstance->config->protologging->value) { Daemon::log(__CLASS__ . ': Caught CopyInResponse'); } } elseif ($type === 'C') { // Close command $type = binarySubstr($packet, 0, 1); if ($type === 'S' || $type === 'P') { list($name) = $this->decodeNULstrings(binarySubstr($packet, 1)); } else { $tag = $this->decodeNULstrings($packet); $tag = explode(' ', $tag[0]); if ($tag[0] === 'INSERT') { $this->insertId = $tag[1]; $this->insertNum = $tag[2]; } elseif ($tag[0] === 'DELETE' || $tag[0] === 'UPDATE' || $tag[0] === 'MOVE' || $tag[0] === 'FETCH' || $tag[0] === 'COPY') { $this->affectedRows = $tag[1]; } } $this->onResultDone(); } elseif ($type === 'n') { // No Data $this->onResultDone(); } elseif ($type === 'E') { // Error Response $code = ord($packet); $message = ''; foreach ($this->decodeNULstrings(binarySubstr($packet, 1), 0xff) as $p) { if ($message !== '') { $message .= ' '; $p = binarySubstr($p, 1); } $message .= $p; } $this->errno = -1; $this->errmsg = $message; if ($this->cstate == 2) { // Auth. error foreach ($this->onConnected as $cb) { call_user_func($cb, $this, FALSE); } $this->cstate = 3; } $this->onError(); if ($this->appInstance->config->protologging->value) { Daemon::log(__CLASS__ . ': Error response caught (0x' . dechex($code) . '): ' . $message); } } elseif ($type === 'I') { // Empty Query Response $this->errno = -1; $this->errmsg = 'Query was empty'; $this->onError(); } elseif ($type === 'S') { // Portal Suspended if ($this->appInstance->config->protologging->value) { Daemon::log(__CLASS__ . ': Caught PortalSuspended'); } } elseif ($type === 'S') { // Parameter Status $u = $this->decodeNULstrings($packet, 2); if (isset($u[0])) { $this->parameters[$u[0]] = isset($u[1]) ? $u[1] : NULL; if ($this->appInstance->config->protologging->value) { Daemon::log(__CLASS__ . ': Parameter ' . $u[0] . ' = \'' . $this->parameters[$u[0]] . '\''); } } } elseif ($type === 'K') { // Backend Key Data list(, $this->backendKey) = unpack('N', $packet); $this->backendKey = isset($u[1]) ? $u[1] : NULL; if ($this->appInstance->config->protologging->value) { Daemon::log(__CLASS__ . ': BackendKey is ' . $this->backendKey); } } elseif ($type === 'Z') { // Ready For Query $this->status = $packet; if ($this->appInstance->config->protologging->value) { Daemon::log(__CLASS__ . ': Ready For Query. Status: ' . $this->status); } } else { Daemon::log(__CLASS__ . ': Caught message with unsupported type - ' . $type); } goto start; }
/** * Called when new data received * @param string New data * @return void */ public function stdin($buf) { $this->buf .= $buf; if ($this->appInstance->config->protologging->value) { Daemon::log('Server --> Client: ' . Debug::exportBytes($buf) . "\n\n"); } start: $this->buflen = strlen($this->buf); if (($packet = $this->getPacketHeader()) === FALSE) { return; } $this->seq = $packet[1] + 1; if ($this->cstate === 0) { if ($this->buflen < 4 + $packet[0]) { // not whole packet yet return; } $this->cstate = 1; $p = 4; $this->protover = ord(binarySubstr($this->buf, $p++, 1)); $this->serverver = ''; while ($p < $this->buflen) { $c = binarySubstr($this->buf, $p++, 1); if ($c === "") { break; } $this->serverver .= $c; } $this->threadId = $this->bytes2int(binarySubstr($this->buf, $p, 4)); $p += 4; $this->scramble = binarySubstr($this->buf, $p, 8); $p += 9; $this->serverCaps = $this->bytes2int(binarySubstr($this->buf, $p, 2)); $p += 2; $this->serverLang = ord(binarySubstr($this->buf, $p++, 1)); $this->serverStatus = $this->bytes2int(binarySubstr($this->buf, $p, 2)); $p += 2; $p += 13; $restScramble = binarySubstr($this->buf, $p, 12); $this->scramble .= $restScramble; $p += 13; $this->auth(); } else { if ($this->buflen < 4 + $packet[0]) { // not whole packet yet return; } $p = 4; $fieldCount = ord(binarySubstr($this->buf, $p, 1)); $p += 1; if ($fieldCount === 0xff) { // Error packet $u = unpack('v', binarySubstr($this->buf, $p, 2)); $p += 2; $this->errno = $u[1]; $state = binarySubstr($this->buf, $p, 6); $p = +6; $this->errmsg = binarySubstr($this->buf, $p, $packet[0] + 4 - $p); $this->onError(); } elseif ($fieldCount === 0x0) { // OK Packet Empty if ($this->cstate === 2) { $this->cstate = 4; if ($this->dbname !== '') { $this->query('USE `' . $this->dbname . '`'); } } $this->affectedRows = $this->parseEncodedBinary($this->buf, $p); $this->insertId = $this->parseEncodedBinary($this->buf, $p); $u = unpack('v', binarySubstr($this->buf, $p, 2)); $p += 2; $this->serverStatus = $u[1]; $u = unpack('v', binarySubstr($this->buf, $p, 2)); $p += 2; $this->warnCount = $u[1]; $this->message = binarySubstr($this->buf, $p, $packet[0] + 4 - $p); $this->onResultDone(); } elseif ($fieldCount === 0xfe) { // EOF Packet ++$this->instate; if ($this->instate === 3) { $this->onResultDone(); } } else { // Data packet --$p; if ($this->instate === 0) { // Result Set Header Packet $extra = $this->parseEncodedBinary($this->buf, $p); ++$this->instate; } elseif ($this->instate === 1) { // Field Packet $field = array('catalog' => $this->parseEncodedString($this->buf, $p), 'db' => $this->parseEncodedString($this->buf, $p), 'table' => $this->parseEncodedString($this->buf, $p), 'org_table' => $this->parseEncodedString($this->buf, $p), 'name' => $this->parseEncodedString($this->buf, $p), 'org_name' => $this->parseEncodedString($this->buf, $p)); ++$p; // filler $u = unpack('v', binarySubstr($this->buf, $p, 2)); $p += 2; $field['charset'] = $u[1]; $u = unpack('V', binarySubstr($this->buf, $p, 4)); $p += 4; $field['length'] = $u[1]; $field['type'] = ord(binarySubstr($this->buf, $p, 1)); ++$p; $u = unpack('v', binarySubstr($this->buf, $p, 2)); $p += 2; $field['flags'] = $u[1]; $field['decimals'] = ord(binarySubstr($this->buf, $p, 1)); ++$p; $this->resultFields[] = $field; } elseif ($this->instate === 2) { // Row Packet $row = array(); for ($i = 0, $nf = sizeof($this->resultFields); $i < $nf; ++$i) { $row[$this->resultFields[$i]['name']] = $this->parseEncodedString($this->buf, $p); } $this->resultRows[] = $row; } } } $this->buf = binarySubstr($this->buf, 4 + $packet[0]); goto start; }
public function stdin($buf) { Debug::debug(Debug::exportBytes($buf)); $this->buf .= $buf; start: if ($this->state === 0) { while (($l = $this->gets()) !== FALSE) { $e = explode(' ', rtrim($l, "\r\n")); if ($e[0] == 'VALUE') { $this->key = $e[1]; $this->valueFlags = $e[2]; $this->valueLength = $e[3]; $this->result = ''; $this->state = 1; break; } elseif ($e[0] == 'STAT') { if ($this->result === NULL) { $this->result = array(); } $this->result[$e[1]] = $e[2]; } elseif ($e[0] === 'STORED' || $e[0] === 'END' || $e[0] === 'DELETED' || $e[0] === 'ERROR' || $e[0] === 'CLIENT_ERROR' || $e[0] === 'SERVER_ERROR') { if ($e[0] !== 'END') { $this->result = FALSE; $this->error = isset($e[1]) ? $e[1] : NULL; } $cb = array_shift($this->callbacks); if ($cb) { call_user_func($cb, $this); } $this->valueSize = 0; $this->result = NULL; } } } if ($this->state === 1) { if ($this->valueSize < $this->valueLength) { $n = $this->valueLength - $this->valueSize; $buflen = strlen($this->buf); if ($buflen > $n) { $this->result .= binarySubstr($this->buf, 0, $n); $this->buf = binarySubstr($this->buf, $n); } else { $this->result .= $this->buf; $n = $buflen; $this->buf = ''; } $this->valueSize += $n; if ($this->valueSize >= $this->valueLength) { $this->state = 0; goto start; } } } }
/** * Called when new data received. * @param string New data. * @return void */ public function stdin($buf) { // from mysqld to client. if ($this->appInstance->config->protologging->value) { Daemon::log('MysqlProxy: Server --> Client: ' . Debug::exportBytes($buf) . "\n\n"); } $this->downstream->write($buf); }