Skip to content
Snippets Groups Projects
Commit 301795dc authored by Nigel Kukard's avatar Nigel Kukard
Browse files

Much better support for non-blocking IO

parent 0f1d82ee
No related branches found
No related tags found
No related merge requests found
...@@ -60,17 +60,25 @@ ...@@ -60,17 +60,25 @@
} else { } else {
$result = stream_socket_client($target, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT); $result = stream_socket_client($target, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT);
} }
if (!$result) { if (!$result) {
return new PEAR_Error("Error connecting to $target: $errstr (code $errno)"); 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 @@ ...@@ -101,7 +109,9 @@
* @return PEAR_Error|string the frame returned by the server, or an error object * @return PEAR_Error|string the frame returned by the server, or an error object
*/ */
function request($xml) { function request($xml) {
$this->sendFrame($xml); if (PEAR::isError($res = $this->sendFrame($xml))) {
return $res;
}
return $this->getFrame(); return $this->getFrame();
} }
......
...@@ -32,24 +32,49 @@ require_once('PEAR.php'); ...@@ -32,24 +32,49 @@ require_once('PEAR.php');
*/ */
class Net_EPP_Protocol { 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 * get an EPP frame from the remote peer
* @param resource $socket a socket connected to the remote peer * @param resource $socket a socket connected to the remote peer
* @return PEAR_Error|string either an error or a string * @return PEAR_Error|string either an error or a string
*/ */
static function getFrame($socket) { static function getFrame($socket) {
// Read header
# NK: Use non-blocking IO if (PEAR::isError($hdr = Net_EPP_Protocol::_fread_nb($socket,4))) {
$hdr = ""; return $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);
}
} }
// Unpack first 4 bytes which is our length
$unpacked = unpack('N', $hdr); $unpacked = unpack('N', $hdr);
$length = $unpacked[1]; $length = $unpacked[1];
if ($length < 5) { if ($length < 5) {
...@@ -57,19 +82,8 @@ class Net_EPP_Protocol { ...@@ -57,19 +82,8 @@ class Net_EPP_Protocol {
} else { } else {
$length -= 4; // discard the length of the header itself $length -= 4; // discard the length of the header itself
// Read frame
// sometimes the socket can be buffered with a limit below the frame return Net_EPP_Protocol::_fread_nb($socket,$length);
// 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;
}
} }
} }
...@@ -79,6 +93,14 @@ class Net_EPP_Protocol { ...@@ -79,6 +93,14 @@ class Net_EPP_Protocol {
* @param string $xml the XML to send * @param string $xml the XML to send
*/ */
static function sendFrame($socket, $xml) { 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;
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment