blob: 9b3883106d1e714da13a8fb41ea89262502efaa4 [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 "mapping.h"
24#include "logger.h"
25
26namespace jami {
27namespace upnp {
28
29Mapping::Mapping(PortType type, uint16_t portExternal, uint16_t portInternal, bool available)
30 : type_(type)
31 , externalPort_(portExternal)
32 , internalPort_(portInternal)
33 , internalAddr_()
34 , igd_()
35 , available_(available)
36 , state_(MappingState::PENDING)
37 , notifyCb_(nullptr)
38 , autoUpdate_(false)
39#if HAVE_LIBNATPMP
40 , renewalTime_(sys_clock::now())
41#endif
42{}
43
44Mapping::Mapping(const Mapping& other)
45{
46 std::lock_guard<std::mutex> lock(other.mutex_);
47
48 internalAddr_ = other.internalAddr_;
49 internalPort_ = other.internalPort_;
50 externalPort_ = other.externalPort_;
51 type_ = other.type_;
52 igd_ = other.igd_;
53 available_ = other.available_;
54 state_ = other.state_;
55 notifyCb_ = other.notifyCb_;
56 autoUpdate_ = other.autoUpdate_;
57#if HAVE_LIBNATPMP
58 renewalTime_ = other.renewalTime_;
59#endif
60}
61
62void
63Mapping::updateFrom(const Mapping::sharedPtr_t& other)
64{
65 updateFrom(*other);
66}
67
68void
69Mapping::updateFrom(const Mapping& other)
70{
71 if (type_ != other.type_) {
72 JAMI_ERR("The source and destination types must match");
73 return;
74 }
75
76 internalAddr_ = std::move(other.internalAddr_);
77 internalPort_ = other.internalPort_;
78 externalPort_ = other.externalPort_;
79 igd_ = other.igd_;
80 state_ = other.state_;
81}
82
83void
84Mapping::setAvailable(bool val)
85{
86 JAMI_DBG("Changing mapping %s state from %s to %s",
87 toString().c_str(),
88 available_ ? "AVAILABLE" : "UNAVAILABLE",
89 val ? "AVAILABLE" : "UNAVAILABLE");
90
91 std::lock_guard<std::mutex> lock(mutex_);
92 available_ = val;
93}
94
95void
96Mapping::setState(const MappingState& state)
97{
98 std::lock_guard<std::mutex> lock(mutex_);
99 state_ = state;
100}
101
102const char*
103Mapping::getStateStr() const
104{
105 std::lock_guard<std::mutex> lock(mutex_);
106 return getStateStr(state_);
107}
108
109std::string
110Mapping::toString(bool extraInfo) const
111{
112 std::lock_guard<std::mutex> lock(mutex_);
113 std::ostringstream descr;
114 descr << UPNP_MAPPING_DESCRIPTION_PREFIX << "-" << getTypeStr(type_);
115 descr << ":" << std::to_string(internalPort_);
116
117 if (extraInfo) {
118 descr << " (state=" << getStateStr(state_)
119 << ", auto-update=" << (autoUpdate_ ? "YES" : "NO") << ")";
120 }
121
122 return descr.str();
123}
124
125bool
126Mapping::isValid() const
127{
128 std::lock_guard<std::mutex> lock(mutex_);
129 if (state_ == MappingState::FAILED)
130 return false;
131 if (internalPort_ == 0)
132 return false;
133 if (externalPort_ == 0)
134 return false;
135 if (not igd_ or not igd_->isValid())
136 return false;
137 IpAddr intAddr(internalAddr_);
138 return intAddr and not intAddr.isLoopback();
139}
140
141bool
142Mapping::hasValidHostAddress() const
143{
144 std::lock_guard<std::mutex> lock(mutex_);
145
146 IpAddr intAddr(internalAddr_);
147 return intAddr and not intAddr.isLoopback();
148}
149
150bool
151Mapping::hasPublicAddress() const
152{
153 std::lock_guard<std::mutex> lock(mutex_);
154
155 return igd_ and igd_->getPublicIp() and not igd_->getPublicIp().isPrivate();
156}
157
158Mapping::key_t
159Mapping::getMapKey() const
160{
161 std::lock_guard<std::mutex> lock(mutex_);
162
163 key_t mapKey = internalPort_;
164 if (type_ == PortType::UDP)
165 mapKey |= 1 << (sizeof(uint16_t) * 8);
166 return mapKey;
167}
168
169PortType
170Mapping::getTypeFromMapKey(key_t key)
171{
172 return (key >> (sizeof(uint16_t) * 8)) ? PortType::UDP : PortType::TCP;
173}
174
175std::string
176Mapping::getExternalAddress() const
177{
178 std::lock_guard<std::mutex> lock(mutex_);
179 if (igd_)
180 return igd_->getPublicIp().toString();
181 return {};
182}
183
184void
185Mapping::setExternalPort(uint16_t port)
186{
187 std::lock_guard<std::mutex> lock(mutex_);
188 externalPort_ = port;
189}
190
191uint16_t
192Mapping::getExternalPort() const
193{
194 std::lock_guard<std::mutex> lock(mutex_);
195 return externalPort_;
196}
197
198std::string
199Mapping::getExternalPortStr() const
200{
201 std::lock_guard<std::mutex> lock(mutex_);
202 return std::to_string(externalPort_);
203}
204
205void
206Mapping::setInternalAddress(const std::string& addr)
207{
208 std::lock_guard<std::mutex> lock(mutex_);
209 internalAddr_ = addr;
210}
211
212std::string
213Mapping::getInternalAddress() const
214{
215 std::lock_guard<std::mutex> lock(mutex_);
216 return internalAddr_;
217}
218
219void
220Mapping::setInternalPort(uint16_t port)
221{
222 std::lock_guard<std::mutex> lock(mutex_);
223 internalPort_ = port;
224}
225
226uint16_t
227Mapping::getInternalPort() const
228{
229 std::lock_guard<std::mutex> lock(mutex_);
230 return internalPort_;
231}
232
233std::string
234Mapping::getInternalPortStr() const
235{
236 std::lock_guard<std::mutex> lock(mutex_);
237 return std::to_string(internalPort_);
238}
239
240PortType
241Mapping::getType() const
242{
243 std::lock_guard<std::mutex> lock(mutex_);
244 return type_;
245}
246
247const char*
248Mapping::getTypeStr() const
249{
250 std::lock_guard<std::mutex> lock(mutex_);
251 return getTypeStr(type_);
252}
253
254bool
255Mapping::isAvailable() const
256{
257 std::lock_guard<std::mutex> lock(mutex_);
258 return available_;
259}
260
261std::shared_ptr<IGD>
262Mapping::getIgd() const
263{
264 std::lock_guard<std::mutex> lock(mutex_);
265 return igd_;
266}
267
268NatProtocolType
269Mapping::getProtocol() const
270{
271 std::lock_guard<std::mutex> lock(mutex_);
272 if (igd_)
273 return igd_->getProtocol();
274 return NatProtocolType::UNKNOWN;
275}
276const char*
277Mapping::getProtocolName() const
278{
279 if (igd_) {
280 if (igd_->getProtocol() == NatProtocolType::NAT_PMP)
281 return "NAT-PMP";
282 if (igd_->getProtocol() == NatProtocolType::PUPNP)
283 return "PUPNP";
284 }
285 return "UNKNOWN";
286}
287
288void
289Mapping::setIgd(const std::shared_ptr<IGD>& igd)
290{
291 std::lock_guard<std::mutex> lock(mutex_);
292 igd_ = igd;
293}
294
295MappingState
296Mapping::getState() const
297{
298 std::lock_guard<std::mutex> lock(mutex_);
299 return state_;
300}
301
302Mapping::NotifyCallback
303Mapping::getNotifyCallback() const
304{
305 std::lock_guard<std::mutex> lock(mutex_);
306 return notifyCb_;
307}
308
309void
310Mapping::setNotifyCallback(NotifyCallback cb)
311{
312 std::lock_guard<std::mutex> lock(mutex_);
313 notifyCb_ = std::move(cb);
314}
315
316void
317Mapping::enableAutoUpdate(bool enable)
318{
319 std::lock_guard<std::mutex> lock(mutex_);
320 autoUpdate_ = enable;
321}
322
323bool
324Mapping::getAutoUpdate() const
325{
326 std::lock_guard<std::mutex> lock(mutex_);
327 return autoUpdate_;
328}
329
330#if HAVE_LIBNATPMP
331sys_clock::time_point
332Mapping::getRenewalTime() const
333{
334 std::lock_guard<std::mutex> lock(mutex_);
335 return renewalTime_;
336}
337
338void
339Mapping::setRenewalTime(sys_clock::time_point time)
340{
341 std::lock_guard<std::mutex> lock(mutex_);
342 renewalTime_ = time;
343}
344#endif
345
346} // namespace upnp
347} // namespace jami