XMPP client receiving server messages - php

I am implementing my custom XMPP PHP library (Packagist repo) and I have trouble fetching messages (that the client sent) from XMPP server.
Library is using PHP sockets to connect to the server, and I am able to fetch a response from server when initially connecting and authenticating. I can also send a message from server to the client, and that part works.
I can't however receive a message.
This is the code I am using when receiving anything from server:
public function getRawResponse()
{
// Wait max 3 seconds before terminating the socket
socket_set_option($this->socket, SOL_SOCKET, SO_RCVTIMEO, ["sec" => $this->options->getSocketWaitPeriod(), "usec" => 0]);
while ($out = socket_read($this->socket, 2048)) {
echo "*** Data ***\n\n";
echo str_replace("><", ">\n<", $out) . "\n\n";
echo "\n\n************\n";
}
}
This while loop is here to fetch all one-batch responses from the server, and it reads from server while it has something to read, otherwise it terminates the connection.
In the main program I am thus doing a do{...}while(true) and putting this method inside so that it doesn't terminate ever. But still I am not getting any response when sending the other way around, from client back to server.

I have found that I needed to send initial empty presence stanza to server
<presence/>
Once I got the server response back, so did the message responses started incoming.

Related

Shutting down a socket in PHP

I created a cache server and client in php, no need to ask why, just for fun. The implementation works, but a problem occures every time when:
Server starts
Client connects
Server stores data
Client disconnects
When I stop the running server process, after a client disconnects and trying to restart the server, the socket_bind throws an error, that the address is already in use. The client always closes connection after the data has been sent or recieved and when I check if the port is in use via sudo netstat, the port is not listed. The server looks like this:
public function run()
{
$this->socket = $this->ioHandler->createServerSocket();
while ($this->running) {
while ($connection = #socket_accept($this->socket)) {
socket_set_nonblock($connection);
$this->maintainer->maintainBucket($this->bucket);
$this->maintainer->checkBackup(time(), $this->bucket);
try {
$dataString = $this->ioHandler->readFromSocket($connection);
$data = unserialize($dataString);
($this->actionHandler)($data, $this->bucket, $this->ioHandler, $connection);
} catch (Exception $ex) {
$this->ioHandler->writeToSocket($connection, self::NACK);
$this->ioHandler->closeSocket($connection);
}
}
}
}
I think the problem might be that the server shuts down via a simple ctrl+c or a start-stop-daemon --stop --pidfile and the socket is still open and there might be some automatized service that cleans up dead sockets. How can I properly shut down the server? Can I somehow terminate the process by sending an input via STDIN to kill the server socket? Or am I wrong on the issue? The full code is available on github: https://github.com/dude920228/php-cache
Perhaps it's related to TIME_WAIT state. Long story short - socket_close() may close the socket, but there still may be data to send. Until the data is sent, the port will not be available.
More info is:
here
here
and here

PHP Server Socket shutting down at seemingly random instances

I have a server online, and I wrote a PHP Code to act as a Socket Server to handle messages. The messages are coming in from devices that connect to the IP and the Port and send messages.
I found this code example that lets me handle multiple connections at the same time and manage the messages as they come in.
I have modified the code to properly parse the messages that come in from my devices.
Everything has been going well during testing. However, when we did extended testing, the PHP Socket Server would shutdown at seemingly random times and would give the error:
socket_read() failed: reason: Connection reset by Peer at line 104.
Looking at the code I am running, this is the code block for line 104, it starts at the if condition.
if (false === ($buf = socket_read($client, 115200, PHP_BINARY_READ))) {
echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($client)) . "\n";
$GLOBALS['mysqli']->close();
break 2;
}
I actually am not sure how to make sense of this error message. During our testing periods, sometimes that error would show up and shut down the Socket Server while the device is sending a message - but we are sure that the device did not send a Socket Shutdown command. At other times, when we would let the Socket Server just run through, that error would show up.
Does anyone know how to effectively keep a PHP Socket Server from shutting down and keep on running?
I know I can run a cronjob that periodically checks if the socket is being used. However, when the socket server shuts down unexpectedly, the PHP Code can't execute as it still reads that the port is still in use, even if the previous socket server instance is already down and we can no longer connect to it. It takes quite some time until the cronjob manages to put the socket back up again and accept messages - and we need the socket server to run virtually all the time.
"Connection reset by Peer" means the client disconnected unexpectedly. For instance, the user may have closed the client before it was done talking to the server.
Your server code needs to be prepared to handle errors on client sockets, and not quit when it gets an error on a client socket. When you get an error from a client socket it's appropriate to just disconnect that client.

Socket connection on same machine, PHP to C++ and back

