|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #15639 detecting end of UDP packets
Submitted: 2002-02-19 22:29 UTC Modified: 2003-07-18 23:16 UTC
Avg. Score:4.4 ± 1.3
Reproduced:7 of 8 (87.5%)
Same Version:4 (57.1%)
Same OS:5 (71.4%)
From: rip at undernet dot org Assigned:
Status: Closed Package: Network related
PHP Version: 4.1.1 OS: All
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.
Block user comment
Status: Assign to:
Bug Type:
From: rip at undernet dot org
New email:
PHP Version: OS:


 [2002-02-19 22:29 UTC] rip at undernet dot org
I am using PHP for UDP stuff (to block access to users based on a DNSBL).
With TCP connections, PHP detects the end of a packet.
This feature doesn't exist while dealing with UDP but it could exist.

If I do a TCP connection and I expect 1 packet (but doesn't know it's size) I'll do this :
$fp=fsockopen ("www.stuff.mars", 80, $errno, $errstr, 30);
fputs ($fp, "GET / HTTP/1.0\r\nHost: www.stuff.mars\r\n\r\n");
echo fread ($fp,4096);
fclose ($fp);

Even if the packet isn't 4096 bytes long, it will be returned entirely until fread gets to it's end.

With UDP, the end of the packet CAN be detected but IS NOT detected, if you use fgets you get NOTHING and if you use fread you get only the number of bytes you asked for. Worst is that if you set 4096 as the length for fread, since it can't detect the end of a packet, it waits and stay stuck on it until it received 4096 bytes worst of packets.

ie :
$fp=fsockopen ("udp://boo.stuff.mars", 13, $errno, $errstr, 3);
fputs ($fp, "\n");
echo fread ($fp,4096);
fclose ($fp);

Though I think you could do even better.

ie :
$fp=fsockopen ("udp://ns.stuff.mars", 53, $errno, $errstr, 3);
fputs ($fp, $dns_packet);
while ($rcvd=fread($fp,4096)) echo ord($rcvd);
fclose ($fp);

That's technically doable...

I know that there are new socket functions and I could probably use those to do what I want to do.
But this report is just about if you want to support UDP sockets as one of the standard features of PHP, then it needs to be well done.

Thank you guys, keep up the good work.
[ I give $10000 to the first one who come up with a PHP compiler for *nix and Win. ]


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2002-02-20 06:35 UTC]
What if you set the socket in non-blocking mode?
Look for socket_set_blocking in the manual.

 [2002-02-20 06:41 UTC] rip at undernet dot org
It will kill Windows compatibility, fixing the functions is way better.
 [2002-02-20 07:02 UTC] rip at undernet dot org
In fact it's worst than that, setting the socket non-blocking makes fread not working on unix/win.
 [2002-02-20 22:42 UTC]
I'll look into UDP sockets in PHP in more detail soon.
In the meantime, I'm not sure that what you are suggesting is possible, since UDP is a connectionless protocol, how can we detect the end of a packet/stream?
UDP is supposed to be used with known packet sizes.
If you can show me some C code where what you propose works, I'll integrate it with the new PHP streams code.
 [2002-02-21 20:07 UTC] rip at undernet dot org
In C, recvfrom() takes a length argument, but behaves with UDP like fread should : "Reading stops when length bytes have been read or EOF is reached, whichever comes first."
Using recvfrom() with length set to 4096 will get the 20 bytes packets without blocking anything.
The bug has prolly something to do with the use of recv() versus recvfrom().
 [2002-03-16 12:16 UTC]
My man page says that recv is identical to recvfrom with
a NULL from parameter, so I don't see how this can fix
I still don't think this is technically possible over UDP.
If you can show me some real working C code where it works,
I will implement it.
 [2002-03-16 14:51 UTC] rip at undernet dot org
It also says it should only be used in connected sockets.
Here is a working exemple from a porky sourcecode I have :
len = recvfrom(sock, data, 50, 0, (struct sockaddr *)&sai, &s_sai);
printf("%d bytes from %s:%d - %s\n",len,inet_ntoa(sai.sin_addr),ntohs(sai.sin_port),data);
goto loop;

The default size is 50, if the UDP packet is < 50 (ie:42) it will print : 42 bytes from - This is only a test. This is only a test!!

So if you modify the recv call to a recvfrom call, it won't break TCP and will make UDP work a better way.
 [2002-04-13 18:09 UTC]
Can you try changing the FG(def_chunk_size) assignment
in the file_globals_ctor function in ext/standard/file.c
and hard-code it to 1.
Then try your UDP script.
If that solves the problem, I will add a method of
setting this from script (using set_file_buffer).
I still don't think using recvfrom will make any
 [2002-04-14 13:09 UTC] rip at undernet dot org
Doesn't seems to change anything.
 [2002-09-26 10:30 UTC]
If someone comes up with some sample C code that definitely
has the behaviour, I will implement it into PHP.
Until then this is suspended.

 [2003-05-01 17:43 UTC]
The FIRST call to recv() detects end of packet just fine.  The trouble is, php_stream_read, in its exuberance to fill the read buffer, makes a SECOND call to php_stream_fill_read_buffer, which in turn makes a SECOND call to php_sockops_read (via stream->ops->read()) and it's THAT call which is waiting for a second packet.

This is *bad* behavior for UDP read operations, is there some way we can tell php_sockop_read if this is the initial call or a subsequent backfill?
 [2003-07-18 23:16 UTC]
Wez fixed this in time for PHP 4.3.2

fread() will now act non-greedily when reading from network streams (i.e. grab the lesser of: one packet or maxlen bytes)

fgets() will continue to act greedily, but it would be inappropriate to use it with UDP streams anyway.

PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Tue Nov 30 14:03:37 2021 UTC