blob: b1b675c6ebf5b4d165987a9cdfeddabfa8b9c0a4 [file] [log] [blame]
François-Simon Fauteux-Chapleau2ef5b662024-03-27 12:30:26 -04001/*
2 * Copyright (C) 2024 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 <fmt/core.h>
20#include <mutex>
21#include <pj/errno.h>
22#include <pj/types.h>
23
24namespace dhtnet {
25
26// PJSIP expects the number of calls to pj_shutdown to match the number of calls
27// to pj_init (https://docs.pjsip.org/en/latest/specific-guides/develop/init_shutdown_thread.html).
28// The intended behavior seems to be the following:
29// - The first call to pj_init actually initializes the library; subsequent calls do nothing.
30// - All calls to pj_shutdown do nothing, except the last one which actually performs the shutdown.
31// Unfortunately, the way this logic is implemented in PJSIP is not thread-safe, so we're
ovari123a15c6882024-09-17 18:34:20 -040032// responsible for making sure that these functions are unable to be called by two threads at the same time.
François-Simon Fauteux-Chapleau2ef5b662024-03-27 12:30:26 -040033class PjInitLock
34{
35private:
36 inline static std::mutex mutex_;
37
38public:
39 PjInitLock()
40 {
41 std::lock_guard lk(mutex_);
42 pj_status_t status = pj_init();
43
44 if (status != PJ_SUCCESS) {
45 char errorMessage[PJ_ERR_MSG_SIZE];
46 pj_strerror(status, errorMessage, sizeof(errorMessage));
47 throw std::runtime_error(
48 fmt::format("pj_init failed: {}", errorMessage));
49 }
50 }
51
52 ~PjInitLock()
53 {
54 std::lock_guard lk(mutex_);
55 pj_shutdown();
56 }
57};
58
59}