LCOV - code coverage report
Current view: top level - src/connectivity - sip_utils.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 75 131 57.3 %
Date: 2024-12-21 08:56:24 Functions: 13 18 72.2 %

          Line data    Source code
       1             : /*
       2             :  *  Copyright (C) 2004-2024 Savoir-faire Linux Inc.
       3             :  *
       4             :  *  This program is free software: you can redistribute it and/or modify
       5             :  *  it under the terms of the GNU General Public License as published by
       6             :  *  the Free Software Foundation, either version 3 of the License, or
       7             :  *  (at your option) any later version.
       8             :  *
       9             :  *  This program is distributed in the hope that it will be useful,
      10             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      12             :  *  GNU General Public License for more details.
      13             :  *
      14             :  *  You should have received a copy of the GNU General Public License
      15             :  *  along with this program. If not, see <https://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "connectivity/sip_utils.h"
      19             : #include "logger.h"
      20             : #include "connectivity/utf8_utils.h"
      21             : 
      22             : #include <pjsip.h>
      23             : #include <pjsip_ua.h>
      24             : #include <pjlib-util.h>
      25             : #include <pjnath.h>
      26             : #include <pjnath/stun_config.h>
      27             : #include <pj/string.h>
      28             : #include <pjsip/sip_types.h>
      29             : #include <pjsip/sip_uri.h>
      30             : #include <pj/list.h>
      31             : 
      32             : #ifndef _WIN32
      33             : #include <netdb.h>
      34             : #include <sys/socket.h>
      35             : #include <netinet/in.h>
      36             : #include <arpa/inet.h>
      37             : #endif
      38             : 
      39             : #include <vector>
      40             : #include <algorithm>
      41             : 
      42             : using namespace std::literals;
      43             : 
      44             : namespace jami {
      45             : namespace sip_utils {
      46             : 
      47             : constexpr pj_str_t USER_AGENT_STR = CONST_PJ_STR("User-Agent");
      48             : 
      49             : std::string
      50           0 : PjsipErrorCategory::message(int condition) const
      51             : {
      52           0 :     std::string err_msg;
      53           0 :     err_msg.reserve(PJ_ERR_MSG_SIZE);
      54           0 :     err_msg.resize(pj_strerror(condition, &err_msg[0], err_msg.capacity()).slen);
      55           0 :     return err_msg;
      56           0 : }
      57             : 
      58             : std::string
      59           0 : fetchHeaderValue(pjsip_msg* msg, const std::string& field)
      60             : {
      61           0 :     pj_str_t name = pj_str((char*) field.c_str());
      62             :     pjsip_generic_string_hdr* hdr = static_cast<pjsip_generic_string_hdr*>(
      63           0 :         pjsip_msg_find_hdr_by_name(msg, &name, NULL));
      64             : 
      65           0 :     if (!hdr)
      66           0 :         return "";
      67             : 
      68           0 :     std::string value(hdr->hvalue.ptr, hdr->hvalue.slen);
      69             : 
      70           0 :     size_t pos = value.find('\n');
      71             : 
      72           0 :     if (pos != std::string::npos)
      73           0 :         return value.substr(0, pos);
      74             :     else
      75           0 :         return "";
      76           0 : }
      77             : 
      78             : pjsip_route_hdr*
      79           0 : createRouteSet(const std::string& route, pj_pool_t* hdr_pool)
      80             : {
      81           0 :     pjsip_route_hdr* route_set = pjsip_route_hdr_create(hdr_pool);
      82             : 
      83           0 :     std::string host;
      84           0 :     int port = 0;
      85           0 :     size_t found = route.find(':');
      86           0 :     if (found != std::string::npos) {
      87           0 :         host = route.substr(0, found);
      88           0 :         port = atoi(route.substr(found + 1, route.length() - found).c_str());
      89             :     } else
      90           0 :         host = route;
      91             : 
      92           0 :     pjsip_route_hdr* routing = pjsip_route_hdr_create(hdr_pool);
      93           0 :     pjsip_sip_uri* url = pjsip_sip_uri_create(hdr_pool, 0);
      94           0 :     url->lr_param = 1;
      95           0 :     routing->name_addr.uri = (pjsip_uri*) url;
      96           0 :     pj_strdup2(hdr_pool, &url->host, host.c_str());
      97           0 :     url->port = port;
      98             : 
      99           0 :     JAMI_DBG("Adding route %s", host.c_str());
     100           0 :     pj_list_push_back(route_set, pjsip_hdr_clone(hdr_pool, routing));
     101             : 
     102           0 :     return route_set;
     103           0 : }
     104             : 
     105             : std::string
     106         107 : parseDisplayName(const pjsip_name_addr* sip_name_addr)
     107             : {
     108         107 :     if (not sip_name_addr->display.ptr or not sip_name_addr->display.slen)
     109           0 :         return {};
     110             : 
     111         107 :     auto displayName = as_view(sip_name_addr->display);
     112             : 
     113             :     // Filter out invalid UTF-8 characters to avoid getting kicked from D-Bus
     114         107 :     if (not utf8_validate(displayName))
     115         107 :         return utf8_make_valid(displayName);
     116             : 
     117           0 :     return std::string(displayName);
     118             : }
     119             : 
     120             : std::string
     121         107 : parseDisplayName(const pjsip_from_hdr* header)
     122             : {
     123             :     // PJSIP return a pjsip_name_addr for To, From and Contact headers
     124         107 :     return parseDisplayName(reinterpret_cast<pjsip_name_addr*>(header->uri));
     125             : }
     126             : 
     127             : std::string
     128           0 : parseDisplayName(const pjsip_contact_hdr* header)
     129             : {
     130             :     // PJSIP return a pjsip_name_addr for To, From and Contact headers
     131           0 :     return parseDisplayName(reinterpret_cast<pjsip_name_addr*>(header->uri));
     132             : }
     133             : 
     134             : std::string_view
     135           1 : stripSipUriPrefix(std::string_view sipUri)
     136             : {
     137             :     // Remove sip: prefix
     138             :     static constexpr auto SIP_PREFIX = "sip:"sv;
     139           1 :     size_t found = sipUri.find(SIP_PREFIX);
     140             : 
     141           1 :     if (found != std::string_view::npos)
     142           1 :         sipUri = sipUri.substr(found + SIP_PREFIX.size());
     143             : 
     144             :     // URI may or may not be between brackets
     145           1 :     found = sipUri.find('<');
     146           1 :     if (found != std::string_view::npos)
     147           0 :         sipUri = sipUri.substr(found + 1);
     148             : 
     149           1 :     found = sipUri.find('@');
     150           1 :     if (found != std::string_view::npos)
     151           1 :         sipUri = sipUri.substr(0, found);
     152             : 
     153           1 :     found = sipUri.find('>');
     154           1 :     if (found != std::string_view::npos)
     155           0 :         sipUri = sipUri.substr(0, found);
     156             : 
     157           1 :     return sipUri;
     158             : }
     159             : 
     160             : std::string_view
     161           0 : getHostFromUri(std::string_view uri)
     162             : {
     163           0 :     auto found = uri.find('@');
     164           0 :     if (found != std::string_view::npos)
     165           0 :         uri = uri.substr(found + 1);
     166             : 
     167           0 :     found = uri.find('>');
     168           0 :     if (found != std::string_view::npos)
     169           0 :         uri = uri.substr(0, found);
     170             : 
     171           0 :     return uri;
     172             : }
     173             : 
     174             : void
     175         337 : addContactHeader(const std::string& contactHdr, pjsip_tx_data* tdata)
     176             : {
     177         337 :     if (contactHdr.empty()) {
     178           0 :         JAMI_WARN("Contact header is unable to be added (empty string)");
     179           0 :         return;
     180             :     }
     181             : 
     182             :     /*
     183             :      * Duplicate contact header because tdata->msg keep a reference to it and
     184             :      * can be used in a callback after destruction of the contact header in
     185             :      * Jami.  Bind lifetime of the duplicated string to the pool allocator of
     186             :      * tdata.
     187             :      */
     188         337 :     auto pjContact = pj_strdup3(tdata->pool, contactHdr.c_str());
     189             : 
     190         337 :     pjsip_contact_hdr* contact = pjsip_contact_hdr_create(tdata->pool);
     191         674 :     contact->uri = pjsip_parse_uri(tdata->pool,
     192             :                                    pjContact.ptr,
     193         337 :                                    pjContact.slen,
     194             :                                    PJSIP_PARSE_URI_AS_NAMEADDR);
     195             :     // remove old contact header (if present)
     196         337 :     pjsip_msg_find_remove_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
     197         337 :     pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) contact);
     198             : }
     199             : 
     200             : void
     201         770 : addUserAgentHeader(const std::string& userAgent, pjsip_tx_data* tdata)
     202             : {
     203         770 :     if (tdata == nullptr or userAgent.empty())
     204         101 :         return;
     205             : 
     206         770 :     auto pjUserAgent = CONST_PJ_STR(userAgent);
     207             : 
     208             :     // Do nothing if user-agent header is present.
     209         770 :     if (pjsip_msg_find_hdr_by_name(tdata->msg, &USER_AGENT_STR, nullptr) != nullptr) {
     210         101 :         return;
     211             :     }
     212             : 
     213             :     // Add Header
     214             :     auto hdr = reinterpret_cast<pjsip_hdr*>(
     215         669 :         pjsip_user_agent_hdr_create(tdata->pool, &USER_AGENT_STR, &pjUserAgent));
     216             : 
     217         669 :     if (hdr != nullptr) {
     218         669 :         pjsip_msg_add_hdr(tdata->msg, hdr);
     219             :     }
     220             : }
     221             : 
     222             : std::string_view
     223         506 : getPeerUserAgent(const pjsip_rx_data* rdata)
     224             : {
     225         506 :     if (rdata == nullptr or rdata->msg_info.msg == nullptr) {
     226           0 :         JAMI_ERR("Unexpected null pointer!");
     227           0 :         return {};
     228             :     }
     229             : 
     230         506 :     if (auto uaHdr = (pjsip_generic_string_hdr*) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
     231             :                                                                             &USER_AGENT_STR,
     232             :                                                                             nullptr)) {
     233         410 :         return as_view(uaHdr->hvalue);
     234             :     }
     235          96 :     return {};
     236             : }
     237             : 
     238             : std::vector<std::string>
     239         506 : getPeerAllowMethods(const pjsip_rx_data* rdata)
     240             : {
     241         506 :     if (rdata == nullptr or rdata->msg_info.msg == nullptr) {
     242           0 :         JAMI_ERR("Unexpected null pointer!");
     243           0 :         return {};
     244             :     }
     245             : 
     246         506 :     std::vector<std::string> methods;
     247             : 
     248             :     pjsip_allow_hdr* allow = static_cast<pjsip_allow_hdr*>(
     249         506 :         pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ALLOW, nullptr));
     250             : 
     251         506 :     if (allow != nullptr) {
     252         315 :         methods.reserve(allow->count);
     253        4094 :         for (unsigned i = 0; i < allow->count; i++) {
     254        3779 :             methods.emplace_back(allow->values[i].ptr, allow->values[i].slen);
     255             :         }
     256             :     }
     257             : 
     258         506 :     return methods;
     259         506 : }
     260             : 
     261             : void
     262         107 : logMessageHeaders(const pjsip_hdr* hdr_list)
     263             : {
     264         107 :     const pjsip_hdr* hdr = hdr_list->next;
     265         107 :     const pjsip_hdr* end = hdr_list;
     266         107 :     std::string msgHdrStr("Message headers:\n");
     267        1498 :     for (; hdr != end; hdr = hdr->next) {
     268             :         char buf[1024];
     269        1391 :         int size = pjsip_hdr_print_on((void*) hdr, buf, sizeof(buf));
     270        1391 :         if (size > 0) {
     271        1391 :             msgHdrStr.append(buf, size);
     272        1391 :             msgHdrStr.push_back('\n');
     273             :         }
     274             :     }
     275             : 
     276         321 :     JAMI_LOG("{}", msgHdrStr);
     277         107 : }
     278             : 
     279             : std::string
     280           2 : sip_strerror(pj_status_t code)
     281             : {
     282             :     char err_msg[PJ_ERR_MSG_SIZE];
     283           2 :     auto ret = pj_strerror(code, err_msg, sizeof err_msg);
     284           2 :     return std::string {ret.ptr, ret.ptr + ret.slen};
     285             : }
     286             : 
     287             : std::string
     288         769 : streamId(const std::string& callId, std::string_view label)
     289             : {
     290         769 :     if (callId.empty())
     291          42 :         return fmt::format("host_{}", label);
     292         727 :     return fmt::format("{}_{}", callId, label);
     293             : }
     294             : 
     295             : void
     296        2736 : sockaddr_to_host_port(pj_pool_t* pool, pjsip_host_port* host_port, const pj_sockaddr* addr)
     297             : {
     298        2736 :     host_port->host.ptr = (char*) pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN + 4);
     299        2736 :     pj_sockaddr_print(addr, host_port->host.ptr, PJ_INET6_ADDRSTRLEN + 4, 0);
     300        2736 :     host_port->host.slen = pj_ansi_strlen(host_port->host.ptr);
     301        2736 :     host_port->port = pj_sockaddr_get_port(addr);
     302        2736 : }
     303             : 
     304             : } // namespace sip_utils
     305             : } // namespace jami

Generated by: LCOV version 1.14