[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