blob: 4b9d5ba0cbbac062f4a562775ea5594b49293436 [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
Adrien Béraud370257c2023-08-15 20:53:09 -040097void
98Mapping::updateState(const MappingState& newState, bool notify)
99{
100 std::unique_lock<std::mutex> lock(mutex_);
101 if (newState == state_)
102 return;
103 state_ = newState;
104
105 if (notify && notifyCb_) {
106 lock.unlock();
107 notifyCb_(shared_from_this());
108 }
109}
110
Adrien Béraud612b55b2023-05-29 10:42:04 -0400111const char*
112Mapping::getStateStr() const
113{
114 std::lock_guard<std::mutex> lock(mutex_);
115 return getStateStr(state_);
116}
117
118std::string
119Mapping::toString(bool extraInfo) const
120{
121 std::lock_guard<std::mutex> lock(mutex_);
122 std::ostringstream descr;
123 descr << UPNP_MAPPING_DESCRIPTION_PREFIX << "-" << getTypeStr(type_);
124 descr << ":" << std::to_string(internalPort_);
125
126 if (extraInfo) {
127 descr << " (state=" << getStateStr(state_)
128 << ", auto-update=" << (autoUpdate_ ? "YES" : "NO") << ")";
129 }
130
131 return descr.str();
132}
133
134bool
135Mapping::isValid() const
136{
137 std::lock_guard<std::mutex> lock(mutex_);
138 if (state_ == MappingState::FAILED)
139 return false;
140 if (internalPort_ == 0)
141 return false;
142 if (externalPort_ == 0)
143 return false;
144 if (not igd_ or not igd_->isValid())
145 return false;
146 IpAddr intAddr(internalAddr_);
147 return intAddr and not intAddr.isLoopback();
148}
149
150bool
151Mapping::hasValidHostAddress() const
152{
153 std::lock_guard<std::mutex> lock(mutex_);
154
155 IpAddr intAddr(internalAddr_);
156 return intAddr and not intAddr.isLoopback();
157}
158
159bool
160Mapping::hasPublicAddress() const
161{
162 std::lock_guard<std::mutex> lock(mutex_);
163
164 return igd_ and igd_->getPublicIp() and not igd_->getPublicIp().isPrivate();
165}
166
167Mapping::key_t
168Mapping::getMapKey() const
169{
170 std::lock_guard<std::mutex> lock(mutex_);
171
172 key_t mapKey = internalPort_;
173 if (type_ == PortType::UDP)
174 mapKey |= 1 << (sizeof(uint16_t) * 8);
175 return mapKey;
176}
177
178PortType
179Mapping::getTypeFromMapKey(key_t key)
180{
181 return (key >> (sizeof(uint16_t) * 8)) ? PortType::UDP : PortType::TCP;
182}
183
184std::string
185Mapping::getExternalAddress() const
186{
187 std::lock_guard<std::mutex> lock(mutex_);
188 if (igd_)
189 return igd_->getPublicIp().toString();
190 return {};
191}
192
193void
194Mapping::setExternalPort(uint16_t port)
195{
196 std::lock_guard<std::mutex> lock(mutex_);
197 externalPort_ = port;
198}
199
200uint16_t
201Mapping::getExternalPort() const
202{
203 std::lock_guard<std::mutex> lock(mutex_);
204 return externalPort_;
205}
206
207std::string
208Mapping::getExternalPortStr() const
209{
210 std::lock_guard<std::mutex> lock(mutex_);
211 return std::to_string(externalPort_);
212}
213
214void
215Mapping::setInternalAddress(const std::string& addr)
216{
217 std::lock_guard<std::mutex> lock(mutex_);
218 internalAddr_ = addr;
219}
220
221std::string
222Mapping::getInternalAddress() const
223{
224 std::lock_guard<std::mutex> lock(mutex_);
225 return internalAddr_;
226}
227
228void
229Mapping::setInternalPort(uint16_t port)
230{
231 std::lock_guard<std::mutex> lock(mutex_);
232 internalPort_ = port;
233}
234
235uint16_t
236Mapping::getInternalPort() const
237{
238 std::lock_guard<std::mutex> lock(mutex_);
239 return internalPort_;
240}
241
242std::string
243Mapping::getInternalPortStr() const
244{
245 std::lock_guard<std::mutex> lock(mutex_);
246 return std::to_string(internalPort_);
247}
248
249PortType
250Mapping::getType() const
251{
252 std::lock_guard<std::mutex> lock(mutex_);
253 return type_;
254}
255
256const char*
257Mapping::getTypeStr() const
258{
259 std::lock_guard<std::mutex> lock(mutex_);
260 return getTypeStr(type_);
261}
262
263bool
264Mapping::isAvailable() const
265{
266 std::lock_guard<std::mutex> lock(mutex_);
267 return available_;
268}
269
270std::shared_ptr<IGD>
271Mapping::getIgd() const
272{
273 std::lock_guard<std::mutex> lock(mutex_);
274 return igd_;
275}
276
277NatProtocolType
278Mapping::getProtocol() const
279{
280 std::lock_guard<std::mutex> lock(mutex_);
281 if (igd_)
282 return igd_->getProtocol();
283 return NatProtocolType::UNKNOWN;
284}
285const char*
286Mapping::getProtocolName() const
287{
288 if (igd_) {
289 if (igd_->getProtocol() == NatProtocolType::NAT_PMP)
290 return "NAT-PMP";
291 if (igd_->getProtocol() == NatProtocolType::PUPNP)
292 return "PUPNP";
293 }
294 return "UNKNOWN";
295}
296
297void
298Mapping::setIgd(const std::shared_ptr<IGD>& igd)
299{
300 std::lock_guard<std::mutex> lock(mutex_);
301 igd_ = igd;
302}
303
304MappingState
305Mapping::getState() const
306{
307 std::lock_guard<std::mutex> lock(mutex_);
308 return state_;
309}
310
311Mapping::NotifyCallback
312Mapping::getNotifyCallback() const
313{
314 std::lock_guard<std::mutex> lock(mutex_);
315 return notifyCb_;
316}
317
318void
319Mapping::setNotifyCallback(NotifyCallback cb)
320{
321 std::lock_guard<std::mutex> lock(mutex_);
322 notifyCb_ = std::move(cb);
323}
324
325void
326Mapping::enableAutoUpdate(bool enable)
327{
328 std::lock_guard<std::mutex> lock(mutex_);
329 autoUpdate_ = enable;
330}
331
332bool
333Mapping::getAutoUpdate() const
334{
335 std::lock_guard<std::mutex> lock(mutex_);
336 return autoUpdate_;
337}
338
339#if HAVE_LIBNATPMP
340sys_clock::time_point
341Mapping::getRenewalTime() const
342{
343 std::lock_guard<std::mutex> lock(mutex_);
344 return renewalTime_;
345}
346
347void
348Mapping::setRenewalTime(sys_clock::time_point time)
349{
350 std::lock_guard<std::mutex> lock(mutex_);
351 renewalTime_ = time;
352}
353#endif
354
355} // namespace upnp
Sébastien Blin464bdff2023-07-19 08:02:53 -0400356} // namespace dhtnet