PHP fsockopen() fails does not open port but telnet works - php

I am facing a weird network problem trying to resolve for the last 2 days. I can not get to open the port 25003 on php web page. The code does not seem to be a problem, however, its as given below.
$host = 'xx.xx.xx.xx'; // statis public ip address assigned by my isp
$ports = array(80, 25003);
foreach ($ports as $port)
{
$connection = fsockopen($host, $port);
if (is_resource($connection))
{
echo '<h2>' . $host . ':' . $port . ' ' . '(' . getservbyport($port, 'tcp') . ') is open.</h2>' . "\n";
fclose($connection);
}
else
{
echo '<h2>' . $host . ':' . $port . ' is not responding.</h2>' . "\n";
}
}
Port 80 shows open but not port 25003.
The site is hosted on Bluehost shared hosting plan with a static IP too. Cross verified with them more than 3 times the fact that port 25003 is open on both incoming and outgoing connections. Would they be lying, I don't think so.
On client PC settings :
(1) Firewall is disabled for testing purpose.
(2) Port forwarding is done correctly in router. I assume so because
I can easily telnet MY PUBLIC IP with a port 25003 within the same
LAN and from phone using sim card's internet.
(3) I did a port check from https://ping.eu/port-chk/ and it shows open.
(4) Client PC has a serproxy installed for serial to IP & Port.
(5) When I do a port check from above link, serproxy shows following message which seems to be okay on its part.
* server thread launched
* server(1) - thread started
* server(1) - EOF from sock
* server(1) - Exiting
(6) Again, when I telnet from external lan, it shows above message in Client PC's Serproxy which means it is doing its work properly. And it shows correct data from serial port to cmd line while telneting.
The problem is when I fsockopen using above pieces of code, it says CONNECTION REFUSED.
Below is my actual code which should try to connect and read data from serial port but CONNECTION REFUSED.
$fp = fsockopen("tcp://xx.xx.xx.xx", 25003, $errno, $errstr);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
if (!feof($fp)) {
$weight = trim(fgets($fp, 64)," ");
}
}
echo $weight;
fclose($fp);
I think the problem lies either in bluehost shared server or client windows PC or SERPROXY or local network configuration. I am afraid there is any major config change possible other than baud rate, com port etc in the SERPROXY which is set correctly.
I am now totally clueless as to how to resolve the said problem. If somebody could help will be greatly appreciated.
I would share the public IP if somebody wants to check the connectivity.

