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