diff --git a/modules/registrars/cozaepp/Net/EPP/Client.php b/modules/registrars/cozaepp/Net/EPP/Client.php index 84208d08f1398ac4939f21e2ac3288a2ac8a3a3d..7ba2c22e5d19cc824ad9e151dcaed32de72ee981 100644 --- a/modules/registrars/cozaepp/Net/EPP/Client.php +++ b/modules/registrars/cozaepp/Net/EPP/Client.php @@ -60,17 +60,25 @@ } else { $result = stream_socket_client($target, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT); - } if (!$result) { return new PEAR_Error("Error connecting to $target: $errstr (code $errno)"); - } else { - $this->socket = $result; - return $this->getFrame(); + } + + // Set our socket + $this->socket = $result; + // Set stream timeout + if (!stream_set_timeout($this->socket,$timeout)) { + return new PEAR_Error("Failed to set timeout on socket: $errstr (code $errno)"); + } + // Set blocking + if (!stream_set_blocking($this->socket,0)) { + return new PEAR_Error("Failed to set blocking on socket: $errstr (code $errno)"); } + return $this->getFrame(); } /** @@ -101,7 +109,9 @@ * @return PEAR_Error|string the frame returned by the server, or an error object */ function request($xml) { - $this->sendFrame($xml); + if (PEAR::isError($res = $this->sendFrame($xml))) { + return $res; + } return $this->getFrame(); } diff --git a/modules/registrars/cozaepp/Net/EPP/Protocol.php b/modules/registrars/cozaepp/Net/EPP/Protocol.php index 3574a4501b6b76868359cd970bd1cc3df6747efe..b12f481268872d099f2e75122cba73886082bc24 100644 --- a/modules/registrars/cozaepp/Net/EPP/Protocol.php +++ b/modules/registrars/cozaepp/Net/EPP/Protocol.php @@ -32,24 +32,49 @@ require_once('PEAR.php'); */ class Net_EPP_Protocol { + static function _fread_nb($socket,$length) { + $result = ''; + + // Loop reading and checking info to see if we hit timeout + $info = stream_get_meta_data($socket); + while (!$info['timed_out'] && !feof($socket)) { + // Try read remaining data from socket + $buffer = @fread($socket,$length - strlen($result)); + // If the buffer actually contains something then add it to the result + if ($buffer !== false) { + $result .= $buffer; + // If we hit the length we looking for, break + if (strlen($result) == $length) { + break; + } + } else { + // Sleep 0.25s + usleep(2500); + } + // Update metadata + $info = stream_get_meta_data($socket); + } + + // Check for timeout + if ($info['timed_out']) { + return new PEAR_Error('Timeout while reading data from socket'); + } + + return $result; + } + /** * get an EPP frame from the remote peer * @param resource $socket a socket connected to the remote peer * @return PEAR_Error|string either an error or a string */ static function getFrame($socket) { - - # NK: Use non-blocking IO - $hdr = ""; - while (strlen($hdr) < 4) { - if (@feof($socket)) return new PEAR_Error('Connection closed (socket is EOF)'); - if (($hdrstr = @fread($socket,4 - strlen($hdr))) !== false) { - $hdr .= $hdrstr; - } else { - return new PEAR_ERROR('Error reading from socket:'.$php_errormsg); - } + // Read header + if (PEAR::isError($hdr = Net_EPP_Protocol::_fread_nb($socket,4))) { + return $hdr; } + // Unpack first 4 bytes which is our length $unpacked = unpack('N', $hdr); $length = $unpacked[1]; if ($length < 5) { @@ -57,19 +82,8 @@ class Net_EPP_Protocol { } else { $length -= 4; // discard the length of the header itself - - // sometimes the socket can be buffered with a limit below the frame - // length, so we continually read from the socket until we get the full frame: - $frame = ''; - while (strlen($frame) < $length) $frame .= fread($socket, ($length)); - - if (strlen($frame) > $length) { - return new PEAR_Error(sprintf("Frame length (%d bytes) doesn't match header (%d bytes)", strlen($frame), ($length))); - - } else { - return $frame; - - } + // Read frame + return Net_EPP_Protocol::_fread_nb($socket,$length); } } @@ -79,6 +93,14 @@ class Net_EPP_Protocol { * @param string $xml the XML to send */ static function sendFrame($socket, $xml) { - fwrite($socket, pack('N', (strlen($xml)+4)).$xml); + // Grab XML length & add on 4 bytes for the counter + $length = strlen($xml) + 4; + $res = fwrite($socket, pack('N',$length) . $xml); + // Check our write matches + if ($length != $res) { + return new PEAR_Error("Short write when sending XML"); + } + + return $res; } }