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 @@
} 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();
}
......
......@@ -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;
}
}
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