예제 #1
0
 public function stream(InputStreamInterface $in) : \Generator
 {
     if ($this->disconnected) {
         throw new WebSocketException('Cannot send message to disconnected web socket');
     }
     $eof = $in->eof();
     $i = 0;
     while (!$eof) {
         $chunk = (yield from $in->read(8188));
         $eof = $in->eof();
         yield from $this->sendFrame(new Frame($i++ === 0 ? Frame::BINARY : Frame::CONTINUATION, $chunk, $eof));
     }
 }
예제 #2
0
 /**
  * Read next inbound frame from the socket.
  *
  * @return Frame or false when connection has been terminated.
  */
 protected function readNextFrane() : \Generator
 {
     try {
         list($a, $b) = array_map('ord', str_split(yield from Stream::readBuffer($this->stream, 2, true), 1));
         $finished = $a & Frame::FINISHED ? true : false;
         $opcode = (int) ($a & Frame::OPCODE);
         $masked = $b & Frame::MASKED ? true : false;
         $len = (int) ($b & Frame::LENGTH);
         if ($this->masked && !$masked) {
             throw new WebSocketException('Client messages must be masked');
         }
         // Parse extended length fields:
         if ($len === 0x7e) {
             $len = unpack('n', yield from Stream::readBuffer($this->stream, 2, true))[1];
         } elseif ($len === 0x7f) {
             $lp = unpack('N2', yield from Stream::readBuffer($this->stream, 8, true));
             // 32 bit int check:
             if (PHP_INT_MAX === 0x7fffffff) {
                 if ($lp[1] !== 0 || $lp[2] < 0) {
                     throw new WebSocketException('Max payload size exceeded');
                 }
                 $len = $lp[2];
             } else {
                 $len = $lp[1] << 32 | $lp[2];
                 if ($len < 0) {
                     throw new WebSocketException('Cannot use most significant bit in 64 bit length field');
                 }
             }
         }
         if ($len < 0) {
             throw new WebSocketException('Payload length must not be negative');
         }
         // Read and unmask data in chunks:
         if ($this->masked) {
             $key = str_split(yield from Stream::readBuffer($this->stream, 4, true), 1);
         }
         $data = '';
         $read = 0;
         $i = 0;
         while ($read < $len && !$this->stream->eof()) {
             $data .= (yield from $this->stream->read($len - $read));
             if ($this->masked) {
                 for ($read = \strlen($data); $i < $read; $i++) {
                     $data[$i] = $data[$i] ^ $key[$i % 4];
                 }
             } else {
                 $read = \strlen($data);
             }
         }
         if (\strlen($data) !== $len) {
             throw new WebSocketException(sprintf('Expected %u bytes, received %u bytes', $len, \strlen($data)));
         }
         return new Frame($opcode, $data, $finished);
     } catch (StreamException $e) {
         if ($this->stream->eof()) {
             return false;
         }
         throw $e;
     } catch (WebSocketException $e) {
         if ($this->stream->eof()) {
             return false;
         }
         throw $e;
     }
 }
예제 #3
0
 protected function broadcastBinary(InputStreamInterface $in, Client $sender = NULL, bool $excludeSender = true) : \Generator
 {
     // Copy clients array to avoid sending partial messages to clients that connect during broadcast.
     $clients = $this->clients;
     $eof = $in->eof();
     $i = 0;
     while (!$eof) {
         $chunk = (yield from $in->read(8188));
         $eof = $in->eof();
         yield from $this->broadcastFrame(new Frame($i++ === 0 ? Frame::BINARY : Frame::CONTINUATION, $chunk, $eof), $clients, $sender, $excludeSender);
     }
 }