I had to implement a communication between an application written in c++ and a web server scripted with PHP.
The basic idea was to create a socket with the c++ application, binding it and listen for the PHP connection to it.
The PHP would then send a message over TCP asking for data and the c++ would send back the answer. Single header request, single string(JSON) answer.
So far, so good.
This is the code I used for the PHP side:
<?php
error_reporting(E_ALL);
$service_port = 8080;
$address = 'localhost';
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
}
echo "Attempting to connect to '$address' on port '$service_port'...";
$result = socket_connect($socket, $address, $service_port);
if ($result === false) {
echo "socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
}
$in = "request1";
$out = '';
socket_write($socket, $in, strlen($in));
$buf = 'This is my buffer.';
if (false !== ($bytes = socket_recv($socket, $buf, 2048, MSG_WAITALL))) {
echo "Read $bytes bytes from socket_recv(). Closing socket...";
} else {
echo "socket_recv() failed; reason: " . socket_strerror(socket_last_error($socket)) . "\n";
}
socket_close($socket);
echo $buf . "\n";
//elaborate the $buf
?>
Now I would like to implement also an auto-update of the data, with the c++ (server side) sending data and the PHP side(client side) to collect them.
The data update should be done every minute.
Sadly I don't have much experience with web developing, so I'm kindly asking some advices on that.
The easiest thing I could do was looping the PHP code untill a known message got received. The problem I faced is that I don't get data untill the loop is over and the PHP script ends.
To overcome the problem I tried to set PHP side the socket to be non-blocking
replacing in the socket_recv the option MSG_WAITALL with MSG_DONTWAIT but nothing changed. Then I tried to break out of the PHP script, but it can't be done since I need to cycle it to get the data every second.
Plus I get another problem, during the loop cycles, the apache server the PHP is running on is getting a 503 error, Server Unavailable.
I don't know why it happens, maybe the received message buffer is full, or the script takes too many resources.
Due to my lack of experience I can't understand why.
I know there are good libraries to perform what I need but I'm working on an embedded machine so I'm limited to work with basic libraries.
How can I achieve the PHP on the Apache server to get timed data from the c++ application ? What am I overlooking ?
Thanks a lot in advance for your help.
Edit: Deleted rhetorical question.
Using php to obtain data from another process via tcp/ip will require a bit more effort compared to sending data from a php script executed via apache to another process using tcp/ip sockets.
Your php script will need to be started outside of apache and will require an infinite loop that continuously listens to the given port to read input data. The following post outlines what I believe you are after.
EDIT
In order to display the results on the web page you could use an in memory data store such as Redis. The php server application would update a data structure in redis, then the webpage onload could pull the latest value from redis and display it on screen, however this would require a page refresh.
If you require that the data be refreshed immediately once received without server postback, this will require some javascript. When a user loads the page you would initialize a websocket connection with a websocket server (people generally use node.js and socket.io for implementing this but you can code a websocket server in anything that supports the technology). The websocket server would be subscribed to a redis channel that when updated would send the new values to all connected clients. I suppose this could be done without redis as well depending on what your requirements are. The program for the websocket server could also be the server that accepts the information from your c++ program using a separate thread. When data comes in from the c++ program you could then send it directly to the clients connected via websocket.
Don't reinvent the wheel. Use a websockets. It's designed to do this async communication and you can send JSON over it just fine.
There are libraries for C++ and PHP, meaning this should be pretty easy.

socket_write(): unable to write to socket [10053]

I'm using whatsapp api with laravel 5.2
https://github.com/mgp25/Chat-API
And i got this error when i trying to send new message
socket_write(): unable to write to socket [10053]: An established connection was aborted by the software in your host machine.
Send Controller
$massage = "Thanks for subscribe";
Whatsapi::send($massage, function ($send) {
$user = User::Find(1);
$send->to($user->phone);
}
While following this tutorial
I was getting the same error in phperror.log which I have configured in my php.ini. Initially I thought it was due to some firewall issue, but it wasn't.
The problem was, I was running the client first and then the server. Client was probably not able to make a connection with the server when it ran for the first time.
So I resolved it by running the server first and then the client, which can now make a successful web socket connection.
EDIT : This error also comes up when we simply reload the client page without properly terminating the previous connection.

Detecting if stream_socket is valid

I have a PHP server-like script that runs indefinitely. It connects to APNS (Apple Push Notification Service) with a stream_socket_client object in PHP.
The problem is that while this works most of the time, I cannot figure out how to validate if the connection to APNS is available when I want to send a push notification. The script receives incoming connections and copies the content to APNS.
When it doesn't work, the script reconnects (the return value of stream_copy_to_stream is 0 on 0 bytes written, which triggers reconnect) and then the next incoming token will succeed, but it logs the following and of course does not deliver the message:
PHP Warning: stream_copy_to_stream(): SSL: An established connection was
aborted by the software in your host machine.
Is there any way to detect the above and thus reconnect to APNS before trying to write to the socket.
And doing this before trying to copy to APNS:
if (!$socketObject) {
// reconnect
}
Does not work, as the object still exists (var_dump will print a description). So how can I check if the connection is still open?
Writing anything to the socket that is not a valid token and payload will cause APNS to disconnect.
The code that performs the writing looks like this:
function writeToAPNS($client) {
return stream_copy_to_stream ( $client, $this->connectionAPNS );
}
Where $client is returned from stream_socket_accept ( $this->socket, -1 ) and $this->socket is a variable containing the local socket object listening for incoming connections. -1 means there is no timeout when waiting for an incoming connection. When it works this function returns the number of bytes written. When it fails it returns 0.
$this->connectionAPNS is the object returned from stream_socket_client when connecting to APNS. This is what I want to check for validity before I perform the stream_copy_to_stream function.
So basically I want to detect if $this->connectionAPNS is valid.
I tried dumping the metadata for the connection object, but it doesn't say anything about the validity, only if it's timed out, protocol type etc.
Did you see this note in the official stream_socket_client documentation?
UDP sockets will sometimes appear to have opened without an error, even if the remote host is unreachable. The error will only become apparent when you read or write data to/from the socket. The reason for this is because UDP is a "connectionless" protocol, which means that the operating system does not try to establish a link for the socket until it actually needs to send or receive data.
Please try this methiod stream_get_meta_data on your connection to try to detect a difference. I can't test it right now, but it might help you. Especially the timed_out property.
Another option to at least mute the error messages, since you are handling them, is to set an appropriate errno on the stream_socket_client.
Well, as explained by M.K., this is how UDP works. And by the way, your code works. Your problem is the warning, which is fairly easy to get rid of by adding an # to your write function.
Your code would then look like :
function writeToAPNS($client) {
return #stream_copy_to_stream ( $client, $this->connectionAPNS );
}

Categories