PHP: receive UDP broadcast - php

Currently I am trying to receive UDP broadcasts with PHP. The topic is very rare to find on the internet and if there are no real solutions that would have led me to success.
Here is my current code how I set up my server-socket to receive the UDP-broadcasts:
$context = stream_context_create([
'socket' => [
\SO_BROADCAST => 1,
'so_broadcast' => 1,
],
]);
$socket = #\stream_socket_server($address, $errno, $errstr, \STREAM_SERVER_BIND, $context);
since i'm not sure if i have to use the constant \SO_BROADCAST or the string 'so_broadcast' i've listed both in this example. of course i've tried everything in different variations. the documentation is actually quite clear here: https://www.php.net/manual/en/context.socket.php#context.socket.so_broadcast
still i can't receive a broadcast. i'm currently testing this via NC:
$ echo 'HELLO' | nc -u -v -b 10.88.0.255 20000
via tcpdump i can also see the broadcast on the server interface, but unfortunately it does not arrive at my socket? if i send a packet directly to the server ip it arrives and i can process it.
anyone else have an idea for me?
regards, volker.
EDIT:
an simple context params reverse check shows:
var_dump(stream_context_get_options($context));
# array(1) {
# ["socket"]=>
# array(1) {
# ["so_broadcast"]=>
# int(1)
# }
#}
so i think the option as string is the right decision...

Answer is easy, check the firewall settings. this was my problem, my local firewall block broadcasts to 255.255.255.255.
here is an complete sample code to receive DHCP broadcast packets on dedicated interface ep1:
<?php
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_set_option($socket, SOL_SOCKET, SO_BINDTODEVICE, 'ep1');
socket_set_option($socket, SOL_SOCKET, SO_BROADCAST, 1);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_set_option($socket, SOL_SOCKET, SO_REUSEPORT, 1);
socket_bind($socket, '255.255.255.255', 67);
while (1) {
if ($src = #socket_recv($socket, $data, 9999, 0)) {
echo $data . PHP_EOL;
}
}

Related

PHP/UDP: Can write via UDP, but recieving data seams not possible

I have this code which is running on php on my local mac:
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
$result = socket_connect($socket, $address, $port);
$msg = "i";
$len = strlen($msg);
socket_send($socket, $msg, $len, 0);
socket_recv($socket, $buf, 512, 0);
echo $buf;
socket_close($socket);
The code works up to "socket_recv". Actually, when running a udp test app on the computer, I can see the answer from the udp server on the terminal screen of the app. However, the script itself is running for ever (I assume that it is waiting for input which never comes through the socket for some reason).
I also tried to run the script on a local Webserver on a synology NAS. Same result.
(Same result with the UDP App obviously closed)
Problem solved by using this code. Apparently one has to close the socket after sending and open a new one for receiving. It seams to be a unique behaviour of this device (server):
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
$bytes = socket_sendto($socket, $message, strlen($message), 0, "192.168.0.37", 7090);
socket_close($socket);
$message="curr 7700";
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($socket, '0.0.0.0', 7090);
$from = '';
$port = 0;
socket_recvfrom($socket, $buf, 512, 0, $from, $port);
echo $buf . PHP_EOL;

How to send data to a specific socket

I am newbie in using PHP Websocket.
Here is my problem:
I have already successful running PHP websocket and creating a simple chat application(web application of course). In receiving client data. All of the clients will receive the data. How could I send data to a specified client or maybe to a several clients(not all clients).
I learn it at here
<?php
// Create a new socket
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// An example list of IP addresses owned by the computer
$sourceips['kevin'] = '127.0.0.1';
$sourceips['madcoder'] = '127.0.0.2';
// Bind the source address
socket_bind($sock, $sourceips['madcoder']);
// Connect to destination address
socket_connect($sock, '127.0.0.1', 80);
// Write
$request = 'GET / HTTP/1.1' . "\r\n" .
'Host: example.com' . "\r\n\r\n";
socket_write($sock, $request);
// Close
socket_close($sock);
?>
SOURCE: http://php.net/manual/en/function.socket-bind.php

socket_connect does not timeout

