Make PHP socket_connect timeout - php

I have a small application I created to analyze the network connection. It runs from a browser and connects to a local PHP/Apache server. It then asks PHP to send a ping packet through a raw socket. THe problem is that if the host I am trying to ping isn't alive or won't answer to pings, we never get an answer from the server.
I beleave the socket request lives until apache is restarted. I have been getting mixed results from my application lately and I am blaming apache using too many sockets. Currently I have set the AJAX call's timeout and I was happy with it. But I really need to make PHP do the timeouting so that I won't have 500,000 sockets open to an unreachable host.
Some sample code:
$sockconn = #socket_connect($socket, $target, null);
if(!$sockconn)
{
$raw['error'] = socket_strerror(socket_last_error());
$raw['status'] = false;
return $raw;
}
This is the function that won't timeout. I need to get it to timeout. Also PHP script execution time DOES NOT affect sockets.
I am clueless.

You can set timeouts for reading and sending using the following options:
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));
Alternatively, you can use non-blocking sockets and periodically poll the socket to see if the remote host responded.

Try setting default_socket_timeout.

Related

PHP stream_socket_enable_crypto hangs indefinitely. Anyway to fix?

I have a PHP script that I use to send emails to my newsletter list in one of my sites.
The script uses STARTTLS for encrypted connections, using the following line to establish the SSL handshake:
stream_set_timeout($s, 35, 0);
if(false == stream_socket_enable_crypto($s, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)){
$msg = "452 failed on tls connection";
} else {
$in_tls = true;
}
The socket $s is set to blocking and is already connected to the remote server after issuing a STARTTLS command and ready to start TLS handshake at this stage. As you can see, I am using stream_set_timeout before the handshake. According to the PHP docs it should abort the handshake after X seconds, but it doesn't seem to affect it.
Now this code works most of the time, but I sometimes run into servers where the TLS handshake would just block indefinitely, causing the script to hang.
I've tried looking into non-blocking solutions, but none of them worked for my PHP version (I use v5.1.6).
The only other option is to somehow monitor this line for timeout (I'm not sure if that's possible), or to somehow transfer the socket handle to another process I can run with a timeout control method.
Anyone knows how to solve this?
You could try to set a timeout on the stream, see php manual for stream_set_timeout($s)
When the stream times out, the 'timed_out' key of the array returned
by stream_get_meta_data() is set to TRUE, although no error/warning is
generated.
Also found this on PHP manual
In case anyone is puzzled, stream_set_timeout DOES NOT work for
sockets created with socket_create or socket_accept. Use
socket_set_option instead.
Instead of:
<?php
stream_set_timeout($socket,$sec,$usec);
?>
Use:
<?php
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec'=>$sec, 'usec'=>$usec));
socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec'=>$sec, 'usec'=>$usec));
?>
Update: This allowed the OP to move past the issue
ini_set('default_socket_timeout', 1);

Execute a PHP script only for fixed time

I have a function which creates a socket connection and listens on a port number for HL7 messages sent by a laboratory machine via TCP.
If the lab machine is not sending anything, my listen function keeps listening. Is there a way to specify that it should listen only for say 10 seconds and then if there are no messages, an error should be thrown?
$address = '0.0.0.0';
$port = 5600;
// Create a TCP Stream socket
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
// Bind the socket to an address/port
$bind = socket_bind($sock, $address, $port);
// Start listening for connections
socket_listen($sock);
$client = socket_accept($sock);
// Read the input from the client
$input = socket_read($client, 2024);
// Strip all white spaces from input
$segs = explode("|",$input);
// Close the master sockets
$close = socket_close($sock);
This is the solution:
socket_set_option($sock,SOL_SOCKET,SO_RCVTIMEO,array("sec"=>10,"usec"=>0)); // after 10 seconds socket will destroy the connection. Also you can set and uses
This looks like the XY problem.
That the thing you want to measure acts as a client rather implies that you might want to do more than just detect an open TCP connection in your script, e.g. capture some data. Further, the underlying OS has a lot of complex, well tested, reliable and tunable mechanisms for tracking the state of connections.
While you could do as stefo91 suggests and try to manipulate receive timeout, I'm not sure if this is applied in the wait for an initial connection. A better solution would be to set the socket to non-blocking. Don't forget to either:
inject some calls to sleep()/usleep() or
use socket_select()
unless you want your script to be burning a lot of resource with nothing to do.
But depending on a lot of information you've not told us about, the right solution might be to run one script as a server, and a second as a monitor. The second could be polling/parsing the output of netstat to check the connection.

Creating PHP relay using sockets between multiple clients and servers

