mirror of
https://github.com/fusionpbx/fusionpbx.git
synced 2025-12-30 00:53:50 +00:00
Event socket bug fix and more docs (#6823)
* Add documentation to methods. Use is_resource for added type detection * Allow connect to specify timeout in microseconds with default 30,000 * Update calling mechanism for event sockets * Update project for new singleton event sockets * remove unused variable * catch errors on closing the socket
This commit is contained in:
@@ -42,26 +42,43 @@ class buffer {
|
||||
//print($b->read_line());
|
||||
//print($b->read_line());
|
||||
|
||||
/**
|
||||
* Subscribes to the event socket of the FreeSWITCH (c) Event Socket Server
|
||||
* @depends buffer::class
|
||||
*/
|
||||
class event_socket {
|
||||
private $buffer;
|
||||
public $fp;
|
||||
|
||||
private static $socket = null;
|
||||
|
||||
/**
|
||||
* Create a new connection to the socket
|
||||
* @param resource|false $fp
|
||||
*/
|
||||
public function __construct($fp = false) {
|
||||
$this->buffer = new buffer;
|
||||
$this->fp = $fp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures a closed connection on destruction of object
|
||||
*/
|
||||
public function __destructor() {
|
||||
$this->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the event body from the socket
|
||||
* @return string|false Content body or false if not connected or empty message
|
||||
* @depends buffer::class
|
||||
*/
|
||||
public function read_event() {
|
||||
if (!$this->fp) {
|
||||
if (!$this->connected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$b = $this->buffer;
|
||||
$content_length = 0;
|
||||
$content = array();
|
||||
|
||||
while (true) {
|
||||
@@ -87,7 +104,7 @@ class event_socket {
|
||||
$str = $b->read_n($content['Content-Length']);
|
||||
if ($str === false) {
|
||||
while (true) {
|
||||
if (feof($this->fp)) {
|
||||
if (!$this->connected()) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -107,69 +124,67 @@ class event_socket {
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function connect($host = null, $port = null, $password = null) {
|
||||
/**
|
||||
* Connect to the FreeSWITCH (c) event socket server
|
||||
* <p>If the configuration is not loaded then the defaults of
|
||||
* host 127.0.0.1, port of 8021, and default password of ClueCon will be used</p>
|
||||
* @global array $conf Global configuration used in fusionpbx/config.conf
|
||||
* @param string $host Host or IP address of FreeSWITCH event socket server. Defaults to 127.0.0.1
|
||||
* @param string $port Port number of FreeSWITCH event socket server. Defaults to 8021
|
||||
* @param string $password Password of FreeSWITCH event socket server. Defaults to ClueCon
|
||||
* @param int $timeout_microseconds Number of microseconds before timeout is triggered on socket
|
||||
* @return bool Returns true on success or false if not connected
|
||||
*/
|
||||
public function connect($host = null, $port = null, $password = null, $timeout_microseconds = 30000) {
|
||||
|
||||
global $conf;
|
||||
|
||||
//get the database connection settings
|
||||
if (empty($host) && empty($conf['event_socket.ip_address'])) {
|
||||
$host = '127.0.0.1';
|
||||
}
|
||||
if (empty($port) && empty($conf['event_socket.port'])) {
|
||||
$port = '8021';
|
||||
}
|
||||
if (empty($password) && empty($conf['switch.event_socket.password'])) {
|
||||
$password = 'ClueCon';
|
||||
}
|
||||
|
||||
//set the event socket variables
|
||||
if (!empty($conf['switch.event_socket.host'])) {
|
||||
$host = $conf['switch.event_socket.host'];
|
||||
}
|
||||
if (!empty($conf['switch.event_socket.port'])) {
|
||||
$port = $conf['switch.event_socket.port'];
|
||||
}
|
||||
if (!empty($conf['switch.event_socket.password'])) {
|
||||
$password = $conf['switch.event_socket.password'];
|
||||
}
|
||||
//set the event socket variables in the order of
|
||||
//param passed to func, conf setting, old conf setting, default
|
||||
$host = $host ?? $conf['switch.event_socket.host'] ?? $conf['event_socket.ip_address'] ?? '127.0.0.1';
|
||||
$port = $port ?? $conf['switch.event_socket.port'] ?? $conf['event_socket.port'] ?? '8021';
|
||||
$password = $password ?? $conf['switch.event_socket.password'] ?? $conf['event_socket.password'] ?? 'ClueCon';
|
||||
|
||||
//open the socket connection
|
||||
$fp = @fsockopen($host, $port, $errno, $errdesc, 3);
|
||||
$this->fp = @fsockopen($host, $port, $errno, $errdesc, 3);
|
||||
|
||||
if (!$fp) {
|
||||
if (!$this->connected()) {
|
||||
return false;
|
||||
}
|
||||
socket_set_timeout($fp, 0, 30000);
|
||||
socket_set_blocking($fp, true);
|
||||
$this->fp = $fp;
|
||||
|
||||
socket_set_timeout($this->fp, 0, $timeout_microseconds);
|
||||
socket_set_blocking($this->fp, true);
|
||||
|
||||
//wait auth request and send response
|
||||
while (!feof($fp)) {
|
||||
$event = $this->read_event();
|
||||
if(@$event['Content-Type'] == 'auth/request'){
|
||||
fputs($fp, "auth $password\n\n");
|
||||
break;
|
||||
}
|
||||
while ($this->connected()) {
|
||||
$event = $this->read_event();
|
||||
if(($event['Content-Type'] ?? '') === 'auth/request'){
|
||||
fputs($this->fp, "auth $password\n\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//wait auth response
|
||||
while (!feof($fp)) {
|
||||
$event = $this->read_event();
|
||||
if (@$event['Content-Type'] == 'command/reply') {
|
||||
if (@$event['Reply-Text'] == '+OK accepted') {
|
||||
return $fp;
|
||||
}
|
||||
$this->fp = false;
|
||||
fclose($fp);
|
||||
return false;
|
||||
while ($this->connected()) {
|
||||
$event = $this->read_event();
|
||||
if (($event['Content-Type'] ?? '') === 'command/reply') {
|
||||
if (($event['Reply-Text'] ?? '') === '+OK accepted') {
|
||||
break;
|
||||
} else {
|
||||
$this->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return $this->connected();
|
||||
}
|
||||
|
||||
public function connected() {
|
||||
if (!$this->fp) {
|
||||
/**
|
||||
* Tests if connected to the FreeSWITCH Event Socket Server
|
||||
* @return bool Returns true when connected or false when not connected
|
||||
*/
|
||||
public function connected(): bool {
|
||||
if (!is_resource($this->fp)) {
|
||||
//not connected to the socket
|
||||
return false;
|
||||
}
|
||||
@@ -177,14 +192,27 @@ class event_socket {
|
||||
//not connected to the socket
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
//connected to the socket
|
||||
return true;
|
||||
}
|
||||
//connected to the socket
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* alias of connected
|
||||
* @return bool
|
||||
*/
|
||||
public function is_connected(): bool {
|
||||
return $this->connected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a command to the FreeSWITCH Event Socket Server
|
||||
* <p>Multi-line commands can be sent when separated by '\n'</p>
|
||||
* @param string $cmd Command to send through the socket
|
||||
* @return mixed Returns the response from FreeSWITCH or false if not connected
|
||||
* @depends read_event()
|
||||
*/
|
||||
public function request($cmd) {
|
||||
if (!$this->fp) {
|
||||
if (!$this->connected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -202,42 +230,90 @@ class event_socket {
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current socket resource returning the old
|
||||
* @param resource|bool $fp Sets the current FreeSWITCH resource
|
||||
* @return mixed Returns the original resource
|
||||
* @deprecated since version 5.1
|
||||
*/
|
||||
public function reset_fp($fp = false){
|
||||
$tmp = $this->fp;
|
||||
$this->fp = $fp;
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the socket
|
||||
*/
|
||||
public function close() {
|
||||
if ($this->fp) {
|
||||
fclose($this->fp);
|
||||
$this->fp = false;
|
||||
//fp is public access so ensure it is a resource before closing it
|
||||
if (is_resource($this->fp)) {
|
||||
try {
|
||||
fclose($this->fp);
|
||||
} catch (\Exception $t) {
|
||||
//report it
|
||||
trigger_error("event_socket failed to close socket", E_USER_WARNING);
|
||||
}
|
||||
} else {
|
||||
//log an error if fp was set to something other than a resource
|
||||
if ($this->fp !== false) {
|
||||
trigger_error("event_socket not a resource", E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
//force fp to be false
|
||||
$this->fp = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create uses a singleton design to return a connected socket to the FreeSWITCH Event Socket Layer
|
||||
* @global array $conf Global configuration used in config.conf
|
||||
* @param string $host Host or IP address of FreeSWITCH event socket server. Defaults to 127.0.0.1
|
||||
* @param string $port Port number of FreeSWITCH event socket server. Defaults to 8021
|
||||
* @param string $password Password of FreeSWITCH event socket server. Defaults to ClueCon
|
||||
* @param int $timeout_microseconds Number of microseconds before timeout is triggered on socket
|
||||
* @return self
|
||||
*/
|
||||
public static function create($host = null, $port = null, $password = null, $timeout_microseconds = 30000): self {
|
||||
//create the event socket object
|
||||
if (self::$socket === null) {
|
||||
self::$socket = new event_socket();
|
||||
}
|
||||
//attempt to connect it
|
||||
if(!self::$socket->connected()) {
|
||||
self::$socket->connect($host, $port, $password, $timeout_microseconds);
|
||||
}
|
||||
return self::$socket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a command on the socket blocking for a response
|
||||
* @param string $cmd
|
||||
* @return string|false Response from server or false if failed
|
||||
*/
|
||||
public static function command(string $cmd) {
|
||||
return self::create()->request($cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an API command on the socket
|
||||
* @param string $api_cmd
|
||||
* @return string|false Response from server or false if failed
|
||||
*/
|
||||
public static function api(string $api_cmd) {
|
||||
return self::command('api '.$api_cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an API command to FreeSWITCH using asynchronous (non-blocking) mode
|
||||
* @param string $cmd API command to send
|
||||
* @returns string $job_id the Job ID for tracking completion status
|
||||
*/
|
||||
public static function async(string $cmd) {
|
||||
return self::command('bgapi '.$cmd);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
function event_socket_create($host, $port, $password) {
|
||||
$esl = new event_socket;
|
||||
if ($esl->connect($host, $port, $password)) {
|
||||
return $esl->reset_fp();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function event_socket_request($fp, $cmd) {
|
||||
$esl = new event_socket($fp);
|
||||
$result = $esl->request($cmd);
|
||||
$esl->reset_fp();
|
||||
return $result;
|
||||
}
|
||||
*/
|
||||
|
||||
// $esl = new event_socket;
|
||||
// $esl->connect('127.0.0.1', 8021, 'ClueCon');
|
||||
// $esl = event_socket::create('127.0.0.1', 8021, 'ClueCon');
|
||||
// print($esl->request('api sofia status'));
|
||||
|
||||
// $fp = event_socket_create('127.0.0.1', 8021, 'ClueCon');
|
||||
// print(event_socket_request($fp, 'api sofia status'));
|
||||
|
||||
?>
|
||||
|
||||
Reference in New Issue
Block a user