/** * Accept incoming client connections * * @return boolean True if a new connection has been accepted succesfully */ public function accept() { $rConnection = null; /* Use parent :: accept to accept incoming connections */ if ($rConnection = @stream_socket_accept($this->m_rSocket, 0)) { /* Get the remote hosts host en port information and split them */ $aRemoteHost = explode(':', stream_socket_get_name($rConnection, true)); /* Check if a connection from this IP is already in the CONNECTING state */ if (array_key_exists($aRemoteHost[0], WebSocketConnection::$aInConnectingState)) { /* Queue it if so */ $this->m_aConnectionQueue[] = array('ip' => $aRemoteHost[0], 'conn' => $rConnection); $rConnection = null; } else { /* Or handle it otherwise */ WebSocketConnection::$aInConnectingState[$aRemoteHost[0]] = true; } } else { /* If no new connection are accepted, see if we can handshake with on old one */ foreach ($this->m_aConnectionQueue as $sKey => &$aConnection) { /* If the previous connection from this client is no longer CONNECTING */ if (!array_key_exists($aConnection['ip'], WebSocketConnection::$aInConnectingState)) { $rConnection = $aConnection['conn']; WebSocketConnection::$aInConnectingState[$aConnection['ip']] = true; /* Remove from queue */ unset($this->m_aConnectionQueue[$sKey]); break; } } /* Unset foreach reference */ unset($aConnection); } if ($rConnection && $rConnection !== null) { /* If the server is using TLS, enable it on the new socket */ if ($this->m_bSecure) { $bTlsStatus = @stream_socket_enable_crypto($rConnection, true, STREAM_CRYPTO_METHOD_TLS_SERVER); } /* If the TLS initializing was not succesfull, close the connection again. */ if ($this->m_bSecure && !$bTlsStatus) { fclose($rConnection); echo 'Terminated connection (TLS Failed)' . PHP_EOL; return false; } /* Take the socket and wrap it in a nice new WebSocketConnection object */ $pNewConnection = new WebSocketConnection($rConnection, $this->m_aProtocols); /* Put the socket in non-blocking mode so we can run multiple sockets in the * thread */ $pNewConnection->setBlocking(false); /* This will handle the handshake for us */ $pNewConnection->accept(); /* Call/raise the onNewConnection method/event in all observers */ $this->onNewConnection($pNewConnection); /* YEEY! succes! */ return true; } /* Nothing to report */ return null; }