Socket fread() sometimes return an empty string - php

I'm using some API to get a remote server's info by sending a packet with fwrite() and then read the returned value by fread(). Most of the times it works properly, but every 5 to 10 times, it will return an empty string from fread(). This is the code I use:
public function getInfo()
{
#fwrite($this->rSocket, $this->createPacket('i'));
$inforead = fread($this->rSocket, 999);
if(strlen($inforead) >= 28)
{
$inforead = substr($inforead, 11);
$aDetails['password'] = (integer) ord(substr($inforead, 0, 1));
$aDetails['players'] = (integer) $this->toInteger(substr($inforead, 1, 2));
$aDetails['maxplayers'] = (integer) $this->toInteger(substr($inforead, 3, 2));
$inforead = substr($inforead, 5);
$iStrlen = ord(substr($inforead, 0, 4));
if(!$iStrlen) return -1;
$aDetails['hostname'] = (string) substr($inforead, 4, $iStrlen);
$inforead = substr($inforead, 4+$iStrlen);
$iStrlen = ord(substr($inforead, 0, 4));
$aDetails['gamemode'] = (string) substr($inforead, 4, $iStrlen);
$inforead = substr($inforead, 4+$iStrlen);
$iStrlen = ord(substr($inforead, 0, 4));
$aDetails['mapname'] = (string) substr($inforead, 4, $iStrlen);
}
return $aDetails;
}
I also debugged fwrite() and it seems it returns the number of bytes written and not false, meaning the error wasn't in fwrite(). Is the problem with my code or with the server failing to provide the info?
The constructor opens the socket, so it won't be visible here.

I've just encountered a strange stream socket situation, my fread code always returned empty string.
I replaced fread by stream_get_contents and problem solved

Related

Am I decrypting this correctly?

Given the following inputs:
CLIENT RANDOM : 61fc160e0a6e96db43aebcca55da7fbccb97cc04d59fcc105490b4396a915ab9
SERVER RANDOM : f0ecb127db6e353a2985894c123532a8d092fafcf7cdce3a444f574e47524401
PREMASTER KEY : 0303ec4418e91f0abf9a012f524b61c0312008641ebce76d68b2417447e3d9a970d02fd65a20e5e3e98413dbd13b6536
First I use these input to calculate the following key buffers:
CLIENT MAC: 500c7c6e6101cb1693b4cee7db6fb0bc2725deca
SERVER MAC: 41e260280fe213bd5f2c0412c69389cac2e39e4f
CLIENT KEY: c17226212f6195c1515602a0c0864ec90e73e7bcd05ad90b196fd5a5cb2445f2
SERVER KEY: 6b07166b634a7e58e623b969eb0c024a1e866bc2719c054e1a05849b87ccf79b
CLIENT IV: dac71f7b3639cf4d4ec86ee51b9530f6
SERVER IV: c1212631365432c8d5a4c93f6f999a8e
I calculate these values using helper functions I found online:
function p_hash($algo, $secret, $seed, $size) {
$output = "";
$a = $seed;
while (strlen($output) < $size) {
$a = hash_hmac($algo, $a, $secret, true);
$output .= hash_hmac($algo, $a . $seed, $secret, true);
}
return substr($output, 0, $size);
}
function prf_tls12($secret, $label, $seed, $size) {
return p_hash("sha256", $secret, $label . $seed, $size);
}
function generate_master($pre_master_secret, $client_random, $server_random) {
return prf_tls12($pre_master_secret, 'master secret', $client_random . $server_random, 48);
}
$client_random = hex2bin('61fc160e0a6e96db43aebcca55da7fbccb97cc04d59fcc105490b4396a915ab9');
$server_random = hex2bin('f0ecb127db6e353a2985894c123532a8d092fafcf7cdce3a444f574e47524401');
$pre_master_secret = hex2bin('0303ec4418e91f0abf9a012f524b61c0312008641ebce76d68b2417447e3d9a970d02fd65a20e5e3e98413dbd13b6536');
$master_secret = generate_master($pre_master_secret, $client_random, $server_random);
$key_buffer = prf_tls12($master_secret, 'key expansion', $server_random . $client_random, 136);
$client_mac = substr($key_buffer, 0, 20);
$server_mac = substr($key_buffer, 20, 20);
$client_key = substr($key_buffer, 40, 32);
$server_key = substr($key_buffer, 72, 32);
$client_iv = substr($key_buffer, 104, 16);
$server_iv = substr($key_buffer, 120, 16);
Here I have an AES_256_CBC encrypted message sent from the CLIENT ---> SERVER in Hex format
$EncryptedMessage = 'f32da333a3416888d55c583c9796f8fc498895e386616a62aa364a41cd2bfc203c1f296b4afd9c4a9674c993bf0db558de0c0cb2b3dc4b083af3824e0b9a3327';
I run the following code using the PHPSECLIB v3.0 plugin:
$cipher = new AES('cbc');
$cipher->setIV($client_iv);
$cipher->setKey($client_key);
$cipher->disablePadding();
$DecryptedMessage = bin2hex($cipher->decrypt(hex2bin($EncryptedMessage)));
print($DecryptedMessage);
I get the following output in Hex:
f889ff0ce7cc744c2182363e7117ae74e34ccb0510099e7c11133c369f98468de9f20fa6e7207c8121484a9663929d1af4bffb5410da37029aa26b9298411e3b
Basically, I have no idea whether I'm doing this right or not. I dont seem to see anything in my decrypted message. Also, unless I specifically use the $cipher->disablePadding(); I will get a PHP Fatal Error saying that PHP Fatal error: Uncaught phpseclib3\Exception\BadDecryptionException: The ciphertext has an invalid padding length (81) compared to the block size (16)
Note: This is supposed to be an "Encrypted Handshake Message" sent as the first message from a client to server after the Key Exchange using TLS 1.2. I am unable to determine if my decryption is correct, since I cant find much on the structure of value anywhere. Any help is appreciated, thanks!

