Exemplo n.º 1
0
 /**
  * Runs this notification server
  *
  * This notification server receives client connections and receives and
  * relays data from connected clients.
  *
  * @return void
  */
 public function run()
 {
     $this->connect();
     while (!$this->moribund) {
         $read = $this->getReadArray();
         // Suppressing warnings for stream_select() because it will raise
         // a warning if interrupted by a signal.
         $result = @stream_select($read, $write = null, $except = null, null);
         if ($result === false || $result < 1) {
             continue;
         }
         // check for new connections
         if (in_array($this->socket->getRawSocket(), $read)) {
             try {
                 $newSocket = new Net_Notifier_Socket_Accept($this->socket, null);
             } catch (Net_Notifier_Socket_Exception $e) {
                 $this->log('Accepting client connection failed: reason: ' . $e->getMessage() . PHP_EOL, Net_Notifier_Logger::VERBOSITY_ERRORS);
             }
             $client = new Net_Notifier_WebSocket_Connection($newSocket);
             $this->clients[] = $client;
             $this->log('client connected from ' . $client->getIPAddress() . PHP_EOL, Net_Notifier_Logger::VERBOSITY_CLIENT);
         }
         // check for client data
         foreach ($this->getReadClients($read) as $client) {
             $moribund = false;
             // check if client closed connection
             $bytes = $client->getSocket()->peek(1);
             if (mb_strlen($bytes, '8bit') === 0) {
                 $this->log(sprintf('client %s closed connection.' . PHP_EOL, $client->getIPAddress()), Net_Notifier_Logger::VERBOSITY_CLIENT);
                 $moribund = true;
             }
             try {
                 if ($client->read(self::READ_BUFFER_LENGTH)) {
                     if ($client->getState() < Net_Notifier_WebSocket_Connection::STATE_CLOSING) {
                         $receivedRelayMessage = false;
                         $messages = $client->getTextMessages();
                         foreach ($messages as $message) {
                             $this->log(sprintf('received message: "%s" from %s' . PHP_EOL, $message, $client->getIPAddress()), Net_Notifier_Logger::VERBOSITY_MESSAGES);
                             $message = json_decode($message, true);
                             if ($message === false || !isset($message['action'])) {
                                 $this->log('=> incorrectly formatted' . PHP_EOL, Net_Notifier_Logger::VERBOSITY_MESSAGES);
                                 $this->startCloseClient($client, Net_Notifier_WebSocket_Connection::CLOSE_PROTOCOL_ERROR, 'Incorrectly formatted message.');
                                 break;
                             }
                             if ($message['action'] === 'shutdown') {
                                 $this->log(sprintf('shutting down at request of %s' . PHP_EOL, $client->getIPAddress()), Net_Notifier_Logger::VERBOSITY_MESSAGES);
                                 $this->startCloseClient($client, Net_Notifier_WebSocket_Connection::CLOSE_NORMAL, 'Received shutdown message.');
                                 $this->moribund = true;
                             }
                             if ($message['action'] === 'listen') {
                                 $this->log(sprintf('set %s to listen' . PHP_EOL, $client->getIPAddress()), Net_Notifier_Logger::VERBOSITY_MESSAGES);
                                 if (!in_array($client, $this->listenClients)) {
                                     $this->listenClients[] = $client;
                                 }
                             } else {
                                 $this->relayNotification($message);
                                 $receivedRelayMessage = true;
                             }
                         }
                         if ($receivedRelayMessage) {
                             $this->startCloseClient($client, Net_Notifier_WebSocket_Connection::CLOSE_NORMAL, 'Received message for relay.');
                         }
                     }
                 } else {
                     $this->log(sprintf('got a message chunk from %s' . PHP_EOL, $client->getIPAddress()), Net_Notifier_Logger::VERBOSITY_CLIENT);
                     if ($client->getState() === Net_Notifier_WebSocket_Connection::STATE_CLOSED) {
                         $this->log(sprintf('completed close handshake from %s' . PHP_EOL, $client->getIPAddress()), Net_Notifier_Logger::VERBOSITY_CLIENT);
                         $moribund = true;
                     }
                 }
             } catch (Net_Notifier_WebSocket_HandshakeFailureException $e) {
                 $this->log(sprintf('failed client handshake: %s' . PHP_EOL, $e->getMessage()), Net_Notifier_Logger::VERBOSITY_CLIENT);
             }
             if ($moribund) {
                 $this->closeClient($client);
             }
         }
     }
     $this->disconnect();
 }
Exemplo n.º 2
0
 /**
  * Disconnects this client from the server
  *
  * @return void
  */
 protected function disconnect()
 {
     // Initiate connection close. The WebSockets RFC recomends against
     // clients initiating the close handshake but we want to ensure the
     // connection is closed as soon as possible.
     $this->connection->startClose(Net_Notifier_WebSocket_Connection::CLOSE_GOING_AWAY, 'Client sent message.');
     // read server close frame
     $state = $this->connection->getState();
     $sec = intval($this->timeout / 1000);
     $usec = $this->timeout % 1000 * 1000;
     while ($state < Net_Notifier_WebSocket_Connection::STATE_CLOSED) {
         $read = array($this->socket->getRawSocket());
         $result = stream_select($read, $write = null, $except = null, $sec, $usec);
         if ($result === 1) {
             $this->connection->read(self::READ_BUFFER_LENGTH);
         } else {
             // read timed out, just close the connection
             $this->connection->close();
         }
         $state = $this->connection->getState();
     }
     $this->connection = null;
 }