3 namespace CoreFramework\Listener\Socket;
6 * A file-based socket listener
8 * @author Roland Haeder <webmaster@ship-simu.org>
10 * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2017 Core Developer Team
11 * @license GNU GPL 3.0 or any newer version
12 * @link http://www.ship-simu.org
14 * This program is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 class SocketFileListener extends BaseListener implements Listenable {
29 * Protected constructor
33 protected function __construct () {
34 // Call parent constructor
35 parent::__construct(__CLASS__);
37 // Set the protocol to file
38 $this->setProtocolName('file');
42 * Creates an instance of this class
44 * @return $listenerInstance An instance a prepared listener class
46 public final static function createSocketFileListener () {
48 $listenerInstance = new SocketFileListener();
50 // Return the prepared instance
51 return $listenerInstance;
55 * Initializes the listener by setting up the required socket server
59 public function initListener() {
61 $mainSocket = socket_create(AF_UNIX, SOCK_STREAM, 0);
63 // Is the socket resource valid?
64 if (!is_resource($mainSocket)) {
65 // Something bad happened
66 throw new InvalidSocketException(array($this, $mainSocket), BaseListener::EXCEPTION_INVALID_SOCKET);
69 // Get socket error code for verification
70 $socketError = socket_last_error($mainSocket);
72 // Check if there was an error else
73 if ($socketError > 0) {
74 // Handle this socket error with a faked recipientData array
75 $this->handleSocketError(__METHOD__, __LINE__, $mainSocket, array('null', '0'));
79 $socketFile = self::createTempPathForFile($this->getConfigInstance()->getConfigEntry('ipc_socket_file_name'));
82 self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-FILE-LISTENER[' . __METHOD__ . ':' . __LINE__ . ']: socketFile=' . $socketFile . ' ...');
84 // File name must not be empty
85 assert(!empty($socketFile));
88 if ((self::isReachableFilePath($socketFile)) && (file_exists($socketFile))) {
90 self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-FILE-LISTENER[' . __METHOD__ . ':' . __LINE__ . ']: WARNING: Old socket at ' . $socketFile . ' found. Will not start.');
92 // Shutdown this socket
93 $this->shutdownSocket($mainSocket);
100 self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-FILE-LISTENER[' . __METHOD__ . ':' . __LINE__ . ']: Binding to ' . $socketFile . ' ...');
103 if (!socket_bind($mainSocket, $socketFile)) {
105 $this->handleSocketError(__METHOD__, __LINE__, $mainSocket, array($socketFile, '0'));
107 // Get socket error code for verification
108 $socketError = socket_last_error($mainSocket);
111 $errorMessage = socket_strerror($socketError);
113 // Shutdown this socket
114 $this->shutdownSocket($mainSocket);
117 throw new InvalidSocketException(array($this, $mainSocket, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
121 // Start listen for connections
122 self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-FILE-LISTENER[' . __METHOD__ . ':' . __LINE__ . ']: Listening for connections.');
123 if (!socket_listen($mainSocket)) {
124 // Handle this socket error with a faked recipientData array
125 $this->handleSocketError(__METHOD__, __LINE__, $mainSocket, array($socketFile, '0'));
127 // Get socket error code for verification
128 $socketError = socket_last_error($mainSocket);
131 $errorMessage = socket_strerror($socketError);
133 // Shutdown this socket
134 $this->shutdownSocket($mainSocket);
137 throw new InvalidSocketException(array($this, $mainSocket, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
141 // Now, we want non-blocking mode
142 self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-FILE-LISTENER[' . __METHOD__ . ':' . __LINE__ . ']: Setting non-blocking mode.');
143 if (!socket_set_nonblock($mainSocket)) {
144 // Handle this socket error with a faked recipientData array
145 $this->handleSocketError(__METHOD__, __LINE__, $mainSocket, array($socketFile, '0'));
147 // Get socket error code for verification
148 $socketError = socket_last_error($mainSocket);
151 $errorMessage = socket_strerror($socketError);
153 // Shutdown this socket
154 $this->shutdownSocket($mainSocket);
157 throw new InvalidSocketException(array($this, $mainSocket, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
161 // Set the main socket
162 $this->registerServerSocketResource($mainSocket);
164 // Initialize the peer pool instance
165 $poolInstance = ObjectFactory::createObjectByConfiguredName('application_pool_class', array($this));
168 $poolInstance->addPeer($mainSocket, BaseConnectionHelper::CONNECTION_TYPE_SERVER);
170 // And add it to this listener
171 $this->setPoolInstance($poolInstance);
173 // Initialize iterator for listening on packages
174 $iteratorInstance = ObjectFactory::createObjectByConfiguredName('socket_listen_iterator_class', array($poolInstance->getPoolEntriesInstance()));
176 // Rewind it and remember it in this class
177 $iteratorInstance->rewind();
178 $this->setIteratorInstance($iteratorInstance);
180 // Initialize the raw data handler
181 $handlerInstance = ObjectFactory::createObjectByConfiguredName('socket_raw_data_handler_class');
183 // Set it in this class
184 $this->setHandlerInstance($handlerInstance);
187 self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-FILE-LISTENER[' . __METHOD__ . ':' . __LINE__ . ']: Socket listener now ready on socket ' . $socketFile . ' for service.');
191 * "Listens" for incoming network packages
195 public function doListen() {
197 $this->doListenSocketSelect('');
201 * Checks whether the listener would accept the given package data array
203 * @param $packageData Raw package data
204 * @return $accepts Whether this listener does accept
206 public function ifListenerAcceptsPackageData (array $packageData) {
207 $this->partialStub('Need to implement this method.');
211 * Monitors incoming raw data from the handler and transfers it to the
212 * given receiver instance.
216 public function monitorIncomingRawData () {
217 $this->partialStub('Need to implement this method.');