Ring Daemon 16.0.0
Loading...
Searching...
No Matches
sip_utils.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2025 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
19#include "logger.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
42using namespace std::literals;
43
44namespace jami {
45namespace sip_utils {
46
47constexpr pj_str_t USER_AGENT_STR = CONST_PJ_STR("User-Agent");
48
49std::string
51{
52 std::string err_msg;
53 err_msg.reserve(PJ_ERR_MSG_SIZE);
54 err_msg.resize(pj_strerror(condition, &err_msg[0], err_msg.capacity()).slen);
55 return err_msg;
56}
57
58std::string
59fetchHeaderValue(pjsip_msg* msg, const std::string& field)
60{
61 pj_str_t name = pj_str((char*) field.c_str());
64
65 if (!hdr)
66 return "";
67
68 std::string value(hdr->hvalue.ptr, hdr->hvalue.slen);
69
70 size_t pos = value.find('\n');
71
72 if (pos != std::string::npos)
73 return value.substr(0, pos);
74 else
75 return "";
76}
77
80{
82
83 std::string host;
84 int port = 0;
85 size_t found = route.find(':');
86 if (found != std::string::npos) {
87 host = route.substr(0, found);
88 port = atoi(route.substr(found + 1, route.length() - found).c_str());
89 } else
90 host = route;
91
94 url->lr_param = 1;
95 routing->name_addr.uri = (pjsip_uri*) url;
96 pj_strdup2(hdr_pool, &url->host, host.c_str());
97 url->port = port;
98
99 JAMI_DBG("Adding route %s", host.c_str());
101
102 return route_set;
103}
104
105std::string
107{
108 if (not sip_name_addr->display.ptr or not sip_name_addr->display.slen)
109 return {};
110
111 auto displayName = as_view(sip_name_addr->display);
112
113 // Filter out invalid UTF-8 characters to avoid getting kicked from D-Bus
114 if (not utf8_validate(displayName))
115 return utf8_make_valid(displayName);
116
117 return std::string(displayName);
118}
119
120std::string
122{
123 // PJSIP return a pjsip_name_addr for To, From and Contact headers
124 return parseDisplayName(reinterpret_cast<pjsip_name_addr*>(header->uri));
125}
126
127std::string
129{
130 // PJSIP return a pjsip_name_addr for To, From and Contact headers
131 return parseDisplayName(reinterpret_cast<pjsip_name_addr*>(header->uri));
132}
133
134std::string_view
135stripSipUriPrefix(std::string_view sipUri)
136{
137 // Remove sip: prefix
138 static constexpr auto SIP_PREFIX = "sip:"sv;
139 size_t found = sipUri.find(SIP_PREFIX);
140
141 if (found != std::string_view::npos)
142 sipUri = sipUri.substr(found + SIP_PREFIX.size());
143
144 // URI may or may not be between brackets
145 found = sipUri.find('<');
146 if (found != std::string_view::npos)
147 sipUri = sipUri.substr(found + 1);
148
149 found = sipUri.find('@');
150 if (found != std::string_view::npos)
151 sipUri = sipUri.substr(0, found);
152
153 found = sipUri.find('>');
154 if (found != std::string_view::npos)
155 sipUri = sipUri.substr(0, found);
156
157 return sipUri;
158}
159
160std::string_view
161getHostFromUri(std::string_view uri)
162{
163 auto found = uri.find('@');
164 if (found != std::string_view::npos)
165 uri = uri.substr(found + 1);
166
167 found = uri.find('>');
168 if (found != std::string_view::npos)
169 uri = uri.substr(0, found);
170
171 return uri;
172}
173
174void
176{
177 if (contactHdr.empty()) {
178 JAMI_WARN("Contact header is unable to be added (empty string)");
179 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 auto pjContact = pj_strdup3(tdata->pool, contactHdr.c_str());
189
191 contact->uri = pjsip_parse_uri(tdata->pool,
192 pjContact.ptr,
193 pjContact.slen,
195 // remove old contact header (if present)
198}
199
200void
202{
203 if (tdata == nullptr or userAgent.empty())
204 return;
205
207
208 // Do nothing if user-agent header is present.
209 if (pjsip_msg_find_hdr_by_name(tdata->msg, &USER_AGENT_STR, nullptr) != nullptr) {
210 return;
211 }
212
213 // Add Header
214 auto hdr = reinterpret_cast<pjsip_hdr*>(
216
217 if (hdr != nullptr) {
219 }
220}
221
222std::string_view
224{
225 if (rdata == nullptr or rdata->msg_info.msg == nullptr) {
226 JAMI_ERR("Unexpected null pointer!");
227 return {};
228 }
229
232 nullptr)) {
233 return as_view(uaHdr->hvalue);
234 }
235 return {};
236}
237
238std::vector<std::string>
240{
241 if (rdata == nullptr or rdata->msg_info.msg == nullptr) {
242 JAMI_ERR("Unexpected null pointer!");
243 return {};
244 }
245
246 std::vector<std::string> methods;
247
248 pjsip_allow_hdr* allow = static_cast<pjsip_allow_hdr*>(
249 pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ALLOW, nullptr));
250
251 if (allow != nullptr) {
252 methods.reserve(allow->count);
253 for (unsigned i = 0; i < allow->count; i++) {
254 methods.emplace_back(allow->values[i].ptr, allow->values[i].slen);
255 }
256 }
257
258 return methods;
259}
260
261void
263{
264 const pjsip_hdr* hdr = hdr_list->next;
265 const pjsip_hdr* end = hdr_list;
266 std::string msgHdrStr("Message headers:\n");
267 for (; hdr != end; hdr = hdr->next) {
268 char buf[1024];
269 int size = pjsip_hdr_print_on((void*) hdr, buf, sizeof(buf));
270 if (size > 0) {
271 msgHdrStr.append(buf, size);
272 msgHdrStr.push_back('\n');
273 }
274 }
275
276 JAMI_LOG("{}", msgHdrStr);
277}
278
279std::string
281{
283 auto ret = pj_strerror(code, err_msg, sizeof err_msg);
284 return std::string {ret.ptr, ret.ptr + ret.slen};
285}
286
287std::string
288streamId(const std::string& callId, std::string_view label)
289{
290 if (callId.empty())
291 return fmt::format("host_{}", label);
292 return fmt::format("{}_{}", callId, label);
293}
294
295void
297{
298 host_port->host.ptr = (char*) pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN + 4);
299 pj_sockaddr_print(addr, host_port->host.ptr, PJ_INET6_ADDRSTRLEN + 4, 0);
300 host_port->host.slen = pj_ansi_strlen(host_port->host.ptr);
301 host_port->port = pj_sockaddr_get_port(addr);
302}
303
304} // namespace sip_utils
305} // namespace jami
std::string message(int condition) const override
Definition sip_utils.cpp:50
#define JAMI_ERR(...)
Definition logger.h:218
#define JAMI_DBG(...)
Definition logger.h:216
#define JAMI_WARN(...)
Definition logger.h:217
#define JAMI_LOG(formatstr,...)
Definition logger.h:225
std::string fetchHeaderValue(pjsip_msg *msg, const std::string &field)
Helper function to parser header from incoming sip messages.
Definition sip_utils.cpp:59
void logMessageHeaders(const pjsip_hdr *hdr_list)
constexpr pj_str_t USER_AGENT_STR
Definition sip_utils.cpp:47
void addUserAgentHeader(const std::string &userAgent, pjsip_tx_data *tdata)
void addContactHeader(const std::string &contactHdr, pjsip_tx_data *tdata)
std::string_view stripSipUriPrefix(std::string_view sipUri)
std::string_view getHostFromUri(std::string_view uri)
pjsip_route_hdr * createRouteSet(const std::string &route, pj_pool_t *hdr_pool)
Definition sip_utils.cpp:79
std::string sip_strerror(pj_status_t code)
constexpr std::string_view as_view(const pj_str_t &str) noexcept
Definition sip_utils.h:107
std::string_view getPeerUserAgent(const pjsip_rx_data *rdata)
std::vector< std::string > getPeerAllowMethods(const pjsip_rx_data *rdata)
std::string parseDisplayName(const pjsip_name_addr *sip_name_addr)
std::string streamId(const std::string &callId, std::string_view label)
void sockaddr_to_host_port(pj_pool_t *pool, pjsip_host_port *host_port, const pj_sockaddr *addr)
constexpr const pj_str_t CONST_PJ_STR(T(&a)[N]) noexcept
Definition sip_utils.h:89
bool utf8_validate(std::string_view str)
utf8_validate:
void emitSignal(Args... args)
Definition ring_signal.h:64
std::string utf8_make_valid(std::string_view name)
const std::string & userAgent()