diff --git a/app/sip_status/cmd.php b/app/sip_status/cmd.php index 817085ba4e..071c9bd55b 100644 --- a/app/sip_status/cmd.php +++ b/app/sip_status/cmd.php @@ -50,6 +50,26 @@ $profile_name = $database->select($sql, $parameters, 'column'); unset($sql, $parameters); +//get the port from sip profile name + $sql = "select sip_profile_setting_value from v_sip_profile_settings "; + $sql .= "where sip_profile_uuid = (select sip_profile_uuid from v_sip_profiles where sip_profile_name = :profile_name limit 1) "; + $sql .= "and sip_profile_setting_name = 'sip-port' "; + $sql .= "and sip_profile_setting_enabled = 'true' "; + $sql .= "limit 1"; + $parameters['profile_name'] = $profile; + $profile_port = $database->select($sql, $parameters, 'column'); + unset($sql, $parameters); + +//get the tls port from sip profile name + $sql = "select sip_profile_setting_value from v_sip_profile_settings "; + $sql .= "where sip_profile_uuid = (select sip_profile_uuid from v_sip_profiles where sip_profile_name = :profile_name limit 1) "; + $sql .= "and sip_profile_setting_name = 'tls-sip-port' "; + $sql .= "and sip_profile_setting_enabled = 'true' "; + $sql .= "limit 1"; + $parameters['profile_name'] = $profile; + $profile_tls_port = $database->select($sql, $parameters, 'column'); + unset($sql, $parameters); + //validate the gateway if (!empty($_GET['gateway']) && is_uuid($_GET['gateway'])) { $gateway_name = $_GET['gateway']; @@ -62,6 +82,9 @@ break; case "start": $command = "sofia profile '".$profile_name."' start"; + //ensure there are no stuck ports before trying to start the profile + force_close_port($profile_port); + force_close_port($profile_tls_port); break; case "stop": $command = "sofia profile '".$profile_name."' stop"; diff --git a/resources/switch.php b/resources/switch.php index e397d88346..7fe60e8f71 100644 --- a/resources/switch.php +++ b/resources/switch.php @@ -1082,4 +1082,56 @@ if(!function_exists('win_find_php')) { } } +/** + * Forces a port to close using the debugger tool. + * Linux OSes do not have an easy mechanism for closing a port already in use. This uses a debugger tool + * to connect to the running freeswitch process and close the port internally using debug symbols. This + * function requires freeswitch to be compiled with the --enable-debug flag. + * @param string $port + * @return void + */ +function force_close_port(string $port): void { + //ensure we can execute cli tools needed + if (PHP_OS !== 'Linux' || PHP_OS !== 'FreeBSD') { + return; + } + + //get the pid of freeswitch + $pid = exec('pidof freeswitch'); + + //ensure it is numeric before proceeding + if (!is_numeric($pid)) { + return; + } + + //get a list of the current connections owned by freeswitch + $connections = ""; + exec("lsof -np {$pid} | grep TCP", $connections); + exec("lsof -np {$pid} | grep UDP", $connections); + + //iterate over all the current ports + foreach ($connections as $conn) { + //seperate in to fields removing empty ones + $fields = array_values(array_filter(explode(" ", $conn), function ($value) { + if (!empty($value)) return true; + else return false; + })); + //remove letter from id + $id = substr($fields[3], 0, strlen($fields[3]) - 1); + //get the address and port parts + $elements = explode(":", $fields[8]); + //get the port from last element as IPv6 can have more than one ':' + $p = array_pop($elements); + //check for lsof renaming port 5060 to sip + if (!is_numeric($p) && $p == "sip") { + $p = "5060"; + } + //check for matching port + if ($p == $port) { + //execute debugger to close the open connection + exec("gdb -p {$pid} -batch 'call close({$id})' -batch 'quit'"); + } + } +} + ?>