Skip to content

Commit 89d9616

Browse files
committed
feat(sip): add parallel -TLS endpoint, drop UseWebRTC/UseSipTls flags
Generates a third per-extension PJSIP endpoint [<num>-TLS] alongside the existing [<num>] (UDP/TCP) and [<num>-WS] (WebRTC). Dial fanout wires all three contact buckets so an incoming call rings any registered transport; BLF hints and DEVICE_STATE checks cover all variants. Auth is shared via the existing [<num>-AUTH] — one credential pair across UDP/TCP/WS/TLS. Generation is gated by certificate presence (SslCertificateService probe cached behind SIPConf::hasCertificates() + resetCertsCache() so long-running workers pick up freshly issued certs). The previous UseWebRTC and the new UseSipTls global flags are removed entirely from PbxSettings, REST schema, GeneralSettings form and Volt — controlled by cert availability alone. Fixes a latent dialplan parser bug in [set-dial-contacts]: variables containing ':' (PJSIP_DIAL_CONTACTS URIs) must stay outside ${IF(?:)} since IF treats ':' as the true/false separator and silently truncates the URI. Bucket join now uses the safe ${VAR}${IF(both?&)}${OTHER} pattern. Switches the [messages] MessageSend From normalization from REPLACE (per-character set removal) to STRREPLACE (substring removal) so the suffix strip no longer mangles arbitrary 'W', 'S', 'T', 'L' bytes in SIP From URIs. REST API: AbstractExtensionStatusAction now emits 'is_tls' alongside 'is_webrtc' so CTI/UI can distinguish TLS-registered contacts. Removes the UseWebRTC key from PBXCoreREST/Lib/GeneralSettings DataStructure (breaking change in v3 schema — clients sending PUT with that key now receive 422).
1 parent 9f9610d commit 89d9616

15 files changed

Lines changed: 175 additions & 61 deletions

File tree

src/AdminCabinet/Forms/GeneralSettingsEditForm.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,6 @@ public function initialize($entity = null, $options = null): void
167167
break;
168168
case PbxSettings::PBX_RECORD_CALLS:
169169
case PbxSettings::PBX_RECORD_CALLS_INNER:
170-
case PbxSettings::USE_WEB_RTC:
171170
case PbxSettings::AJAM_ENABLED:
172171
case PbxSettings::AMI_ENABLED:
173172
case PbxSettings::ARI_ENABLED:

src/AdminCabinet/Views/GeneralSettings/sip.volt

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,6 @@
3838
{{ form.render('SIPAuthPrefix') }}
3939
</div>
4040
</div>
41-
<div class="field">
42-
<div class="ui segment">
43-
<div class="ui toggle checkbox">
44-
<label for="UseWebRTC">{{ t._('gs_UseWebRTC') }}
45-
<i class="small info circle icon field-info-icon"
46-
data-field="UseWebRTC"></i>
47-
</label>
48-
{{ form.render('UseWebRTC') }}
49-
</div>
50-
</div>
51-
</div>
5241

5342
<h4 class="ui header">{{ t._('gs_KeepAliveHeader') }}</h4>
5443
<div class="inline field">

src/Common/Messages/en/GeneralSettings.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
'gs_RTPStunServer' => 'STUN server address (example: stun.test.net:10000)',
2525
'gs_SIPAuthPrefix' => 'Auth Username prefix for authorization. The prefix will be added to the end of Username.',
2626
'gs_SIPAuthPrefixInvalid' => 'The Auth Username prefix can only contain Latin letters.',
27-
'gs_UseWebRTC' => 'Use WebRTC',
2827
'gs_DisableAllModules' => 'Disable marketplace',
2928
'gs_ErrorSaveSettings' => 'Error saving settings',
3029
'gs_SSHDisablePasswordLogins' => 'Disable password authentication',

