<?php
$INC = isset($INC) ? $INC : dirname(__FILE__);
$rg_conns = array();
$rg_events = array('r' => array(), 'w' => array());
/*
* Prepares a string to be sent over a socket
*/
function rg_conn_prepare($s)
{
if (is_array($s))
$s = serialize($s);
return addcslashes($s, "\n\r\\");
}
/*
* Shutts down a connection
*/
function rg_conn_shutdown($key, $what)
{
global $rg_conns;
if (!isset($rg_conns[$key]['socket']))
return;
if (!is_resource($rg_conns[$key]['socket']))
return;
@socket_shutdown($rg_conns[$key]['socket'], $what);
rg_log($key . ': shutdown ' . $what);
}
/*
* Destroys a connection
*/
function rg_conn_destroy($key)
{
global $rg_conns;
global $rg_events;
if (!isset($rg_conns[$key]))
rg_internal_error('key not defined!');
if ($rg_conns[$key]['exit_on_close'])
exit(1);
if (isset($rg_conns[$key]['func_destroy']))
$rg_conns[$key]['func_destroy']($key);
if (isset($rg_events['r'][$key]))
unset($rg_events['r'][$key]);
if (isset($rg_events['w'][$key]))
unset($rg_events['w'][$key]);
if (isset($rg_conns[$key]['socket']))
if (is_resource($rg_conns[$key]['socket']))
@socket_close($rg_conns[$key]['socket']);
unset($rg_conns[$key]);
}
/*
* Registers a new socket
*/
function rg_conn_new($key, $socket)
{
global $rg_conns;
global $rg_events;
$ip = '?';
$port ='?';
if (strcmp($key, 'master') != 0)
@socket_getpeername($socket, $ip, $port);
$rg_conns[$key] = array(
'socket' => $socket,
'recv' => '',
'send' => '',
'itime' => time(),
'exit_on_close' => 0,
'func_error' => 'rg_conn_func_error',
'func_close' => 'rg_conn_func_close',
'ip' => $ip,
'port' => $port
);
$rg_events['r'][$key] = $socket;
socket_set_nonblock($socket);
}
/*
* Enqueues data to a socket
*/
function rg_conn_enq($key, $buf)
{
global $rg_conns;
global $rg_events;
$s = &$rg_conns[$key];
$s['send'] .= $buf;
$rg_events['w'][$key] = $s['socket'];
}
/*
* Called when a socket is ready to send data
*/
function rg_conn_send($key)
{
global $rg_conns;
global $rg_events;
$s = &$rg_conns[$key];
rg_log('SEND: ' . $s['send']);
$r = @socket_send($s['socket'], $s['send'], strlen($s['send']), 0);
if ($r === FALSE) {
rg_log('Cannot send: ' . socket_strerror(socket_last_error()));
$s['func_error']($key);
rg_conn_destroy($key);
return FALSE;
}
$s['send'] = substr($s['send'], $r);
if (empty($s['send']))
unset($rg_events['w'][$key]);
return $r;
}
/*
* Called when a socket is ready to be read
*/
function rg_conn_recv($key)
{
global $rg_conns;
global $rg_events;
$s = &$rg_conns[$key];
if (isset($s['func_new'])) {
$client = @socket_accept($s['socket']);
if ($client === FALSE) {
rg_log($key . ':Cannot accept!');
return;
}
if (isset($s['func_new_arg']))
$arg = $s['func_new_arg'];
else
$arg = FALSE;
socket_set_nonblock($client);
$c = intval($client);
rg_conn_new($c, $client);
$s['func_new']($c, $arg);
return;
}
$r = @socket_recv($s['socket'], $buf, 4096, 0);
if ($r === FALSE) {
rg_log($key . ':Cannot receive (err): ' . socket_strerror(socket_last_error()));
$s['func_error']($key);
rg_conn_destroy($key);
return FALSE;
}
if ($r === 0) {
rg_log($key . ':Cannot receive (0): ' . socket_strerror(socket_last_error()));
$s['func_close']($key);
rg_conn_destroy($key);
return FALSE;
}
rg_log('RECV: ' . $buf);
$s['recv'] .= $buf;
if (isset($s['func_data'])) {
$s['func_data']($key);
return;
}
if (!isset($s['func_cmd'])) {
rg_log_ml($key . ': s: ' . print_r($s, TRUE));
rg_log($key . ':Neither func_data nor func_cmd present!');
return;
}
while (1) {
$pos = strpos($s['recv'], "\n");
if ($pos === FALSE)
break;
$cmd = substr($s['recv'], 0, $pos);
$s['recv'] = substr($s['recv'], $pos + 1);
$s['func_cmd']($key, $cmd);
}
}
/*
* Function that waits for activity and calls different functions
*/
function rg_conn_wait($timeout)
{
global $rg_conns;
global $rg_events;
$r2 = $rg_events['r'];
$w2 = $rg_events['w'];
$e2 = array();
$r = @socket_select($r2, $w2, $e2, $timeout);
if ($r === FALSE) {
rg_log('Cannot select: ' . socket_strerror(socket_last_error()));
return;
}
if ($r === 0)
return;
if (!empty($r2))
rg_log_ml('read events: ' . print_r($r2, TRUE));
foreach ($r2 as $key => $sock)
rg_conn_recv($key);
if (!empty($w2))
rg_log_ml('write events: ' . print_r($w2, TRUE));
foreach ($w2 as $key => $sock)
rg_conn_send($key);
if (!empty($e2))
rg_log_ml('error events: ' . print_r($e2, TRUE));
foreach ($e2 as $key => $sock)
rg_conn_destroy($key);
}
/*
* Generic function called when there is an error on a socket
*/
function rg_conn_func_error($key)
{
}
/*
* Generic function called when a socket closes
*/
function rg_conn_func_close($key)
{
}
?>