Like I mentioned - previously when I attempted to connect all attempts failed but both methods below now work so I'd assume the problem is fixed. I'd maybe suggest restarting the webserver and browser(s)
<?php
set_time_limit( 0 );
error_reporting( E_ALL );
$address = 'xxx.xxx.xxx.xxx';
$port = 25003;
/* Method #1 */
$fp = fsockopen( "tcp://{$address}", 25003, $errno, $errstr );
if( !$fp ) echo "$errstr ($errno)<br />\n";
else {
if( !feof( $fp ) ) {
$weight = trim(fgets($fp, 64)," ");
}
}
printf('<h1>Method #1</h1>Weight: %s<br /><br />',$weight);
fclose($fp);
/* Method #2 */
function geterror(){
$obj=new stdClass;
$obj->code=socket_last_error();
$obj->error=socket_strerror( $obj->code );
return $obj;
}
function negotiate( $socket ) {
socket_recv( $socket, $buffer, 1024, 0 );
for( $chr = 0; $chr < strlen( $buffer ); $chr++ ) {
if( $buffer[ $chr ] == chr( 255 ) ) {
$send = ( isset( $send ) ? $send . $buffer[$chr] : $buffer[$chr] );
$chr++;
if( in_array($buffer[$chr], array(chr(251), chr(252))) ) $send .= chr(254);
if( in_array($buffer[$chr], array(chr(253), chr(254))) ) $send .= chr(252);
$chr++;
$send .= $buffer[$chr];
} else {
break;
}
}
if( isset($send)) socket_send($socket, $send, strlen($send), 0);
if( $chr - 1 < strlen($buffer)) return substr($buffer, $chr);
}
$socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
try{
if( $socket && is_resource( $socket ) ){
if( !socket_connect( $socket, $address, $port ) ){
$err=geterror();
throw new Exception( sprintf( 'socket_connect: %s', $err->error ), $err->code );
} else {
while( true ){
$e=null;
$w=null;
$r = array( $socket );
$c = socket_select( $r, $w, $e, 5 );
foreach( $r as $read_socket ) {
if( $r = negotiate( $read_socket ) ) {
exit( sprintf( '<h1>Method #2</h1>Reading: %s', print_r( $r, true ) ) );
}
}
}
}
} else {
$err=geterror();
throw new Exception( sprintf( 'Failed to create socket: %s',$err->error ), $err->code );
}
}catch( Exception $e ){
printf( "
<pre>
<h1>Error: %d</h1>\nMessage: %s\nTrace: %s\nLine: %d
</pre>",$e->getCode(),$e->getMessage(),$e->getTraceAsString(),$e->getLine() );
}
socket_close( $socket );
?>

Related

Hostname was NOT found in DNS cache

One of my projects has intermittent connection problems to gateway.watsonplatform.net. It had been working fine, nothing has changed, but now, 80% of the time, it cannot find hostname in DNS Cache.
I've tried to set CURLOPT_RESOLVE option but it just prepends a line to the output about adding hostname into the cache, but then it's still not found.
I'm trying to run the project locally and I figured out it is network-specific. It works on one access point fine, on the other, it has connection issues.
And another strange hint: curl command in shell works.
There is the output:
Added gateway.watsonplatform.net:80:158.85.132.88 to DNS cache
Hostname was NOT found in DNS cache
Could not resolve host: gateway.watsonplatform.net
UPDATE:
The port should be 443, not 80. After this change, it works. After deleting whole this assignment, it still works. Now, I cannot reproduce the problem.
I had the same problem when I implement one project with IBM Watson inside one Customer. And in this case: You need to release the URL inside your Proxy network.
The reason for cURL and Nodejs calls works is because the server is calling through Firewall, and not passing for your proxy network.
Make sure if the url works when you set the proxy inside your Server: Connect advanced inside your SO (Options internet).
as a little ugly hack to get it working, you could add a hosts file alias, perhaps reinforced with a hourly cronjob to update the real IP - at the cost of the script failing for up to 1 hour every time they actually change IP? (i actually did this a couple of years back when i was facing a similar problem, i don't think i still have the source code though, ill check)
edit: i don't have the original cronjob, but it looked something like this:
<?php
declare(strict_types = 1);
$hosts = '/etc/hosts';
assert ( is_file ( $hosts ) && is_readable ( $hosts ) && is_writable ( $hosts ), 'need access to ' . $hosts );
$host = 'google.com';
$ip = getIP ( $host );
$str = file_get_contents ( $hosts );
$start = strpos ( $str, '#<wtf_cronjob>' );
$end = strpos ( $str, '#</wtf_cronjob>' );
assert ( false !== $start && false !== $end, 'invalid syntax for hosts file!' );
$end += strlen ( '#</wtf_cronjob>' );
$newstr = substr ( $str, 0, $start ) . '#<wtf_cronjob>' . "\n" . $ip . ' ' . $host . ' ' . "\n" . '#</wtf_cronjob>' . substr ( $str, $end );
file_put_contents ( $hosts, $newstr );
function getIP(string $host, string $dns = '8.8.8.8'): string {
exec ( 'host ' . escapeshellarg ( $host ) . ' ' . escapeshellarg ( $dns ) . ' 2>&1', $lines, $ret );
if ($ret !== 0) {
ob_start ();
var_dump ( $lines, $ret );
$debugstr = ob_get_clean ();
throw new \RuntimeException ( 'host failed. debuginfo: ' . $debugstr );
}
foreach ( $lines as $line ) {
if (false === stripos ( $line, 'has address ' )) {
continue;
}
// found it
$ret = trim ( substr ( $line, stripos ( $line, 'has address ' ) + strlen ( 'has address ' ) ) );
if (! filter_var ( $ret, FILTER_VALIDATE_IP )) {
throw new \RuntimeException ( 'the extracted ip address is invalid! (wrong syntax for host?)' );
}
return $ret;
}
throw new \RuntimeException ( 'could not find ip address!' );
}
with the following new lines in the hosts file:
#<wtf_cronjob>
216.58.209.142 google.com
#</wtf_cronjob>
I've tried to assign manually how the domain should be resolved. Since this step, the request is working and after deleting this assignment, it still works.

socket_recv I want readable data not byte count

Hello All hopefully you guys don't shoot me with virtual guns if already asked but, here goes.
I am socket_send to an ip/port i see the server receives and responds with data back. My code receives xxxx bytes. I want to know what those bytes entail IE: xml string back so I can parse and use the data back in my application. cURL is not doable in this situation because the server receives headers and does not respond at all.
**Code:**
/* Create a TCP/IP socket. */
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
} else {
echo "OK.\n";
}
/* Create a TCP/IP socket. */
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
} else {
echo "OK.\n";
}
echo "Attempting to connect to '$address' on port '$port'...";
$result = socket_connect($socket, $address, $port);
if ($result === false) {
echo "socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
} else {
echo "OK.\n";
}
$in = $xml;
$out = '';
echo "Sending HTTP HEAD request...";
socket_write($socket, $in, strlen($in));
echo "OK.\n";
socket_shutdown($socket, 1);
echo "Reading response:\n\n";
$buf = '';
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";
echo "OK.\n\n";
?>
Response:
TCP/IP Connection
OK. OK. Attempting to connect to 'xxx.xxx.xxx.xxx' on port '9000'...OK. Sending HTTP HEAD request...OK. Reading response: Read 1365 bytes from socket_recv(). Closing socket... OK.
Firstly, you can use cURL and not send headers! Just an fyi.
Secondly, it's going to be tricky to determine exactly what type of content it is... Is the server returning any sort of "content type"? If so, you may be able to read that.
Afterwards, you can then use $buf and then attempt to use XML libraries to parse the string (such as PHP's SimpleXML Library).
If, for example, it doesn't parse the XML, then you know it's either a regular string or something else.
cURL should return the content type, however.
After crazy headaches and several medicine hits I found the issue: 1 line OMG
If any one else gets this issue with socket the line after socket_close($socket) I added echo html_entity_decode($buf).

connect master server stream_socket_client

I wrote a script to pull a server list from the master server from Enemy Territory; However it silently fails; I had it working; but for some unknown reason it doesn't anymore.
I used this document to "talk" with the server : http://src.gnu-darwin.org/ports/games/masterserver/work/masterserver-0.4.1/docs/PROTOCOLS
This seems valid since it worked before and it still works on game servers; This is my code :
<?php
// set sv_master1 "etmaster.idsoftware.com"
// set sv_master2 "master0.gamespy.com"
// set sv_master3 "wolfmaster.idsoftware.com"
// set sv_master4 "clanservers.net"
// set sv_master5 "master0.etmaster.net" 213.108.29.23
$host = 'etmaster.idsoftware.com';
$port = '27950';
// $status = chr(255) . chr(255) . chr(255) . chr(255) . chr(0x02) . 'getservers' . chr(0x00);
$status = "\xFF\xFF\xFF\xFFgetservers\x00";
$fp = stream_socket_client("udp://" . $host . ":" . $port, $errno, $errstr, 10);
if (!$fp) {
echo "ERROR: " . $errno . $errstr . "<br>\n";
} else {
fwrite($fp, $status);
//stream_set_timeout($fp, 10); // this is for debugging;
$data = fread($fp, 1024);
fclose($fp);
print_r($data);
}
I attempted 60 seconds execution time (its localhost) but it still doesn't work ... any help is appreciated !
When I check the steps (in cli) the longest time is spend on fread(); but $data contains only an empty string;
The error is small; there had to be 5* \xFF tag; and I only used 4.

PHP SocketServer not acception more than 255 concurrent connections

I'm running a PHP (5.4.12) script on a Windows Server 2008 machine.
When the total concurrent connections hit 255, the script crashes.
On a PHP 5.2.x system the SocketServer end with an error:
"An operation was attempted on something that is not a socket."
PHP 5.4.12, does not crash but does not handle the connections anymore.
I'm using the following code, taken from the PHP.net website:
http://php.net/manual/en/sockets.examples.php
<?php
error_reporting(E_ALL);
set_time_limit(0);
ob_implicit_flush();
$address = '192.168.1.7';
$port = 8676;
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
echo "socket_create() last error " . socket_strerror(socket_last_error()) . "\n";
}
if (socket_bind($sock, $address, $port) === false) {
echo "socket_bind() last error " . socket_strerror(socket_last_error($sock)) . "\n";
}
if (socket_listen($sock, 5) === false) {
echo "socket_listen() last error " . socket_strerror(socket_last_error($sock)) . "\n";
}
$clients = array();
do {
$read = array();
$read[] = $sock;
$read = array_merge($read,$clients);
$write = NULL;
$except = NULL;
if(socket_select($read,$write , $except , $tv_sec = 5)===false)
{
echo(PHP_EOL.'\n\ncrash\n\n'.PHP_EOL);
exit();
}
if (in_array($sock, $read)) {
if (($msgsock = socket_accept($sock)) === false) {
echo "socket_accept() falló: razón: " . socket_strerror(socket_last_error($sock)) . "\n";
// break;
}
$clients[] = $msgsock;
$key = array_keys($clients, $msgsock);
$msg = "{$key[0]} welcome msg\n".PHP_EOL;
socket_write($msgsock, $msg, strlen($msg));
}
// Handle Input
foreach ($clients as $key => $client) { // for each client
if (in_array($client, $read)) {
if (false === ($buf = socket_read($client, 2048))) {
echo "socket_read() last error: " . socket_strerror(socket_last_error($client)) . "\n";
// break 2;
}
if (!$buf = trim($buf)) {
continue;
}
if ($buf == 'quit') {
$talkback = print_r($clients);
socket_write($client, $talkback, strlen($talkback));
unset($clients[$key]);
socket_close($client);
break;
}
if ($buf == 'shutdown') {
socket_close($client);
break 2;
}
$talkback = "Client {$key}: Echo: '$buf'.\n";
socket_write($client, $talkback, strlen($talkback));
echo "$buf\n";
}
}
} while (true);
socket_close($sock);
?>
I've tested the script by running "EchoServerTest.exe". I creates a number of concurrent connections.
First I thought it was a problem in WinSock, but I can't find that there is a limitation on 255 connections with WinSock.
I also changed the registry settings TcpNumConnections, TcpTimedWaitDelay and MaxUserPort.
I used the same code on a Ubuntu server, so the problem much be related to Windows.
I tested this on two different servers, both Windows Server 2008 (32bit and 64bit).
One locally and one on the internet. So firewall or other external problems should be ruled out.
I'm out of options.
Before you ask, do you really need so many connections? Yes.
There are many 'dead' connections, so I've altered the code. Now those 'dead' connection are now 'Timed-out'. So I have some time to solve this, but eventually the number of concurrent connections will reach 255 again.
Any ideas on this one?
I think the problem is in this line:
if (socket_listen($sock, 5) === false) {
You are manually restricting to 5 the number of backlog incoming connections queued for processing. In Linux this is silently truncated to SOMAXCONN, not that way on Windows. Try using SOMAXCONN instead of 5.

Writing then reading back via sockets in PHP issues

I writing a command and then reading back from a server via sockets in PHP. We have 20 servers that all run a Node JS script which can receive these commands and execute them. The Node JS script will return "ok" which PHP reads back to confirm the command has gone through.
The Node JS script listens on port 9000 and is set to allow half open.
Most of the time this works fine, but when a high volume of commands are sent we get errors back occasionally that say this:
Contents: Message received back from socket was 'Unexpected token {'
Transport endpoint is not connected
The transport endpoint message suggests to me that it has not connected successfully.
I am no expert in sockets so I don't know whether the implementation I have used is "correct". It does work most of the time but I am aware that there are functions like socket_bind and socket_listen that may work better, though I am not sure what they do.
Here is the PHP code that we are using. Any suggestions would be most appreciated.
public function sendDaemonCommand($address, $template_id, $params = array()) {
$hostname = $this->getHostnameFromPrivateIP($address);
$port = 9000;
$command = array('template_id' => $template_id, 'params' => $params);
$command = json_encode($command);
// Create a TCP Stream socket
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
$this->mailError("Command Failed - " . $hostname, "Failed to create socket on " . $address . "\n\n" . socket_strerror(socket_last_error()) . "\n\nCommand:\n\n" . $command . "\n" . $this->functionTraceback());
return false;
}
// Connect to socket
if (socket_connect($sock, $address, $port) === false) {
$this->mailError("Command Failed - " . $hostname, "Failed to connect to socket on " . $address . "\n\n" . socket_strerror(socket_last_error($sock)) . "\n\nCommand:\n\n" . $command. "\n" . $this->functionTraceback());
socket_close($sock);
return false;
}
// Write command to socket
$_command = $command;
$length = strlen($_command);
while (true) {
$sent = socket_write($sock, $_command, $length);
if ($sent === false) {
$this->mailError("Command Failed - " . $hostname, "Failed to write command to socket on " . $address . "\n\n" . socket_strerror(socket_last_error($sock)) . "\n\nCommand:\n\n" . $command. "\n" . $this->functionTraceback());
socket_shutdown($sock, 2);
socket_close($sock);
return false;
}
if ($sent < $length) {
$_command = substr($_command, $sent);
$length -= $sent;
}
else {
break;
}
}
socket_shutdown($sock, 1);
// Read back from socket
if (($out = socket_read($sock, 1024)) !== false) {
#socket_shutdown($sock, 0);
$out = trim($out);
if ($out !== "ok") {
$this->mailError("Command Failed - " . $hostname, "Message received back from socket was '" . $out . "' on " . $address . "\n\n" . socket_strerror(socket_last_error($sock)) . "\n\nCommand:\n\n" . $command. "\n" . $this->functionTraceback());
socket_close($sock);
return false;
}
}
else {
$this->mailError("Command Failed - " . $hostname, "Failed to read from socket on " . $address . "\n\n" . socket_strerror(socket_last_error($sock)) . "\n\nCommand:\n\n" . $command. "\n" . $this->functionTraceback());
socket_shutdown($sock, 0);
socket_close($sock);
return false;
}
socket_close($sock);
return $out;
}
For a simple socket client such as this, I much prefer fsockopen() - it drastically reduces the complication of the client code and does not require the sockets extension, which is not available everywhere. The main disadvantage to this is that you lose the string error messages, but these are rarely that useful anyway - you still get an error string from creating the socket, and if read/write operations fail it's because the socket has become disconnected.
I'm also not sure how useful "allow half open" is in this context - I think it is likely to create more problems than it solves. The calls to socket_shutdown() are not doing anything useful here (and may be the source of your problems) - you would only use this if you are operating on a socket that will not be closed and may be operated on at a later point in time by some other code. Since you create a new socket and destroy it in the same routine, this is not the case.
Here is your code rewritten to use fsockopen() - as you can see, it is somewhat shorter and simpler. I have also modified it slightly so that it always returns a bool - your code returns either bool FALSE or string ok, and since there are only these two options it makes more sense for the function to always return a bool.
public function sendDaemonCommand($address, $template_id, $params = array()) {
// Prepare data
$hostname = $this->getHostnameFromPrivateIP($address);
$port = 9000;
$command = array('template_id' => $template_id, 'params' => $params);
$_command = $command = json_encode($command);
$length = strlen($_command);
// Connect to socket
if (!$sock = fsockopen($address, $port, $errNo, $errStr)) {
$this->mailError("Command Failed - " . $hostname, "Failed to connect to socket on " . $address . "\n\n" . $errStr . "\n\nCommand:\n\n" . $command. "\n" . $this->functionTraceback());
return false;
}
// Write command to socket
while (true) {
// Try and write data to socket
$sent = fwrite($sock, $_command, $length);
// If it failed, error out
if ($sent === false) {
$this->mailError("Command Failed - " . $hostname, "Failed to write command to socket on " . $address . "\n\nCommand:\n\n" . $command. "\n" . $this->functionTraceback());
fclose($sock);
return false;
}
// If there is data left to send, try again
if ($sent < $length) {
$_command = substr($_command, $sent);
$length -= $sent;
continue;
}
// If we get here the write operation was successful
break;
}
// Read back from socket and close it
$out = fread($sock, 1024);
fclose($sock);
// Test the response from the server
if ($out === false) {
$this->mailError("Command Failed - " . $hostname, "Failed to read from socket on " . $address . "\n\nCommand:\n\n" . $command. "\n" . $this->functionTraceback());
return false;
} else if (($out = trim($out)) !== "ok") {
$this->mailError("Command Failed - " . $hostname, "Message received back from socket was '" . $out . "' on " . $address . "\n\nCommand:\n\n" . $command. "\n" . $this->functionTraceback());
return false;
} else {
return true;
}
}

Categories