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