Line data Source code
1 : /*
2 : * Copyright (C) 2004-2026 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 : #pragma once
18 :
19 : #include "media/media_codec.h"
20 : #include "noncopyable.h"
21 :
22 : #include <string>
23 : #include <vector>
24 : #include <cstring> // strcmp
25 :
26 : #include <dhtnet/ip_utils.h>
27 :
28 : #include <pjsip/sip_msg.h>
29 : #include <pjlib.h>
30 : #include <pj/pool.h>
31 : #include <pjsip/sip_endpoint.h>
32 : #include <pjsip/sip_dialog.h>
33 :
34 : namespace jami {
35 : namespace sip_utils {
36 :
37 : using namespace std::literals;
38 :
39 : // SIP methods. Only list methods that need to be explicitly
40 : // handled
41 :
42 : namespace SIP_METHODS {
43 : constexpr std::string_view MESSAGE = "MESSAGE"sv;
44 : constexpr std::string_view INFO = "INFO"sv;
45 : constexpr std::string_view OPTIONS = "OPTIONS"sv;
46 : constexpr std::string_view PUBLISH = "PUBLISH"sv;
47 : constexpr std::string_view REFER = "REFER"sv;
48 : constexpr std::string_view NOTIFY = "NOTIFY"sv;
49 : } // namespace SIP_METHODS
50 :
51 : static constexpr int DEFAULT_SIP_PORT {5060};
52 : static constexpr int DEFAULT_SIP_TLS_PORT {5061};
53 : static constexpr int DEFAULT_AUTO_SELECT_PORT {0};
54 :
55 : /// PjsipErrorCategory - a PJSIP error category for std::error_code
56 : class PjsipErrorCategory final : public std::error_category
57 : {
58 : public:
59 0 : const char* name() const noexcept override { return "pjsip"; }
60 : std::string message(int condition) const override;
61 : };
62 :
63 : /// PJSIP related exception
64 : /// Based on std::system_error with code() returning std::error_code with PjsipErrorCategory category
65 : class PjsipFailure : public std::system_error
66 : {
67 : private:
68 : static constexpr const char* what_ = "PJSIP call failed";
69 :
70 : public:
71 : PjsipFailure()
72 : : std::system_error(std::error_code(PJ_EUNKNOWN, PjsipErrorCategory()), what_)
73 : {}
74 :
75 : explicit PjsipFailure(pj_status_t status)
76 : : std::system_error(std::error_code(status, PjsipErrorCategory()), what_)
77 : {}
78 : };
79 :
80 : std::string sip_strerror(pj_status_t code);
81 :
82 : // Helper function that return a constant pj_str_t from an array of any types
83 : // that may be statically casted into char pointer.
84 : // Per convention, the input array is supposed to be null terminated.
85 : template<typename T, std::size_t N>
86 : constexpr const pj_str_t
87 2362 : CONST_PJ_STR(T (&a)[N]) noexcept
88 : {
89 2362 : return {const_cast<char*>(a), N - 1};
90 : }
91 :
92 : inline const pj_str_t
93 9756 : CONST_PJ_STR(const std::string& str) noexcept
94 : {
95 9756 : return {const_cast<char*>(str.c_str()), (pj_ssize_t) str.size()};
96 : }
97 :
98 : inline constexpr pj_str_t
99 1060 : CONST_PJ_STR(const std::string_view& str) noexcept
100 : {
101 1060 : return {const_cast<char*>(str.data()), (pj_ssize_t) str.size()};
102 : }
103 :
104 : inline constexpr std::string_view
105 3548 : as_view(const pj_str_t& str) noexcept
106 : {
107 3548 : return {str.ptr, (size_t) str.slen};
108 : }
109 :
110 : static constexpr const char*
111 272 : getKeyExchangeName(KeyExchangeProtocol kx)
112 : {
113 272 : return kx == KeyExchangeProtocol::SDES ? "sdes" : "";
114 : }
115 :
116 : static inline KeyExchangeProtocol
117 24 : getKeyExchangeProtocol(std::string_view name)
118 : {
119 24 : return name == "sdes"sv ? KeyExchangeProtocol::SDES : KeyExchangeProtocol::NONE;
120 : }
121 :
122 : /**
123 : * Helper function to parser header from incoming sip messages
124 : * @return Header from SIP message
125 : */
126 : std::string fetchHeaderValue(pjsip_msg* msg, const std::string& field);
127 :
128 : pjsip_route_hdr* createRouteSet(const std::string& route, pj_pool_t* hdr_pool);
129 :
130 : std::string_view stripSipUriPrefix(std::string_view sipUri);
131 :
132 : std::string parseDisplayName(const pjsip_name_addr* sip_name_addr);
133 : std::string parseDisplayName(const pjsip_from_hdr* header);
134 : std::string parseDisplayName(const pjsip_contact_hdr* header);
135 :
136 : std::string_view getHostFromUri(std::string_view sipUri);
137 :
138 : void addContactHeader(const std::string& contact, pjsip_tx_data* tdata);
139 : void addUserAgentHeader(const std::string& userAgent, pjsip_tx_data* tdata);
140 : std::string_view getPeerUserAgent(const pjsip_rx_data* rdata);
141 : std::vector<std::string> getPeerAllowMethods(const pjsip_rx_data* rdata);
142 : void logMessageHeaders(const pjsip_hdr* hdr_list);
143 :
144 : constexpr std::string_view DEFAULT_VIDEO_STREAMID = "video_0";
145 : constexpr std::string_view DEFAULT_AUDIO_STREAMID = "audio_0";
146 :
147 : std::string streamId(const std::string& callId, std::string_view label);
148 :
149 : // PJSIP dialog locking in RAII way
150 : // Usage: declare local variable like this: sip_utils::PJDialogLock lock {dialog};
151 : // The lock is kept until the local variable is deleted
152 : class PJDialogLock
153 : {
154 : public:
155 348 : explicit PJDialogLock(pjsip_dialog* dialog)
156 348 : : dialog_(dialog)
157 : {
158 348 : pjsip_dlg_inc_lock(dialog_);
159 348 : }
160 :
161 348 : ~PJDialogLock() { pjsip_dlg_dec_lock(dialog_); }
162 :
163 : private:
164 : NON_COPYABLE(PJDialogLock);
165 : pjsip_dialog* dialog_ {nullptr};
166 : };
167 :
168 : // Helper on PJSIP memory pool allocation from endpoint
169 : // This encapsulate the allocated memory pool inside a unique_ptr
170 : struct PoolDeleter
171 : {
172 1642 : void operator()(pj_pool_t* pool) const noexcept { pj_pool_release(pool); }
173 : };
174 : using PoolPtr = std::unique_ptr<pj_pool_t, PoolDeleter>;
175 :
176 : static inline PoolPtr
177 348 : smart_alloc_pool(pjsip_endpoint* endpt, const char* const name, pj_size_t initial, pj_size_t inc)
178 : {
179 348 : auto* pool = pjsip_endpt_create_pool(endpt, name, initial, inc);
180 348 : if (not pool)
181 0 : throw std::bad_alloc();
182 348 : return PoolPtr(pool);
183 : }
184 :
185 : void sockaddr_to_host_port(pj_pool_t* pool, pjsip_host_port* host_port, const pj_sockaddr* addr);
186 :
187 : static constexpr int POOL_TP_INIT {512};
188 : static constexpr int POOL_TP_INC {512};
189 : static constexpr int TRANSPORT_INFO_LENGTH {64};
190 :
191 : } // namespace sip_utils
192 : } // namespace jami
|