]> git.mxchange.org Git - hub.git/blob - application/hub/classes/helper/connection/ipv4/class_BaseIpV4ConnectionHelper.php
3db9b16c97afc4ff6d8c9eaba8afd9271dc191f4
[hub.git] / application / hub / classes / helper / connection / ipv4 / class_BaseIpV4ConnectionHelper.php
1 <?php
2 /**
3  * A ??? connection helper class
4  *
5  * @author              Roland Haeder <webmaster@ship-simu.org>
6  * @version             0.0.0
7  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2015 Hub Developer Team
8  * @license             GNU GPL 3.0 or any newer version
9  * @link                http://www.ship-simu.org
10  * @todo                Find an interface for hub helper
11  *
12  * This program is free software: you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation, either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program. If not, see <http://www.gnu.org/licenses/>.
24  */
25 class BaseIpV4ConnectionHelper extends BaseConnectionHelper {
26         /**
27          * Port number used
28          */
29         private $connectionPort = 0;
30
31         /**
32          * Protected constructor
33          *
34          * @param       $className      Name of implementing class
35          * @return      void
36          */
37         protected function __construct ($className) {
38                 // Call parent constructor
39                 parent::__construct($className);
40         }
41
42         /**
43          * Getter for port number to satify HandleableProtocol
44          *
45          * @return      $connectionPort The port number
46          */
47         public final function getConnectionPort () {
48                 return $this->connectionPort;
49         }
50
51         /**
52          * Setter for port number to satify HandleableProtocol
53          *
54          * @param       $connectionPort The port number
55          * @return      void
56          */
57         protected final function setConnectionPort ($connectionPort) {
58                 $this->connectionPort = $connectionPort;
59         }
60
61         /**
62          * Initializes the current connection
63          *
64          * @return      void
65          * @throws      SocketOptionException   If setting any socket option fails
66          */
67         protected function initConnection () {
68                 // Get socket resource
69                 $socketResource = $this->getSocketResource();
70
71                 // Set the option to reuse the port
72                 if (!socket_set_option($socketResource, SOL_SOCKET, SO_REUSEADDR, 1)) {
73                         // Handle this socket error with a faked recipientData array
74                         $this->handleSocketError(__METHOD__, __LINE__, $socketResource, array('0.0.0.0', '0'));
75
76                         // And throw again
77                         // @TODO Move this to the socket error handler
78                         throw new SocketOptionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
79                 } // END - if
80
81                 /*
82                  * Set socket to non-blocking mode before trying to establish a link to
83                  * it. This is now the default behaviour for all connection helpers who
84                  * call initConnection(); .
85                  */
86                 if (!socket_set_nonblock($socketResource)) {
87                         // Handle this socket error with a faked recipientData array
88                         $helperInstance->handleSocketError(__METHOD__, __LINE__, $socketResource, array('0.0.0.0', '0'));
89
90                         // And throw again
91                         throw new SocketOptionException(array($helperInstance, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
92                 } // END - if
93
94                 // Last step: mark connection as initialized
95                 $this->setIsInitialized(TRUE);
96         }
97
98         /**
99          * Attempts to connect to a peer by given IP number and port from a valid
100          * unlData array with currently configured timeout.
101          *
102          * @param       $unlData                Valid UNL data array
103          * @return      $isConnected    Whether the connection went fine
104          * @see         Please see http://de.php.net/manual/en/function.socket-connect.php#84465 for original code
105          * @todo        Rewrite the while() loop to a iterator to not let the software stay very long here
106          */
107         protected function connectToPeerByUnlData (array $unlData) {
108                 // Only call this if the connection is initialized by initConnection()
109                 assert($this->isInitialized());
110
111                 // Is unlData complete?
112                 assert(isset($unlData[UniversalNodeLocator::UNL_PART_PROTOCOL]));
113                 assert(isset($unlData[UniversalNodeLocator::UNL_PART_ADDRESS]));
114                 assert(isset($unlData[UniversalNodeLocator::UNL_PART_PORT]));
115
116                 // Get current time
117                 $time = time();
118
119                 // "Cache" socket resource and timeout config
120                 $socketResource = $this->getSocketResource();
121                 $timeout = $this->getConfigInstance()->getConfigEntry('socket_timeout_seconds');
122
123                 // Debug output
124                 self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __METHOD__ . ':' . __LINE__ . ']: Trying to connect to ' . $unlData[UniversalNodeLocator::UNL_PART_ADDRESS] . ':' . $unlData[UniversalNodeLocator::UNL_PART_PORT] . ' with socketResource[' . gettype($socketResource) . ']=' . $socketResource . ' ...');
125
126                 // Try to connect until it is connected
127                 while ($isConnected = !@socket_connect($socketResource, $unlData[UniversalNodeLocator::UNL_PART_ADDRESS], $unlData[UniversalNodeLocator::UNL_PART_PORT])) {
128                         // Get last socket error
129                         $socketError = socket_last_error($socketResource);
130
131                         // Skip any errors which may happen on non-blocking connections
132                         if (($socketError == SOCKET_EINPROGRESS) || ($socketError == SOCKET_EALREADY)) {
133                                 // Now, is that attempt within parameters?
134                                 if ((time() - $time) >= $timeout) {
135                                         // Didn't work within timeout
136                                         $isConnected = FALSE;
137                                         break;
138                                 } // END - if
139
140                                 // Sleep about one second
141                                 $this->idle(1000);
142                         } elseif ($socketError != 0) {
143                                 // Stop on everything else pronto
144                                 $isConnected = FALSE;
145                                 break;
146                         }
147                 } // END - while
148
149                 // Is the peer connected?
150                 if ($isConnected === TRUE) {
151                         // Connection is fully established here, so change the state.
152                         PeerStateFactory::createPeerStateInstanceByName('connected', $this);
153                 } else {
154                         /*
155                          * There was a problem connecting to the peer (this state is a meta
156                          * state until the error handler has found the real cause).
157                          */
158                         PeerStateFactory::createPeerStateInstanceByName('problem', $this);
159                 }
160
161                 // Return status
162                 return $isConnected;
163         }
164
165         /**
166          * Marks this connection as shutted down
167          *
168          * @return      void
169          */
170         protected final function markConnectionShuttedDown () {
171                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __METHOD__ . ':' . __LINE__ . ']: ' . $this->__toString() . ' has been marked as shutted down');
172                 $this->shuttedDown = TRUE;
173
174                 // And remove the (now invalid) socket
175                 $this->setSocketResource(FALSE);
176         }
177
178         // ************************************************************************
179         //                 Socket error handler call-back methods
180         // ************************************************************************
181
182         /**
183          * Handles socket error 'connection timed out', but does not clear it for
184          * later debugging purposes.
185          *
186          * @param       $socketResource         A valid socket resource
187          * @param       $unlData                        A valid UNL data array
188          * @return      void
189          * @throws      SocketConnectionException       The connection attempts fails with a time-out
190          */
191         protected function socketErrorConnectionTimedOutHandler ($socketResource, array $unlData) {
192                 // Get socket error code for verification
193                 $socketError = socket_last_error($socketResource);
194
195                 // Get error message
196                 $errorMessage = socket_strerror($socketError);
197
198                 // Shutdown this socket
199                 $this->shutdownSocket($socketResource);
200
201                 // Throw it again
202                 throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
203         }
204
205         /**
206          * Handles socket error 'resource temporary unavailable', but does not
207          * clear it for later debugging purposes.
208          *
209          * @param       $socketResource         A valid socket resource
210          * @param       $unlData                        A valid UNL data array
211          * @return      void
212          * @throws      SocketConnectionException       The connection attempts fails with a time-out
213          */
214         protected function socketErrorResourceUnavailableHandler ($socketResource, array $unlData) {
215                 // Get socket error code for verification
216                 $socketError = socket_last_error($socketResource);
217
218                 // Get error message
219                 $errorMessage = socket_strerror($socketError);
220
221                 // Shutdown this socket
222                 $this->shutdownSocket($socketResource);
223
224                 // Throw it again
225                 throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
226         }
227
228         /**
229          * Handles socket error 'connection refused', but does not clear it for
230          * later debugging purposes.
231          *
232          * @param       $socketResource         A valid socket resource
233          * @param       $unlData                        A valid UNL data array
234          * @return      void
235          * @throws      SocketConnectionException       The connection attempts fails with a time-out
236          */
237         protected function socketErrorConnectionRefusedHandler ($socketResource, array $unlData) {
238                 // Get socket error code for verification
239                 $socketError = socket_last_error($socketResource);
240
241                 // Get error message
242                 $errorMessage = socket_strerror($socketError);
243
244                 // Shutdown this socket
245                 $this->shutdownSocket($socketResource);
246
247                 // Throw it again
248                 throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
249         }
250
251         /**
252          * Handles socket error 'no route to host', but does not clear it for later
253          * debugging purposes.
254          *
255          * @param       $socketResource         A valid socket resource
256          * @param       $unlData                        A valid UNL data array
257          * @return      void
258          * @throws      SocketConnectionException       The connection attempts fails with a time-out
259          */
260         protected function socketErrorNoRouteToHostHandler ($socketResource, array $unlData) {
261                 // Get socket error code for verification
262                 $socketError = socket_last_error($socketResource);
263
264                 // Get error message
265                 $errorMessage = socket_strerror($socketError);
266
267                 // Shutdown this socket
268                 $this->shutdownSocket($socketResource);
269
270                 // Throw it again
271                 throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
272         }
273
274         /**
275          * Handles socket error 'operation already in progress' which happens in
276          * method connectToPeerByUnlData() on timed out connection
277          * attempts.
278          *
279          * @param       $socketResource         A valid socket resource
280          * @param       $unlData                        A valid UNL data array
281          * @return      void
282          * @throws      SocketConnectionException       The connection attempts fails with a time-out
283          */
284         protected function socketErrorOperationAlreadyProgressHandler ($socketResource, array $unlData) {
285                 // Get socket error code for verification
286                 $socketError = socket_last_error($socketResource);
287
288                 // Get error message
289                 $errorMessage = socket_strerror($socketError);
290
291                 // Half-shutdown this socket (see there for difference to shutdownSocket())
292                 $this->halfShutdownSocket($socketResource);
293
294                 // Throw it again
295                 throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
296         }
297
298         /**
299          * Handles socket error 'connection reset by peer', but does not clear it for
300          * later debugging purposes.
301          *
302          * @param       $socketResource         A valid socket resource
303          * @param       $unlData                        A valid UNL data array
304          * @return      void
305          * @throws      SocketConnectionException       The connection attempts fails with a time-out
306          */
307         protected function socketErrorConnectionResetByPeerHandler ($socketResource, array $unlData) {
308                 // Get socket error code for verification
309                 $socketError = socket_last_error($socketResource);
310
311                 // Get error message
312                 $errorMessage = socket_strerror($socketError);
313
314                 // Shutdown this socket
315                 $this->shutdownSocket($socketResource);
316
317                 // Throw it again
318                 throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
319         }
320
321         /**
322          * Handles socket "error" 'operation now in progress' which can be safely
323          * passed on with non-blocking connections.
324          *
325          * @param       $socketResource         A valid socket resource
326          * @param       $unlData                        A valid UNL data array
327          * @return      void
328          */
329         protected function socketErrorOperationInProgressHandler ($socketResource, array $unlData) {
330                 self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __METHOD__ . ':' . __LINE__ . ']: Operation is now in progress, this is usual for non-blocking connections and is no bug.');
331         }
332 }
333
334 // [EOF]
335 ?>