From 8f3646a9c93a06f76f6abb31020fdb74b4b1fc59 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Sun, 9 Apr 2023 20:50:33 +0300 Subject: exp: jaeger tracing --- .../thrift/src/Transport/TBufferedTransport.php | 206 ++++++++++++ .../packaged/thrift/src/Transport/TCurlClient.php | 281 ++++++++++++++++ .../thrift/src/Transport/TFramedTransport.php | 192 +++++++++++ .../packaged/thrift/src/Transport/THttpClient.php | 258 +++++++++++++++ .../thrift/src/Transport/TMemoryBuffer.php | 106 ++++++ .../thrift/src/Transport/TNullTransport.php | 56 ++++ .../packaged/thrift/src/Transport/TPhpStream.php | 124 +++++++ .../packaged/thrift/src/Transport/TSSLSocket.php | 117 +++++++ vendor/packaged/thrift/src/Transport/TSocket.php | 366 +++++++++++++++++++++ .../packaged/thrift/src/Transport/TSocketPool.php | 310 +++++++++++++++++ .../packaged/thrift/src/Transport/TTransport.php | 98 ++++++ 11 files changed, 2114 insertions(+) create mode 100644 vendor/packaged/thrift/src/Transport/TBufferedTransport.php create mode 100644 vendor/packaged/thrift/src/Transport/TCurlClient.php create mode 100644 vendor/packaged/thrift/src/Transport/TFramedTransport.php create mode 100644 vendor/packaged/thrift/src/Transport/THttpClient.php create mode 100644 vendor/packaged/thrift/src/Transport/TMemoryBuffer.php create mode 100644 vendor/packaged/thrift/src/Transport/TNullTransport.php create mode 100644 vendor/packaged/thrift/src/Transport/TPhpStream.php create mode 100644 vendor/packaged/thrift/src/Transport/TSSLSocket.php create mode 100644 vendor/packaged/thrift/src/Transport/TSocket.php create mode 100644 vendor/packaged/thrift/src/Transport/TSocketPool.php create mode 100644 vendor/packaged/thrift/src/Transport/TTransport.php (limited to 'vendor/packaged/thrift/src/Transport') diff --git a/vendor/packaged/thrift/src/Transport/TBufferedTransport.php b/vendor/packaged/thrift/src/Transport/TBufferedTransport.php new file mode 100644 index 000000000..253c5acfb --- /dev/null +++ b/vendor/packaged/thrift/src/Transport/TBufferedTransport.php @@ -0,0 +1,206 @@ +transport_ = $transport; + $this->rBufSize_ = $rBufSize; + $this->wBufSize_ = $wBufSize; + } + + public function isOpen() + { + return $this->transport_->isOpen(); + } + + /** + * @inheritdoc + * + * @throws TTransportException + */ + public function open() + { + $this->transport_->open(); + } + + public function close() + { + $this->transport_->close(); + } + + public function putBack($data) + { + if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) { + $this->rBuf_ = $data; + } else { + $this->rBuf_ = ($data . $this->rBuf_); + } + } + + /** + * The reason that we customize readAll here is that the majority of PHP + * streams are already internally buffered by PHP. The socket stream, for + * example, buffers internally and blocks if you call read with $len greater + * than the amount of data available, unlike recv() in C. + * + * Therefore, use the readAll method of the wrapped transport inside + * the buffered readAll. + * + * @throws TTransportException + */ + public function readAll($len) + { + $have = TStringFuncFactory::create()->strlen($this->rBuf_); + if ($have == 0) { + $data = $this->transport_->readAll($len); + } elseif ($have < $len) { + $data = $this->rBuf_; + $this->rBuf_ = ''; + $data .= $this->transport_->readAll($len - $have); + } elseif ($have == $len) { + $data = $this->rBuf_; + $this->rBuf_ = ''; + } elseif ($have > $len) { + $data = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len); + $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len); + } + + return $data; + } + + /** + * @inheritdoc + * + * @param int $len + * @return string + * @throws TTransportException + */ + public function read($len) + { + if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) { + $this->rBuf_ = $this->transport_->read($this->rBufSize_); + } + + if (TStringFuncFactory::create()->strlen($this->rBuf_) <= $len) { + $ret = $this->rBuf_; + $this->rBuf_ = ''; + + return $ret; + } + + $ret = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len); + $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len); + + return $ret; + } + + /** + * @inheritdoc + * + * @param string $buf + * @throws TTransportException + */ + public function write($buf) + { + $this->wBuf_ .= $buf; + if (TStringFuncFactory::create()->strlen($this->wBuf_) >= $this->wBufSize_) { + $out = $this->wBuf_; + + // Note that we clear the internal wBuf_ prior to the underlying write + // to ensure we're in a sane state (i.e. internal buffer cleaned) + // if the underlying write throws up an exception + $this->wBuf_ = ''; + $this->transport_->write($out); + } + } + + /** + * @inheritdoc + * + * @throws TTransportException + */ + public function flush() + { + if (TStringFuncFactory::create()->strlen($this->wBuf_) > 0) { + $out = $this->wBuf_; + + // Note that we clear the internal wBuf_ prior to the underlying write + // to ensure we're in a sane state (i.e. internal buffer cleaned) + // if the underlying write throws up an exception + $this->wBuf_ = ''; + $this->transport_->write($out); + } + $this->transport_->flush(); + } +} diff --git a/vendor/packaged/thrift/src/Transport/TCurlClient.php b/vendor/packaged/thrift/src/Transport/TCurlClient.php new file mode 100644 index 000000000..f781da969 --- /dev/null +++ b/vendor/packaged/thrift/src/Transport/TCurlClient.php @@ -0,0 +1,281 @@ +strlen($uri) > 0) && ($uri[0] != '/')) { + $uri = '/' . $uri; + } + $this->scheme_ = $scheme; + $this->host_ = $host; + $this->port_ = $port; + $this->uri_ = $uri; + $this->request_ = ''; + $this->response_ = null; + $this->timeout_ = null; + $this->headers_ = array(); + } + + /** + * Set read timeout + * + * @param float $timeout + */ + public function setTimeoutSecs($timeout) + { + $this->timeout_ = $timeout; + } + + /** + * Whether this transport is open. + * + * @return boolean true if open + */ + public function isOpen() + { + return true; + } + + /** + * Open the transport for reading/writing + * + * @throws TTransportException if cannot open + */ + public function open() + { + } + + /** + * Close the transport. + */ + public function close() + { + $this->request_ = ''; + $this->response_ = null; + } + + /** + * Read some data into the array. + * + * @param int $len How much to read + * @return string The data that has been read + * @throws TTransportException if cannot read any more data + */ + public function read($len) + { + if ($len >= strlen($this->response_)) { + return $this->response_; + } else { + $ret = substr($this->response_, 0, $len); + $this->response_ = substr($this->response_, $len); + + return $ret; + } + } + + /** + * Guarantees that the full amount of data is read. Since TCurlClient gets entire payload at + * once, parent readAll cannot be used. + * + * @return string The data, of exact length + * @throws TTransportException if cannot read data + */ + public function readAll($len) + { + $data = $this->read($len); + + if (TStringFuncFactory::create()->strlen($data) !== $len) { + throw new TTransportException('TCurlClient could not read '.$len.' bytes'); + } + + return $data; + } + + /** + * Writes some data into the pending buffer + * + * @param string $buf The data to write + * @throws TTransportException if writing fails + */ + public function write($buf) + { + $this->request_ .= $buf; + } + + /** + * Opens and sends the actual request over the HTTP connection + * + * @throws TTransportException if a writing error occurs + */ + public function flush() + { + if (!self::$curlHandle) { + register_shutdown_function(array('Thrift\\Transport\\TCurlClient', 'closeCurlHandle')); + self::$curlHandle = curl_init(); + curl_setopt(self::$curlHandle, CURLOPT_RETURNTRANSFER, true); + curl_setopt(self::$curlHandle, CURLOPT_BINARYTRANSFER, true); + curl_setopt(self::$curlHandle, CURLOPT_USERAGENT, 'PHP/TCurlClient'); + curl_setopt(self::$curlHandle, CURLOPT_CUSTOMREQUEST, 'POST'); + curl_setopt(self::$curlHandle, CURLOPT_FOLLOWLOCATION, true); + curl_setopt(self::$curlHandle, CURLOPT_MAXREDIRS, 1); + } + // God, PHP really has some esoteric ways of doing simple things. + $host = $this->host_ . ($this->port_ != 80 ? ':' . $this->port_ : ''); + $fullUrl = $this->scheme_ . "://" . $host . $this->uri_; + + $headers = array(); + $defaultHeaders = array('Accept' => 'application/x-thrift', + 'Content-Type' => 'application/x-thrift', + 'Content-Length' => TStringFuncFactory::create()->strlen($this->request_)); + foreach (array_merge($defaultHeaders, $this->headers_) as $key => $value) { + $headers[] = "$key: $value"; + } + + curl_setopt(self::$curlHandle, CURLOPT_HTTPHEADER, $headers); + + if ($this->timeout_ > 0) { + if ($this->timeout_ < 1.0) { + // Timestamps smaller than 1 second are ignored when CURLOPT_TIMEOUT is used + curl_setopt(self::$curlHandle, CURLOPT_TIMEOUT_MS, 1000 * $this->timeout_); + } else { + curl_setopt(self::$curlHandle, CURLOPT_TIMEOUT, $this->timeout_); + } + } + curl_setopt(self::$curlHandle, CURLOPT_POSTFIELDS, $this->request_); + $this->request_ = ''; + + curl_setopt(self::$curlHandle, CURLOPT_URL, $fullUrl); + $this->response_ = curl_exec(self::$curlHandle); + $responseError = curl_error(self::$curlHandle); + + $code = curl_getinfo(self::$curlHandle, CURLINFO_HTTP_CODE); + + // Handle non 200 status code / connect failure + if ($this->response_ === false || $code !== 200) { + curl_close(self::$curlHandle); + self::$curlHandle = null; + $this->response_ = null; + $error = 'TCurlClient: Could not connect to ' . $fullUrl; + if ($responseError) { + $error .= ', ' . $responseError; + } + if ($code) { + $error .= ', HTTP status code: ' . $code; + } + throw new TTransportException($error, TTransportException::UNKNOWN); + } + } + + public static function closeCurlHandle() + { + try { + if (self::$curlHandle) { + curl_close(self::$curlHandle); + self::$curlHandle = null; + } + } catch (\Exception $x) { + error_log('There was an error closing the curl handle: ' . $x->getMessage()); + } + } + + public function addHeaders($headers) + { + $this->headers_ = array_merge($this->headers_, $headers); + } +} diff --git a/vendor/packaged/thrift/src/Transport/TFramedTransport.php b/vendor/packaged/thrift/src/Transport/TFramedTransport.php new file mode 100644 index 000000000..39d186987 --- /dev/null +++ b/vendor/packaged/thrift/src/Transport/TFramedTransport.php @@ -0,0 +1,192 @@ +transport_ = $transport; + $this->read_ = $read; + $this->write_ = $write; + } + + public function isOpen() + { + return $this->transport_->isOpen(); + } + + public function open() + { + $this->transport_->open(); + } + + public function close() + { + $this->transport_->close(); + } + + /** + * Reads from the buffer. When more data is required reads another entire + * chunk and serves future reads out of that. + * + * @param int $len How much data + */ + public function read($len) + { + if (!$this->read_) { + return $this->transport_->read($len); + } + + if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) { + $this->readFrame(); + } + + // Just return full buff + if ($len >= TStringFuncFactory::create()->strlen($this->rBuf_)) { + $out = $this->rBuf_; + $this->rBuf_ = null; + + return $out; + } + + // Return TStringFuncFactory::create()->substr + $out = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len); + $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len); + + return $out; + } + + /** + * Put previously read data back into the buffer + * + * @param string $data data to return + */ + public function putBack($data) + { + if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) { + $this->rBuf_ = $data; + } else { + $this->rBuf_ = ($data . $this->rBuf_); + } + } + + /** + * Reads a chunk of data into the internal read buffer. + */ + private function readFrame() + { + $buf = $this->transport_->readAll(4); + $val = unpack('N', $buf); + $sz = $val[1]; + + $this->rBuf_ = $this->transport_->readAll($sz); + } + + /** + * Writes some data to the pending output buffer. + * + * @param string $buf The data + * @param int $len Limit of bytes to write + */ + public function write($buf, $len = null) + { + if (!$this->write_) { + return $this->transport_->write($buf, $len); + } + + if ($len !== null && $len < TStringFuncFactory::create()->strlen($buf)) { + $buf = TStringFuncFactory::create()->substr($buf, 0, $len); + } + $this->wBuf_ .= $buf; + } + + /** + * Writes the output buffer to the stream in the format of a 4-byte length + * followed by the actual data. + */ + public function flush() + { + if (!$this->write_ || TStringFuncFactory::create()->strlen($this->wBuf_) == 0) { + return $this->transport_->flush(); + } + + $out = pack('N', TStringFuncFactory::create()->strlen($this->wBuf_)); + $out .= $this->wBuf_; + + // Note that we clear the internal wBuf_ prior to the underlying write + // to ensure we're in a sane state (i.e. internal buffer cleaned) + // if the underlying write throws up an exception + $this->wBuf_ = ''; + $this->transport_->write($out); + $this->transport_->flush(); + } +} diff --git a/vendor/packaged/thrift/src/Transport/THttpClient.php b/vendor/packaged/thrift/src/Transport/THttpClient.php new file mode 100644 index 000000000..4d6be32fe --- /dev/null +++ b/vendor/packaged/thrift/src/Transport/THttpClient.php @@ -0,0 +1,258 @@ +strlen($uri) > 0) && ($uri[0] != '/')) { + $uri = '/' . $uri; + } + $this->scheme_ = $scheme; + $this->host_ = $host; + $this->port_ = $port; + $this->uri_ = $uri; + $this->buf_ = ''; + $this->handle_ = null; + $this->timeout_ = null; + $this->headers_ = array(); + $this->context_ = $context; + } + + /** + * Set read timeout + * + * @param float $timeout + */ + public function setTimeoutSecs($timeout) + { + $this->timeout_ = $timeout; + } + + /** + * Whether this transport is open. + * + * @return boolean true if open + */ + public function isOpen() + { + return true; + } + + /** + * Open the transport for reading/writing + * + * @throws TTransportException if cannot open + */ + public function open() + { + } + + /** + * Close the transport. + */ + public function close() + { + if ($this->handle_) { + @fclose($this->handle_); + $this->handle_ = null; + } + } + + /** + * Read some data into the array. + * + * @param int $len How much to read + * @return string The data that has been read + * @throws TTransportException if cannot read any more data + */ + public function read($len) + { + $data = @fread($this->handle_, $len); + if ($data === false || $data === '') { + $md = stream_get_meta_data($this->handle_); + if ($md['timed_out']) { + throw new TTransportException( + 'THttpClient: timed out reading ' . $len . ' bytes from ' . + $this->host_ . ':' . $this->port_ . $this->uri_, + TTransportException::TIMED_OUT + ); + } else { + throw new TTransportException( + 'THttpClient: Could not read ' . $len . ' bytes from ' . + $this->host_ . ':' . $this->port_ . $this->uri_, + TTransportException::UNKNOWN + ); + } + } + + return $data; + } + + /** + * Writes some data into the pending buffer + * + * @param string $buf The data to write + * @throws TTransportException if writing fails + */ + public function write($buf) + { + $this->buf_ .= $buf; + } + + /** + * Opens and sends the actual request over the HTTP connection + * + * @throws TTransportException if a writing error occurs + */ + public function flush() + { + // God, PHP really has some esoteric ways of doing simple things. + $host = $this->host_ . ($this->port_ != 80 ? ':' . $this->port_ : ''); + + $headers = array(); + $defaultHeaders = array('Host' => $host, + 'Accept' => 'application/x-thrift', + 'User-Agent' => 'PHP/THttpClient', + 'Content-Type' => 'application/x-thrift', + 'Content-Length' => TStringFuncFactory::create()->strlen($this->buf_)); + foreach (array_merge($defaultHeaders, $this->headers_) as $key => $value) { + $headers[] = "$key: $value"; + } + + $options = $this->context_; + + $baseHttpOptions = isset($options["http"]) ? $options["http"] : array(); + + $httpOptions = $baseHttpOptions + array('method' => 'POST', + 'header' => implode("\r\n", $headers), + 'max_redirects' => 1, + 'content' => $this->buf_); + if ($this->timeout_ > 0) { + $httpOptions['timeout'] = $this->timeout_; + } + $this->buf_ = ''; + + $options["http"] = $httpOptions; + $contextid = stream_context_create($options); + $this->handle_ = @fopen( + $this->scheme_ . '://' . $host . $this->uri_, + 'r', + false, + $contextid + ); + + // Connect failed? + if ($this->handle_ === false) { + $this->handle_ = null; + $error = 'THttpClient: Could not connect to ' . $host . $this->uri_; + throw new TTransportException($error, TTransportException::NOT_OPEN); + } + } + + public function addHeaders($headers) + { + $this->headers_ = array_merge($this->headers_, $headers); + } +} diff --git a/vendor/packaged/thrift/src/Transport/TMemoryBuffer.php b/vendor/packaged/thrift/src/Transport/TMemoryBuffer.php new file mode 100644 index 000000000..fee03a2a4 --- /dev/null +++ b/vendor/packaged/thrift/src/Transport/TMemoryBuffer.php @@ -0,0 +1,106 @@ +buf_ = $buf; + } + + protected $buf_ = ''; + + public function isOpen() + { + return true; + } + + public function open() + { + } + + public function close() + { + } + + public function write($buf) + { + $this->buf_ .= $buf; + } + + public function read($len) + { + $bufLength = TStringFuncFactory::create()->strlen($this->buf_); + + if ($bufLength === 0) { + throw new TTransportException( + 'TMemoryBuffer: Could not read ' . + $len . ' bytes from buffer.', + TTransportException::UNKNOWN + ); + } + + if ($bufLength <= $len) { + $ret = $this->buf_; + $this->buf_ = ''; + + return $ret; + } + + $ret = TStringFuncFactory::create()->substr($this->buf_, 0, $len); + $this->buf_ = TStringFuncFactory::create()->substr($this->buf_, $len); + + return $ret; + } + + public function getBuffer() + { + return $this->buf_; + } + + public function available() + { + return TStringFuncFactory::create()->strlen($this->buf_); + } + + public function putBack($data) + { + $this->buf_ = $data . $this->buf_; + } +} diff --git a/vendor/packaged/thrift/src/Transport/TNullTransport.php b/vendor/packaged/thrift/src/Transport/TNullTransport.php new file mode 100644 index 000000000..7e086b67c --- /dev/null +++ b/vendor/packaged/thrift/src/Transport/TNullTransport.php @@ -0,0 +1,56 @@ +read_ = $mode & self::MODE_R; + $this->write_ = $mode & self::MODE_W; + } + + public function open() + { + if ($this->read_) { + $this->inStream_ = @fopen(self::inStreamName(), 'r'); + if (!is_resource($this->inStream_)) { + throw new TException('TPhpStream: Could not open php://input'); + } + } + if ($this->write_) { + $this->outStream_ = @fopen('php://output', 'w'); + if (!is_resource($this->outStream_)) { + throw new TException('TPhpStream: Could not open php://output'); + } + } + } + + public function close() + { + if ($this->read_) { + @fclose($this->inStream_); + $this->inStream_ = null; + } + if ($this->write_) { + @fclose($this->outStream_); + $this->outStream_ = null; + } + } + + public function isOpen() + { + return + (!$this->read_ || is_resource($this->inStream_)) && + (!$this->write_ || is_resource($this->outStream_)); + } + + public function read($len) + { + $data = @fread($this->inStream_, $len); + if ($data === false || $data === '') { + throw new TException('TPhpStream: Could not read ' . $len . ' bytes'); + } + + return $data; + } + + public function write($buf) + { + while (TStringFuncFactory::create()->strlen($buf) > 0) { + $got = @fwrite($this->outStream_, $buf); + if ($got === 0 || $got === false) { + throw new TException( + 'TPhpStream: Could not write ' . TStringFuncFactory::create()->strlen($buf) . ' bytes' + ); + } + $buf = TStringFuncFactory::create()->substr($buf, $got); + } + } + + public function flush() + { + @fflush($this->outStream_); + } + + private static function inStreamName() + { + if (php_sapi_name() == 'cli') { + return 'php://stdin'; + } + + return 'php://input'; + } +} diff --git a/vendor/packaged/thrift/src/Transport/TSSLSocket.php b/vendor/packaged/thrift/src/Transport/TSSLSocket.php new file mode 100644 index 000000000..b4a0adb54 --- /dev/null +++ b/vendor/packaged/thrift/src/Transport/TSSLSocket.php @@ -0,0 +1,117 @@ +host_ = $this->getSSLHost($host); + $this->port_ = $port; + $this->context_ = $context; + $this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log'; + } + + /** + * Creates a host name with SSL transport protocol + * if no transport protocol already specified in + * the host name. + * + * @param string $host Host to listen on + * @return string $host Host name with transport protocol + */ + private function getSSLHost($host) + { + $transport_protocol_loc = strpos($host, "://"); + if ($transport_protocol_loc === false) { + $host = 'ssl://' . $host; + } + return $host; + } + + /** + * Connects the socket. + */ + public function open() + { + if ($this->isOpen()) { + throw new TTransportException('Socket already connected', TTransportException::ALREADY_OPEN); + } + + if (empty($this->host_)) { + throw new TTransportException('Cannot open null host', TTransportException::NOT_OPEN); + } + + if ($this->port_ <= 0) { + throw new TTransportException('Cannot open without port', TTransportException::NOT_OPEN); + } + + $this->handle_ = @stream_socket_client( + $this->host_ . ':' . $this->port_, + $errno, + $errstr, + $this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000), + STREAM_CLIENT_CONNECT, + $this->context_ + ); + + // Connect failed? + if ($this->handle_ === false) { + $error = 'TSocket: Could not connect to ' . + $this->host_ . ':' . $this->port_ . ' (' . $errstr . ' [' . $errno . '])'; + if ($this->debug_) { + call_user_func($this->debugHandler_, $error); + } + throw new TException($error); + } + } +} diff --git a/vendor/packaged/thrift/src/Transport/TSocket.php b/vendor/packaged/thrift/src/Transport/TSocket.php new file mode 100644 index 000000000..5147efa63 --- /dev/null +++ b/vendor/packaged/thrift/src/Transport/TSocket.php @@ -0,0 +1,366 @@ +host_ = $host; + $this->port_ = $port; + $this->persist_ = $persist; + $this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log'; + } + + /** + * @param resource $handle + * @return void + */ + public function setHandle($handle) + { + $this->handle_ = $handle; + stream_set_blocking($this->handle_, false); + } + + /** + * Sets the send timeout. + * + * @param int $timeout Timeout in milliseconds. + */ + public function setSendTimeout($timeout) + { + $this->sendTimeoutSec_ = floor($timeout / 1000); + $this->sendTimeoutUsec_ = + ($timeout - ($this->sendTimeoutSec_ * 1000)) * 1000; + } + + /** + * Sets the receive timeout. + * + * @param int $timeout Timeout in milliseconds. + */ + public function setRecvTimeout($timeout) + { + $this->recvTimeoutSec_ = floor($timeout / 1000); + $this->recvTimeoutUsec_ = + ($timeout - ($this->recvTimeoutSec_ * 1000)) * 1000; + } + + /** + * Sets debugging output on or off + * + * @param bool $debug + */ + public function setDebug($debug) + { + $this->debug_ = $debug; + } + + /** + * Get the host that this socket is connected to + * + * @return string host + */ + public function getHost() + { + return $this->host_; + } + + /** + * Get the remote port that this socket is connected to + * + * @return int port + */ + public function getPort() + { + return $this->port_; + } + + /** + * Tests whether this is open + * + * @return bool true if the socket is open + */ + public function isOpen() + { + return is_resource($this->handle_); + } + + /** + * Connects the socket. + */ + public function open() + { + if ($this->isOpen()) { + throw new TTransportException('Socket already connected', TTransportException::ALREADY_OPEN); + } + + if (empty($this->host_)) { + throw new TTransportException('Cannot open null host', TTransportException::NOT_OPEN); + } + + if ($this->port_ <= 0) { + throw new TTransportException('Cannot open without port', TTransportException::NOT_OPEN); + } + + if ($this->persist_) { + $this->handle_ = @pfsockopen( + $this->host_, + $this->port_, + $errno, + $errstr, + $this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000) + ); + } else { + $this->handle_ = @fsockopen( + $this->host_, + $this->port_, + $errno, + $errstr, + $this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000) + ); + } + + // Connect failed? + if ($this->handle_ === false) { + $error = 'TSocket: Could not connect to ' . + $this->host_ . ':' . $this->port_ . ' (' . $errstr . ' [' . $errno . '])'; + if ($this->debug_) { + call_user_func($this->debugHandler_, $error); + } + throw new TException($error); + } + + if (function_exists('socket_import_stream') && function_exists('socket_set_option')) { + $socket = socket_import_stream($this->handle_); + socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1); + } + } + + /** + * Closes the socket. + */ + public function close() + { + @fclose($this->handle_); + $this->handle_ = null; + } + + /** + * Read from the socket at most $len bytes. + * + * This method will not wait for all the requested data, it will return as + * soon as any data is received. + * + * @param int $len Maximum number of bytes to read. + * @return string Binary data + */ + public function read($len) + { + $null = null; + $read = array($this->handle_); + $readable = @stream_select( + $read, + $null, + $null, + $this->recvTimeoutSec_, + $this->recvTimeoutUsec_ + ); + + if ($readable > 0) { + $data = fread($this->handle_, $len); + if ($data === false) { + throw new TTransportException('TSocket: Could not read ' . $len . ' bytes from ' . + $this->host_ . ':' . $this->port_); + } elseif ($data == '' && feof($this->handle_)) { + throw new TTransportException('TSocket read 0 bytes'); + } + + return $data; + } elseif ($readable === 0) { + throw new TTransportException('TSocket: timed out reading ' . $len . ' bytes from ' . + $this->host_ . ':' . $this->port_); + } else { + throw new TTransportException('TSocket: Could not read ' . $len . ' bytes from ' . + $this->host_ . ':' . $this->port_); + } + } + + /** + * Write to the socket. + * + * @param string $buf The data to write + */ + public function write($buf) + { + $null = null; + $write = array($this->handle_); + + // keep writing until all the data has been written + while (TStringFuncFactory::create()->strlen($buf) > 0) { + // wait for stream to become available for writing + $writable = @stream_select( + $null, + $write, + $null, + $this->sendTimeoutSec_, + $this->sendTimeoutUsec_ + ); + if ($writable > 0) { + // write buffer to stream + $written = fwrite($this->handle_, $buf); + if ($written === -1 || $written === false) { + throw new TTransportException( + 'TSocket: Could not write ' . TStringFuncFactory::create()->strlen($buf) . ' bytes ' . + $this->host_ . ':' . $this->port_ + ); + } + // determine how much of the buffer is left to write + $buf = TStringFuncFactory::create()->substr($buf, $written); + } elseif ($writable === 0) { + throw new TTransportException( + 'TSocket: timed out writing ' . TStringFuncFactory::create()->strlen($buf) . ' bytes from ' . + $this->host_ . ':' . $this->port_ + ); + } else { + throw new TTransportException( + 'TSocket: Could not write ' . TStringFuncFactory::create()->strlen($buf) . ' bytes ' . + $this->host_ . ':' . $this->port_ + ); + } + } + } + + /** + * Flush output to the socket. + * + * Since read(), readAll() and write() operate on the sockets directly, + * this is a no-op + * + * If you wish to have flushable buffering behaviour, wrap this TSocket + * in a TBufferedTransport. + */ + public function flush() + { + // no-op + } +} diff --git a/vendor/packaged/thrift/src/Transport/TSocketPool.php b/vendor/packaged/thrift/src/Transport/TSocketPool.php new file mode 100644 index 000000000..cb9e8ddfa --- /dev/null +++ b/vendor/packaged/thrift/src/Transport/TSocketPool.php @@ -0,0 +1,310 @@ + $val) { + $ports[$key] = $port; + } + } + + foreach ($hosts as $key => $host) { + $this->servers_ [] = array('host' => $host, + 'port' => $ports[$key]); + } + } + + /** + * Add a server to the pool + * + * This function does not prevent you from adding a duplicate server entry. + * + * @param string $host hostname or IP + * @param int $port port + */ + public function addServer($host, $port) + { + $this->servers_[] = array('host' => $host, 'port' => $port); + } + + /** + * Sets how many time to keep retrying a host in the connect function. + * + * @param int $numRetries + */ + public function setNumRetries($numRetries) + { + $this->numRetries_ = $numRetries; + } + + /** + * Sets how long to wait until retrying a host if it was marked down + * + * @param int $numRetries + */ + public function setRetryInterval($retryInterval) + { + $this->retryInterval_ = $retryInterval; + } + + /** + * Sets how many time to keep retrying a host before marking it as down. + * + * @param int $numRetries + */ + public function setMaxConsecutiveFailures($maxConsecutiveFailures) + { + $this->maxConsecutiveFailures_ = $maxConsecutiveFailures; + } + + /** + * Turns randomization in connect order on or off. + * + * @param bool $randomize + */ + public function setRandomize($randomize) + { + $this->randomize_ = $randomize; + } + + /** + * Whether to always try the last server. + * + * @param bool $alwaysTryLast + */ + public function setAlwaysTryLast($alwaysTryLast) + { + $this->alwaysTryLast_ = $alwaysTryLast; + } + + /** + * Connects the socket by iterating through all the servers in the pool + * and trying to find one that works. + */ + public function open() + { + // Check if we want order randomization + if ($this->randomize_) { + shuffle($this->servers_); + } + + // Count servers to identify the "last" one + $numServers = count($this->servers_); + + for ($i = 0; $i < $numServers; ++$i) { + // This extracts the $host and $port variables + extract($this->servers_[$i]); + + // Check APC cache for a record of this server being down + $failtimeKey = 'thrift_failtime:' . $host . ':' . $port . '~'; + + // Cache miss? Assume it's OK + $lastFailtime = apc_fetch($failtimeKey); + if ($lastFailtime === false) { + $lastFailtime = 0; + } + + $retryIntervalPassed = false; + + // Cache hit...make sure enough the retry interval has elapsed + if ($lastFailtime > 0) { + $elapsed = time() - $lastFailtime; + if ($elapsed > $this->retryInterval_) { + $retryIntervalPassed = true; + if ($this->debug_) { + call_user_func( + $this->debugHandler_, + 'TSocketPool: retryInterval ' . + '(' . $this->retryInterval_ . ') ' . + 'has passed for host ' . $host . ':' . $port + ); + } + } + } + + // Only connect if not in the middle of a fail interval, OR if this + // is the LAST server we are trying, just hammer away on it + $isLastServer = false; + if ($this->alwaysTryLast_) { + $isLastServer = ($i == ($numServers - 1)); + } + + if (($lastFailtime === 0) || + ($isLastServer) || + ($lastFailtime > 0 && $retryIntervalPassed)) { + // Set underlying TSocket params to this one + $this->host_ = $host; + $this->port_ = $port; + + // Try up to numRetries_ connections per server + for ($attempt = 0; $attempt < $this->numRetries_; $attempt++) { + try { + // Use the underlying TSocket open function + parent::open(); + + // Only clear the failure counts if required to do so + if ($lastFailtime > 0) { + apc_store($failtimeKey, 0); + } + + // Successful connection, return now + return; + } catch (TException $tx) { + // Connection failed + } + } + + // Mark failure of this host in the cache + $consecfailsKey = 'thrift_consecfails:' . $host . ':' . $port . '~'; + + // Ignore cache misses + $consecfails = apc_fetch($consecfailsKey); + if ($consecfails === false) { + $consecfails = 0; + } + + // Increment by one + $consecfails++; + + // Log and cache this failure + if ($consecfails >= $this->maxConsecutiveFailures_) { + if ($this->debug_) { + call_user_func( + $this->debugHandler_, + 'TSocketPool: marking ' . $host . ':' . $port . + ' as down for ' . $this->retryInterval_ . ' secs ' . + 'after ' . $consecfails . ' failed attempts.' + ); + } + // Store the failure time + apc_store($failtimeKey, time()); + + // Clear the count of consecutive failures + apc_store($consecfailsKey, 0); + } else { + apc_store($consecfailsKey, $consecfails); + } + } + } + + // Oh no; we failed them all. The system is totally ill! + $error = 'TSocketPool: All hosts in pool are down. '; + $hosts = array(); + foreach ($this->servers_ as $server) { + $hosts [] = $server['host'] . ':' . $server['port']; + } + $hostlist = implode(',', $hosts); + $error .= '(' . $hostlist . ')'; + if ($this->debug_) { + call_user_func($this->debugHandler_, $error); + } + throw new TException($error); + } +} diff --git a/vendor/packaged/thrift/src/Transport/TTransport.php b/vendor/packaged/thrift/src/Transport/TTransport.php new file mode 100644 index 000000000..35921c666 --- /dev/null +++ b/vendor/packaged/thrift/src/Transport/TTransport.php @@ -0,0 +1,98 @@ +read($len); + + $data = ''; + $got = 0; + while (($got = TStringFuncFactory::create()->strlen($data)) < $len) { + $data .= $this->read($len - $got); + } + + return $data; + } + + /** + * Writes the given data out. + * + * @param string $buf The data to write + * @throws TTransportException if writing fails + */ + abstract public function write($buf); + + /** + * Flushes any pending data out of a buffer + * + * @throws TTransportException if a writing error occurs + */ + public function flush() + { + } +} -- cgit v1.2.3