php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #66266 socket_sendto always returns true
Submitted: 2013-12-12 00:51 UTC Modified: 2021-06-22 14:23 UTC
Votes:3
Avg. Score:3.0 ± 1.6
Reproduced:0 of 1 (0.0%)
From: chuck at jumis dot com Assigned: cmb (profile)
Status: Closed Package: Sockets related
PHP Version: 5.4.22 OS: Darwin Kernel Version 13.0.0
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: chuck at jumis dot com
New email:
PHP Version: OS:

 

 [2013-12-12 00:51 UTC] chuck at jumis dot com
Description:
------------
This always returns true, and the full amount of bytes, even when the remote port is closed. Running socket_recvfrom simply results in an Unavailable error.

This is in contrast to running something like socat which will return an error after sending data. Note that the manual does say that UDP connections should return an error following socket_sendto.

I've not been able to find a work-around. At present I simply can not test if the target UDP port is open. May be an ICMP issue.

Test script:
---------------
$fp = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
$bytes = socket_sendto($fp, $json."\n", strlen($json)+1, 0, $ip, $port);

$fp && $bytes > 0 && socket_last_error($fp) == 0;

Expected result:
----------------
When the remote UDP port is closed, socket_sendto should return false or otherwise socket_recvfrom should return false.

Actual result:
--------------
The socket pointer and socket_sendto return true -- it is not distinguishable whether or not the remote UDP port is open.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2013-12-12 02:34 UTC] phpmpan at mpan dot pl
This is a correct and expected behaviour. Please read some introduction to UDP. Wikipedia provides basic information on that matter: <https://en.wikipedia.org/wiki/User_Datagram_Protocol>.

UDP is connectionless (hence there is no such thing as "UDP connection"), fire-and-forget protocol. There is no way to tell if the data was delivered, if it was delivered uncorrupted and sendto can not detect such condition. If you require such functionality, use TCP or proper application-level protocol. However, if you require to know synchronously that a particular packet was not delivered, only application-level protocol will do, and it will be extremely slow (even way below 1kB/s).

It is possible to implement closed-port detection. If the remote machine cooperates and no devices on the route block it, one may receive ICMP type 3 code 3 packet. This is how network scanners and few other applications work. However, such solution is unsuitable for sendto as it requires wating for the mentioned packet. Also it may only detect errors: no-error conditions may be false positives.

Also the documentation for `socket_sendto` contains no information you have written about.
 [2013-12-12 04:26 UTC] chuck at jumis dot com
Well let's expand things a little. "fsockopen" has the note about UDP.

"UDP sockets will sometimes appear to have opened without an error, even if the remote host is unreachable. The error will only become apparent when you read or write data to/from the socket."

And let's expand things a little with ICMP. e.g. "closed-port detection" for the UDP socket type in a non-root environment, functioning on OS X.

Is that reasonable? It seems reasonable to me.
 [2013-12-12 06:01 UTC] phpmpan at mpan dot pl
If it works in non-root environment then either binary has setuid flag set or the application is doing UDP ping, which requires only SOCK_DGRAM, not SOCK_RAW. But it is also not true ICMP ping. See man page for icmp(4) on MacOS X. mtr provides such functionality too (-u option or "u" key in curses mode).

As to `fsockopen`: the note is true. The function may not detect the condition, as it performs no communication with the remote machine. The error may become apparent only when you perform the communication: you'll not receive responses from the remote. _If_ the underlying sockets implementation is detecting ICMPs it _may_ give a warning. For example the Linux IP stack does this and you may sometimes receive 111 even with UDP. However, the errno is set only on the next write attempt and only if the ICMP packet is actually received (which implies it is ever sent by the remote). This is why you may receive warnings from `php_sockop_write` (main/streams/xp_socket.c). However it is using `send`, not `sendto`. As for `sendto`... I don't remember encountering 111 with it, so either it's not doing this, it's very rare for it to produce ECONNREFUSED or I have bad memory.

Anyway: PHP's `socket_sendto` is jut a plain wrapper around system `sendto`. It does nothing except translating arguments and then passing return value. See the source. Actually whole sockets extension is actually more or less a simple wrapper around POSIX sockets. Hence this bug report (or rather a feature request) belongs to various operating systems dev boards, not PHP.
 [2013-12-12 06:18 UTC] chuck at jumis dot com
The note about multiple sendto calls is interesting. I had some struggle with a subsequent recvfrom which may-or-may not be an artifact of that behavior.

The wording on fsockopen is a little more ambiguous perhaps than it should be: it sounds like the behavior for write is undefined (varies across OS).

I'd hoped I could use recvfrom; no luck there. Feel free to close this bug report.
 [2021-06-22 14:23 UTC] cmb@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: cmb
 [2021-06-22 14:23 UTC] cmb@php.net
I agree that this ticket can be closed.  A PR[1] regarding the
documentation would be welcome, though.

[1] <https://github.com/php/doc-en/pulls>
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Mar 19 09:01:30 2024 UTC