-
Notifications
You must be signed in to change notification settings - Fork 72
Description
The method \PhpMqtt\Client\MqttClient::writeToSocket() currently has an implementation of socket_set_blocking() to ensure correct writing:
This is wrong:
if ($this->settings->shouldUseBlockingSocket()) {
socket_set_blocking($this->socket, false);
}
And this is wrong too:
if ($result === false || $result !== $length) {
Please referer to the php documentation to stream_set_blocking(), it says:
This affects calls like [fgets()](https://www.php.net/manual/en/function.fgets.php) and [fread()](https://www.php.net/manual/en/function.fread.php) that read from the stream. It says nothing about writing.
In addition it says for fwrite():
Writing to a network stream may end before the whole string is written. Return value of fwrite() may be checked
and then shows a loop that calls fwrite() until all bytes are written.
Understanding the problem:
socket_set_blocking() sets the O_NONBLOCK flag. That means it will not block the local process from execution if it tries to read from or write to a receiver.
It has no impact how the data actually can be written over the line. This is made by a underlying I/O-controller. Sending more data than the receiver buffer can handle will result in broken pipe errors (the ones that are silenced via @-operator).
But even if fwrite() returns false, it could be just a temporary problem and must be retried. You may check stream_get_meta_data() for some stream state or even feof() if the connection was really closed.
Long story short: never rely on blocking sockets for write operations.
- Check the return value by fwrite()
- Repeat until all data was sent
- Don't stop after a "false"
- Only abort after a timeout or by other bad condition