blob: b2556177715e18233493dc7f6724767a13175006 [file] [log] [blame]
Adrien BĂ©raud612b55b2023-05-29 10:42:04 -04001/*
2 * Copyright (C) 2004-2023 Savoir-faire Linux Inc.
3 *
4 * Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
5 * Author: Eden Abitbol <eden.abitbol@savoirfairelinux.com>
6 * Author: Mohamed Chibani <mohamed.chibani@savoirfairelinux.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#include "upnp_control.h"
24
25namespace jami {
26namespace upnp {
27
28Controller::Controller()
29{
30 try {
31 upnpContext_ = UPnPContext::getUPnPContext();
32 } catch (std::runtime_error& e) {
33 JAMI_ERR("UPnP context error: %s", e.what());
34 }
35
36 assert(upnpContext_);
37 upnpContext_->registerController(this);
38
39 JAMI_DBG("Controller@%p: Created UPnP Controller session", this);
40}
41
42Controller::~Controller()
43{
44 JAMI_DBG("Controller@%p: Destroying UPnP Controller session", this);
45
46 releaseAllMappings();
47 upnpContext_->unregisterController(this);
48}
49
50void
51Controller::setPublicAddress(const IpAddr& addr)
52{
53 assert(upnpContext_);
54
55 if (addr and addr.getFamily() == AF_INET) {
56 upnpContext_->setPublicAddress(addr);
57 }
58}
59
60bool
61Controller::isReady() const
62{
63 assert(upnpContext_);
64 return upnpContext_->isReady();
65}
66
67IpAddr
68Controller::getExternalIP() const
69{
70 assert(upnpContext_);
71 if (upnpContext_->isReady()) {
72 return upnpContext_->getExternalIP();
73 }
74 return {};
75}
76
77Mapping::sharedPtr_t
78Controller::reserveMapping(uint16_t port, PortType type)
79{
80 Mapping map(type, port, port);
81 return reserveMapping(map);
82}
83
84Mapping::sharedPtr_t
85Controller::reserveMapping(Mapping& requestedMap)
86{
87 assert(upnpContext_);
88
89 // Try to get a provisioned port
90 auto mapRes = upnpContext_->reserveMapping(requestedMap);
91 if (mapRes)
92 addLocalMap(*mapRes);
93 return mapRes;
94}
95
96void
97Controller::releaseMapping(const Mapping& map)
98{
99 assert(upnpContext_);
100
101 removeLocalMap(map);
102 return upnpContext_->releaseMapping(map);
103}
104
105void
106Controller::releaseAllMappings()
107{
108 assert(upnpContext_);
109
110 std::lock_guard<std::mutex> lk(mapListMutex_);
111 for (auto const& [_, map] : mappingList_) {
112 upnpContext_->releaseMapping(map);
113 }
114 mappingList_.clear();
115}
116
117void
118Controller::addLocalMap(const Mapping& map)
119{
120 if (map.getMapKey()) {
121 std::lock_guard<std::mutex> lock(mapListMutex_);
122 auto ret = mappingList_.emplace(map.getMapKey(), map);
123 if (not ret.second) {
124 JAMI_WARN("Mapping request for %s already in the list!", map.toString().c_str());
125 }
126 }
127}
128
129bool
130Controller::removeLocalMap(const Mapping& map)
131{
132 assert(upnpContext_);
133
134 std::lock_guard<std::mutex> lk(mapListMutex_);
135 if (mappingList_.erase(map.getMapKey()) != 1) {
136 JAMI_ERR("Failed to remove mapping %s from local list", map.getTypeStr());
137 return false;
138 }
139
140 return true;
141}
142
143uint16_t
144Controller::generateRandomPort(PortType type)
145{
146 return UPnPContext::generateRandomPort(type);
147}
148
149} // namespace upnp
150} // namespace jami