I am using sockets to send data to a server that may not be responding. So I am trying to define a timeout by using this solution in SO.
Make PHP socket_connect timeout
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 1, 'usec' => 0));
socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec' => 1, 'usec' => 0));
This works when the connection is made and the server takes too long to respond.
But when it can't create a connection socket_connect($socket, $addr, $port); the timeout is about 20 seconds.
Why is this 20 second timeout happening and how can I force the connection creation to timeout after 1 second too?
You can do this by switching to a non-blocking socket, looping until either a connection is gained or a timeout was reached, then back to blocking again.
// an unreachable address
$host = '10.0.0.1';
$port = 50000;
$timeout = 2;
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// switch to non-blocking
socket_set_nonblock($sock);
// store the current time
$time = time();
// loop until a connection is gained or timeout reached
while (!#socket_connect($sock, $host, $port)) {
$err = socket_last_error($sock);
// success!
if($err === 56) {
print('connected ok');
break;
}
// if timeout reaches then call exit();
if ((time() - $time) >= $timeout) {
socket_close($sock);
print('timeout reached!');
exit();
}
// sleep for a bit
usleep(250000);
}
// re-block the socket if needed
socket_set_block($sock);
edit: see #letiagoalves answer for an neater solution if you are using sockets created with fsockopen() or stream_socket_client()
I changed my socket communication mechanism to use stream_socket_client ($remote_socket, &$errno, &$errstr, $timeout) function instead. This function allows to define the connect timeout unlike socket_connect ($socket, $address, $port) which doesn't.
To force a timeout using socket_connect see #bigtallbill answer.
I tried a lot of variants with sockets..
fsockopen the best for simple operations, ex. testing connections
The SO_RCVTIMEO/SO_SNDTIMEO options don't work for socket_connect on some platforms, but only for socket_recv/socket_send. I can see it works on Ubuntu, but not Mac OSX.

get UDP Multicast stream in PHP

I am trying to receive a UDP multicast stream in PHP. The receive command never gets anything and waits forever.
I can watch the stream using VLC player so the stream is accessible on my machine. Any help on how to do this using PHP is highly appreciated.
Here is my code.
<?php
error_reporting(E_ALL | E_STRICT);
//create a new socket
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
//i am not sure about this command. I think i have to set this option to start receiving packets.
socket_set_option($socket, SOL_SOCKET, MCAST_JOIN_SOURCE_GROUP, array("group"=>"239.194.0.73","interface"=>"eth0","source"=>"239.194.0.73"));
$binded = socket_bind($socket, '127.0.0.1', 6073);
//receive data
$from = '';
$port = 0;
socket_recvfrom($socket, $buf, 12, MSG_WAITALL, $from, $port);
echo "Received $buf from remote address $from and remote port $port" . PHP_EOL;
?>
$binded = socket_bind($socket, '127.0.0.1', 6073);
Should be
$binded = socket_bind($socket, '0.0.0.0', 6073);
Or else you will only recv packets originating from the local host.

How to read php socket connection response?

Following is my socket connection request and response order.
$socket = socket_create(AF_INET, SOCK_STREAM, 0);
$connection = socket_connect($socket, $Host, $Port);
$Md5CheckSum = md5($msg);
$WillWait = 'SOAP '. $Md5CheckSum. ' WILL_WAIT'."\n";
socket_write($socket,$WillWait);
socket_write($socket,$msg);
socket_write($socket, SoapSender::$TERM_CHAR);
sleep(1);
$buf = socket_read($socket, 2048);
//socket_write($socket,"&\r\n");
echo "$buf\n";
Please could somebody tell me how to read response that I receive after last socket_write request. I have been searching for this answer all day but have not been able to find any help through Google.
Thanks a lot for your time.
Two functions should be used:
stream_set_blocking($socket, true);
And
stream_get_contents($socket);
Setting a block on your stream requires the return of data before your application will continue execution of the script.
If you do not set a stream block, sometimes latency will cause your PHP script to think there was no response, causing you to not receive data.
Also, use stream_get_contents to pull from the socket. This will grab by default the full buffer.
The correct way is to use socket_read, not stream_get_contests as someone else suggested.
Here is an example:
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$result = socket_connect($sock, "10.197.24.40", "5000");
$request = '{ "request" : { "id" : "some_function_id", "data": "55555555-5"} }';
// We send the request
socket_write($sock,$request);
socket_read($sock,1000000);
socket_close($sock);
I have tested this code in a live environment and it works correctly.

Categories