PHP Websocket server - Handle more frames in socket_recv

Hope this wasn't solved here before, but I was really trying to look for answer!
I Have a problem with receiving frames via socket_recv in PHP server. Problem appears when I send more than 1 messages from client in one time (e.g. in cycle). By the stream length it's match frames count but I'm not able to unmask frames correctly and my unmask function return only first frame. I'm using part of php server I found here and for one message it's working properly, but when I receive more messages at time, it don't unmask all.
I tryed to add loop to go thru all frames, but I'm not able to find end of frame and continue to other.
Here is main while of server:
while (true) {
//manage multipal connections
$changed = $clients;
//returns the socket resources in $changed array
socket_select($changed, $null, $null, 0, 10);
//check for new socket
if (in_array($socket, $changed)) {
$socket_new = socket_accept($socket); //accpet new socket
$clients[] = $socket_new; //add socket to client array
$header = socket_read($socket_new, 10240); //read data sent by the socket
perform_handshaking($header, $socket_new, $host, $port); //perform websocket handshake
socket_getpeername($socket_new, $ip); //get ip address of connected socket
$response = mask(json_encode(array('type' => 'system', 'status' => true, "id" => "SRV_CONNECTED", 'message' => $ip . ' connected'))); //prepare json data
send_message($response); //notify all users about new connection
//make room for new socket
$found_socket = array_search($socket, $changed);
unset($changed[$found_socket]);
}
foreach ($changed as $changed_socket) {
while (#socket_recv($changed_socket, $buf, 1024, 0) >= 1) {
$received_text = unmask($buf); //unmask data
$tst_msg = json_decode($received_text, true); //json decode
$response_text = parse_msg($tst_msg, $changed_socket);
break 2; //exit this loop
}
$buf = #socket_read($changed_socket, 10240, PHP_NORMAL_READ);
if ($buf === false) { // check disconnected client
// remove client for $clients array
$found_socket = array_search($changed_socket, $clients);
socket_getpeername($changed_socket, $ip);
unset($clients[$found_socket]);
//notify all users about disconnected connection
$response = mask(json_encode(array('type' => 'system', 'message' => $ip . ' disconnected')));
send_message($response);
}
}
I Need to call parse_msg by count of frames received in #socket_recv which should be returned by unmask function.
And here is unmask function:
function unmask($payload){
$decMessages = Array();
do { // This should be running until all frames are unmasked and added to $decMessages Array
$length = ord($payload[1]) & 127;
if($length == 126) {
$masks = substr($payload, 4, 4);
$data = substr($payload, 8);
$len = (ord($payload[2]) << 8) + ord($payload[3]);
}elseif($length == 127) {
$masks = substr($payload, 10, 4);
$data = substr($payload, 14);
$len = (ord($payload[2]) << 56) + (ord($payload[3]) << 48) +
(ord($payload[4]) << 40) + (ord($payload[5]) << 32) +
(ord($payload[6]) << 24) +(ord($payload[7]) << 16) +
(ord($payload[8]) << 8) + ord($payload[9]);
}else {
$masks = substr($payload, 2, 4);
$data = substr($payload, 6);
$len = $length;
}
$text = '';
for ($i = 0; $i < $len; ++$i) {
$text .= $data[$i] ^ $masks[$i%4];
}
$decMessages[] = $text;
// Here is problem. It doesn't put correct substr to $payload, so it could run again on stream shorted by last message
$payload = substr($payload, $length, strlen($payload));
}while (($len < strlen($data)) and $countert < 10);
return $decMessages;
}
I think my problem is here: $payload = substr($payload, $length, strlen($payload)); Where I'm putting wrongly rest of stream?
So my questions are:
Why #socket_recv return more than one frame
How can i change my unmask function to go thru all frames, not just a first one
I will be extremelly greatfull for any help, because I'm fighting with this more than I should.
Thanks in advance
Klara!
so, I found solution for this. As I thought, problem was multiple frames in one receive. I needed to edit my unmask function to check if there are still frames in stream.
Basically, what I had was right but $length in
$payload = substr($payload, $length, strlen($payload));
was wrong. Instead of $length I used $len + 8, 14 od 6 depend on $length. I'm not sure how to describe why this but I'm sure somebody will. That's all. Now it's working as it should!
Thanks!

PHP Cross Session Global Counter Variable (Shared Memory)

On a very busy PHP server, I am trying to get a global counter going and thought shared memory would be the way to go. Ideally I would use APC
apc_add('counter',1);
apc_inc('counter',1);
var_dump(apc_fetch('counter'));
except that it is not available on the servers and I am restricted to what is available. The servers do have shmop so tried to get that to work, however it seems to be session specific. Is there anything else that could be used?
The shmop code I tried:
$shm_key = ftok(__FILE__, 't');
$shm_id = shmop_open($shm_key, "c", 0644, 8);
$shm_data = shmop_read($shm_id, 0, 8);
$shm_data = shmop_read($shm_id, 0, 8);
var_dump($shm_data);
if (empty($shm_data)) {
//counter has not been set
$shm_bytes_written = shmop_write($shm_id, 0, 1);
} else {
$shm_bytes_written = shmop_write($shm_id, (int)$shm_data + 1, 0);
}
$shm_data = shmop_read($shm_id, 0, 8);
var_dump($shm_data);

How do I Add Parsing JSON to PHP Script

So here's my sample code that I pull from SEOMOZ API for links on a targeted URL.
this script is command line
#!/usr/bin/php
<?php
$objectURL = $domain_url;$accessID = "xyz";
$secretKey = "xya";
$expires = mktime() + 300;
$stringToSign = $accessID."\n".$expires;
$binarySignature = hash_hmac('sha1', $stringToSign, $secretKey, true);
$urlSafeSignature = urlencode(base64_encode($binarySignature));
$urlToFetch = "http://lsapi.seomoz.com/linkscape/links/".urlencode($objectURL)."?AccessID=".$accessID."&Expires=".$expires."&Signature=".$urlSafeSignature."&SourceCols=26&&TargetCols=4&Scope=page_to_domain&Filter=follow&Sort=page_authority&Limit=10";
$handle = fopen($urlToFetch, "r");
$links_contents = '';
while (!feof($handle)) {
$links_contents .= fread($handle, 8192);
}
fclose($handle);
echo $links_contents;
?>
the result of the script is that it returns info in JSON format but in a huge glob not in an orderly manner. Whats the easiest way to format the result into a more neater/readable display?
here is the return from JSON
{
"frid": 1,
"lf": 2,
"lrid": 3,
"lsrc": 4,
"ltgt": 5,
"luuu": 6,
"prid": 7,
"ufq": 8,
"upl": 9,
"urid": 10
}
You mean json_decode($links_contents)?

How to communicate between php and boost library IPC?

I have client and server in php communicating over shared memory, Now I would like to access this shred memory object using Boost.Interprocess how can I access it?
server.php:
function create_image($str){
// Create a blank image and add some text
$im = imagecreatetruecolor(300, 20);
$text_color = imagecolorallocate($im, 233, 14, 91);
$stringBanner=exec("date").$str;
imagestring($im, 1, 5, 5, $stringBanner , $text_color);
ob_start();
imagejpeg($im);
$i = ob_get_contents();
ob_get_clean();
imagedestroy($im);
return $i;
}
echo "\n".__FILE__."\n";
$shm_key = ftok(__FILE__, 't');
echo $shm_key."\n";
$shm_id = shmop_open($shm_key, "a", 0, 0);
if ($shm_id) {
//it is already created
shmop_delete($shm_id);
shmop_close($shm_id);
}
//you need to create it with shmop_open using "c" only
echo "try to create\n";
if(!$shm_id = shmop_open($shm_key, "c", 0777, 1024*4))exit(-1);
echo "ID ".$shm_id."\n";
$i=0;
for(;;){
sleep(1);
$s="i=".$i++;
$str=$i;
$im=serialize(create_image($str));
$data=serialize(strlen($im));
$shm_bytes_written = shmop_write($shm_id, $data, 0);
$shm_bytes_written = shmop_write($shm_id, $im, 32);
echo $shm_bytes_written." bytes is written: ".$s." ID = $shm_id\n";
}
client.php
<?php
$shm_key =1946222626;// ftok(__FILE__, 't');
$shm_id = shmop_open(
$shm_key, "a",
0644,1024*4
);
$s=shmop_size($shm_id);
$data = unserialize(
shmop_read( $shm_id, 0,
31)
);
$im = unserialize(
shmop_read( $shm_id, 32,
$data)
);
// Set the content type header - in this case image/jpeg
header('Content-Type: image/jpeg');
// Output the image
echo $im;
What kind of key I should provide to Boost to get this memory region?
boost_client.cpp
#include <boost/interprocess/shared_memory_object.hpp>
#include <iostream>
#include "sys/msg.h"
int main()
{
int msqid;
key_t key;
char f[]="??????";
int mid;
//key = ftok(, 't');
//msqid = msgget(key, 0666 | IPC_CREAT);
std::cout<<msqid<<std::endl;
boost::interprocess::shared_memory_object
shdmem(boost::interprocess::open_or_create,
f,//"shmem_server",
boost::interprocess::read_write);
shdmem.truncate(1024);
std::cout << shdmem.get_name() << std::endl;
boost::interprocess::offset_t size;
if (shdmem.get_size(size))
std::cout << size << std::endl;
}
EDIT:
Well I found the solution in Boost IPC library Docs:
XSI_KEY based example from boost Docs
I'm not an expert in what you're doing, but from what I read in your question and my knowledge, I would drop that pure IPC thing and wrap it into ZMQ (you'll find wrapper in every language you need). It's meant to solve those kind of problems and provide a single API that could run over IPC or more common TCP socket.

Categories