Socket Buffering
Server now buffers incoming messages until it (thinks it) receives the full message. Slight tweak of HyBi-10: spacing, FIN indicator, continuation frame recognition Sockets close() if container is destroyed
This commit is contained in:
		
							parent
							
								
									bf0787b7cd
								
							
						
					
					
						commit
						ad258e6eaa
					
				@ -41,8 +41,10 @@ class HyBi10 implements VersionInterface {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // estimate frame type:
 | 
					        // estimate frame type:
 | 
				
			||||||
        $firstByteBinary  = sprintf('%08b', ord($data[0]));
 | 
					        $firstByteBinary  = sprintf('%08b', ord($data[0]));
 | 
				
			||||||
		$secondByteBinary = sprintf('%08b', ord($data[1]));
 | 
					        $finIndicator     = bindec(substr($firstByteBinary, 0, 1));
 | 
				
			||||||
        $opcode           = bindec(substr($firstByteBinary, 4, 4));
 | 
					        $opcode           = bindec(substr($firstByteBinary, 4, 4));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $secondByteBinary = sprintf('%08b', ord($data[1]));
 | 
				
			||||||
        $isMasked         = ($secondByteBinary[0] == '1') ? true : false;
 | 
					        $isMasked         = ($secondByteBinary[0] == '1') ? true : false;
 | 
				
			||||||
        $payloadLength    = ord($data[1]) & 127;
 | 
					        $payloadLength    = ord($data[1]) & 127;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -52,11 +54,21 @@ class HyBi10 implements VersionInterface {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        switch($opcode) {
 | 
					        switch($opcode) {
 | 
				
			||||||
 | 
					            // continuation frame
 | 
				
			||||||
 | 
					            case 0:
 | 
				
			||||||
 | 
					                $decodedData['type'] = 'text'; // incomplete
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // text frame:
 | 
					            // text frame:
 | 
				
			||||||
            case 1:
 | 
					            case 1:
 | 
				
			||||||
                $decodedData['type'] = 'text';  
 | 
					                $decodedData['type'] = 'text';  
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // binary data frame
 | 
				
			||||||
 | 
					            case 2:
 | 
				
			||||||
 | 
					                $decodedData['type'] = 'binary';
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // connection close frame:
 | 
					            // connection close frame:
 | 
				
			||||||
            case 8:
 | 
					            case 8:
 | 
				
			||||||
                $decodedData['type'] = 'close';
 | 
					                $decodedData['type'] = 'close';
 | 
				
			||||||
@ -91,7 +103,7 @@ class HyBi10 implements VersionInterface {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        $dataLength = strlen($data);
 | 
					        $dataLength = strlen($data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if($isMasked === true) {
 | 
					        if($isMasked === true) { // This will always pass...
 | 
				
			||||||
            for($i = $payloadOffset; $i < $dataLength; $i++) {
 | 
					            for($i = $payloadOffset; $i < $dataLength; $i++) {
 | 
				
			||||||
                $j = $i - $payloadOffset;
 | 
					                $j = $i - $payloadOffset;
 | 
				
			||||||
                $unmaskedPayload .= $data[$i] ^ $mask[$j % 4];
 | 
					                $unmaskedPayload .= $data[$i] ^ $mask[$j % 4];
 | 
				
			||||||
 | 
				
			|||||||
@ -8,8 +8,14 @@ use Ratchet\Command\CommandInterface;
 | 
				
			|||||||
 * Creates an open-ended socket to listen on a port for incomming connections.  Events are delegated through this to attached applications
 | 
					 * Creates an open-ended socket to listen on a port for incomming connections.  Events are delegated through this to attached applications
 | 
				
			||||||
 * @todo Consider using _connections as master reference and passing iterator_to_array(_connections) to socket_select
 | 
					 * @todo Consider using _connections as master reference and passing iterator_to_array(_connections) to socket_select
 | 
				
			||||||
 * @todo Currently passing Socket object down the decorated chain - should be sending reference to it instead; Receivers do not interact with the Socket directly, they do so through the Command pattern
 | 
					 * @todo Currently passing Socket object down the decorated chain - should be sending reference to it instead; Receivers do not interact with the Socket directly, they do so through the Command pattern
 | 
				
			||||||
 | 
					 * @todo With all these options for the server I should probably use a DIC
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
class Server implements SocketObserver, \IteratorAggregate {
 | 
					class Server implements SocketObserver, \IteratorAggregate {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * This is probably temporary
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    const RECV_BYTES = 1024;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * The master socket, receives all connections
 | 
					     * The master socket, receives all connections
 | 
				
			||||||
     * @type Socket
 | 
					     * @type Socket
 | 
				
			||||||
@ -65,6 +71,9 @@ class Server implements SocketObserver, \IteratorAggregate {
 | 
				
			|||||||
        set_time_limit(0);
 | 
					        set_time_limit(0);
 | 
				
			||||||
        ob_implicit_flush();
 | 
					        ob_implicit_flush();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->_master->set_nonblock();
 | 
				
			||||||
 | 
					        declare(ticks = 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (false === ($this->_master->bind($address, (int)$port))) {
 | 
					        if (false === ($this->_master->bind($address, (int)$port))) {
 | 
				
			||||||
            throw new Exception($this->_master);
 | 
					            throw new Exception($this->_master);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -73,9 +82,6 @@ class Server implements SocketObserver, \IteratorAggregate {
 | 
				
			|||||||
            throw new Exception($this->_master);
 | 
					            throw new Exception($this->_master);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->_master->set_nonblock();
 | 
					 | 
				
			||||||
        declare(ticks = 1); 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        do {
 | 
					        do {
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                $changed     = $this->_resources;
 | 
					                $changed     = $this->_resources;
 | 
				
			||||||
@ -86,13 +92,24 @@ class Server implements SocketObserver, \IteratorAggregate {
 | 
				
			|||||||
                        $res = $this->onOpen($this->_master);
 | 
					                        $res = $this->onOpen($this->_master);
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
                        $conn  = $this->_connections[$resource];
 | 
					                        $conn  = $this->_connections[$resource];
 | 
				
			||||||
                        $data  = null;
 | 
					                        $data  = $buf = '';
 | 
				
			||||||
                        $bytes = $conn->recv($data, 4096, 0);
 | 
					
 | 
				
			||||||
 | 
					                        $bytes = $conn->recv($buf, static::RECV_BYTES, 0);
 | 
				
			||||||
 | 
					                        if ($bytes > 0) {
 | 
				
			||||||
 | 
					                            $data = $buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            // This idea works* but...
 | 
				
			||||||
 | 
					                            // 1) A single DDOS attack will block the entire application (I think)
 | 
				
			||||||
 | 
					                            // 2) What if the last message in the frame is equal to RECV_BYTES?  Would loop until another msg is sent
 | 
				
			||||||
 | 
					                            // Need to 1) proc_open the recv() calls.  2) ???
 | 
				
			||||||
 | 
					                            while ($bytes === static::RECV_BYTES) {
 | 
				
			||||||
 | 
					                                $bytes = $conn->recv($buf, static::RECV_BYTES, 0);
 | 
				
			||||||
 | 
					                                $data .= $buf;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        if ($bytes == 0) {
 | 
					 | 
				
			||||||
                            $res = $this->onClose($conn);
 | 
					 | 
				
			||||||
                        } else {
 | 
					 | 
				
			||||||
                            $res = $this->onRecv($conn, $data);
 | 
					                            $res = $this->onRecv($conn, $data);
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            $res = $this->onClose($conn);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -34,6 +34,10 @@ class Socket implements SocketInterface {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __destruct() {
 | 
				
			||||||
 | 
					        @socket_close($this->_resource);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @return resource (Socket)
 | 
					     * @return resource (Socket)
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user