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

Reply via email to