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