From a20a91bf12d3994b458e3187aa1cdf19a8b3df69 Mon Sep 17 00:00:00 2001 From: Jan Philipp Timme Date: Sun, 28 Nov 2010 16:38:03 +0000 Subject: [PATCH] [TASK] Added the reconnect-flag that works now. --- Classes/Client/AbstractClient.php | 10 ++ Classes/Client/ClientManager.php | 17 ++++ Classes/Client/IrcClient.php | 11 ++- Classes/Connection/ConnectionHandler.php | 117 ++++++++++++++++++++++- Classes/Connection/ConnectionPool.php | 8 +- Classes/Socket/SocketHandler.php | 10 ++ Testcode/Client/ClientManagerTest.php | 1 + 7 files changed, 166 insertions(+), 8 deletions(-) diff --git a/Classes/Client/AbstractClient.php b/Classes/Client/AbstractClient.php index a38fff3..478dc62 100644 --- a/Classes/Client/AbstractClient.php +++ b/Classes/Client/AbstractClient.php @@ -61,6 +61,16 @@ abstract class Client_AbstractClient { */ abstract public function loadConfig($config); + /** + * Will reset the connectionStatus of the client. + * Implementation depends on the client. + * Should be used to reset internal variables. + * @return void + */ + public function resetConnectionStatus() { + + } + /** * @param int $id */ diff --git a/Classes/Client/ClientManager.php b/Classes/Client/ClientManager.php index 197f769..0ff4708 100644 --- a/Classes/Client/ClientManager.php +++ b/Classes/Client/ClientManager.php @@ -80,7 +80,24 @@ class Client_ClientManager { foreach($connectionHandlers["read"] AS $connectionHandler) { //handle disconnects if($connectionHandler->isConnected() === FALSE && $connectionHandler->isListening() === FALSE) { + //check whether the reconnect-flag is set + if($connectionHandler->getReconnect() === TRUE) { + //have the connectionHandler do the reconnect. + $newConnectionHandler = $connectionHandler->reconnect(); + //get the client and reset it. + $client = $this->clientPool[$connectionHandler->getID()]; + $client->resetConnectionStatus(); + //assign the client to the new connectionHandler. + $this->clientPool[$newConnectionHandler->getID()] = $client; + //get the config and assign it to the new connectionHandler, too. + $config = $this->configPool[$connectionHandler->getID()]; + $this->configPool[$newConnectionHandler->getID()] = $config; + //remove old connection + $this->removeConnection($connectionHandler); + } $this->removeClientForConnectionHandler($connectionHandler); + //reconnect or not - this connectionHandler won't do that much. + continue; } //handle accepted sockets, adopt them and treat them with care :-) if($connectionHandler->isListening() === TRUE) { diff --git a/Classes/Client/IrcClient.php b/Classes/Client/IrcClient.php index 9b06ced..8e5728c 100644 --- a/Classes/Client/IrcClient.php +++ b/Classes/Client/IrcClient.php @@ -21,6 +21,14 @@ class Client_IrcClient extends Client_AbstractClient { function __construct() { $this->nick = "Serena"; $this->channels = array(); + $this->resetConnectionStatus(); + } + + /** + * Will reset the clients internal variables concerning the connection status. + * @return void + */ + public function resetConnectionStatus() { $this->lines = 0; $this->got_001 = FALSE; $this->joined = FALSE; @@ -34,8 +42,7 @@ class Client_IrcClient extends Client_AbstractClient { */ public function processContentObject($contentObject) { $data = $contentObject->rawData; - //echo "[RECV] ".$data; - + echo "[RECV] ".$data; $this->clientManager->sendToGroup("srv", "[#".$this->ID."] ".$data."\r\n\r\n"); $return = ""; diff --git a/Classes/Connection/ConnectionHandler.php b/Classes/Connection/ConnectionHandler.php index 12cb541..9a372d5 100644 --- a/Classes/Connection/ConnectionHandler.php +++ b/Classes/Connection/ConnectionHandler.php @@ -31,6 +31,11 @@ class Connection_ConnectionHandler { */ protected $socketHandler; + /** + * @var Connection_ConnectionPool + */ + protected $connectionPool; + /** * A boolean that indicates whether this Connection is a listening server socket or a usual client socket. * @var boolean @@ -54,6 +59,26 @@ class Connection_ConnectionHandler { */ protected $protocol; + /** + * @var boolean + */ + protected $IPv6; + + /** + * @var string + */ + protected $host; + + /** + * @var int + */ + protected $port; + + /** + * @var boolean + */ + protected $reconnect_on_disconnect; + /** * Calls parent constructor. * @param $socket @@ -68,6 +93,10 @@ class Connection_ConnectionHandler { $this->group = $group; $this->protocol = $protocol; $this->is_server = FALSE; + $this->host = ""; + $this->port = 0; + $this->reconnect_on_disconnect = FALSE; + $this->IPv6 = FALSE; } /** @@ -78,6 +107,14 @@ class Connection_ConnectionHandler { unset($this->socketHandler); } + /** + * Injector for the internal ConnectionPool access. + * @param Connection_ConnectionPool $connectionPool + */ + public function injectConnectionPool($connectionPool) { + $this->connectionPool = $connectionPool; + } + /** * @return string */ @@ -107,6 +144,40 @@ class Connection_ConnectionHandler { return $this->is_server; } + /** + * Sets the IPv6-flag. + * @param boolean $IPv6 + */ + public function setIPv6($IPv6) { + $this->IPv6 = $IPv6; + } + + /** + * Sets reconnect_on_disconnect flag. + * @param boolean $reconnect + */ + public function setReconnect($reconnect) { + $this->reconnect_on_disconnect = $reconnect; + } + + /** + * Gets reconnect_on_disconnect flag. + * @return boolean + */ + public function getReconnect() { + return $this->reconnect_on_disconnect; + } + + /** + * This function is called when socket_read() or socket_write() fail. + * It creates a new ConnectionHandler that will reconnect. + * @return void + */ + protected function shutdown() { + $this->setConnected(FALSE); + $this->close(); + } + /** * Reads from SocketHandler, writes into buffer_incoming. * Returns a boolean that will indicate whether the socket is still okay. @@ -115,7 +186,11 @@ class Connection_ConnectionHandler { */ public function readToBuffer() { $data = $this->socketHandler->read(); - if($data === "") return FALSE; + //set connection status flag properly. + if($data === "") { + $this->shutdown(); + return FALSE; + } $this->buffer_incoming->addData($data); return TRUE; } @@ -129,7 +204,10 @@ class Connection_ConnectionHandler { public function writeFromBuffer() { while($this->buffer_outgoing->hasLines()) { $result = $this->socketHandler->write($this->buffer_outgoing->getNextLine()); - if($result === FALSE) return FALSE; + if($result === FALSE) { + $this->shutdown(); + return FALSE; + } } return TRUE; } @@ -219,15 +297,36 @@ class Connection_ConnectionHandler { } /** - * Calls SocketHandler + * Calls SocketHandler, stores connection data. * @see Socket_SocketHandler * @throws Exception_SocketException + * @param string $address + * @param int $port * @return void */ public function connect($address, $port) { + $this->host = $address; + $this->port = $port; return $this->socketHandler->connect($address, $port); } + /** + * Calls SocketHandler, uses stored connection data to fork a new instance of itself. + * @see Socket_SocketHandler + * @throws Exception_SocketException + * @throws Exception_GeneralException + * @return Connection_ConnectionHandler + */ + public function reconnect() { + if($this->reconnect_on_disconnect === FALSE) throw new Exception_GeneralException("Cannot reconnect: Reconnect-Flag not set!", 1290951385); + if(empty($this->host) === TRUE) throw new Exception_GeneralException("Cannot reconnect: No host specified.", 1290950818); + if(empty($this->port) === TRUE) throw new Exception_GeneralException("Cannot reconnect: No port specified.", 1290950844); + $newConnectionHandler = $this->connectionPool->createTcpConnection($this->group, $this->protocol, $this->IPv6); + $newConnectionHandler->setReconnect($this->getReconnect()); + $newConnectionHandler->connect($this->host, $this->port); + return $newConnectionHandler; + } + /** * Calls SocketHandler * @see Socket_SocketHandler @@ -235,6 +334,8 @@ class Connection_ConnectionHandler { * @return void */ public function bind($address, $port) { + $this->host = $address; + $this->port = $port; return $this->socketHandler->bind($address, $port); } @@ -257,6 +358,16 @@ class Connection_ConnectionHandler { return $this->socketHandler->isConnected(); } + /** + * Sets the is_connected-flag in the socket handler. + * @see Socket_SocketHandler + * @param boolean $connected + * @return void + */ + private function setConnected($connected) { + return $this->socketHandler->setConnected($connected); + } + /** * @see Socket_SocketHandler * @return boolean diff --git a/Classes/Connection/ConnectionPool.php b/Classes/Connection/ConnectionPool.php index 1160528..da9722a 100644 --- a/Classes/Connection/ConnectionPool.php +++ b/Classes/Connection/ConnectionPool.php @@ -50,6 +50,8 @@ class Connection_ConnectionPool { public function createTcpConnection($group = "", $protocol = "RAW", $IPv6 = FALSE) { $socket = $this->socketPool->createTcpSocket($IPv6); $connectionHandler = new Connection_ConnectionHandler($socket, $this->nextID, $group, $protocol); + $connectionHandler->setIPv6($IPv6); + $connectionHandler->injectConnectionPool($this); $this->addConnectionHandler($connectionHandler); return $connectionHandler; } @@ -117,13 +119,13 @@ class Connection_ConnectionPool { $connectionHandler = $this->getConnectionHandlerForSocketRessource($socket); switch($selectedType) { case "read": - if($connectionHandler->isServer() === FALSE) { - if($connectionHandler->readToBuffer() === FALSE) $this->removeConnectionHandler($connectionHandler); - } else { + if($connectionHandler->isServer() === TRUE) { $acceptedSocket = $connectionHandler->accept(); $acceptedSocketHandler = new Connection_ConnectionHandler($acceptedSocket, $this->nextID, $connectionHandler->getGroup(), $connectionHandler->getProtocol()); $acceptedSocketHandler->hasBeenAccepted(); $this->addConnectionHandler($acceptedSocketHandler); + } else { + $connectionHandler->readToBuffer(); } break; case "write": diff --git a/Classes/Socket/SocketHandler.php b/Classes/Socket/SocketHandler.php index 545dfe1..737503b 100644 --- a/Classes/Socket/SocketHandler.php +++ b/Classes/Socket/SocketHandler.php @@ -65,6 +65,15 @@ class Socket_SocketHandler { return $this->is_connected; } + /** + * Sets is_connected-flag. + * @param boolean $connected + * @return void + */ + public function setConnected($connected) { + $this->is_connected = $connected; + } + /** * @return boolean */ @@ -206,6 +215,7 @@ class Socket_SocketHandler { * @throws Exception_SocketException */ protected function error() { + if(is_resource($this->socket) === FALSE) throw new Exception_SocketException("No socket resource available!", 1290954177); $errno = socket_last_error($this->socket); $error = socket_strerror($errno); socket_clear_error(); diff --git a/Testcode/Client/ClientManagerTest.php b/Testcode/Client/ClientManagerTest.php index 9633785..5791e68 100644 --- a/Testcode/Client/ClientManagerTest.php +++ b/Testcode/Client/ClientManagerTest.php @@ -10,6 +10,7 @@ $clientManager->attachConfig(array( "channels" => array("#mstasty") ), $freenode); $freenode->connect("irc.freenode.net", 6667); +$freenode->setReconnect(TRUE); $freenode = $clientManager->createTcpConnection("freenode", "irc"); $clientManager->attachConfig(array(