I'm having a problem getting the following code to work properly.
There's a few things that are causing problems. One, I am trying to emulate linked lists from C in PHP because I want to be able to handle as many descriptors as I want. I don't think that is working right.
Second, I want to be able to handle multiple incoming persistent connections at once. I know how to do all this using C, yet I'm having a very difficult time getting this server script to work properly.
<?
// Turn on detailed error reporting.
error_reporting (E_ALL);
// Allow the script to hang around waiting for connections.
set_time_limit (0);
// Define some constants and global variables.
define("DAEMON_ADDRESS", "127.0.0.1");
define("DAEMON_PORT", 4001);
define("_LISTEN_BACKLOG", 20);
define("_MAX_CONNECTIONS", 25);
class DESCRIPTOR {
var $nextObj = null;
var $descriptor = -1;
var $inBuf = "";
var $outBuf = "";
function DESCRIPTOR($desc) {
$this->descriptor = $desc;
return;
}
function setInBuf($inBuf) {
$this->inBuf = $inBuf;
return;
}
function getInBuf() {
return $this->inBuf;
}
function appendInBuf($buf) {
$this->inBuf = $this->inBuf . $buf;
return;
}
function setOutBuf($outBuf) {
$this->outBuf = $outBuf;
return;
}
function appendOutBuf($buf) {
$this->outBuf = $this->outBuf . $buf;
return;
}
function clearOutBuf() {
$this->outBuf = "";
return;
}
function clearInBuf() {
$this->inBuf = "";
return;
}
function getOutBuf() {
return $this->outBuf;
}
function close() {
$this->inBuf = "";
$this->outBuf = "";
close($this->descriptor);
return;
}
function readDescriptor() {
echo("Reading from descriptor " . $this->descriptor . ".\n");
$nRead = read($this->descriptor, $buf, 2048);
if ($nRead > 0) {
$this->appendInBuf($buf);
} else if ($nRead == 0) {
echo("read(): EOF encountered on read");
return false;
} else {
echo "read() failed for descriptor " . $this->descriptor . ": reason: " . strerror($nRead) . "\n";
return false;
}
return true;
}
function readInBuf() {
echo("Reading InBuf\n");
$argument = trim($this->getInBuf());
if ($argument == "") {
return false;
}
echo("ReadInBuf: $argument\n");
return true;
}
function processOutput() {
echo("Processing Output\n");
if ($this->writeDescriptor($this->descriptor, $this->getOutBuf()) == false) {
return false;
}
return true;
}
function writeDescriptor($buf) {
echo("Low level writing to descriptor\n");
if (write($this->descriptor, $buf, strlen($buf)) == false) {
return false;
}
return true;
}
}
function remove_from_list($list, $obj) {
if ($list == $obj) {
$list = $obj->nextObj;
} else {
$prev = null;
for ($prev = $list; $prev != 0; $prev = $prev->nextObj) {
if ($prev->nextObj == $obj) {
$prev->nextObj = $obj->nextObj;
break;
}
}
if ($prev == 0) {
echo("Remove_from_list: object not found in list.");
return;
}
}
}
function interpret($desc, $argument) {
if ($argument == "shutdown") {
$bMainLoop = false;
}
return;
}
function init_descriptor($descriptor, $descriptor_list) {
echo("Initializing incoming descriptor " . $descriptor . ".\n");
$desc = new DESCRIPTOR($descriptor);
if ($descriptor_list == null) {
$descriptor_list = $desc;
} else {
$desc->nextObj = $descriptor_list;
$descriptor_list = $desc;
}
$desc->writeDescriptor("CONNECT OK\n");
return $desc;
}
function free_descriptor($desc) {
unset($desc);
return;
}
$descriptor_list = null;
// Open the socket
if (($ioSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
die("socket() failed: reason: " . strerror ($ioSocket) . "\n");
}
if (($ret = setsockopt($ioSocket, SOL_SOCKET, SO_REUSEADDR, 1)) < 0) {
die("setsockopt() failed: reason: " . strerror ($ioSocket) . "\n");
}
if (($ret = set_nonblock($ioSocket)) < 0) {
die("set_nonblock() failed: reason: " . strerror ($ioSocket) . "\n");
}
// Bind the open socket to an address and port
if (($ret = bind ($ioSocket, DAEMON_ADDRESS, DAEMON_PORT)) < 0) {
die("bind() failed: reason: " . strerror ($ret) . "\n");
}
// Enable the socket to listen for connections
if (($ret = listen ($ioSocket, _LISTEN_BACKLOG)) < 0) {
die("listen() failed: reason: " . strerror ($ret) . "\n");
}
/
Run the main loop -
Checks for connections, initializes new descriptors, reads input from all
open descriptors, processes input, and returns output, then starts over.
/
$bMainLoop = true;
do {
if (($descriptor = accept_connect($ioSocket)) > 0) {
init_descriptor($descriptor, $descriptor_list);
}
for ($desc = $descriptor_list; $desc != null; $desc = $desc_next) {
$desc_next = $desc->nextObj;
echo("loop 1\n");
if ($desc->readDescriptor() == false) {
remove_from_list($descriptor_list, $desc);
free_descriptor($desc);
continue;
}
if ($desc->readInBuf() == true) {
interpret($desc, $desc->getInBuf());
}
$desc->clearInBuf();
}
for ($desc = $descriptor_list; $desc != null; $desc = $desc_next) {
$desc_next = $desc->nextObj;
echo("loop 2\n");
if ($desc->processOutput() == false) {
remove_from_list($descriptor_list, $desc);
free_descriptor($desc);
continue;
}
$desc->clearOutBuf();
}
// Sleep for a bit so we don't take up too much CPU.
usleep(100000);
} while ($bMainLoop == true);
close($ioSocket);
?>