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 1245 : CONST_PJ_STR(T (&a)[N]) noexcept
88 : {
89 1245 : return {const_cast<char*>(a), N - 1};
90 : }
91 :
92 : inline const pj_str_t
93 4831 : CONST_PJ_STR(const std::string& str) noexcept
94 : {
95 4831 : return {const_cast<char*>(str.c_str()), (pj_ssize_t) str.size()};
96 : }
97 :
98 : inline constexpr pj_str_t
99 300 : CONST_PJ_STR(const std::string_view& str) noexcept
100 : {
101 300 : return {const_cast<char*>(str.data()), (pj_ssize_t) str.size()};
102 : }
103 :
104 : inline constexpr std::string_view
105 1492 : as_view(const pj_str_t& str) noexcept
106 : {
107 1492 : if (str.ptr == nullptr || str.slen <= 0)
108 1 : return {};
109 :
110 1491 : return {str.ptr, (size_t) str.slen};
111 : }
112 :
113 : static constexpr const char*
114 272 : getKeyExchangeName(KeyExchangeProtocol kx)
115 : {
116 272 : return kx == KeyExchangeProtocol::SDES ? "sdes" : "";
117 : }
118 :
119 : static inline KeyExchangeProtocol
120 24 : getKeyExchangeProtocol(std::string_view name)
121 : {
122 24 : return name == "sdes"sv ? KeyExchangeProtocol::SDES : KeyExchangeProtocol::NONE;
123 : }
124 :
125 : /**
126 : * Helper function to parser header from incoming sip messages
127 : * @return Header from SIP message
128 : */
129 : std::string fetchHeaderValue(pjsip_msg* msg, const std::string& field);
130 :
131 : pjsip_route_hdr* createRouteSet(const std::string& route, pj_pool_t* hdr_pool);
132 :
133 : std::string_view stripSipUriPrefix(std::string_view sipUri);
134 :
135 : std::string parseDisplayName(const pjsip_name_addr* sip_name_addr);
136 : std::string parseDisplayName(const pjsip_from_hdr* header);
137 : std::string parseDisplayName(const pjsip_contact_hdr* header);
138 :
139 : std::string_view getHostFromUri(std::string_view sipUri);
140 :
141 : void addContactHeader(const std::string& contact, pjsip_tx_data* tdata);
142 : void addUserAgentHeader(const std::string& userAgent, pjsip_tx_data* tdata);
143 : std::string_view getPeerUserAgent(const pjsip_rx_data* rdata);
144 : std::vector<std::string> getPeerAllowMethods(const pjsip_rx_data* rdata);
145 : void logMessageHeaders(const pjsip_hdr* hdr_list);
146 :
147 : constexpr std::string_view DEFAULT_VIDEO_STREAMID = "video_0";
148 : constexpr std::string_view DEFAULT_AUDIO_STREAMID = "audio_0";
149 :
150 : std::string streamId(const std::string& callId, std::string_view label);
151 :
152 : // PJSIP dialog locking in RAII way
153 : // Usage: declare local variable like this: sip_utils::PJDialogLock lock {dialog};
154 : // The lock is kept until the local variable is deleted
155 : class PJDialogLock
156 : {
157 : public:
158 57 : explicit PJDialogLock(pjsip_dialog* dialog)
159 57 : : dialog_(dialog)
160 : {
161 57 : pjsip_dlg_inc_lock(dialog_);
162 57 : }
163 :
164 57 : ~PJDialogLock() { pjsip_dlg_dec_lock(dialog_); }
165 :
166 : private:
167 : NON_COPYABLE(PJDialogLock);
168 : pjsip_dialog* dialog_ {nullptr};
169 : };
170 :
171 : // Helper on PJSIP memory pool allocation from endpoint
172 : // This encapsulate the allocated memory pool inside a unique_ptr
173 : struct PoolDeleter
174 : {
175 876 : void operator()(pj_pool_t* pool) const noexcept { pj_pool_release(pool); }
176 : };
177 : using PoolPtr = std::unique_ptr<pj_pool_t, PoolDeleter>;
178 :
179 : static inline PoolPtr
180 152 : smart_alloc_pool(pjsip_endpoint* endpt, const char* const name, pj_size_t initial, pj_size_t inc)
181 : {
182 152 : auto* pool = pjsip_endpt_create_pool(endpt, name, initial, inc);
183 152 : if (not pool)
184 0 : throw std::bad_alloc();
185 152 : return PoolPtr(pool);
186 : }
187 :
188 : void sockaddr_to_host_port(pj_pool_t* pool, pjsip_host_port* host_port, const pj_sockaddr* addr);
189 :
190 : static constexpr int POOL_TP_INIT {512};
191 : static constexpr int POOL_TP_INC {512};
192 : static constexpr int TRANSPORT_INFO_LENGTH {64};
193 :
194 : } // namespace sip_utils
195 : } // namespace jami
|