THRIFT-778. php: PHP socket listening server
This patch which adds TServerTransport/TServerSocket, along with a generic TServer and TSimpleServer implementation.
Patch: Nick Jones
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@984864 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/php/src/protocol/TProtocol.php b/lib/php/src/protocol/TProtocol.php
index be47100..ac1facd 100644
--- a/lib/php/src/protocol/TProtocol.php
+++ b/lib/php/src/protocol/TProtocol.php
@@ -368,7 +368,7 @@
/**
* Build a protocol from the base transport
*
- * @return TProtcol protocol
+ * @return TProtocol protocol
*/
public function getProtocol($trans);
}
diff --git a/lib/php/src/server/TServer.php b/lib/php/src/server/TServer.php
new file mode 100644
index 0000000..b25a9ee
--- /dev/null
+++ b/lib/php/src/server/TServer.php
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * Generic class for a Thrift server.
+ *
+ * @package thrift.server
+ */
+abstract class TServer {
+
+ /**
+ * Processor to handle new clients
+ *
+ * @var TProcessor
+ */
+ protected $processor_;
+
+ /**
+ * Server transport to be used for listening
+ * and accepting new clients
+ *
+ * @var TServerTransport
+ */
+ protected $transport_;
+
+ /**
+ * Input transport factory
+ *
+ * @var TTransportFactory
+ */
+ protected $inputTransportFactory_;
+
+ /**
+ * Output transport factory
+ *
+ * @var TTransportFactory
+ */
+ protected $outputTransportFactory_;
+
+ /**
+ * Input protocol factory
+ *
+ * @var TProtocolFactory
+ */
+ protected $inputProtocolFactory_;
+
+ /**
+ * Output protocol factory
+ *
+ * @var TProtocolFactory
+ */
+ protected $outputProtocolFactory_;
+
+ /**
+ * Sets up all the factories, etc
+ *
+ * @param object $processor
+ * @param TServerTransport $transport
+ * @param TTransportFactory $inputTransportFactory
+ * @param TTransportFactory $outputTransportFactory
+ * @param TProtocolFactory $inputProtocolFactory
+ * @param TProtocolFactory $outputProtocolFactory
+ * @return void
+ */
+ public function __construct($processor,
+ TServerTransport $transport,
+ TTransportFactory $inputTransportFactory,
+ TTransportFactory $outputTransportFactory,
+ TProtocolFactory $inputProtocolFactory,
+ TProtocolFactory $outputProtocolFactory) {
+ $this->processor_ = $processor;
+ $this->transport_ = $transport;
+ $this->inputTransportFactory_ = $inputTransportFactory;
+ $this->outputTransportFactory_ = $outputTransportFactory;
+ $this->inputProtocolFactory_ = $inputProtocolFactory;
+ $this->outputProtocolFactory_ = $outputProtocolFactory;
+ }
+
+ /**
+ * Serves the server. This should never return
+ * unless a problem permits it to do so or it
+ * is interrupted intentionally
+ *
+ * @abstract
+ * @return void
+ */
+ abstract public function serve();
+
+ /**
+ * Stops the server serving
+ *
+ * @abstract
+ * @return void
+ */
+ abstract public function stop();
+}
diff --git a/lib/php/src/server/TSimpleServer.php b/lib/php/src/server/TSimpleServer.php
new file mode 100644
index 0000000..f7d0a32
--- /dev/null
+++ b/lib/php/src/server/TSimpleServer.php
@@ -0,0 +1,54 @@
+<?php
+
+include_once $GLOBALS['THRIFT_ROOT'].'/server/TServer.php';
+
+/**
+ * Simple implemtation of a Thrift server.
+ *
+ * @package thrift.server
+ */
+class TSimpleServer extends TServer {
+ /**
+ * Flag for the main serving loop
+ *
+ * @var bool
+ */
+ private $stop_ = false;
+
+ /**
+ * Listens for new client using the supplied
+ * transport. It handles TTransportExceptions
+ * to avoid timeouts etc killing it
+ *
+ * @return void
+ */
+ public function serve() {
+ $this->transport_->listen();
+
+ while (!$this->stop_) {
+ try {
+ $transport = $this->transport_->accept();
+
+ if ($transport != null) {
+ $inputTransport = $this->inputTransportFactory_->getTransport($transport);
+ $outputTransport = $this->outputTransportFactory_->getTransport($transport);
+ $inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport);
+ $outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport);
+ while ($this->processor_->process($inputProtocol, $outputProtocol)) { }
+ }
+ }
+ catch (TTransportException $e) { }
+ }
+ }
+
+ /**
+ * Stops the server running. Kills the transport
+ * and then stops the main serving loop
+ *
+ * @return void
+ */
+ public function stop() {
+ $this->transport_->close();
+ $this->stop_ = true;
+ }
+}
diff --git a/lib/php/src/transport/TServerSocket.php b/lib/php/src/transport/TServerSocket.php
new file mode 100644
index 0000000..cac12ab
--- /dev/null
+++ b/lib/php/src/transport/TServerSocket.php
@@ -0,0 +1,96 @@
+<?php
+
+include_once $GLOBALS['THRIFT_ROOT'].'/transport/TServerTransport.php';
+include_once $GLOBALS['THRIFT_ROOT'].'/transport/TSocket.php';
+
+/**
+ * Socket implementation of a server agent.
+ *
+ * @package thrift.transport
+ */
+class TServerSocket extends TServerTransport {
+
+ /**
+ * Handle for the listener socket
+ *
+ * @var resource
+ */
+ private $listener_;
+
+ /**
+ * Port for the listener to listen on
+ *
+ * @var int
+ */
+ private $port_;
+
+ /**
+ * Timeout when listening for a new client
+ *
+ * @var int
+ */
+ private $acceptTimeout_ = 30000;
+
+ /**
+ * Host to listen on
+ *
+ * @var string
+ */
+ private $host_;
+
+ /**
+ * ServerSocket constructor
+ *
+ * @param string $host Host to listen on
+ * @param int $port Port to listen on
+ * @return void
+ */
+ public function __construct($host = 'localhost', $port = 9090) {
+ $this->host_ = $host;
+ $this->port_ = $port;
+ }
+
+ /**
+ * Sets the accept timeout
+ *
+ * @param int $acceptTimeout
+ * @return void
+ */
+ public function setAcceptTimeout($acceptTimeout) {
+ $this->acceptTimeout_ = $acceptTimeout;
+ }
+
+ /**
+ * Opens a new socket server handle
+ *
+ * @return void
+ */
+ public function listen() {
+ $this->listener_ = stream_socket_server('tcp://' . $this->host_ . ':' . $this->port_);
+ }
+
+ /**
+ * Closes the socket server handle
+ *
+ * @return void
+ */
+ public function close() {
+ @fclose($this->listener_);
+ $this->listener_ = null;
+ }
+
+ /**
+ * Implementation of accept. If not client is accepted in the given time
+ *
+ * @return TSocket
+ */
+ protected function acceptImpl() {
+ $handle = @stream_socket_accept($this->listener_, $this->acceptTimeout_ / 1000.0);
+ if(!$handle) return null;
+
+ $socket = new TSocket();
+ $socket->setHandle($handle);
+
+ return $socket;
+ }
+}
diff --git a/lib/php/src/transport/TServerTransport.php b/lib/php/src/transport/TServerTransport.php
new file mode 100644
index 0000000..e92ca77
--- /dev/null
+++ b/lib/php/src/transport/TServerTransport.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * Generic class for Server agent.
+ *
+ * @package thrift.transport
+ */
+abstract class TServerTransport {
+ /**
+ * List for new clients
+ *
+ * @abstract
+ * @return void
+ */
+ abstract public function listen();
+
+ /**
+ * Close the server
+ *
+ * @abstract
+ * @return void
+ */
+ abstract public function close();
+
+ /**
+ * Subclasses should use this to implement
+ * accept.
+ *
+ * @abstract
+ * @return TTransport
+ */
+ protected abstract function acceptImpl();
+
+ /**
+ * Uses the accept implemtation. If null is returned, an
+ * exception is thrown.
+ *
+ * @throws TTransportException
+ * @return TTransport
+ */
+ public function accept() {
+ $transport = $this->acceptImpl();
+
+ if ($transport == null) {
+ throw new TTransportException("accept() may not return NULL");
+ }
+
+ return $transport;
+ }
+}
diff --git a/lib/php/src/transport/TSocket.php b/lib/php/src/transport/TSocket.php
index a3000f7..bbe1987 100644
--- a/lib/php/src/transport/TSocket.php
+++ b/lib/php/src/transport/TSocket.php
@@ -110,6 +110,14 @@
}
/**
+ * @param resource $handle
+ * @return void
+ */
+ public function setHandle($handle) {
+ $this->handle_ = $handle;
+ }
+
+ /**
* Sets the send timeout.
*
* @param int $timeout Timeout in milliseconds.
@@ -167,6 +175,17 @@
* 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_,
@@ -225,16 +244,16 @@
if ($buf === FALSE || $buf === '') {
$md = stream_get_meta_data($this->handle_);
if ($md['timed_out']) {
- throw new TException('TSocket: timed out reading '.$len.' bytes from '.
+ throw new TTransportException('TSocket: timed out reading '.$len.' bytes from '.
$this->host_.':'.$this->port_);
} else {
- throw new TException('TSocket: Could not read '.$len.' bytes from '.
+ throw new TTransportException('TSocket: Could not read '.$len.' bytes from '.
$this->host_.':'.$this->port_);
}
} else if (($sz = strlen($buf)) < $len) {
$md = stream_get_meta_data($this->handle_);
if ($md['timed_out']) {
- throw new TException('TSocket: timed out reading '.$len.' bytes from '.
+ throw new TTransportException('TSocket: timed out reading '.$len.' bytes from '.
$this->host_.':'.$this->port_);
} else {
$pre .= $buf;
@@ -261,10 +280,10 @@
if ($data === FALSE || $data === '') {
$md = stream_get_meta_data($this->handle_);
if ($md['timed_out']) {
- throw new TException('TSocket: timed out reading '.$len.' bytes from '.
+ throw new TTransportException('TSocket: timed out reading '.$len.' bytes from '.
$this->host_.':'.$this->port_);
} else {
- throw new TException('TSocket: Could not read '.$len.' bytes from '.
+ throw new TTransportException('TSocket: Could not read '.$len.' bytes from '.
$this->host_.':'.$this->port_);
}
}
@@ -286,10 +305,10 @@
if ($got === 0 || $got === FALSE) {
$md = stream_get_meta_data($this->handle_);
if ($md['timed_out']) {
- throw new TException('TSocket: timed out writing '.strlen($buf).' bytes from '.
+ throw new TTransportException('TSocket: timed out writing '.strlen($buf).' bytes from '.
$this->host_.':'.$this->port_);
} else {
- throw new TException('TSocket: Could not write '.strlen($buf).' bytes '.
+ throw new TTransportException('TSocket: Could not write '.strlen($buf).' bytes '.
$this->host_.':'.$this->port_);
}
}
diff --git a/lib/php/src/transport/TTransportFactory.php b/lib/php/src/transport/TTransportFactory.php
new file mode 100644
index 0000000..ac0a65a
--- /dev/null
+++ b/lib/php/src/transport/TTransportFactory.php
@@ -0,0 +1,12 @@
+<?php
+
+class TTransportFactory {
+ /**
+ * @static
+ * @param TTransport $transport
+ * @return TTransport
+ */
+ public static function getTransport(TTransport $transport) {
+ return $transport;
+ }
+}