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