[SR-Users] Guidance tracking down "qm_free(): BUG: freeing already freed pointer"
Anthony Joseph Messina
amessina at messinet.com
Fri Jul 23 16:08:37 CEST 2021
It's built upon the standard branch_route, but is customized to add rtpengine
and dialog storage.
I've attached the related routes. Thanks. -A
On Friday, July 23, 2021 2:43:04 AM CDT Daniel-Constantin Mierla wrote:
> Hello,
>
> is it a custom configuration file or simply the default kamailio.cfg
> with parts of branch_route enabled/disabled? If it is custom, can you
> paste here the content of the branch route that you disable/enable parts
> of it and get the error messages?
>
> Overall, seem like trying to (re-)use a terminated transaction or branch.
>
> Cheers,
> Daniel
>
> On 23.07.21 00:19, Anthony Joseph Messina wrote:
> > I'm seeking guidance on how to track down "qm_free(): BUG: freeing already
> > freed pointer" which occurs only on branched calls. These errors don't
> > crash so I don't get any core dumps. The different log entries below are
> > the result of me selectively disabling sections of the script that apply
> > in branch route, all to no avail. I'm running Kamailio on the current
> > tip of the 5.5 branch (1f9f6fff6e). I'm reviewing
> > https://www.kamailio.org/wiki/tutorials/troubleshooting/memory in the
> > meantime as a place to start.
> >
> >
> > version: kamailio 5.5.1-5.git1f9f6fff6e.fc34 (x86_64/linux) 7abebb
> > flags: USE_TCP, USE_TLS, USE_SCTP, TLS_HOOKS, USE_RAW_SOCKS,
> > DISABLE_NAGLE, USE_MCAST, DNS_IP_HACK, SHM_MMAP, PKG_MALLOC, Q_MALLOC,
> > F_MALLOC, TLSF_MALLOC, DBG_SR_MEMORY, USE_FUTEX, FAST_LOCK-ADAPTIVE_WAIT,
> > USE_DNS_CACHE, USE_DNS_FAILOVER, USE_NAPTR, USE_DST_BLOCKLIST,
> > HAVE_RESOLV_RES, TLS_PTHREAD_MUTEX_SHARED ADAPTIVE_WAIT_LOOPS 1024,
> > MAX_RECV_BUFFER_SIZE 262144, MAX_URI_SIZE 1024, BUF_SIZE 65535, DEFAULT
> > PKG_SIZE 8MB poll method support: poll, epoll_lt, epoll_et, sigio_rt,
> > select.
> >
> > CRITICAL: <core> [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing
> > already freed pointer (0x7f04b8f47e90), called from core:
> > core/data_lump.c: free_lump(470), first free textops: textops.c:
> > add_hf_helper(3474) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7f04b8f06c70), called from core: core/data_lump.c: free_lump(470),
> > first free textops: textops.c: add_hf_helper(3474) - ignoring CRITICAL:
> > <core> [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed
> > pointer (0x7f08e8f9cf80), called from core: core/data_lump.c:
> > free_lump(470), first free core: core/parser/msg_parser.c: reset_ua(994)
> > - ignoring CRITICAL: <core> [core/mem/q_malloc.c:519]: qm_free(): BUG:
> > freeing already freed pointer (0x7f2afafa60d8), called from core:
> > core/parser/sdp/sdp.c: free_sdp(825), first free core:
> > core/parser/sdp/sdp.c: init_p_payload_attr(183) - ignoring CRITICAL:
> > <core> [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed
> > pointer (0x7f2afae2a018), called from core: core/data_lump.c:
> > free_lump(470), first free core: core/parser/msg_parser.c: reset_ua(994)
> > - ignoring CRITICAL: <core> [core/mem/q_malloc.c:519]: qm_free(): BUG:
> > freeing already freed pointer (0x7f2afae431e8), called from core:
> > core/data_lump.c: free_lump(470), first free core:
> > core/parser/msg_parser.c: reset_ua(994) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7f2afafa3900), called from core: core/data_lump.c: free_lump(470),
> > first free core: core/parser/msg_parser.c: reset_ua(994) - ignoring
> > CRITICAL: <core> [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing
> > already freed pointer (0x7f5fd4044ef0), called from core:
> > core/data_lump.c: free_lump(470), first free core:
> > core/parser/msg_parser.c: reset_ua(994) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7ffbb2d2e2f0), called from core: core/data_lump.c: free_lump(470),
> > first free core: core/parser/msg_parser.c: reset_ua(994) - ignoring
> > CRITICAL: <core> [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing
> > already freed pointer (0x7f6d1a50b1d8), called from core:
> > core/data_lump.c: free_lump(470), first free core:
> > core/parser/msg_parser.c: reset_ua(994) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7fc19c165c70), called from core: core/parser/msg_parser.c:
> > reset_instance(916), first free core: core/parser/parse_addr_spec.c:
> > free_to_params(895) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7fc19c17adb8), called from core: core/parser/msg_parser.c:
> > reset_instance(916), first free core: core/parser/parse_addr_spec.c:
> > free_to_params(895) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7fc19c125790), called from core: core/data_lump.c: free_lump(470),
> > first free core: core/parser/msg_parser.c: reset_ua(994) - ignoring
> > CRITICAL: <core> [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing
> > already freed pointer (0x7f4d969c9d48), called from core:
> > core/data_lump.c: free_lump(470), first free core:
> > core/parser/msg_parser.c: reset_ua(994) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7fc29bdca3d0), called from core: core/data_lump.c: free_lump(470),
> > first free textops: textops.c: add_hf_helper(3474) - ignoring CRITICAL:
> > <core> [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed
> > pointer (0x7fc2c2eccc80), called from core: core/data_lump.c:
> > free_lump(470), first free textops: textops.c: add_hf_helper(3474) -
> > ignoring CRITICAL: <core> [core/mem/q_malloc.c:519]: qm_free(): BUG:
> > freeing already freed pointer (0x7fc2c2ec52c0), called from core:
> > core/data_lump.c: free_lump(470), first free core:
> > core/parser/msg_parser.c: reset_ua(994) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7f910c04e240), called from core: core/data_lump.c: free_lump(470),
> > first free textops: textops.c: add_hf_helper(3474) - ignoring CRITICAL:
> > <core> [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed
> > pointer (0x7fa351286b18), called from core: core/parser/msg_parser.c:
> > reset_instance(916), first free core: core/parser/parse_addr_spec.c:
> > free_to_params(895) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7fa3512a7ae8), called from core: core/data_lump.c: free_lump(470),
> > first free textops: textops.c: add_hf_helper(3474) - ignoring CRITICAL:
> > <core> [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed
> > pointer (0x7fa0777d9e70), called from core: core/parser/msg_parser.c:
> > reset_instance(916), first free core: core/parser/parse_addr_spec.c:
> > free_to_params(895) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7fa0777d7a80), called from core: core/parser/msg_parser.c:
> > reset_instance(916), first free core: core/parser/parse_addr_spec.c:
> > free_to_params(895) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7f4f2c92cf20), called from core: core/data_lump.c: free_lump(470),
> > first free core: core/parser/msg_parser.c: reset_ua(994) - ignoring
> > CRITICAL: <core> [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing
> > already freed pointer (0x7f4f2c8afa00), called from core:
> > core/data_lump.c: free_lump(470), first free textops: textops.c:
> > add_hf_helper(3474) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7f4f2c92aa48), called from core: core/parser/sdp/sdp.c: free_sdp(825),
> > first free core: core/parser/msg_parser.c: reset_ua(994) - ignoring
> > CRITICAL: <core> [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing
> > already freed pointer (0x7fe55825eb30), called from core:
> > core/parser/sdp/sdp.c: free_sdp(825), first free core:
> > core/parser/sdp/sdp.c: init_p_payload_attr(183) - ignoring CRITICAL:
> > <core> [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed
> > pointer (0x7f6526db8378), called from core: core/parser/sdp/sdp.c:
> > free_sdp(825), first free core: core/parser/msg_parser.c: reset_ua(994) -
> > ignoring CRITICAL: <core> [core/mem/q_malloc.c:519]: qm_free(): BUG:
> > freeing already freed pointer (0x7fcd9b465980), called from core:
> > core/parser/msg_parser.c: reset_instance(916), first free core:
> > core/parser/hf.c: free_hdr_field_lst(217) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7ff7ca92ff60), called from core: core/parser/msg_parser.c:
> > reset_instance(916), first free core: core/parser/parse_addr_spec.c:
> > free_to_params(895) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7f978a2dc938), called from core: core/parser/msg_parser.c:
> > reset_instance(916), first free core: core/parser/parse_addr_spec.c:
> > free_to_params(895) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7f978a2b7eb8), called from core: core/parser/msg_parser.c:
> > reset_instance(916), first free core: core/parser/parse_addr_spec.c:
> > free_to_params(895) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7fa1556c1610), called from core: core/parser/sdp/sdp.c: free_sdp(825),
> > first free core: core/parser/msg_parser.c: reset_ua(994) - ignoring
> > CRITICAL: <core> [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing
> > already freed pointer (0x7fd81dfbba78), called from core:
> > core/parser/sdp/sdp.c: free_sdp(825), first free core:
> > core/parser/msg_parser.c: reset_ua(994) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7fb2750d9988), called from core: core/parser/sdp/sdp.c: free_sdp(825),
> > first free core: core/parser/msg_parser.c: reset_ua(994) - ignoring
> > CRITICAL: <core> [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing
> > already freed pointer (0x7fb2750e1b28), called from core:
> > core/parser/msg_parser.c: reset_instance(916), first free core:
> > core/parser/parse_addr_spec.c: free_to_params(895) - ignoring CRITICAL:
> > <core> [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed
> > pointer (0x7f32f7b45d30), called from core: core/parser/msg_parser.c:
> > reset_instance(916), first free core: core/parser/hf.c:
> > free_hdr_field_lst(217) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7f35849e1940), called from core: core/parser/msg_parser.c:
> > reset_instance(916), first free core: core/parser/hf.c:
> > free_hdr_field_lst(217) - ignoring CRITICAL: <core>
> > [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing already freed pointer
> > (0x7fd3a2c04280), called from core: core/parser/sdp/sdp.c: free_sdp(825),
> > first free core: core/parser/msg_parser.c: reset_ua(994) - ignoring
> > CRITICAL: <core> [core/mem/q_malloc.c:519]: qm_free(): BUG: freeing
> > already freed pointer (0x7f5de857a040), called from core:
> > core/parser/msg_parser.c: reset_instance(916), first free core:
> > core/parser/hf.c: free_hdr_field_lst(217) - ignoring
-------------- next part --------------
### Note WITH_NAT is unset so this route does nothing...
route[NATMANAGE] {
#!ifdef WITH_NAT
if(is_request()) {
if(has_totag()) {
if(check_route_param("nat=yes")) {
setbflag(FLB_NATB);
}
}
}
if(!(isflagset(FLT_NATS) || isbflagset(FLB_NATB))) return;
# We are sending everything to route(RTPENGINE_MANAGE), not based on NAT
# route(RTPENGINE_MANAGE);
if(is_request()) {
if(!has_totag()) {
if(t_is_branch_route()) {
add_rr_param(";nat=yes");
}
}
}
if(is_reply()) {
if(isbflagset(FLB_NATB)) {
if(is_first_hop()) {
set_contact_alias();
}
}
}
if(isbflagset(FLB_NATB)) {
# no connect message in a dialog involving NAT traversal
if(is_request()) {
if(has_totag()) {
set_forward_no_connect();
}
}
}
#!endif
return;
}
# Manage outgoing branches
branch_route[MANAGE_BRANCH] {
# Drop selected branch duplicates
route(MULTIBRANCH_INVITE);
# Route to NATMANAGE and RTPENGINE_MANAGE
route(NATMANAGE);
route(RTPENGINE_MANAGE);
# Modify headers based on destination and privacy
if(!isflagset(FLT_LCR) && $xavu(id=>pai)!=$null) {
append_hf("P-Asserted-Identity: $xavu(id=>pai)\r\n");
}
}
# Manage incoming replies
reply_route {
if(!sanity_check("17604", "6")) {
sd_journal_print("LOG_INFO", "[$cfg(route)] Malformed SIP response from $si:$sp");
drop;
}
}
# Manage incoming replies in transaction context
onreply_route[MANAGE_REPLY] {
if(status=~"[12][0-9][0-9]") {
route(NATMANAGE);
route(RTPENGINE_MANAGE);
}
# Set multi-leg accounting variables
route(ACC_MULTI_LEG);
route(ACC_CDR_EXTRA_CHAIN);
}
# Drop selected outgoing branches
route[MULTIBRANCH_INVITE] {
#!ifdef WITH_APPEND_BRANCHES
# Only process on branch_route
if(!t_is_branch_route()) return;
# Only process INVITEs with multiple branches (flag set in route[LOCATION])
if(!isflagset(FLT_MULTIBRANCH_INVITE)) return;
# Drop selected branches where lookup_branches found no match or
# where the Request-URI matches the caller's Contact-URI
if(uri==myself ||
(@contact.uri.user==@ruri.user && @contact.uri.hostport==@ruri.hostport) ||
(route(ASTERISK_IS_SRC) && @contact.uri.hostport==@ruri.hostport)) {
sd_journal_print("LOG_DEBUG", "[$cfg(route)][$T_branch_idx] Loop detected for branched call to $ou from $ct on branch $ru");
drop;
}
# Drop branches where $ru has an 'rinstance' parameter and $fU corresponds
# to $rU, indicating a Bria or Zoiper client is registered on the device
if($(ru{param.value,rinstance})!=$null) {
if(($fU=~"2001" && $rU=="user1") || ($fU=~"2001" && $rU=="user2")) {
sd_journal_print("LOG_DEBUG", "[$cfg(route)][$T_branch_idx] Loop detected for branched call to $ou from $ct on branch $ru with rinstance $(ru{param.value,rinstance})");
drop;
}
}
#!endif
return;
}
# Test if request is from Asterisk
route[ASTERISK_IS_SRC] {
#!ifdef WITH_ASTERISK
if(src_port==ASTERISK_PORT && (src_ip==ASTERISK_IP4_LAN || src_ip==ASTERISK_IP4_WAN || src_ip==[ASTERISK_IP6_LAN] || src_ip==[ASTERISK_IP6_WAN])) {
if(is_present_hf("X-Asterisk-LinkedID")) {
$avp(linkedid)=$hdr(X-Asterisk-LinkedID);
remove_hf("X-Asterisk-LinkedID");
}
return 1;
}
#!endif
return -1;
}
# RTPengine management route
route[RTPENGINE_MANAGE] {
#!ifdef WITH_RTPENGINE
# Define $avp(dst) for interface direction, and $avp(rp) for protocol -- $nh(d) and $rP don't exist in reply route
if(is_request()) {
$avp(dst)=$(nh(d){s.unbracket});
$avp(dst_port)=$nh(p);
$avp(rp)=$(rP{s.toupper});
} else {
$avp(dst)=$T_req($(si{s.unbracket}));
$avp(dst_port)=$T_req($sp);
$avp(rp)=$T_req($(proto{s.toupper}));
}
# Handle INVITE in failure_route
if(t_is_failure_route()) {
if(is_method("INVITE")) {
if(rtpengine_manage()) {
# Reset branch flags for failover (VoiceMail or LCR auth)
# resetbflag(FLB_RTPENGINE);
resetbflag(FLB_RTPENGINE_AVP);
resetbflag(FLB_RTPENGINE_AVPF);
resetbflag(FLB_RTPENGINE_SAVP);
resetbflag(FLB_RTPENGINE_SAVPF);
sd_journal_print("LOG_DEBUG", "[$cfg(route)][$T_branch_idx] RTPengine (in failure route) delete $rdir(name) $rm ($mt), source $proto:$si:$sp, destination $avp(rp):$avp(dst):$avp(dst_port), status $T_reply_code");
}
}
return;
}
# Handle BYE
if(is_method("BYE")) {
if(is_request()) {
# RTPengine mos_A/B_label must be set for BYE transaction
$avp(mos_A_label)="caller";
$avp(mos_B_label)="callee";
if(rtpengine_manage()) {
route(ACC_CDR_EXTRA_RTPENGINE);
sd_journal_print("LOG_DEBUG", "[$cfg(route)][$T_branch_idx] RTPengine delete $rdir(name) $rm ($mt), source $proto:$si:$sp, destination $avp(rp):$avp(dst):$avp(dst_port), status $T_reply_code");
}
}
return;
}
# Handle CANCEL
if(is_method("CANCEL")) {
if(is_request()) {
if(rtpengine_manage()) {
sd_journal_print("LOG_DEBUG", "[$cfg(route)][$T_branch_idx] RTPengine delete $rdir(name) $rm ($mt), source $proto:$si:$sp, destination $avp(rp):$avp(dst):$avp(dst_port), status $T_reply_code");
}
}
return;
}
# Don't process below this point without SDP
if(!has_body("application/sdp")) {
return;
}
if(is_method("ACK")) {
# RTPengine answer on ACK with SDP (NO-SDP-INVITE-reply-ACK case)
if($dlg_var(rtpengine_answer)!=$null) {
if(rtpengine_manage($dlg_var(rtpengine_answer))) {
sd_journal_print("LOG_DEBUG", "[$cfg(route)][$T_branch_idx] RTPengine answer $rdir(name) $rm ($mt), source $proto:$si:$sp, destination $avp(rp):$avp(dst):$avp(dst_port), dialog flags: $dlg_var(rtpengine_answer)");
$dlg_var(rtpengine_answer)=$null;
}
# Remember the caller rtp_transport_protocol in the dialog (for re-INVITE)
if($dlg_var(caller_rtp_transport_protocol)==$null) {
sdp_transport("$avp(caller_rtp_transport_protocol)");
$dlg_var(caller_rtp_transport_protocol)=$avp(caller_rtp_transport_protocol);
}
}
return;
}
if(is_method("INVITE|UPDATE")) {
# RTPengine answer on reply to INVITE (standard INVITE-reply case)
if(is_reply()) {
if($xavp(ra=>$T_branch_idx)!=$null) {
if(rtpengine_manage($xavp(ra=>$T_branch_idx))) {
sd_journal_print("LOG_DEBUG", "[$cfg(route)][$T_branch_idx] RTPengine answer $rdir(name) $rm ($mt), status $rs, source $proto:$si:$sp, destination $avp(rp):$avp(dst):$avp(dst_port), flags: $xavp(ra=>$T_branch_idx)");
}
# Remember the callee rtp_transport_protocol in the dialog (for re-INVITE)
if(status=~"2[0-9][0-9]") {
if($dlg_var(callee_rtp_transport_protocol)==$null) {
sdp_transport("$avp(callee_rtp_transport_protocol)");
$dlg_var(callee_rtp_transport_protocol)=$avp(callee_rtp_transport_protocol);
}
}
return;
}
}
# RTPengine prepare default offer/answer flags
$xavp(ro=>$T_branch_idx)="replace-origin replace-session-connection strict-source";
$xavp(ra=>$T_branch_idx)="replace-origin replace-session-connection strict-source";
# Use $dlg_var for RTP profile (on reinvites)
# RTP/AVP, RTP/SAVP, RTP/AVPF, RTP/SAVPF, or DTLS transport, using OSRTP for unknowns destinations
if($avp(rp)=~"^WS") {
# SDES-off needs to happen even on re-INVITE (in case of adding or removing video)
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " DTLS DTLS=passive SDES-off";
} else if(is_request() && $rdir(name)=="downstream") {
if(isbflagset(FLB_RTPENGINE_SAVP) || $dlg_var(callee_rtp_transport_protocol)=="RTP/SAVP") {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " RTP/SAVP DTLS=off SDES-pad";
} else if(isbflagset(FLB_RTPENGINE_SAVPF) || $dlg_var(callee_rtp_transport_protocol)=="RTP/SAVPF") {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " RTP/SAVPF DTLS=off SDES-pad";
} else if(isbflagset(FLB_RTPENGINE_AVP) || $dlg_var(callee_rtp_transport_protocol)=="RTP/AVP") {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " RTP/AVP";
} else if(isbflagset(FLB_RTPENGINE_AVPF) || $dlg_var(callee_rtp_transport_protocol)=="RTP/AVPF") {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " RTP/AVPF";
} else {
# If the destination's profile is unknown try OSRTP
#$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " RTP/AVP OSRTP-offer OSRTP-accept DTLS=off SDES-pad";
#$xavp(ra=>$T_branch_idx)=$xavp(ra=>$T_branch_idx) + " DTLS=off SDES-pad";
# Default to SRTP on first offer (Bria/Zoiper don't really accept OSRTP, encryption only allows "never" or "always")
if(!has_totag()) {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " RTP/SAVP DTLS=off SDES-pad";
}
}
} else {
if($dlg_var(caller_rtp_transport_protocol)=="RTP/SAVP") {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " RTP/SAVP DTLS=off SDES-pad";
} else if($dlg_var(caller_rtp_transport_protocol)=="RTP/SAVPF") {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " RTP/SAVPF DTLS=off SDES-pad";
} else if($dlg_var(caller_rtp_transport_protocol)=="RTP/AVP") {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " RTP/AVP";
} else if ($dlg_var(caller_rtp_transport_protocol)=="RTP/AVPF") {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " RTP/AVPF";
} else {
# If the destination's profile is unknown try OSRTP
#$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " RTP/AVP OSRTP-offer OSRTP-accept DTLS=off SDES-pad";
#$xavp(ra=>$T_branch_idx)=$xavp(ra=>$T_branch_idx) + " DTLS=off SDES-pad";
# Default to SRTP on first offer (Bria/Zoiper don't really accept OSRTP, encryption only allows "never" or "always")
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " RTP/SAVP DTLS=off SDES-pad";
}
}
# Remember the rtp_transport_protocol in the dialog (for re-INVITE)
sdp_transport("$avp(rtp_transport_protocol)");
if(is_request()) {
if($dlg_var(caller_rtp_transport_protocol)==$null) {
$dlg_var(caller_rtp_transport_protocol)=$avp(rtp_transport_protocol);
}
} else {
if($dlg_var(callee_rtp_transport_protocol)==$null) {
$dlg_var(callee_rtp_transport_protocol)=$avp(rtp_transport_protocol);
}
}
# DTLS/SDES handling for Websocket, Bria, Zoiper, etc.
if($avp(rtp_transport_protocol)=~"^UDP/TLS") {
$xavp(ra=>$T_branch_idx)=$xavp(ra=>$T_branch_idx) + " DTLS DTLS=passive SDES-off";
} else if($avp(rtp_transport_protocol)=~"^RTP/SAVP") {
$xavp(ra=>$T_branch_idx)=$xavp(ra=>$T_branch_idx) + " DTLS=off SDES-pad " + $avp(rtp_transport_protocol);
} else {
$xavp(ra=>$T_branch_idx)=$xavp(ra=>$T_branch_idx) + " " + $avp(rtp_transport_protocol);
}
# Only on first offer
if(!has_totag()) {
# Add via-branch=next functionality
$xavp(ro=>$T_branch_idx)="via-branch=next " + $xavp(ro=>$T_branch_idx);
$xavp(ra=>$T_branch_idx)="via-branch=1 " + $xavp(ra=>$T_branch_idx);
# Call leg labels
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " label=caller";
$xavp(ra=>$T_branch_idx)=$xavp(ra=>$T_branch_idx) + " label=callee";
# Call recording (don't record voicemail)
if($rU=="voicemail") {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " record-call=off";
} else {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " record-call";
}
# Interface direction
if(src_ip==10.0.0.0/24 || src_ip==2001:dB8:1234::/48) {
if(is_in_subnet("$avp(dst)", "10.0.0.0/24,2001:dB8:1234::/48")) {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " direction=priv direction=priv";
} else {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " direction=priv direction=pub";
}
} else if(is_in_subnet("$avp(dst)", "10.0.0.0/24,2001:dB8:1234::/48")) {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " direction=pub direction=priv";
} else {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " direction=pub direction=pub";
}
# Interface address-family
if(af==INET && is_ipv6($avp(dst))) {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " address-family=IP6";
} else if(af==INET6 && (is_ipv4($avp(dst)) || !is_ip($avp(dst)))) {
# Default to IPv4 when $avp(dst) is not an IP address
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " address-family=IP4";
}
}
if(is_request()) {
# ICE & RTCP
if(proto==WSS || proto==WS) {
# WebSocket clients often use fake IPv4 addresses in the c= line,
# but are speaking IPv6, in which case, the audio will never really
# connect if RTPengine thinks it's looking for IPv4 input. It also
# seems to be SIP-source-address disables "learning mode" and removes endless
# logging of "Successful STUN binding request... Kernelizing media stream"
if($avp(rp)=~"^WS") {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " SIP-source-address ICE=force-relay";
$xavp(ra=>$T_branch_idx)=$xavp(ra=>$T_branch_idx) + " SIP-source-address ICE=force-relay";
} else {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " SIP-source-address ICE=remove rtcp-mux-demux";
}
} else if(sdp_with_ice()) {
if($avp(rp)=~"^WS") {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " rtcp-mux-offer";
$xavp(ra=>$T_branch_idx)=$xavp(ra=>$T_branch_idx) + " SIP-source-address";
} else {
# Still need to remove here so we don't offer ICE to SIP trunks (if we have ICE on the caller side -- we don't care about the answer)
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " ICE=remove";
}
} else {
if($avp(rp)=~"^WS") {
$xavp(ro=>$T_branch_idx)=$xavp(ro=>$T_branch_idx) + " rtcp-mux-offer";
$xavp(ra=>$T_branch_idx)=$xavp(ra=>$T_branch_idx) + " SIP-source-address";
}
}
}
# RTPengine offer
if(rtpengine_manage($xavp(ro=>$T_branch_idx))) {
if(is_request()) {
sd_journal_print("LOG_DEBUG", "[$cfg(route)][$T_branch_idx] RTPengine offer $rdir(name) $rm ($mt), source $proto:$si:$sp, destination $avp(rp):$avp(dst):$avp(dst_port), flags: $xavp(ro=>$T_branch_idx)");
} else {
sd_journal_print("LOG_DEBUG", "[$cfg(route)][$T_branch_idx] RTPengine offer $rdir(name) $rm ($mt), status $rs, source $proto:$si:$sp, destination $avp(rp):$avp(dst):$avp(dst_port), flags: $xavp(ro=>$T_branch_idx)");
# Store $xavp(ra=>$T_branch_idx) for answer on ACK
$dlg_var(rtpengine_answer)=$xavp(ra=>$T_branch_idx);
}
}
# RTPengine music on hold
if(is_method("INVITE") && has_totag()) {
if(is_audio_on_hold()) {
sd_journal_print("LOG_DEBUG", "[$cfg(route)][$T_branch_idx] RTPengine play $rdir(name) audio on hold");
play_media("from-tag=$tt file=/etc/rtpengine/wallace_chapman-check_it_out.mp3 repeat-times=10");
dlg_setflag(FLD_RTPENGINE_PLAY_MEDIA);
} else if(dlg_isflagset(FLD_RTPENGINE_PLAY_MEDIA)) {
sd_journal_print("LOG_DEBUG", "[$cfg(route)][$T_branch_idx] RTPengine stop $rdir(name) audio on hold");
stop_media("from-tag=$tt");
dlg_resetflag(FLD_RTPENGINE_PLAY_MEDIA);
}
}
}
#!endif
return;
}
# Set acc multi-leg accounting variables
route[ACC_MULTI_LEG] {
if(status=~"2[0-9][0-9]") {
$avp(leg_dst_user)=$(T_branch(uri){uri.user});
$avp(leg_dst_domain)=$(T_branch(uri){uri.host});
$avp(leg_sip_code)=$T_reply_code;
$avp(leg_time)=$timef(%F %T);
$avp(leg_to_tag)=$tt;
}
return;
}
# Route to set acc_cdr_extra "chain" in "$dlg_var(chain)"
# https://www.kamailio.org/docs/modules/stable/modules/acc#multi-cdr-call-legs
route[ACC_CDR_EXTRA_CHAIN] {
#!ifdef WITH_ACCDB_CDR_EXTRA
if(dlg_isflagset(FLD_ACC_CDR_EXTRA_CHAIN)) {
dlg_resetflag(FLD_ACC_CDR_EXTRA_CHAIN);
jansson_set("integer", "id", "$dlg(ref)", "$var(chain)");
if($xavu(caller)!=$null) jansson_set("string", "from_uri", "$xavu(caller)", "$var(chain)");
if($xavu(callee)!=$null) jansson_set("string", "to_uri", "$xavu(callee)", "$var(chain)");
if($xavu(time)!=$null) jansson_set("string", "time", "$xavu(time)", "$var(chain)");
if($xavu(reason)!=$null) jansson_set("string", "reason", "$xavu(reason)", "$var(chain)");
if($xavu(replaces=>ci)!=$null) {
jansson_set("string", "callid", "$xavu(replaces=>ci)", "$var(chain_replaces)");
if($xavu(replaces=>ft)!=$null) jansson_set("string", "from_tag", "$xavu(replaces=>ft)", "$var(chain_replaces)");
if($xavu(replaces=>tt)!=$null) jansson_set("string", "to_tag", "$xavu(replaces=>tt)", "$var(chain_replaces)");
jansson_set("obj", "replaces", "$var(chain_replaces)", "$var(chain)");
}
# Save to dialog/acc_cdrs
if($dlg_var(chain)==$null) {
$dlg_var(chain)="[]";
}
jansson_append("obj", "", "$var(chain)", "$dlg_var(chain)");
}
#!endif
return;
}
# Route to set acc_cdr_extra "rtpengine" with RTPengine statistics in "$dlg_var(rtpengine)"
route[ACC_CDR_EXTRA_RTPENGINE] {
#!ifdef WITH_ACCDB_CDR_EXTRA
#!ifdef WITH_RTPENGINE
# MOS
if($avp(mos_min)!=$null) {
jansson_set("string", "dialog.min", "$avp(mos_min)", "$vn(mos)");
if($avp(mos_min_at)!=$null) jansson_set("string", "dialog.min_at", "$avp(mos_min_at)", "$vn(mos)");
if($avp(mos_min_packetloss)!=$null) jansson_set("integer", "dialog.min_packetloss", "$avp(mos_min_packetloss)", "$vn(mos)");
if($avp(mos_min_jitter)!=$null) jansson_set("integer", "dialog.min_jitter", "$avp(mos_min_jitter)", "$vn(mos)");
if($avp(mos_min_roundtrip)!=$null) jansson_set("integer", "dialog.min_roundtrip", "$avp(mos_min_roundtrip)", "$vn(mos)");
if($avp(mos_min_roundtrip_leg)!=$null) jansson_set("integer", "dialog.min_roundtrip_leg", "$avp(mos_min_roundtrip_leg)", "$vn(mos)");
}
if($avp(mos_max)!=$null) {
jansson_set("string", "dialog.max", "$avp(mos_max)", "$vn(mos)");
if($avp(mos_max_at)!=$null) jansson_set("string", "dialog.max_at", "$avp(mos_max_at)", "$vn(mos)");
if($avp(mos_max_packetloss)!=$null) jansson_set("integer", "dialog.max_packetloss", "$avp(mos_max_packetloss)", "$vn(mos)");
if($avp(mos_max_jitter)!=$null) jansson_set("integer", "dialog.max_jitter", "$avp(mos_max_jitter)", "$vn(mos)");
if($avp(mos_max_roundtrip)!=$null) jansson_set("integer", "dialog.max_roundtrip", "$avp(mos_max_roundtrip)", "$vn(mos)");
if($avp(mos_max_roundtrip_leg)!=$null) jansson_set("integer", "dialog.max_roundtrip_leg", "$avp(mos_max_roundtrip_leg)", "$vn(mos)");
}
if($avp(mos_average)!=$null) {
jansson_set("string", "dialog.average", "$avp(mos_average)", "$vn(mos)");
if($avp(mos_average_packetloss)!=$null) jansson_set("integer", "dialog.average_packetloss", "$avp(mos_average_packetloss)", "$vn(mos)");
if($avp(mos_average_jitter)!=$null) jansson_set("integer", "dialog.average_jitter", "$avp(mos_average_jitter)", "$vn(mos)");
if($avp(mos_average_roundtrip)!=$null) jansson_set("integer", "dialog.average_roundtrip", "$avp(mos_average_roundtrip)", "$vn(mos)");
if($avp(mos_average_roundtrip_leg)!=$null) jansson_set("integer", "dialog.average_roundtrip_leg", "$avp(mos_average_roundtrip_leg)", "$vn(mos)");
if($avp(mos_average_samples)!=$null) jansson_set("integer", "dialog.average_samples", "$avp(mos_average_samples)", "$vn(mos)");
}
# MOS _A
if($avp(mos_min_A)!=$null) {
jansson_set("string", "A.min", "$avp(mos_min_A)", "$vn(mos)");
if($avp(mos_min_at_A)!=$null) jansson_set("string", "A.min_at", "$avp(mos_min_at_A)", "$vn(mos)");
if($avp(mos_min_packetloss_A)!=$null) jansson_set("integer", "A.min_packetloss", "$avp(mos_min_packetloss_A)", "$vn(mos)");
if($avp(mos_min_jitter_A)!=$null) jansson_set("integer", "A.min_jitter", "$avp(mos_min_jitter_A)", "$vn(mos)");
if($avp(mos_min_roundtrip_A)!=$null) jansson_set("integer", "A.min_roundtrip", "$avp(mos_min_roundtrip_A)", "$vn(mos)");
if($avp(mos_min_roundtrip_leg_A)!=$null) jansson_set("integer", "A.min_roundtrip_leg", "$avp(mos_min_roundtrip_leg_A)", "$vn(mos)");
}
if($avp(mos_max_A)!=$null) {
jansson_set("string", "A.max", "$avp(mos_max_A)", "$vn(mos)");
if($avp(mos_max_at_A)!=$null) jansson_set("string", "A.max_at", "$avp(mos_max_at_A)", "$vn(mos)");
if($avp(mos_max_packetloss_A)!=$null) jansson_set("integer", "A.max_packetloss", "$avp(mos_max_packetloss_A)", "$vn(mos)");
if($avp(mos_max_jitter_A)!=$null) jansson_set("integer", "A.max_jitter", "$avp(mos_max_jitter_A)", "$vn(mos)");
if($avp(mos_max_roundtrip_A)!=$null) jansson_set("integer", "A.max_roundtrip", "$avp(mos_max_roundtrip_A)", "$vn(mos)");
if($avp(mos_max_roundtrip_leg_A)!=$null) jansson_set("integer", "A.max_roundtrip_leg", "$avp(mos_max_roundtrip_leg_A)", "$vn(mos)");
}
if($avp(mos_average_A)!=$null) {
jansson_set("string", "A.average", "$avp(mos_average_A)", "$vn(mos)");
if($avp(mos_average_packetloss_A)!=$null) jansson_set("integer", "A.average_packetloss", "$avp(mos_average_packetloss_A)", "$vn(mos)");
if($avp(mos_average_jitter_A)!=$null) jansson_set("integer", "A.average_jitter", "$avp(mos_average_jitter_A)", "$vn(mos)");
if($avp(mos_average_roundtrip_A)!=$null) jansson_set("integer", "A.average_roundtrip", "$avp(mos_average_roundtrip_A)", "$vn(mos)");
if($avp(mos_average_roundtrip_leg_A)!=$null) jansson_set("integer", "A.average_roundtrip_leg", "$avp(mos_average_roundtrip_leg_A)", "$vn(mos)");
if($avp(mos_average_samples_A)!=$null) jansson_set("integer", "A.average_samples", "$avp(mos_average_samples_A)", "$vn(mos)");
}
# MOS _B
if($avp(mos_min_B)!=$null) {
jansson_set("string", "B.min", "$avp(mos_min_B)", "$vn(mos)");
if($avp(mos_min_at_B)!=$null) jansson_set("string", "B.min_at", "$avp(mos_min_at_B)", "$vn(mos)");
if($avp(mos_min_packetloss_B)!=$null) jansson_set("integer", "B.min_packetloss", "$avp(mos_min_packetloss_B)", "$vn(mos)");
if($avp(mos_min_jitter_B)!=$null) jansson_set("integer", "B.min_jitter", "$avp(mos_min_jitter_B)", "$vn(mos)");
if($avp(mos_min_roundtrip_B)!=$null) jansson_set("integer", "B.min_roundtrip", "$avp(mos_min_roundtrip_B)", "$vn(mos)");
if($avp(mos_min_roundtrip_leg_B)!=$null) jansson_set("integer", "B.min_roundtrip_leg", "$avp(mos_min_roundtrip_leg_B)", "$vn(mos)");
}
if($avp(mos_max_B)!=$null) {
jansson_set("string", "B.max", "$avp(mos_max_B)", "$vn(mos)");
if($avp(mos_max_at_B)!=$null) jansson_set("string", "B.max_at", "$avp(mos_max_at_B)", "$vn(mos)");
if($avp(mos_max_packetloss_B)!=$null) jansson_set("integer", "B.max_packetloss", "$avp(mos_max_packetloss_B)", "$vn(mos)");
if($avp(mos_max_jitter_B)!=$null) jansson_set("integer", "B.max_jitter", "$avp(mos_max_jitter_B)", "$vn(mos)");
if($avp(mos_max_roundtrip_B)!=$null) jansson_set("integer", "B.max_roundtrip", "$avp(mos_max_roundtrip_B)", "$vn(mos)");
if($avp(mos_max_roundtrip_leg_B)!=$null) jansson_set("integer", "B.max_roundtrip_leg", "$avp(mos_max_roundtrip_leg_B)", "$vn(mos)");
}
if($avp(mos_average_B)!=$null) {
jansson_set("string", "B.average", "$avp(mos_average_B)", "$vn(mos)");
if($avp(mos_average_packetloss_B)!=$null) jansson_set("integer", "B.average_packetloss", "$avp(mos_average_packetloss_B)", "$vn(mos)");
if($avp(mos_average_jitter_B)!=$null) jansson_set("integer", "B.average_jitter", "$avp(mos_average_jitter_B)", "$vn(mos)");
if($avp(mos_average_roundtrip_B)!=$null) jansson_set("integer", "B.average_roundtrip", "$avp(mos_average_roundtrip_B)", "$vn(mos)");
if($avp(mos_average_roundtrip_leg_B)!=$null) jansson_set("integer", "B.average_roundtrip_leg", "$avp(mos_average_roundtrip_leg_B)", "$vn(mos)");
if($avp(mos_average_samples_B)!=$null) jansson_set("integer", "B.average_samples", "$avp(mos_average_samples_B)", "$vn(mos)");
}
# Save to dialog/acc_cdrs
if($vn(mos)!=$null) {
jansson_set("obj", "mos", "$vn(mos)", "$dlg_var(rtpengine)");
}
#!endif
#!endif
return;
}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.kamailio.org/pipermail/sr-users/attachments/20210723/34d3d97e/attachment.sig>
More information about the sr-users
mailing list