ID: 24101
User updated by: wzaccone at telcordia dot com
Reported By: wzaccone at telcordia dot com
-Status: Feedback
+Status: Open
Bug Type: Sockets related
Operating System: Solaris 5.8 / Sparc
PHP Version: 4.3.2
New Comment:
Here is the complete function that calls socket_select. we put some
tracing (echos) around the socket_select, and saw it never returned.
function readMsgsFromHosts($sockets){
// needs to read a "message" from each server where message has the
following format:
// STX - 1 byte
// pad bytes - 1 byte
// msg len - 2 bytes
// data - variable number of bytes
// padding - variable number of bytes - from 0 to 3
// ETX - 1 byte
set_time_limit(0);
$numSockets = count($sockets);
// the following are the available states for the sockets
$STXSTATE = 1;
$PADBYTES = 2;
$MSGLEN = 3;
$DATA = 4;
$PADDING = 5;
$ETXSTATE = 6;
$FINISHED = 7;
$STX=chr(02);
$ETX=chr(03);
$socketsPadBytes = array();
$socketsMsgLen = array();
$socketsByteCount = array();
$socketsState = array();
$dataFromSockets = array();
$keys = array_keys($sockets);
foreach ($keys as $key){
$socketsPadBytes[$key] = 0;
$socketsMsgLen[$key] = 0;
$socketsByteCount[$key] = 0;
$socketsState[$key] = $STXSTATE;
$dataFromSockets[$key] = "";
}
$finishedCount = 0;
while ($finishedCount != $numSockets){
$socketsCopy = Array();
//$keys = array_keys($sockets);
foreach ($keys as $key){
$socketsCopy[$key] = $sockets[$key];
}
if (@socket_select($socketsCopy, $w = NULL, $e = NULL, $tv = NULL)
!== FALSE){
foreach($socketsCopy as $sock){
$index = array_search($sock, $socketsCopy, true);
if ($socketsState[$index] != $FINISHED){
$readAmount = 4;
if ($socketsByteCount[$index] >= 4){
$readAmount = $socketsMsgLen[$index] -
$socketsByteCount[$index];
}
$string = fread($sock, $readAmount);
//echo "\n\n<P>Read: ".$string."(".strlen($string)."
bytes)<P>\n\n";
if ($string === FALSE){
// error while reading from socket
return array("error while reading from socket<P>");
}
else if (strlen($string) == 0){
// end of file was reached
// shouldn't happen since we use ETX to determine the end
of message
return array("Reached end of file before ETX<P>");
}
else {
// data was read from socket
while (strlen($string) > 0){
//echo "\n\nString left: " .
$string."(".strlen($string)." bytes)<P>\n\n";
if ($socketsState[$index] == $STXSTATE ||
$socketsState[$index] == ""){
// read in the STX and update state
if ($string[0] != $STX){
// error
// ignore and keep looping
}
else {
$socketsState[$index] = $PADBYTES;
$socketsByteCount[$index] = $socketsByteCount[$index]
+ 1;
}
$string = substr($string, 1);
}
else if ($socketsState[$index] == $PADBYTES){
// read in the pad bytes and update state
$socketsPadBytes[$index] = ord($string[0]);
$string = substr($string, 1);
$socketsState[$index] = $MSGLEN;
$socketsByteCount[$index] = $socketsByteCount[$index] +
1;
}
else if ($socketsState[$index] == $MSGLEN){
// read in the message length and update state
if ($socketsMsgLen[$index] == 0){
// have not yet read any msglen info
if (strlen($string) == 1){
$socketsMsgLen[$index] = ord($string[0]) * 256;
// only a partial read - don't update state
$string = substr($string, 1);
$socketsByteCount[$index] =
$socketsByteCount[$index] + 1;
}
else {
// this should be the normal occurence
$socketsMsgLen[$index] = ord($string[0]) * 256 +
ord($string[1]);
// full read
$string = substr($string, 2);
$socketsByteCount[$index] =
$socketsByteCount[$index] + 2;
$socketsState[$index] = $DATA;
}
}
else {
// this is the rest of the msg len - add to existing
number
$socketsMsgLen[$index] = $socketsMsgLen[$index] +
ord($string[0]);
$string = substr($string, 1);
$socketsByteCount[$index] = $socketsByteCount[$index]
+ 1;
$socketsState[$index] = $DATA;
}
}
else if ($socketsState[$index] == $DATA){
// read in data - if bytes read exceeds limit of data
then update state
// this should read up until $socketsMsgLen[$index] -
$socketsPadBytes[$index] - 1
if ($socketsByteCount[$index] + strlen($string) >=
$socketsMsgLen[$index] - $socketsPadBytes[$index] - 1){
// need to truncate $string
$data = substr($string, 0, $socketsMsgLen[$index] -
$socketsPadBytes[$index] - 1 - $socketsByteCount[$index]);
$string = substr($string, ($socketsMsgLen[$index] -
$socketsPadBytes[$index] - 1 - $socketsByteCount[$index]));
$socketsState[$index] = $PADDING;
}
else {
$data = $string;
$string = "";
}
$dataFromSockets[$index] = $dataFromSockets[$index] .
$data;
$socketsByteCount[$index] = $socketsByteCount[$index] +
strlen($data);
}
else if ($socketsState[$index] == $PADDING){
// read the padding bytes and update state when
finished
if ($socketsPadBytes[$index] == 0){
//either this message has no padding or some error
occured.
// lets assume that there is no padding, shall we?
$socketsState[$index] = $ETXSTATE;
}
else {
// read one byte from the string
$string = substr($string, 1);
$socketsByteCount[$index] = $socketsByteCount[$index]
+ 1;
$socketsPadBytes[$index] = $socketsPadBytes[$index] -
1;
if ($socketsPadBytes[$index] == 0){
//echo "Setting state to ETXSTATE<P>\n\n";
$socketsState[$index] = $ETXSTATE;
}
}
}
else if ($socketsState[$index] == $ETXSTATE){
//echo "Reading ETX<P>";
if ($string[0] != $ETX){
// illegal end character
// ignore and keep looping
//echo "Illegal end character"."<P>";
}
else {
$socketsState[$index] = $FINISHED;
$socketsByteCount[$index] = $socketsByteCount[$index]
+ 1;
}
$string = substr($string, 1);
// update $finishedCount variable
$finishedCount++;
}
else {
//print_r($dataFromSockets);
return array("<HR>Error: reached an undefined
state<P>");
}
}
}
}
else {
// already finished so don't read anything from this socket
}
}
}
else {
// error condition
return array("error in select<P>");
}
}
// all the sockets have been completely read
return $dataFromSockets;
}
Previous Comments:
------------------------------------------------------------------------
[2003-06-09 23:40:31] [EMAIL PROTECTED]
Could you give a complete (but short, please) script
that shows this problem clearly..? (can't reproduce, but I'm propably
missing some part here..)
------------------------------------------------------------------------
[2003-06-09 14:02:38] wzaccone at telcordia dot com
we upgraded our application from php 4.1.2 to 4.3.2 and are testing.
and found the following code no longer works:
if (@socket_select($socketsCopy, $w = NULL, $e = NULL, $tv = NULL) !==
FALSE){
foreach($socketsCopy as $sock){
The socket_select call appears to be never returning with php 4.3.2..
code worked correctly with 4.1.2.
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/?id=24101&edit=1