php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #64803 async stream_socket_client return
Submitted: 2013-05-09 18:27 UTC Modified: 2023-05-08 16:59 UTC
Votes:2
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: rdlowrey at gmail dot com Assigned: bukka (profile)
Status: Duplicate Package: Streams related
PHP Version: 5.4.15 OS: Fedora 17
Private report: No CVE-ID: None
 [2013-05-09 18:27 UTC] rdlowrey at gmail dot com
Description:
------------
Normally when creating a client socket connection asynchronously you have to wait 
until the socket stream can be selected as writable to determine whether or not 
the connection succeeded. However, when connecting to a nonexistent server on the 
loopback address there is no way to differentiate between a failed connection and 
a successful connection using the STREAM_CLIENT_ASYNC_CONNECT flag.

The example code connects to a nonexistent server so it should always fail. PHP 
reports the connection as having succeeded and it's not until you actually 
attempt to read or write to the socket stream that you can get an accurate 
`feof()` return value.

Test script:
---------------
<?php
$uri = '127.0.0.1:9000'; // <-- NOTHING LISTENING ON THIS PORT!
$flags = STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT;
$socket = stream_socket_client($uri, $errNo, $errStr, $timeout=42, $flags);

usleep(50000); // just in case

var_dump($socket); // resource(5) of type (stream)

$w = [$socket];
$r = $e = [];
if (stream_select($r, $w, $e, 0, 0)) {
    $selectedSock = current($w);
    var_dump($selectedSock); // resource(5) of type (stream) ... says it's writable, BUT IT CAN'T POSSIBLY BE WRITABLE
}

$r = [$socket];
$w = $e = [];
if (stream_select($r, $w, $e, 0, 0)) {
    $selectedSock = current($r);
    var_dump($selectedSock); // resource(5) of type (stream) ... says it's readable, let's check for EOF
}

usleep(50000); // just in case

$isFeof = feof($selectedSock);
var_dump($isFeof); // bool(false) ... not EOF ... WTF?

var_dump(fread($selectedSock, 8192)); // string(0) ""

var_dump(feof($selectedSock)); // bool(TRUE) -- Now we know the truth!

Expected result:
----------------
feof($socket) on an asynchronously connected socket stream should return TRUE if 
the connection attempt failed once the socket becomes "writable."

Actual result:
--------------
It's not possible to determine if the connection attempt failed without first 
attempting to read/write to/from the socket stream.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2023-05-08 16:59 UTC] bukka@php.net
-Status: Open +Status: Duplicate -Type: Bug +Type: Feature/Change Request -Assigned To: +Assigned To: bukka
 [2023-05-08 16:59 UTC] bukka@php.net
I have done some debugging of this and the way how stream_select works is expected because it matches the C behavior. The connect man page even specifies that it is necessary to use select / poll after the async connect (connect on non blocking socket). Basically when the async connect is done, then it might return EINPROGRESS and if that happens it is marked as successful and the user should use select to wait for finishing of the operation. The problem is that there is no way to get socket error info. It means calling 

getsockopt(fd, SOL_SOCKET, SO_ERROR, ...)

It would need some function like stream_socket_last_error(). This is actually already requested in https://bugs.php.net/bug.php?id=34380 and after just reading comments, it even specifies this issue so marking this as a duplicate.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Feb 29 06:01:28 2024 UTC