public function isAdmin(WebSocketConnection $con) { return $this->getAdminKey() === $con->getAdminKey(); }
/** * This function will read a full WebSocketFrame from the connection * that was passed as the first parameter. Keep calling this function * untill the frame has been read completely because a frame might * need to be read in parts from the socket. * * @param WebSocketConnection $pConnection The WebSocketConnection from which to read the frame */ public function read(WebSocketConnection $pConnection) { /* If we haven't read the first 2 bytes and the read-buffer is smaller * then 2 bytes, wait for the next round and hope the bytes will be * available then. */ if (!$this->m_bFirstBytesRead && $pConnection->getReadBufferSize() < 2) { return true; } /* At this point we are sure there are at least 2 bytes in the read-buffer, * so we can start by reading the first 2 if we haven't already done that. * I'll refer to these two bytes as header*/ if (!$this->m_bFirstBytesRead) { /* Read the two bytes */ $nData = $pConnection->read(2); $this->m_bFirstBytesRead = true; /* Extract the values from the bytes using bit-wise operations. * Point 4.2 of the protocol goes more into details as to how * WebSocket Frames are formed */ $this->m_bFinal = (0x80 & $nData[0]) == 0x80 ? true : false; $this->m_nRsv = (0x70 & $nData[0]) >> 4; $this->m_nType = 0xf & $nData[0]; $this->m_bMasked = (0x80 & $nData[1]) == 0x80 ? true : false; $this->m_nPayLoadLength = 0x7f & $nData[1]; } /* If the payloadlength in the header is 126, the actual payload length * is in the next two bytes. So read those. If the value in the header * is 127, the actual payloadlength is in the next 8 bytes. */ if (!$this->m_bLengthRead && $this->m_nPayLoadLength == 126) { if ($pConnection->getReadBufferSize() >= 2) { $this->m_nPayLoadLength = $this->repack($pConnection->read(2)); $this->m_bLengthRead = true; } } elseif (!$this->m_bLengthRead && $this->m_nPayLoadLength == 127) { if ($pConnection->getReadBufferSize() >= 8) { $this->m_nPayLoadLength = $this->repack($pConnection->read(8)); $this->m_bLengthRead = true; } } else { /* Or the payloadlength in the header was the actual payloadlength */ $this->m_bLengthRead = true; } /* If the payloadlength is larger then WebSocketFrame :: m_nMaxLengthIn we can't process it properly */ if ($this->m_nPayLoadLength > static::$m_nMaxLengthIn) { return false; } /* The header contains a masking-bit. When this bit is set, the next 4 bytes are a * masking key that is used to mask the payloaddata using XOR encryption. */ if (!$this->m_bMaskingKeyRead && $this->m_bMasked && count($this->m_aMaskingKey) == 0) { if ($pConnection->getReadBufferSize() >= 4) { $this->m_aMaskingKey = $pConnection->read(4); $this->m_bMaskingKeyRead = true; } } /* If there is enough data in the read-buffer, read the data. */ if ($pConnection->getReadBufferSize() >= $this->m_nPayLoadLength) { $this->m_aData = $pConnection->read($this->m_nPayLoadLength); /* If the masking bit is set, unmask the data using the masking-key we * read from the stream earlier. */ if ($this->m_bMasked) { $this->unMask(); } /* At this point the frame has been read completely */ $this->m_bIsComplete = true; } else { /* The frame is not complete yet */ $this->m_bIsComplete = false; } /* Nothing went wrong! YEEY! */ return true; }
public function __construct(WebSocketSocket $socket, array $headers, $clientHandshake) { $this->_clientHandshake = $clientHandshake; parent::__construct($socket, $headers); }
/** * 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; }