/** * Called when new data received * @return void */ public function onRead() { $packet = $this->read(1024); $orig = $packet; $type = Binary::getByte($packet); $code = Binary::getByte($packet); $checksum = Binary::getStrWord($packet); $id = Binary::getWord($packet); $seq = Binary::getWord($packet); if ($checksum !== self::checksum(substr_replace($orig, "", 2, 2))) { $status = 'badChecksum'; } elseif ($type === 0x3) { $status = isset(static::$unreachableCodes[$code]) ? static::$unreachableCodes[$code] : 'unk' . $code . 'unreachable'; } else { $status = 'unknownType0x' . dechex($type); } while (!$this->onResponse->isEmpty()) { $el = $this->onResponse->shift(); if ($el instanceof CallbackWrapper) { $el = $el->unwrap(); } list($cb, $st) = $el; call_user_func($cb, microtime(true) - $st, $status); } $this->finish(); }
/** * Called when new UDP packet received. * @param string $pct * @return void */ public function onUdpPacket($pct) { $orig = $pct; $this->response = []; /*$id = */ Binary::getWord($pct); $bitmap = Binary::getBitmap(Binary::getByte($pct)) . Binary::getBitmap(Binary::getByte($pct)); //$qr = (int) $bitmap[0]; $opcode = bindec(substr($bitmap, 1, 4)); //$aa = (int) $bitmap[5]; //$tc = (int) $bitmap[6]; //$rd = (int) $bitmap[7]; //$ra = (int) $bitmap[8]; //$z = bindec(substr($bitmap, 9, 3)); //$rcode = bindec(substr($bitmap, 12)); $qdcount = Binary::getWord($pct); $ancount = Binary::getWord($pct); $nscount = Binary::getWord($pct); $arcount = Binary::getWord($pct); for ($i = 0; $i < $qdcount; ++$i) { $name = Binary::parseLabels($pct, $orig); $typeInt = Binary::getWord($pct); $type = isset(Pool::$type[$typeInt]) ? Pool::$type[$typeInt] : 'UNK(' . $typeInt . ')'; $classInt = Binary::getWord($pct); $class = isset(Pool::$class[$classInt]) ? Pool::$class[$classInt] : 'UNK(' . $classInt . ')'; if (!isset($this->response[$type])) { $this->response[$type] = []; } $record = ['name' => $name, 'type' => $type, 'class' => $class]; $this->response['query'][] = $record; } $getResRecord = function (&$pct) use($orig) { $name = Binary::parseLabels($pct, $orig); $typeInt = Binary::getWord($pct); $type = isset(Pool::$type[$typeInt]) ? Pool::$type[$typeInt] : 'UNK(' . $typeInt . ')'; $classInt = Binary::getWord($pct); $class = isset(Pool::$class[$classInt]) ? Pool::$class[$classInt] : 'UNK(' . $classInt . ')'; $ttl = Binary::getDWord($pct); $length = Binary::getWord($pct); $data = binarySubstr($pct, 0, $length); $pct = binarySubstr($pct, $length); $record = ['name' => $name, 'type' => $type, 'class' => $class, 'ttl' => $ttl]; if ($type === 'A') { if ($data === "") { $record['ip'] = false; $record['ttl'] = 5; } else { $record['ip'] = inet_ntop($data); } } elseif ($type === 'NS') { $record['ns'] = Binary::parseLabels($data); } elseif ($type === 'CNAME') { $record['cname'] = Binary::parseLabels($data, $orig); } return $record; }; for ($i = 0; $i < $ancount; ++$i) { $record = $getResRecord($pct); if (!isset($this->response[$record['type']])) { $this->response[$record['type']] = []; } $this->response[$record['type']][] = $record; } for ($i = 0; $i < $nscount; ++$i) { $record = $getResRecord($pct); if (!isset($this->response[$record['type']])) { $this->response[$record['type']] = []; } $this->response[$record['type']][] = $record; } for ($i = 0; $i < $arcount; ++$i) { $record = $getResRecord($pct); if (!isset($this->response[$record['type']])) { $this->response[$record['type']] = []; } $this->response[$record['type']][] = $record; } $this->onResponse->executeOne($this->response); if (!$this->keepalive) { $this->finish(); return; } else { $this->checkFree(); } }
/** * Called when new UDP packet received. * @param string $pct * @return void */ public function onUdpPacket($pct) { if (mb_orig_strlen($pct) < 10) { return; } $orig = $pct; $this->response = []; Binary::getWord($pct); // ID $bitmap = Binary::getBitmap(Binary::getByte($pct)) . Binary::getBitmap(Binary::getByte($pct)); //$qr = (int) $bitmap[0]; $opcode = bindec(substr($bitmap, 1, 4)); //$aa = (int) $bitmap[5]; //$tc = (int) $bitmap[6]; //$rd = (int) $bitmap[7]; //$ra = (int) $bitmap[8]; //$z = bindec(substr($bitmap, 9, 3)); $rcode = bindec(mb_orig_substr($bitmap, 12)); $this->response['status'] = ['rcode' => $rcode, 'msg' => $this->getMessageByRcode($rcode)]; $qdcount = Binary::getWord($pct); $ancount = Binary::getWord($pct); $nscount = Binary::getWord($pct); $arcount = Binary::getWord($pct); for ($i = 0; $i < $qdcount; ++$i) { $name = Binary::parseLabels($pct, $orig); $typeInt = Binary::getWord($pct); $type = isset(Pool::$type[$typeInt]) ? Pool::$type[$typeInt] : 'UNK(' . $typeInt . ')'; $classInt = Binary::getWord($pct); $class = isset(Pool::$class[$classInt]) ? Pool::$class[$classInt] : 'UNK(' . $classInt . ')'; if (!isset($this->response[$type])) { $this->response[$type] = []; } $record = ['name' => $name, 'type' => $type, 'class' => $class]; $this->response['query'][] = $record; } $getResRecord = function (&$pct) use($orig) { $name = Binary::parseLabels($pct, $orig); $typeInt = Binary::getWord($pct); $type = isset(Pool::$type[$typeInt]) ? Pool::$type[$typeInt] : 'UNK(' . $typeInt . ')'; $classInt = Binary::getWord($pct); $class = isset(Pool::$class[$classInt]) ? Pool::$class[$classInt] : 'UNK(' . $classInt . ')'; $ttl = Binary::getDWord($pct); $length = Binary::getWord($pct); $data = mb_orig_substr($pct, 0, $length); $pct = mb_orig_substr($pct, $length); $record = ['name' => $name, 'type' => $type, 'class' => $class, 'ttl' => $ttl]; if ($type === 'A' || $type === 'AAAA') { if ($data === "") { $record['ip'] = false; $record['ttl'] = 5; } else { $record['ip'] = inet_ntop($data); } } elseif ($type === 'NS') { $record['ns'] = Binary::parseLabels($data, $orig); } elseif ($type === 'CNAME') { $record['cname'] = Binary::parseLabels($data, $orig); } elseif ($type === 'SOA') { $record['mname'] = Binary::parseLabels($data, $orig); $record['rname'] = Binary::parseLabels($data, $orig); $record['serial'] = Binary::getDWord($data); $record['refresh'] = Binary::getDWord($data); $record['retry'] = Binary::getDWord($data); $record['expire'] = Binary::getDWord($data); $record['nx'] = Binary::getDWord($data); } elseif ($type === 'MX') { $record['preference'] = Binary::getWord($data); $record['exchange'] = Binary::parseLabels($data, $orig); } elseif ($type === 'TXT') { $record['text'] = ''; $lastLength = -1; while (($length = mb_orig_strlen($data)) > 0 && $length !== $lastLength) { $record['text'] .= Binary::parseLabels($data, $orig); $lastLength = $length; } } elseif ($type === 'SRV') { $record['priority'] = Binary::getWord($data); $record['weight'] = Binary::getWord($data); $record['port'] = Binary::getWord($data); $record['target'] = Binary::parseLabels($data, $orig); } return $record; }; for ($i = 0; $i < $ancount; ++$i) { $record = $getResRecord($pct); if (!isset($this->response[$record['type']])) { $this->response[$record['type']] = []; } $this->response[$record['type']][] = $record; } for ($i = 0; $i < $nscount; ++$i) { $record = $getResRecord($pct); if (!isset($this->response[$record['type']])) { $this->response[$record['type']] = []; } $this->response[$record['type']][] = $record; } for ($i = 0; $i < $arcount; ++$i) { $record = $getResRecord($pct); if (!isset($this->response[$record['type']])) { $this->response[$record['type']] = []; } $this->response[$record['type']][] = $record; } $this->onResponse->executeOne($this->response); if (!$this->keepalive) { $this->finish(); return; } else { $this->checkFree(); } }
/** * onRead * @return void */ protected function onRead() { start: if ($this->state === static::STATE_STANDBY) { if (($hdr = $this->readExact(2)) === false) { return; // not enough data } $u = unpack('S', $hdr); $this->responseCode = $u[1]; $this->state = static::STATE_PACKET_HDR; } if ($this->state === static::STATE_PACKET_HDR) { if ($this->responseCode === static::REPL_KVAL) { $this->result = []; if (($hdr = $this->readExact(9)) === false) { return; // not enough data } $this->encoding = Binary::getByte($hdr); $this->responseLength = Binary::getDword($hdr, true) - 4; $this->totalNum = Binary::getDword($hdr, true); $this->readedNum = 0; $this->state = static::STATE_PACKET_DATA; } else { if (($hdr = $this->lookExact(5)) === false) { return; // not enough data } $this->encoding = Binary::getByte($hdr); $pl = Binary::getDword($hdr, true); if ($this->getInputLength() < 5 + $pl) { return; // not enough data } $this->drain(5); $this->responseLength = $pl; if ($this->responseLength > $this->pool->maxAllowedPacket) { $this->log('max-allowed-packet (' . $this->pool->config->maxallowedpacket->getHumanValue() . ') exceed, aborting connection'); $this->finish(); return; } if ($this->responseCode === static::REPL_ERR_NOT_FOUND) { $this->drain($this->responseLength); $this->result = null; $this->isFinal = true; $this->totalNum = 0; $this->readedNum = 0; $this->executeCb(); } elseif ($this->responseCode === static::REPL_OK) { $this->drain($this->responseLength); $this->result = true; $this->isFinal = true; $this->totalNum = 0; $this->readedNum = 0; $this->executeCb(); } elseif ($this->responseCode === static::REPL_ERR_MEM || $this->responseCode === static::REPL_ERR_NAN || $this->responseCode === static::REPL_ERR_LOCKED) { $this->drain($this->responseLength); $this->result = false; $this->isFinal = true; $this->totalNum = 0; $this->readedNum = 0; $this->executeCb(); } else { if ($this->responseCode === static::REPL_KVAL && $this->totalNum <= 0) { $this->drain($this->responseLength); $this->isFinal = true; $this->totalNum = 0; $this->readedNum = 0; $this->result = []; $this->executeCb(); } else { $this->state = static::STATE_PACKET_DATA; } } } } if ($this->state === static::STATE_PACKET_DATA) { if ($this->responseCode === static::REPL_KVAL) { $keyAdded = false; nextElement: $l = $this->getInputLength(); if ($l < 9) { goto cursorCall; } if (($hdr = $this->lookExact($o = 4)) === false) { goto cursorCall; } $keyLen = Binary::getDword($hdr, true); if (($key = $this->lookExact($keyLen, $o)) === false) { goto cursorCall; } $o += $keyLen; if (($encoding = $this->lookExact(1, $o)) === false) { goto cursorCall; } $encoding = ord($encoding); ++$o; if (($hdr = $this->lookExact(4, $o)) === false) { goto cursorCall; } $o += 4; $valLen = Binary::getDword($hdr, true); if ($o + $valLen > $l) { goto cursorCall; } $this->drain($o); if ($encoding === static::GB_ENC_NUMBER) { $val = $this->read($valLen); $this->result[$key] = $valLen === 8 ? Binary::getQword($val, true) : Binary::getDword($val, true); } else { $this->result[$key] = $this->read($valLen); } $keyAdded = true; if (++$this->readedNum >= $this->totalNum) { $this->isFinal = true; $this->executeCb(); goto start; } else { goto nextElement; } cursorCall: if ($keyAdded) { $this->onResponse->executeAndKeepOne($this); } return; } else { if (($this->result = $this->readExact($this->responseLength)) === false) { $this->setWatermark($this->responseLength); return; } $this->setWatermark(2, $this->pool->maxAllowedPacket); if ($this->encoding === static::GB_ENC_NUMBER) { $this->result = $this->responseLength === 8 ? Binary::getQword($this->result, true) : Binary::getDword($this->result, true); } $this->isFinal = true; $this->totalNum = 1; $this->readedNum = 1; $this->executeCb(); } } goto start; }