Skip to content

Commit

Permalink
Fixed masking key and is now able to respond
Browse files Browse the repository at this point in the history
  • Loading branch information
calcinai committed Oct 16, 2015
1 parent de1bf57 commit 5363d2c
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 20 deletions.
4 changes: 2 additions & 2 deletions examples/client.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
echo "State changed to: $newState\n";
});

$client->on('message', function($message){
print_r($message);
$client->on('message', function($message) use ($client){

});

$loop->run();
Expand Down
4 changes: 4 additions & 0 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,8 @@ public function setOrigin($origin) {
return $this;
}

public function send($string) {
$this->transport->send($string);
}

}
4 changes: 4 additions & 0 deletions src/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ public function addBody($body) {
return $this;
}

public function getBody() {
return $this->body;
}

public function isComplete() {
return $this->is_complete;
}
Expand Down
3 changes: 2 additions & 1 deletion src/Protocol/ProtocolInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
namespace Calcinai\Bolt\Protocol;

interface ProtocolInterface {
public function upgrade();
public function onStreamData(&$buffer);
public function upgrade();
public function send($string);
public static function getVersion();
}
12 changes: 9 additions & 3 deletions src/Protocol/RFC6455.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ private function addFragmentToMessage(Frame $frame) {
->setIsComplete($frame->isFinalFragment());

if($this->current_message->isComplete()){
$this->client->emit('message', [$this->current_message]);
$this->client->emit('message', [$this->current_message->getBody()]);
unset($this->current_message);
}
}
Expand Down Expand Up @@ -137,14 +137,21 @@ private function processUpgrade(Response $response) {

}


public function getExpectedAcceptKey(){
if(!isset($this->websocket_key)){
//todo handle
}
return base64_encode(pack('H*', sha1($this->websocket_key . self::WEBSOCKET_GUID)));
}


public function send($string, $type = Frame::OP_TEXT) {
$frame = new Frame($string, $type);
$this->stream->write($frame->encode());
}



protected static function generateKey() {
static $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"$&/()=[]{}0123456789';
$key = '';
Expand All @@ -159,5 +166,4 @@ public static function getVersion() {
return 10;
}


}
118 changes: 104 additions & 14 deletions src/Protocol/RFC6455/Frame.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,28 @@ class Frame {
const FRAME_BITS_MASKED = 1;
const FRAME_BITS_LENGTH = 7;

const EXT_PAYLOAD_BITS_S = 16;
const EXT_PAYLOAD_BITS_L = 64;

public function __construct($payload = null, $opcode = null, $fin = true){

public function __construct(){
$this->meta_decoded = false;

if($payload === null || $opcode === null){
return;
}

$this->frame_fin = $fin ? 0b1 : 0b0;
$this->frame_rsv1 = 0b0;
$this->frame_rsv2 = 0b0;
$this->frame_rsv3 = 0b0;
$this->frame_opcode = $opcode;
$this->frame_masked = 0b0;
$this->frame_length = strlen($payload);

$this->payload = $payload;


}

public function isMasked() {
Expand All @@ -63,6 +82,52 @@ public function getPayload() {
return $this->payload;
}


public function encode($masked = true){

$this->frame_masked = $masked ? 0b1 : 0b0;

$control = 0;
self::addBits($control, self::FRAME_BITS_FIN, $this->frame_fin);
self::addBits($control, self::FRAME_BITS_RSV1, $this->frame_rsv1); //Reserved
self::addBits($control, self::FRAME_BITS_RSV2, $this->frame_rsv2); //Reserved
self::addBits($control, self::FRAME_BITS_RSV3, $this->frame_rsv3); //Reserved
self::addBits($control, self::FRAME_BITS_OPCODE, $this->frame_opcode);
self::addBits($control, self::FRAME_BITS_MASKED, $this->frame_masked);

//Work out how many extended bits need to be added based on payload size
if ($this->frame_length > pow(2, self::EXT_PAYLOAD_BITS_S) -1) {
// >16 bit - 8 bytes size
self::addBits($control, self::FRAME_BITS_LENGTH, 127);

$low = $this->frame_length & pow(2, 32) - 1;
$high = $this->frame_length >> 32;
$packed = pack('nNN', $control, $high, $low);

} elseif($this->frame_length > 125) {
// 2 bytes size
self::addBits($control, self::FRAME_BITS_LENGTH, 126);

$packed = pack('nn', $control, $this->frame_length);
} else {
// standard size frame
self::addBits($control, self::FRAME_BITS_LENGTH, $this->frame_length);
$packed = pack('n', $control);
}

if($this->isMasked()){
$this->masking_key = self::generateMaskingKey();
$packed .= pack('N', $this->masking_key);
self::mask($this->payload, $this->masking_key);
}

$packed .= $this->payload;

return $packed;

}


/**
* @param $buffer
* @return string
Expand All @@ -79,15 +144,10 @@ public function appendBuffer(&$buffer){
public function appendPayload($buffer){

if($this->isMasked()){
//What good does this even do!?
$mask_size = strlen($this->masking_key);
foreach(str_split($buffer, $mask_size) as $chunk){
$this->payload .= $chunk ^ ($this->masking_key >> ($mask_size - strlen($chunk))); //That strlen catches the remainder.
}
} else {
$this->payload .= $buffer;
self::mask($buffer, $this->masking_key);
}

$this->payload .= $buffer;

$payload_length = strlen($this->payload);
if($payload_length < $this->frame_length){
Expand Down Expand Up @@ -134,6 +194,17 @@ public function decode(&$buffer){
}


private function eatBytes(&$buffer, $num_bytes){

if(!isset($buffer[$num_bytes])){
throw new IncompleteFrameException($this);
}

$consumed = substr($buffer, 0, $num_bytes);
$buffer = substr($buffer, $num_bytes);

return $consumed;
}

public static function extractBits(&$data, $num_bits){

Expand All @@ -145,16 +216,35 @@ public static function extractBits(&$data, $num_bits){
return $bits;
}

private function eatBytes(&$buffer, $num_bytes){
private static function addBits(&$data, $num_bits, $bits){

if(!isset($buffer[$num_bytes])){
throw new IncompleteFrameException($this);
$data = $data << $num_bits;
$data |= $bits;
}


public static function generateMaskingKey() {
$mask = 0;

for ($i = 0; $i < 32; $i += 8) {
$mask |= rand(32, 255) << $i;
}

$consumed = substr($buffer, 0, $num_bytes);
$buffer = substr($buffer, $num_bytes);
return $mask;
}

return $consumed;

private static function mask(&$data, $masking_key) {

$data_size = strlen($data);

for($i = 0; $i < $data_size; $i++) {
$remainder = 3 - $i % 4; //work backward through the masking key
$shift_bits = $remainder * 8; //Make the shift a whole byte
$xor = $masking_key >> $shift_bits;
$data[$i] = $data[$i] ^ chr($xor);
}
}


}

0 comments on commit 5363d2c

Please sign in to comment.