I've got a Python server which multiple clients connect to using sockets. At the moment one server isn't able to cope with the load so I'm looking at ways to split the clients up according to some criteria such as their username.
The intention is to put clients with usernames starting with A-G on server 1, H-P on server 2 and P-Z on server 3.
What I'm trying to do is to write a process that will listen for connections on port 45000 and will then forward those on to the appropriate server on 45001, 45002 and 45003.
At the moment, when a client connects to the original server they connect via a TCP port e.g. 45000. The server checks that they are authorised and responds on a random port with a handshake e.g. 59117, 60647 or 61573.
The response port is not specified when the client first connects so my question is, when is the value determined and how does the client know to listen on that port for the reply ?
So far I've written a PHP process which takes the data from the clients and forwards it to the appropriate server but I can't work out which port to listen on for the response back from the server. Is there some way that PHP sockets can negotiate the response port so that it can be stored in a variable in my script ?
Here's my basic connection code in PHP. I have no knowledge of Python so this is going to have to be done in PHP:
// Define remote Server
$socket=socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// Open socket on remote server to send $buf data to
socket_connect($socket, 'X.X.X.X', 40149);
echo ("Forwarding data ($buf) to $socket ....\r\n");
$bytesWritten=socket_write($socket, $buf, strlen($buf));
echo ("Wrote: $bytesWritten bytes\r\n");
// Now listen for response but this will be on another socket
// How do we know what this is ?
if (false === ($response = socket_read($socket, 16384))) {
echo ("Response: $response\r\n");
}
This is way out of my comfort zone so I may have this completely wrong but an afternoon spent Googling has turned up any answers yet.

socket_accept seems to hang on the first connection

I'm trying to make a simple listener on port 8195. When I try the following code block in PHP CLI conditions, it only shows 'Test' once, then hangs. If I delete the file 'votifier.run', the file designed to be the on/off switch, it still continues to hang. It never shows 'Client connected'.
Furthermore, if I try to connect to the host via Telnet on port 8195 while the script is running, I simply get a connection failed message. It's like it's looking for one connection and just not giving up.
// Set the IP and port to listen to
$address = 'localhost';
$port = 8195;
// Create a TCP Stream socket
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
// Bind the socket to an address/port
socket_bind($sock, $address, $port);
// Start listening for connections
socket_listen($sock);
// Loop continuously
while ( file_exists('votifier.run') ) {
echo 'Test';
$client = socket_accept($sock);
if( $client ) {
echo 'Client connected';
// Don't hang on slow connections
socket_set_timeout($client, 5);
// Send them our version
socket_write("VOTIFIER MCWEBLINK\n");
// Read the 256 byte block
$block = socket_read($client, 256);
...
The answer:
socket_accept() will usually hang until a connection is made. If a connection attempt was made, the script would continue, but because the socket was being created on localhost, it would only accept connections to it from localhost.
The fix is to use your external IP rather than 'localhost' or '127.0.0.1'. Then you can Telnet to it.
I'm just guessing here, but could it be that the address you are trying to bind to should not be a hostname?
If the socket is of the AF_INET family, the address is an IP in dotted-quad notation (e.g. 127.0.0.1).
EDIT
Ok, I've taken your script and tried to reproduce your error but couldn't. There are a couple of flaws in it but none that would cause a telnet client's connection attempt to fail.
Since none of the aforementioned applies, let's go thru the checklist one by one:
sockets module loaded/compiled
localhost does resolve to 127.0.0.1
the port isn't taken by any other application running
there's no rule of any sort of firewall that would prevent communication between the telnet client and your server
the machine which you connect from is allowed to connect to the server host (try the same host if it isn't)
the file that's being checked in the while-loop does exist
you are sure that there isn't another fatal error within your script that would prevent the snippet you posted from running
These are all the possible error sources I can think of, atm. Try fixing up the minor flaws first, then go thru the checklist.
if( $client ) {
echo 'Client connected';
// Don't hang on slow connections
socket_set_option(
$client,
SOL_SOCKET,
SO_RCVTIMEO | SO_SNDTIMEO,
array('sec' => 5, 'usec' => 0)
);
// Send them our version
socket_write($client, "VOTIFIER MCWEBLINK\n");
^^^^^^^
// Read the 256 byte block
$block = socket_read($client, 256);
You should be using threads. If the client never sends anything your code will block in the read() method. Each accepted socket should be completely handled in a new thread.
You may want to check this:
PHP Votifier example for Minecraft Topsites
It explains how the code works, it's the basic function that makes the encryption, fills up the 256 blank spaces and sends the packet too. You can work a little with it as you may want to improve it.
You can see a live demo of the running php for the plugin here: http://topg.org/test_votifier

Reusable socket

I tryed to create a socket in php and reuse it from other process.
I know this can be done with a daemon script but I want to do this without.
I created a socket and binded it to a specific port.
$sock = socket_create (AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option ($sock, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind ($sock, 'xx.xx.xx.xx', 10000);
socket_connect ($sock, $host, $port);
And from another php file I did the same thing. But the packets that I send from the 2 file are not "validated" by host. I sniffed all ports and I see that it uses same local and destination port. I don't understand where is the problem.
Can you help me with this?
It's ok in any other programming language, or any other solution for this.
Andrew
Sockets are not symmetrical. The server side listens on a specific port for a client to conect - the client does not specify the local port - only the remote port and address. Its nothing to do with the language you implement it in.
There's a very good socket server implementation available at http://www.phpclasses.org/browse/package/5758.html with examples.
C.
You can't really use persistent sockets in php. When you execute a php file, a new process is created which cannot access the variables - or sockets - of a different php process so it won't know if there already exists a socket and just creates it.

Categories