src/Common/Messages/ru/GeneralSettings.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
'gs_RTPStunServer' => 'Адрес STUN сервера (пример: stun.test.net:10000)',
2727
'gs_SIPAuthPrefix' => 'Префикс Auth Username для авторизации. Префикс будет добавлен в конец Username.',
2828
'gs_SIPAuthPrefixInvalid' => 'Префикс Auth Username может содержать только латинские буквы.',
29-
'gs_UseWebRTC' => 'Использовать WebRTC',
3029
'gs_DisableAllModules' => 'Отключить маркетплейс',
3130
'gs_ErrorSaveSettings' => 'Ошибка сохранения настроек',
3231
'gs_SSHDisablePasswordLogins' => 'Отключить авторизацию по паролю',

src/Common/Models/PBXSettings/PbxSettingsConstantsTrait.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,6 @@ trait PbxSettingsConstantsTrait
125125
public const string RTP_PORT_TO = 'RTPPortTo';
126126
/** @FieldType('string') */
127127
public const string RTP_STUN_SERVER = 'RTPStunServer';
128-
/** @FieldType('boolean') */
129-
public const string USE_WEB_RTC = 'UseWebRTC';
130-
131128
// IAX settings
132129
/** @FieldType('integer') */
133130
public const string IAX_PORT = 'IAXPort';

src/Common/Models/PBXSettings/PbxSettingsDefaultValuesTrait.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ public static function getDefaultArrayValues(): array
4848
PbxSettings::RTP_PORT_FROM => '10000',
4949
PbxSettings::RTP_PORT_TO => '10200',
5050
PbxSettings::RTP_STUN_SERVER => '',
51-
PbxSettings::USE_WEB_RTC => '0',
5251
PbxSettings::IAX_PORT => '4569',
5352
PbxSettings::AMI_ENABLED => '1',
5453
PbxSettings::AMI_PORT => '5038',

src/Core/Asterisk/AsteriskManager.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1572,8 +1572,17 @@ public function getPjSipPeer(string $peer, string $prefix = ''): array
15721572
if ($wsResult['state'] !== 'UNKNOWN') {
15731573
$result = $wsResult;
15741574
}
1575+
// Query SIP/TLS variant endpoint and append its contacts with a -TLS{idx} suffix
1576+
// so they coexist with the base and WebRTC endpoints in the same result map.
1577+
$tlsRes = $this->sendRequestTimeout('PJSIPShowEndpoint', ['Endpoint' => trim($peer) . "-TLS"]);
1578+
foreach ($tlsRes['data']['ContactStatusDetail'] ?? [] as $index => $tlsData) {
1579+
$suffix = "-TLS$index";
1580+
foreach ($tlsData as $key => $value) {
1581+
$result["$key$suffix"] = $value;
1582+
}
1583+
}
15751584
$parameters = ['Endpoint' => trim($peer)];
1576-
unset($wsResult);
1585+
unset($wsResult, $tlsRes);
15771586
} else {
15781587
$parameters = ['Endpoint' => trim($peer) . "-$prefix"];
15791588
}
@@ -1626,6 +1635,15 @@ public function getPjSipPeerContacts(string $peer): array
16261635
}
16271636
}
16281637

1638+
// Also check for SIP/TLS endpoint
1639+
$tlsRes = $this->sendRequestTimeout('PJSIPShowEndpoint', ['Endpoint' => trim($peer) . "-TLS"]);
1640+
foreach ($tlsRes['data']['ContactStatusDetail'] ?? [] as $contactData) {
1641+
if (!empty($contactData['URI'])) {
1642+
$contactData['IsTls'] = true;
1643+
$contacts[] = $contactData;
1644+
}
1645+
}
1646+
16291647
return $contacts;
16301648
}
16311649

