blob: bcd53b5d35fbbf61e27c46d36c3703dca6e768ea [file] [log] [blame]
Adrien Béraud612b55b2023-05-29 10:42:04 -04001/*
2 * Copyright (C) 2004-2023 Savoir-faire Linux Inc.
3 *
Adrien Béraudcb753622023-07-17 22:32:49 -04004 * This program is free software: you can redistribute it and/or modify
Adrien Béraud612b55b2023-05-29 10:42:04 -04005 * it under the terms of the GNU General Public License as published by
Adrien Béraudcb753622023-07-17 22:32:49 -04006 * the Free Software Foundation, either version 3 of the License, or
Adrien Béraud612b55b2023-05-29 10:42:04 -04007 * (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
Adrien Béraudcb753622023-07-17 22:32:49 -040011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Adrien Béraud612b55b2023-05-29 10:42:04 -040012 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
Adrien Béraudcb753622023-07-17 22:32:49 -040015 * along with this program. If not, see <https://www.gnu.org/licenses/>.
Adrien Béraud612b55b2023-05-29 10:42:04 -040016 */
Morteza Namvar5f639522023-07-04 17:08:58 -040017#include "upnp/mapping.h"
18// #include "logger.h"
Adrien Béraud33a03ba2023-06-21 11:35:54 -040019#include "igd.h"
Adrien Béraud612b55b2023-05-29 10:42:04 -040020
Adrien Béraud1ae60aa2023-07-07 09:55:09 -040021namespace dhtnet {
Adrien Béraud612b55b2023-05-29 10:42:04 -040022namespace upnp {
23
24Mapping::Mapping(PortType type, uint16_t portExternal, uint16_t portInternal, bool available)
25 : type_(type)
26 , externalPort_(portExternal)
27 , internalPort_(portInternal)
28 , internalAddr_()
29 , igd_()
30 , available_(available)
31 , state_(MappingState::PENDING)
32 , notifyCb_(nullptr)
33 , autoUpdate_(false)
34#if HAVE_LIBNATPMP
35 , renewalTime_(sys_clock::now())
36#endif
37{}
38
39Mapping::Mapping(const Mapping& other)
40{
41 std::lock_guard<std::mutex> lock(other.mutex_);
42
43 internalAddr_ = other.internalAddr_;
44 internalPort_ = other.internalPort_;
45 externalPort_ = other.externalPort_;
46 type_ = other.type_;
47 igd_ = other.igd_;
48 available_ = other.available_;
49 state_ = other.state_;
50 notifyCb_ = other.notifyCb_;
51 autoUpdate_ = other.autoUpdate_;
52#if HAVE_LIBNATPMP
53 renewalTime_ = other.renewalTime_;
54#endif
55}
56
57void
58Mapping::updateFrom(const Mapping::sharedPtr_t& other)
59{
60 updateFrom(*other);
61}
62
63void
64Mapping::updateFrom(const Mapping& other)
65{
66 if (type_ != other.type_) {
Morteza Namvar5f639522023-07-04 17:08:58 -040067 // JAMI_ERR("The source and destination types must match");
Adrien Béraud612b55b2023-05-29 10:42:04 -040068 return;
69 }
70
71 internalAddr_ = std::move(other.internalAddr_);
72 internalPort_ = other.internalPort_;
73 externalPort_ = other.externalPort_;
74 igd_ = other.igd_;
75 state_ = other.state_;
76}
77
78void
79Mapping::setAvailable(bool val)
80{
Morteza Namvar5f639522023-07-04 17:08:58 -040081 // JAMI_DBG("Changing mapping %s state from %s to %s",
82 // toString().c_str(),
83 // available_ ? "AVAILABLE" : "UNAVAILABLE",
84 // val ? "AVAILABLE" : "UNAVAILABLE");
Adrien Béraud612b55b2023-05-29 10:42:04 -040085
86 std::lock_guard<std::mutex> lock(mutex_);
87 available_ = val;
88}
89
90void
91Mapping::setState(const MappingState& state)
92{
93 std::lock_guard<std::mutex> lock(mutex_);
94 state_ = state;
95}
96
97const char*
98Mapping::getStateStr() const
99{
100 std::lock_guard<std::mutex> lock(mutex_);
101 return getStateStr(state_);
102}
103
104std::string
105Mapping::toString(bool extraInfo) const
106{
107 std::lock_guard<std::mutex> lock(mutex_);
108 std::ostringstream descr;
109 descr << UPNP_MAPPING_DESCRIPTION_PREFIX << "-" << getTypeStr(type_);
110 descr << ":" << std::to_string(internalPort_);
111
112 if (extraInfo) {
113 descr << " (state=" << getStateStr(state_)
114 << ", auto-update=" << (autoUpdate_ ? "YES" : "NO") << ")";
115 }
116
117 return descr.str();
118}
119
120bool
121Mapping::isValid() const
122{
123 std::lock_guard<std::mutex> lock(mutex_);
124 if (state_ == MappingState::FAILED)
125 return false;
126 if (internalPort_ == 0)
127 return false;
128 if (externalPort_ == 0)
129 return false;
130 if (not igd_ or not igd_->isValid())
131 return false;
132 IpAddr intAddr(internalAddr_);
133 return intAddr and not intAddr.isLoopback();
134}
135
136bool
137Mapping::hasValidHostAddress() const
138{
139 std::lock_guard<std::mutex> lock(mutex_);
140
141 IpAddr intAddr(internalAddr_);
142 return intAddr and not intAddr.isLoopback();
143}
144
145bool
146Mapping::hasPublicAddress() const
147{
148 std::lock_guard<std::mutex> lock(mutex_);
149
150 return igd_ and igd_->getPublicIp() and not igd_->getPublicIp().isPrivate();
151}
152
153Mapping::key_t
154Mapping::getMapKey() const
155{
156 std::lock_guard<std::mutex> lock(mutex_);
157
158 key_t mapKey = internalPort_;
159 if (type_ == PortType::UDP)
160 mapKey |= 1 << (sizeof(uint16_t) * 8);
161 return mapKey;
162}
163
164PortType
165Mapping::getTypeFromMapKey(key_t key)
166{
167 return (key >> (sizeof(uint16_t) * 8)) ? PortType::UDP : PortType::TCP;
168}
169
170std::string
171Mapping::getExternalAddress() const
172{
173 std::lock_guard<std::mutex> lock(mutex_);
174 if (igd_)
175 return igd_->getPublicIp().toString();
176 return {};
177}
178
179void
180Mapping::setExternalPort(uint16_t port)
181{
182 std::lock_guard<std::mutex> lock(mutex_);
183 externalPort_ = port;
184}
185
186uint16_t
187Mapping::getExternalPort() const
188{
189 std::lock_guard<std::mutex> lock(mutex_);
190 return externalPort_;
191}
192
193std::string
194Mapping::getExternalPortStr() const
195{
196 std::lock_guard<std::mutex> lock(mutex_);
197 return std::to_string(externalPort_);
198}
199
200void
201Mapping::setInternalAddress(const std::string& addr)
202{
203 std::lock_guard<std::mutex> lock(mutex_);
204 internalAddr_ = addr;
205}
206
207std::string
208Mapping::getInternalAddress() const
209{
210 std::lock_guard<std::mutex> lock(mutex_);
211 return internalAddr_;
212}
213
214void
215Mapping::setInternalPort(uint16_t port)
216{
217 std::lock_guard<std::mutex> lock(mutex_);
218 internalPort_ = port;
219}
220
221uint16_t
222Mapping::getInternalPort() const
223{
224 std::lock_guard<std::mutex> lock(mutex_);
225 return internalPort_;
226}
227
228std::string
229Mapping::getInternalPortStr() const
230{
231 std::lock_guard<std::mutex> lock(mutex_);
232 return std::to_string(internalPort_);
233}
234
235PortType
236Mapping::getType() const
237{
238 std::lock_guard<std::mutex> lock(mutex_);
239 return type_;
240}
241
242const char*
243Mapping::getTypeStr() const
244{
245 std::lock_guard<std::mutex> lock(mutex_);
246 return getTypeStr(type_);
247}
248
249bool
250Mapping::isAvailable() const
251{
252 std::lock_guard<std::mutex> lock(mutex_);
253 return available_;
254}
255
256std::shared_ptr<IGD>
257Mapping::getIgd() const
258{
259 std::lock_guard<std::mutex> lock(mutex_);
260 return igd_;
261}
262
263NatProtocolType
264Mapping::getProtocol() const
265{
266 std::lock_guard<std::mutex> lock(mutex_);
267 if (igd_)
268 return igd_->getProtocol();
269 return NatProtocolType::UNKNOWN;
270}
271const char*
272Mapping::getProtocolName() const
273{
274 if (igd_) {
275 if (igd_->getProtocol() == NatProtocolType::NAT_PMP)
276 return "NAT-PMP";
277 if (igd_->getProtocol() == NatProtocolType::PUPNP)
278 return "PUPNP";
279 }
280 return "UNKNOWN";
281}
282
283void
284Mapping::setIgd(const std::shared_ptr<IGD>& igd)
285{
286 std::lock_guard<std::mutex> lock(mutex_);
287 igd_ = igd;
288}
289
290MappingState
291Mapping::getState() const
292{
293 std::lock_guard<std::mutex> lock(mutex_);
294 return state_;
295}
296
297Mapping::NotifyCallback
298Mapping::getNotifyCallback() const
299{
300 std::lock_guard<std::mutex> lock(mutex_);
301 return notifyCb_;
302}
303
304void
305Mapping::setNotifyCallback(NotifyCallback cb)
306{
307 std::lock_guard<std::mutex> lock(mutex_);
308 notifyCb_ = std::move(cb);
309}
310
311void
312Mapping::enableAutoUpdate(bool enable)
313{
314 std::lock_guard<std::mutex> lock(mutex_);
315 autoUpdate_ = enable;
316}
317
318bool
319Mapping::getAutoUpdate() const
320{
321 std::lock_guard<std::mutex> lock(mutex_);
322 return autoUpdate_;
323}
324
325#if HAVE_LIBNATPMP
326sys_clock::time_point
327Mapping::getRenewalTime() const
328{
329 std::lock_guard<std::mutex> lock(mutex_);
330 return renewalTime_;
331}
332
333void
334Mapping::setRenewalTime(sys_clock::time_point time)
335{
336 std::lock_guard<std::mutex> lock(mutex_);
337 renewalTime_ = time;
338}
339#endif
340
341} // namespace upnp
342} // namespace jami