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-05-10 07:56:25 Functions: 11 16 68.8 %

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

Generated by: LCOV version 1.14