src/Core/Asterisk/Configs/ExtensionsConf.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ public static function sortArrayByPriority(array $a, array $b): int
6262
*/
6363
protected function generateConfigProtected(): void
6464
{
65+
// Force a fresh certificate-presence probe — InternalContexts uses
66+
// SIPConf::hasCertificates() to decide whether to wire WS/TLS dial buckets.
67+
SIPConf::resetCertsCache();
68+
6569
/** @scrutinizer ignore-call */
6670
$conf = "[globals]" .PHP_EOL.
6771
"TRANSFER_CONTEXT=internal-transfer;".PHP_EOL;
@@ -124,7 +128,7 @@ private function generateOtherExten(string &$conf): void
124128
'exten => _X.,1,NoOp("Sending message, To ${MESSAGE(to)}, Hint ${ARG1}, From ${MESSAGE(from)}, CID ${CALLERID}, Body ${MESSAGE(body)}")' . PHP_EOL ."\t".
125129
'same => n,Gosub(set-dial-contacts,${EXTEN},1)' . PHP_EOL ."\t".
126130
'same => n,While($["${SET(contact=${SHIFT(DST_CONTACT,&):6})}" != ""])' . PHP_EOL ."\t".
127-
'same => n,MessageSend(pjsip:${contact},${REPLACE(MESSAGE(from),-WS)})' . PHP_EOL ."\t".
131+
'same => n,MessageSend(pjsip:${contact},${STRREPLACE(STRREPLACE(MESSAGE(from),-WS,),-TLS,)})' . PHP_EOL ."\t".
128132
'same => n,NoOp("Send status is ${MESSAGE_SEND_STATUS}")' . PHP_EOL ."\t".
129133
'same => n,EndWhile' . PHP_EOL ."\t".
130134
'same => n,HangUp()' . PHP_EOL .PHP_EOL;

src/Core/Asterisk/Configs/Generators/Extensions/InternalContexts.php

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,22 @@ public function makeDialplan(): string
105105
$conf .= '[set-dial-contacts]'.PHP_EOL.
106106
'exten => _X!,1,NoOp()'.PHP_EOL."\t";
107107

108-
// If WebRTC is used, set up SIP and WS contacts. Otherwise, set DST contact.
109-
if(PbxSettings::getValueByKey(PbxSettings::USE_WEB_RTC) === '1') {
110-
$conf .= 'same => n,Set(SIP_CONTACT=${PJSIP_DIAL_CONTACTS(${EXTEN})})'.PHP_EOL."\t".
111-
'same => n,Set(WS_CONTACTS=${PJSIP_DIAL_CONTACTS(${EXTEN}-WS)})'.PHP_EOL."\t".
112-
'same => n,Set(DST_CONTACT=${SIP_CONTACT}${IF($["${SIP_CONTACT}x" != "x" && "${WS_CONTACTS}x" != "x"]?&)}${WS_CONTACTS})'.PHP_EOL."\t";
113-
}else{
114-
$conf .= 'same => n,Set(DST_CONTACT=${PJSIP_DIAL_CONTACTS(${EXTEN})})'.PHP_EOL."\t";
108+
// Resolve dial contacts for every transport variant of the extension.
109+
// PJSIP_DIAL_CONTACTS returns empty string when the endpoint has no registered
110+
// contacts. Buckets are stitched with '&' only when both sides are non-empty.
111+
//
112+
// IMPORTANT: variables containing ':' (PJSIP_DIAL_CONTACTS returns URIs like
113+
// "PJSIP/201/sip:201@host:port") MUST stay outside ${IF(...?...)} — the IF
114+
// function treats ':' as the true/false separator and would slice the URI in half.
115+
// The safe pattern is: ${VAR_A}${IF(both_nonempty?&)}${VAR_B} — VAR_A/VAR_B
116+
// outside the IF, only the neutral '&' inside.
117+
$hasCerts = SIPConf::hasCertificates();
118+
$conf .= 'same => n,Set(DST_CONTACT=${PJSIP_DIAL_CONTACTS(${EXTEN})})'.PHP_EOL."\t";
119+
if ($hasCerts) {
120+
$conf .= 'same => n,Set(WS_CONTACTS=${PJSIP_DIAL_CONTACTS(${EXTEN}-WS)})'.PHP_EOL."\t".
121+
'same => n,Set(DST_CONTACT=${DST_CONTACT}${IF($["${DST_CONTACT}x" != "x" && "${WS_CONTACTS}x" != "x"]?&)}${WS_CONTACTS})'.PHP_EOL."\t".
122+
'same => n,Set(TLS_CONTACTS=${PJSIP_DIAL_CONTACTS(${EXTEN}-TLS)})'.PHP_EOL."\t".
123+
'same => n,Set(DST_CONTACT=${DST_CONTACT}${IF($["${DST_CONTACT}x" != "x" && "${TLS_CONTACTS}x" != "x"]?&)}${TLS_CONTACTS})'.PHP_EOL."\t";
115124
}
116125
$conf .= 'same => n,return'.PHP_EOL.PHP_EOL;
117126

@@ -403,7 +412,12 @@ private function generateInternalUsers(): string
403412

404413
// Generate additional modules internal users context
405414
$conf .= $this->generateAdditionalModulesInternalUsersContext();
406-
$conf .= 'same => n,ExecIf($["${DEVICE_STATE(' . $this->technology . '/${EXTEN})}" == "BUSY" || "${DEVICE_STATE(' . $this->technology . '/${EXTEN}-WS)}" == "BUSY"]?Set(IS_BUSY=1))' . " \n\t";
415+
$busyCheck = '"${DEVICE_STATE(' . $this->technology . '/${EXTEN})}" == "BUSY"';
416+
if (SIPConf::hasCertificates()) {
417+
$busyCheck .= ' || "${DEVICE_STATE(' . $this->technology . '/${EXTEN}-WS)}" == "BUSY"'
418+
. ' || "${DEVICE_STATE(' . $this->technology . '/${EXTEN}-TLS)}" == "BUSY"';
419+
}
420+
$conf .= 'same => n,ExecIf($[' . $busyCheck . ']?Set(IS_BUSY=1))' . " \n\t";
407421
$conf .= 'same => n,ExecIf($["${IS_BUSY}" == "1"]?Set(DIALSTATUS=BUSY))' . " \n\t";
408422
$conf .= 'same => n,GotoIf($["${IS_BUSY}" == "1" && "${QUEUE_SRC_CHAN}x" == "x"]?fw_start)' . " \n\t";
409423

src/Core/Asterisk/Configs/RtpConf.php

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -59,21 +59,18 @@ protected function generateConfigProtected(): void
5959
"rtpstart={$rtpStart}".PHP_EOL.
6060
"rtpend={$rtpEnd}".PHP_EOL;
6161

62-
// Add DTLS configuration for WebRTC if enabled
63-
$useWebRTC = PbxSettings::getValueByKey(PbxSettings::USE_WEB_RTC);
64-
if ($useWebRTC === '1') {
65-
// Prepare certificates for DTLS
66-
$certs = SslCertificateService::prepareAsteriskCertificates('asterisk-rtp-dtls');
67-
68-
if (!empty($certs['certPath']) && !empty($certs['keyPath'])) {
69-
$conf .= PHP_EOL .
70-
"; DTLS configuration for WebRTC\n" .
71-
"dtlsenable=yes".PHP_EOL.
72-
"dtlscertfile={$certs['certPath']}".PHP_EOL.
73-
"dtlsprivatekey={$certs['keyPath']}".PHP_EOL.
74-
"dtlssetup=actpass".PHP_EOL.
75-
"dtlsverify=no".PHP_EOL;
76-
}
62+
// Add DTLS configuration for WebRTC when certificates are available.
63+
// WebRTC clients require DTLS-SRTP; without certs the WSS transport and
64+
// -WS endpoints aren't generated either, so this block stays consistent.
65+
$certs = SslCertificateService::prepareAsteriskCertificates('asterisk-rtp-dtls');
66+
if (!empty($certs['certPath']) && !empty($certs['keyPath'])) {
67+
$conf .= PHP_EOL .
68+
"; DTLS configuration for WebRTC\n" .
69+
"dtlsenable=yes".PHP_EOL.
70+
"dtlscertfile={$certs['certPath']}".PHP_EOL.
71+
"dtlsprivatekey={$certs['keyPath']}".PHP_EOL.
72+
"dtlssetup=actpass".PHP_EOL.
73+
"dtlsverify=no".PHP_EOL;
7774
}
7875

7976
$conf .= PHP_EOL;

0 commit comments

Comments
 (0)