From 89ccb511444a8a1a02a848cc20d75d13f61ed620 Mon Sep 17 00:00:00 2001 From: Alexey Melnichuk Date: Tue, 25 Aug 2015 14:14:28 +0400 Subject: [PATCH] Fix. Parse ESL response more accurate. Problem with commands that do not return Content (e.g. sendevent) In this case `event_socket_request` go to busy wait cycle without chance to success. On my system it require alot process time and may take >30 sec to save one extension. --- resources/classes/EventSocket.php | 196 ++++++++++++++++++++++++++++++ resources/switch.php | 84 +++---------- 2 files changed, 213 insertions(+), 67 deletions(-) create mode 100644 resources/classes/EventSocket.php diff --git a/resources/classes/EventSocket.php b/resources/classes/EventSocket.php new file mode 100644 index 0000000000..0f4bb239fd --- /dev/null +++ b/resources/classes/EventSocket.php @@ -0,0 +1,196 @@ +content = ''; + $this->eol = "\n"; + } + + public function append($str) { + $this->content .= $str; + } + + public function read_line() { + $ar = explode($this->eol, $this->content, 2); + if (count($ar) != 2) { + return false; + } + $this->content = $ar[1]; + return $ar[0]; + } + + public function read_n($n) { + if (strlen($this->content) < $n) { + return false; + } + $s = substr($this->content, 0, $n); + $this->content = substr($this->content, $n); + return $s; + } + + public function read_all($n) { + $tmp = $this->content; + $this->content = ''; + return $tmp; + } +} + +//$b = new Buffer; +//$b->append("hello\nworld\n"); +//print($b->read_line()); +//print($b->read_line()); + +class EventSocket { + private $buffer; + private $fp; + + public function __construct($fp = false) { + $this->buffer = new Buffer; + $this->fp = $fp; + } + + public function __destructor() { + $this->close(); + } + + public function read_event() { + if (!$this->fp) { + return false; + } + + $b = $this->buffer; + $content_length = 0; + $content = Array(); + + while (true) { + while(($line = $b->read_line()) !== false ) { + if ($line == '') { + break 2; + } + $kv = explode(':', $line, 2); + $content[trim($kv[0])] = trim($kv[1]); + } + usleep(100); + + if (feof($this->fp)) { + break; + } + + $buffer = fgets($this->fp, 1024); + $b->append($buffer); + } + + if (array_key_exists('Content-Length', $content)) { + $str = $b->read_n($content['Content-Length']); + if ($str === false) { + while (!feof($this->fp)) { + $buffer = fgets($this->fp, 1024); + $b->append($buffer); + $str = $b->read_n($content['Content-Length']); + if ($str !== false) { + break; + } + } + } + if ($str !== false) { + $content['$'] = $str; + } + } + + return $content; + } + + public function connect($host, $port, $password) { + $fp = fsockopen($host, $port, $errno, $errdesc, 3); + + if (!$fp) { + return false; + } + + socket_set_blocking($fp, false); + $this->fp = $fp; + + // 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; + } + } + + // 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; + } + } + + return false; + } + + public function request($cmd) { + if (!$this->fp) { + return false; + } + + $cmd_array = explode("\n", $cmd); + foreach ($cmd_array as &$value) { + fputs($this->fp, $value."\n"); + } + fputs($this->fp, "\n"); //second line feed to end the headers + + $event = $this->read_event(); + + if (array_key_exists('$', $event)) { + return $event['$']; + } + return $event; + } + + public function reset_fp($fp = false){ + $tmp = $this->fp; + $this->fp = $fp; + return $tmp; + } + + public function close() { + if ($this->fp) { + fclose($fp); + $this->fp = false; + } + } +} + +/* +function event_socket_create($host, $port, $password) { + $esl = new EventSocket; + if ($esl->connect($host, $port, $password)) { + return $esl->reset_fp(); + } + return false; +} + +function event_socket_request($fp, $cmd) { + $esl = new EventSocket($fp); + $result = $esl->request($cmd); + $esl->reset_fp(); + return $result; +} +*/ + +// $esl = new EventSocket; +// $esl->connect('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')); diff --git a/resources/switch.php b/resources/switch.php index 753639d677..ff873d1ca7 100644 --- a/resources/switch.php +++ b/resources/switch.php @@ -110,76 +110,22 @@ function load_extensions() { load_extensions(); function event_socket_create($host, $port, $password) { - $fp = fsockopen($host, $port, $errno, $errdesc, 3); - socket_set_blocking($fp,false); - - if (!$fp) { - //error "invalid handle
\n"; - //echo "error number: ".$errno."
\n"; - //echo "error description: ".$errdesc."
\n"; + $esl = new EventSocket; + if ($esl->connect($host, $port, $password)) { + return $esl->reset_fp(); } - else { - //connected to the socket return the handle - while (!feof($fp)) { - $buffer = fgets($fp, 1024); - usleep(100); //allow time for reponse - if (trim($buffer) == "Content-Type: auth/request") { - fputs($fp, "auth $password\n\n"); - break; - } - } - return $fp; - } -} //end function + return false; +} function event_socket_request($fp, $cmd) { - if ($fp) { - $cmd_array = explode("\n",$cmd); - foreach ($cmd_array as &$value) { - fputs($fp, $value."\n"); - } - fputs($fp, "\n"); //second line feed to end the headers - - $response = ''; - $i = 0; - $content_length = 0; - while (!feof($fp)) { - $buffer = fgets($fp, 4096); - if ($content_length > 0) { - $response .= $buffer; - } - - if ($content_length == 0) { //if the content has length don't process again - if (strlen(trim($buffer)) > 0) { //run only if buffer has content - $array = explode(":", trim($buffer)); - if ($array[0] == "Content-Length") { - $content_length = trim($array[1]); - } - } - } - - if ($content_length > 0) { //is content_length set - //stop reading if all content has been read. - if (strlen($response) >= $content_length) { - break; - } - } - else { - //prevent an endless loop - if ($i > 300000) { break; } - } - $i++; - } - - return $response; - } - else { - echo "no handle"; - } + $esl = new EventSocket($fp); + $result = $esl->request($cmd); + $esl->reset_fp(); + return $result; } function event_socket_request_cmd($cmd) { - global $db, $domain_uuid, $host; + global $db; if (file_exists($_SERVER['DOCUMENT_ROOT'].PROJECT_PATH."/app/settings/app_config.php")) { $sql = "select * from v_settings "; @@ -195,9 +141,13 @@ function event_socket_request_cmd($cmd) { unset ($prep_statement); } - $fp = event_socket_create($event_socket_ip_address, $event_socket_port, $event_socket_password); - $response = event_socket_request($fp, $cmd); - fclose($fp); + $esl = new EventSocket; + if (!$esl->connect($event_socket_ip_address, $event_socket_port, $event_socket_password)) { + return false; + } + $response = $esl->request($cmd); + $esl->close(); + return $response; } function byte_convert($bytes, $decimals = 2) {