imported ConnectionInfoFactory
[core.git] / framework / main / classes / listener / class_BaseListener.php
1 <?php
2 // Own namespace
3 namespace CoreFramework\Listener;
4
5 // Import framework stuff
6 use CoreFramework\Factory\Connection\ConnectionInfoFactory;
7 use CoreFramework\Factory\ObjectFactory;
8 use CoreFramework\Factory\Registry\Socket\SocketRegistryFactory;
9 use CoreFramework\Generic\UnsupportedOperationException;
10 use CoreFramework\Object\BaseFrameworkSystem;
11 use CoreFramework\Pool\Poolable;
12 use CoreFramework\Visitor\Visitable;
13 use CoreFramework\Visitor\Visitor;
14
15 /**
16  * A general listener class
17  *
18  * @author              Roland Haeder <webmaster@shipsimu.org>
19  * @version             0.0.0
20  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2017 Core Developer Team
21  * @license             GNU GPL 3.0 or any newer version
22  * @link                http://www.shipsimu.org
23  *
24  * This program is free software: you can redistribute it and/or modify
25  * it under the terms of the GNU General Public License as published by
26  * the Free Software Foundation, either version 3 of the License, or
27  * (at your option) any later version.
28  *
29  * This program is distributed in the hope that it will be useful,
30  * but WITHOUT ANY WARRANTY; without even the implied warranty of
31  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32  * GNU General Public License for more details.
33  *
34  * You should have received a copy of the GNU General Public License
35  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
36  */
37 class BaseListener extends BaseFrameworkSystem implements Visitable {
38         // Exception code constants
39         const EXCEPTION_INVALID_SOCKET                   = 0xa00;
40         const EXCEPTION_SOCKET_ALREADY_REGISTERED        = 0xa01;
41         const EXCEPTION_SOCKET_CREATION_FAILED           = 0xa02;
42         const EXCEPTION_NO_SOCKET_ERROR                  = 0xa03;
43         const EXCEPTION_CONNECTION_ALREADY_REGISTERED    = 0xa04;
44         const EXCEPTION_UNEXPECTED_PACKAGE_STATUS        = 0xa05;
45         const EXCEPTION_UNSUPPORTED_PACKAGE_CODE_HANDLER = 0xa06;
46         const EXCEPTION_FINAL_CHUNK_VERIFICATION         = 0xa07;
47         const EXCEPTION_INVALID_DATA_CHECKSUM            = 0xa08;
48
49         /**
50          * Address (IP mostly) we shall listen on
51          */
52         private $listenAddress = '0.0.0.0'; // This is the default and listens on all interfaces
53
54         /**
55          * Port we shall listen on (or wait for incoming data)
56          */
57         private $listenPort = 0; // This port MUST be changed by your application
58
59         /**
60          * Whether we are in blocking or non-blocking mode (default: non-blocking
61          */
62         private $blockingMode = false;
63
64         /**
65          * A peer pool instance
66          */
67         private $poolInstance = NULL;
68
69         /**
70          * Protected constructor
71          *
72          * @param       $className      Name of the class
73          * @return      void
74          */
75         protected function __construct ($className) {
76                 // Call parent constructor
77                 parent::__construct($className);
78         }
79
80         /**
81          * Checks whether the given socket resource is a server socket
82          *
83          * @param       $socketResource         A valid socket resource
84          * @return      $isServerSocket         Whether the socket resource is a server socket
85          */
86         protected function isServerSocketResource ($socketResource) {
87                 // Check it
88                 $isServerSocket = ((is_resource($socketResource)) && (!@socket_getpeername($socketResource, $peerName)));
89
90                 // We need to clear the error here if it is a resource
91                 if ($isServerSocket === true) {
92                         // Clear the error
93                         //* DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('socketResource[]=' . gettype($socketResource));
94                         socket_clear_error($socketResource);
95                 } // END - if
96
97                 // Check peer name, it must be empty
98                 $isServerSocket = (($isServerSocket) && (empty($peerName)));
99
100                 // Return result
101                 return $isServerSocket;
102         }
103
104         /**
105          * Setter for listen address
106          *
107          * @param       $listenAddress  The address this listener should listen on
108          * @return      void
109          */
110         protected final function setListenAddress ($listenAddress) {
111                 $this->listenAddress = (string) $listenAddress;
112         }
113
114         /**
115          * Getter for listen address
116          *
117          * @return      $listenAddress  The address this listener should listen on
118          */
119         public final function getListenAddress () {
120                 return $this->listenAddress;
121         }
122
123         /**
124          * Setter for listen port
125          *
126          * @param       $listenPort             The port this listener should listen on
127          * @return      void
128          */
129         protected final function setListenPort ($listenPort) {
130                 $this->listenPort = (int) $listenPort;
131         }
132
133         /**
134          * Getter for listen port
135          *
136          * @return      $listenPort             The port this listener should listen on
137          */
138         public final function getListenPort () {
139                 return $this->listenPort;
140         }
141
142         /**
143          * "Setter" to set listen address from configuration entry
144          *
145          * @param       $configEntry    The configuration entry holding our listen address
146          * @return      void
147          */
148         public final function setListenAddressByConfiguration ($configEntry) {
149                 $this->setListenAddress($this->getConfigInstance()->getConfigEntry($configEntry));
150         }
151
152         /**
153          * "Setter" to set listen port from configuration entry
154          *
155          * @param       $configEntry    The configuration entry holding our listen port
156          * @return      void
157          */
158         public final function setListenPortByConfiguration ($configEntry) {
159                 $this->setListenPort($this->getConfigInstance()->getConfigEntry($configEntry));
160         }
161
162         /**
163          * Setter for blocking-mode
164          *
165          * @param       $blockingMode   Whether blocking-mode is disabled (default) or enabled
166          * @return      void
167          */
168         protected final function setBlockingMode ($blockingMode) {
169                 $this->blockingMode = (boolean) $blockingMode;
170         }
171
172         /**
173          * Checks whether blocking-mode is enabled or disabled
174          *
175          * @return      $blockingMode   Whether blocking mode is disabled or enabled
176          */
177         public final function isBlockingModeEnabled () {
178                 return $this->blockingMode;
179         }
180
181         /**
182          * Setter for peer pool instance
183          *
184          * @param       $poolInstance   The peer pool instance we shall set
185          * @return      void
186          */
187         protected final function setPoolInstance (PoolablePeer $poolInstance) {
188                 $this->poolInstance = $poolInstance;
189         }
190
191         /**
192          * Getter for peer pool instance
193          *
194          * @return      $poolInstance   The peer pool instance we shall set
195          */
196         public final function getPoolInstance () {
197                 return $this->poolInstance;
198         }
199
200         /**
201          * Getter for connection type
202          *
203          * @return      $connectionType         Connection type for this listener
204          */
205         public final function getConnectionType () {
206                 // Wrap the real getter
207                 return $this->getProtocolName();
208         }
209
210         /**
211          * Registeres the given socket resource for "this" listener instance. This
212          * will be done in a seperate class to allow package writers to use it
213          * again.
214          *
215          * @param       $socketResource         A valid server socket resource
216          * @return      void
217          * @throws      InvalidServerSocketException            If the given resource is no server socket
218          * @throws      SocketAlreadyRegisteredException        If the given resource is already registered
219          */
220         protected function registerServerSocketResource ($socketResource) {
221                 // First check if it is valid
222                 if (!$this->isServerSocketResource($socketResource)) {
223                         // No server socket
224                         throw new InvalidServerSocketException(array($this, $socketResource), self::EXCEPTION_INVALID_SOCKET);
225                 } elseif ($this->isServerSocketRegistered($socketResource)) {
226                         // Already registered
227                         throw new SocketAlreadyRegisteredException($this, self::EXCEPTION_SOCKET_ALREADY_REGISTERED);
228                 }
229
230                 // Get a socket registry instance (singleton)
231                 $registryInstance = SocketRegistryFactory::createSocketRegistryInstance();
232
233                 // Get a connection info instance
234                 $infoInstance = ConnectionInfoFactory::createConnectionInfoInstance($this->getProtocolName(), 'listener');
235
236                 // Will the info instance with listener data
237                 $infoInstance->fillWithListenerInformation($this);
238
239                 // Register the socket
240                 $registryInstance->registerSocket($infoInstance, $socketResource);
241
242                 // And set it here
243                 $this->setSocketResource($socketResource);
244         }
245
246         /**
247          * Checks whether given socket resource is registered in socket registry
248          *
249          * @param       $socketResource         A valid server socket resource
250          * @return      $isRegistered           Whether given server socket is registered
251          */
252         protected function isServerSocketRegistered ($socketResource) {
253                 // Get a socket registry instance (singleton)
254                 $registryInstance = SocketRegistryFactory::createSocketRegistryInstance();
255
256                 // Get a connection info instance
257                 $infoInstance = ConnectionInfoFactory::createConnectionInfoInstance($this->getProtocolName(), 'listener');
258
259                 // Will the info instance with listener data
260                 $infoInstance->fillWithListenerInformation($this);
261
262                 // Check it
263                 $isRegistered = $registryInstance->isSocketRegistered($infoInstance, $socketResource);
264
265                 // Return result
266                 return $isRegistered;
267         }
268
269         /**
270          * Accepts the visitor to process the visit "request"
271          *
272          * @param       $visitorInstance        An instance of a Visitor class
273          * @return      void
274          */
275         public function accept (Visitor $visitorInstance) {
276                 // Debug message
277                 //* DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(strtoupper($this->getProtocolName()) . '-LISTENER[' . __METHOD__ . ':' . __LINE__ . ']: ' . $visitorInstance->__toString() . ' has visited ' . $this->__toString() . ' - CALLED!');
278
279                 // Visit this listener
280                 $visitorInstance->visitListener($this);
281
282                 // Visit the pool if set
283                 if ($this->getPoolInstance() instanceof Poolable) {
284                         $this->getPoolInstance()->accept($visitorInstance);
285                 } // END - if
286
287                 // Debug message
288                 //* DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(strtoupper($this->getProtocolName()) . '-LISTENER[' . __METHOD__ . ':' . __LINE__ . ']: ' . $visitorInstance->__toString() . ' has visited ' . $this->__toString() . ' - EXIT!');
289         }
290
291         /**
292          * Monitors incoming raw data from the handler and transfers it to the
293          * given receiver instance. This method should not be called, please call
294          * the decorator's version instead to separator node/client traffic.
295          *
296          * @return      void
297          * @throws      UnsupportedOperatorException    If this method is called by a mistake
298          */
299         public function monitorIncomingRawData () {
300                 throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
301         }
302
303         /**
304          * Constructs a callable method name from given socket error code. If the
305          * method is not found, a generic one is used.
306          *
307          * @param       $errorCode              Error code from socket_last_error()
308          * @return      $handlerName    Call-back method name for the error handler
309          * @throws      UnsupportedSocketErrorHandlerException If the error handler is not implemented
310          */
311         protected function getSocketErrorHandlerFromCode ($errorCode) {
312                 // Create a name from translated error code
313                 $handlerName = 'socketError' . self::convertToClassName($this->translateSocketErrorCodeToName($errorCode)) . 'Handler';
314
315                 // Is the call-back method there?
316                 if (!method_exists($this, $handlerName)) {
317                         // Please implement this
318                         throw new UnsupportedSocketErrorHandlerException(array($this, $handlerName, $errorCode), BaseConnectionHelper::EXCEPTION_UNSUPPORTED_ERROR_HANDLER);
319                 } // END - if
320
321                 // Return it
322                 return $handlerName;
323         }
324
325         /**
326          * Translates socket error codes into our own internal names which can be
327          * used for call-backs.
328          *
329          * @param       $errorCode      The error code from socket_last_error() to be translated
330          * @return      $errorName      The translated name (all lower-case, with underlines)
331          */
332         public function translateSocketErrorCodeToName ($errorCode) {
333                 // Nothing bad happened by default
334                 $errorName = BaseRawDataHandler::SOCKET_CONNECTED;
335
336                 // Is the code a number, then we have to change it
337                 switch ($errorCode) {
338                         case 0: // Silently ignored, the socket is connected
339                                 break;
340
341                         case 11:  // "Resource temporary unavailable"
342                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_RESOURCE_UNAVAILABLE;
343                                 break;
344
345                         case 13:  // "Permission denied"
346                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_PERMISSION_DENIED;
347                                 break;
348
349                         case 32:  // "Broken pipe"
350                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_BROKEN_PIPE;
351                                 break;
352
353                         case 104: // "Connection reset by peer"
354                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_CONNECTION_RESET_BY_PEER;
355                                 break;
356
357                         case 107: // "Transport end-point not connected"
358                         case 134: // On some (?) systems for 'transport end-point not connected'
359                                 // @TODO On some systems it is 134, on some 107?
360                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_TRANSPORT_ENDPOINT;
361                                 break;
362
363                         case 110: // "Connection timed out"
364                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_CONNECTION_TIMED_OUT;
365                                 break;
366
367                         case 111: // "Connection refused"
368                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_CONNECTION_REFUSED;
369                                 break;
370
371                         case 113: // "No route to host"
372                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_NO_ROUTE_TO_HOST;
373                                 break;
374
375                         case 114: // "Operation already in progress"
376                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_OPERATION_ALREADY_PROGRESS;
377                                 break;
378
379                         case 115: // "Operation now in progress"
380                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_OPERATION_IN_PROGRESS;
381                                 break;
382
383                         default: // Everything else <> 0
384                                 // Unhandled error code detected, so first debug it because we may want to handle it like the others
385                                 self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-HUB[' . __METHOD__ . ':' . __LINE__ . '] UNKNOWN ERROR CODE = ' . $errorCode . ', MESSAGE = ' . socket_strerror($errorCode));
386
387                                 // Change it only in this class
388                                 $errorName = BaseRawDataHandler::SOCKET_ERROR_UNKNOWN;
389                                 break;
390                 }
391
392                 // Return translated name
393                 return $errorName;
394         }
395
396         /**
397          * Shuts down a given socket resource. This method does only ease calling
398          * the right visitor.
399          *
400          * @param       $socketResource         A valid socket resource
401          * @return      void
402          */
403         public function shutdownSocket ($socketResource) {
404                 // Debug message
405                 self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('HUB-SYSTEM: Shutting down socket resource ' . $socketResource . ' with state ' . $this->getPrintableState() . ' ...');
406
407                 // Set socket resource
408                 $this->setSocketResource($socketResource);
409
410                 // Get a visitor instance
411                 $visitorInstance = ObjectFactory::createObjectByConfiguredName('shutdown_socket_visitor_class');
412
413                 // Debug output
414                 self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('HUB-SYSTEM:' . $this->__toString() . ': visitorInstance=' . $visitorInstance->__toString());
415
416                 // Call the visitor
417                 $this->accept($visitorInstance);
418         }
419
420         /**
421          * Half-shuts down a given socket resource. This method does only ease calling
422          * an other visitor than shutdownSocket() does.
423          *
424          * @param       $socketResource         A valid socket resource
425          * @return      void
426          */
427         public function halfShutdownSocket ($socketResource) {
428                 // Debug message
429                 self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('HUB-SYSTEM: Half-shutting down socket resource ' . $socketResource . ' with state ' . $this->getPrintableState() . ' ...');
430
431                 // Set socket resource
432                 $this->setSocketResource($socketResource);
433
434                 // Get a visitor instance
435                 $visitorInstance = ObjectFactory::createObjectByConfiguredName('half_shutdown_socket_visitor_class');
436
437                 // Debug output
438                 self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('HUB-SYSTEM:' . $this->__toString() . ': visitorInstance=' . $visitorInstance->__toString());
439
440                 // Call the visitor
441                 $this->accept($visitorInstance);
442         }
443
444         // ************************************************************************
445         //                 Socket error handler call-back methods
446         // ************************************************************************
447
448         /**
449          * Handles socket error 'permission denied', but does not clear it for
450          * later debugging purposes.
451          *
452          * @param       $socketResource         A valid socket resource
453          * @param       $socketData                     A valid socket data array (0 = IP/file name, 1 = port)
454          * @return      void
455          * @throws      SocketBindingException  The socket could not be bind to
456          */
457         protected function socketErrorPermissionDeniedHandler ($socketResource, array $socketData) {
458                 // Get socket error code for verification
459                 $socketError = socket_last_error($socketResource);
460
461                 // Get error message
462                 $errorMessage = socket_strerror($socketError);
463
464                 // Shutdown this socket
465                 $this->shutdownSocket($socketResource);
466
467                 // Throw it again
468                 throw new SocketBindingException(array($this, $socketData, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
469         }
470
471         /**
472          * "Listens" for incoming network packages
473          *
474          * @param       $peerSuffix             Suffix for peer name (e.g. :0 for TCP(/UDP?) connections)
475          * @return      void
476          * @throws      InvalidSocketException  If an invalid socket resource has been found
477          */
478         protected function doListenSocketSelect ($peerSuffix) {
479                 // Check on all instances
480                 assert($this->getPoolInstance() instanceof Poolable);
481                 assert(is_resource($this->getSocketResource()));
482
483                 // Get all readers
484                 $readers = $this->getPoolInstance()->getAllSingleSockets();
485                 $writers = array();
486                 $excepts = array();
487
488                 // Check if we have some peers left
489                 $left = socket_select(
490                         $readers,
491                         $writers,
492                         $excepts,
493                         0,
494                         150
495                 );
496
497                 // Some new peers found?
498                 if ($left < 1) {
499                         // Debug message
500                         //* EXTREME-NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('TCP-LISTENER[' . __METHOD__ . ':' . __LINE__ . ']: left=' . $left . ',serverSocket=' . $this->getSocketResource() . ',readers=' . print_r($readers, true));
501
502                         // Nothing new found
503                         return;
504                 } // END - if
505
506                 // Debug message
507                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('TCP-LISTENER[' . __METHOD__ . ':' . __LINE__ . ']: serverSocket=' . $this->getSocketResource() . ',readers=' . print_r($readers, true));
508
509                 // Do we have changed peers?
510                 if (in_array($this->getSocketResource(), $readers)) {
511                         /*
512                          * Then accept it, if this socket is set to non-blocking IO and the
513                          * connection is NOT sending any data, socket_read() may throw
514                          * error 11 (Resource temporary unavailable). This really nasty
515                          * because if you have blocking IO socket_read() will wait and wait
516                          * and wait ...
517                          */
518                         $newSocket = socket_accept($this->getSocketResource());
519
520                         // Debug message
521                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('TCP-LISTENER[' . __METHOD__ . ':' . __LINE__ . ']: newSocket=' . $newSocket . ',serverSocket=' .$this->getSocketResource());
522
523                         // Array for timeout settings
524                         $options  = array(
525                                 // Seconds
526                                 'sec'  => $this->getConfigInstance()->getConfigEntry('tcp_socket_accept_wait_sec'),
527                                 // Milliseconds
528                                 'usec' => $this->getConfigInstance()->getConfigEntry('tcp_socket_accept_wait_usec')
529                         );
530
531                         // Set timeout to configured seconds
532                         // @TODO Does this work on Windozer boxes???
533                         if (!socket_set_option($newSocket, SOL_SOCKET, SO_RCVTIMEO, $options)) {
534                                 // Handle this socket error with a faked recipientData array
535                                 $this->handleSocketError(__METHOD__, __LINE__, $newSocket, array('0.0.0.0', '0'));
536                         } // END - if
537
538                         // Output result (only for debugging!)
539                         /*
540                         $option = socket_get_option($newSocket, SOL_SOCKET, SO_RCVTIMEO);
541                         self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SO_RCVTIMEO[' . gettype($option) . ']=' . print_r($option, true));
542                         */
543
544                         // Enable SO_OOBINLINE
545                         if (!socket_set_option($newSocket, SOL_SOCKET, SO_OOBINLINE ,1)) {
546                                 // Handle this socket error with a faked recipientData array
547                                 $this->handleSocketError(__METHOD__, __LINE__, $newSocket, array('0.0.0.0', '0'));
548                         } // END - if
549
550                         // Set non-blocking
551                         if (!socket_set_nonblock($newSocket)) {
552                                 // Handle this socket error with a faked recipientData array
553                                 $this->handleSocketError(__METHOD__, __LINE__, $newSocket, array('0.0.0.0', '0'));
554                         } // END - if
555
556                         // Add it to the peers
557                         $this->getPoolInstance()->addPeer($newSocket, BaseConnectionHelper::CONNECTION_TYPE_INCOMING);
558
559                         // Get peer name
560                         if (!socket_getpeername($newSocket, $peerName)) {
561                                 // Handle this socket error with a faked recipientData array
562                                 $this->handleSocketError(__METHOD__, __LINE__, $newSocket, array('0.0.0.0', '0'));
563                         } // END - if
564
565                         // Get node instance
566                         $nodeInstance = NodeObjectFactory::createNodeInstance();
567
568                         // Create a faked package data array
569                         $packageData = array(
570                                 NetworkPackage::PACKAGE_DATA_SENDER    => $peerName . $peerSuffix,
571                                 NetworkPackage::PACKAGE_DATA_RECIPIENT => $nodeInstance->getSessionId(),
572                                 NetworkPackage::PACKAGE_DATA_STATUS    => NetworkPackage::PACKAGE_STATUS_FAKED
573                         );
574
575                         // Get a connection info instance
576                         $infoInstance = ConnectionInfoFactory::createConnectionInfoInstance($this->getProtocolName(), 'listener');
577
578                         // Will the info instance with listener data
579                         $infoInstance->fillWithListenerInformation($this);
580
581                         // Get a socket registry
582                         $registryInstance = SocketRegistryFactory::createSocketRegistryInstance();
583
584                         // Register the socket with the registry and with the faked array
585                         $registryInstance->registerSocket($infoInstance, $newSocket, $packageData);
586                 } // END - if
587
588                 // Do we have to rewind?
589                 if (!$this->getIteratorInstance()->valid()) {
590                         // Rewind the list
591                         $this->getIteratorInstance()->rewind();
592                 } // END - if
593
594                 // Get the current value
595                 $currentSocket = $this->getIteratorInstance()->current();
596
597                 // Handle it here, if not main server socket
598                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('TCP-LISTENER[' . __METHOD__ . ':' . __LINE__ . ']: currentSocket=' . $currentSocket[BasePool::SOCKET_ARRAY_RESOURCE] . ',type=' . $currentSocket[BasePool::SOCKET_ARRAY_CONN_TYPE] . ',serverSocket=' . $this->getSocketResource());
599                 if (($currentSocket[BasePool::SOCKET_ARRAY_CONN_TYPE] != BaseConnectionHelper::CONNECTION_TYPE_SERVER) && ($currentSocket[BasePool::SOCKET_ARRAY_RESOURCE] != $this->getSocketResource())) {
600                         // ... or else it will raise warnings like 'Transport endpoint is not connected'
601                         $this->getHandlerInstance()->processRawDataFromResource($currentSocket);
602                 } // END - if
603
604                 // Advance to next entry. This should be the last line.
605                 $this->getIteratorInstance()->next();
606         }
607
608 }