blob: 30642a0ba1fbf83af8dcec11e19415fdf1a79bab [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 */
Adrien Béraud612b55b2023-05-29 10:42:04 -040017#pragma once
18
19#include "connectivity/upnp/protocol/upnp_protocol.h"
20#include "connectivity/upnp/protocol/igd.h"
21#include "pmp_igd.h"
22
23#include "logger.h"
24#include "connectivity/ip_utils.h"
25#include "noncopyable.h"
26#include "compiler_intrinsics.h"
27
28// uncomment to enable native natpmp error messages
29//#define ENABLE_STRNATPMPERR 1
30#include <natpmp.h>
31
32#include <atomic>
33#include <thread>
34
Adrien Béraud1ae60aa2023-07-07 09:55:09 -040035namespace dhtnet {
Adrien Béraud612b55b2023-05-29 10:42:04 -040036class IpAddr;
37}
38
Adrien Béraud1ae60aa2023-07-07 09:55:09 -040039namespace dhtnet {
Adrien Béraud612b55b2023-05-29 10:42:04 -040040namespace upnp {
41
42// Requested lifetime in seconds. The actual lifetime might be different.
43constexpr static unsigned int MAPPING_ALLOCATION_LIFETIME {60 * 60};
44// Max number of IGD search attempts before failure.
45constexpr static unsigned int MAX_RESTART_SEARCH_RETRIES {3};
46// Time-out between two successive read response.
47constexpr static auto TIMEOUT_BEFORE_READ_RETRY {std::chrono::milliseconds(300)};
48// Max number of read attempts before failure.
49constexpr static unsigned int MAX_READ_RETRIES {3};
50// Base unit for the timeout between two successive IGD search.
51constexpr static auto NATPMP_SEARCH_RETRY_UNIT {std::chrono::seconds(10)};
52
53class NatPmp : public UPnPProtocol
54{
55public:
56 NatPmp();
57 ~NatPmp();
58
59 // Set the observer.
60 void setObserver(UpnpMappingObserver* obs) override;
61
62 // Returns the protocol type.
63 NatProtocolType getProtocol() const override { return NatProtocolType::NAT_PMP; }
64
65 // Get protocol type as string.
66 char const* getProtocolName() const override { return "NAT-PMP"; }
67
68 // Notifies a change in network.
69 void clearIgds() override;
70
71 // Renew pmp_igd.
72 void searchForIgd() override;
73
74 // Get the IGD list.
75 std::list<std::shared_ptr<IGD>> getIgdList() const override;
76
77 // Return true if it has at least one valid IGD.
78 bool isReady() const override;
79
80 // Request a new mapping.
81 void requestMappingAdd(const Mapping& mapping) override;
82
83 // Renew an allocated mapping.
84 void requestMappingRenew(const Mapping& mapping) override;
85
86 // Removes a mapping.
87 void requestMappingRemove(const Mapping& mapping) override;
88
89 // Get the host (local) address.
90 const IpAddr getHostAddress() const override;
91
92 // Terminate. Nothing to do here, the clean-up is done when
93 // the IGD is cleared.
94 void terminate() override;
95
96private:
97 NON_COPYABLE(NatPmp);
98
99 std::weak_ptr<NatPmp> weak() { return std::static_pointer_cast<NatPmp>(shared_from_this()); }
100
101 // Helpers to run tasks on NAT-PMP internal execution queue.
102 ScheduledExecutor* getNatpmpScheduler() { return &natpmpScheduler_; }
103 template<typename Callback>
104 void runOnNatPmpQueue(Callback&& cb)
105 {
106 natpmpScheduler_.run([cb = std::forward<Callback>(cb)]() mutable { cb(); });
107 }
108
109 // Helpers to run tasks on UPNP context execution queue.
110 ScheduledExecutor* getUpnContextScheduler() { return UpnpThreadUtil::getScheduler(); }
111
112 void terminate(std::condition_variable& cv);
113
114 void initNatPmp();
115 void getIgdPublicAddress();
116 void removeAllMappings();
117 int readResponse(natpmp_t& handle, natpmpresp_t& response);
118 int sendMappingRequest(const Mapping& mapping, uint32_t& lifetime);
119
120 // Adds a port mapping.
121 int addPortMapping(Mapping& mapping);
122 // Removes a port mapping.
123 void removePortMapping(Mapping& mapping);
124
125 // True if the error is fatal.
126 bool isErrorFatal(int error);
127 // Gets NAT-PMP error code string.
128 const char* getNatPmpErrorStr(int errorCode) const;
129 // Get local getaway.
130 std::unique_ptr<IpAddr> getLocalGateway() const;
131
132 // Helpers to process user's callbacks
133 void processIgdUpdate(UpnpIgdEvent event);
134 void processMappingAdded(const Mapping& map);
135 void processMappingRequestFailed(const Mapping& map);
136 void processMappingRenewed(const Mapping& map);
137 void processMappingRemoved(const Mapping& map);
138
139 // Check if the IGD has a local match
140 bool validIgdInstance(const std::shared_ptr<IGD>& igdIn);
141
142 // Increment errors counter.
143 void incrementErrorsCounter(const std::shared_ptr<IGD>& igd);
144
145 std::atomic_bool initialized_ {false};
146
147 // Data members
148 std::shared_ptr<PMPIGD> igd_;
149 natpmp_t natpmpHdl_;
150 ScheduledExecutor natpmpScheduler_ {"natpmp"};
151 std::shared_ptr<Task> searchForIgdTimer_ {};
152 unsigned int igdSearchCounter_ {0};
153 UpnpMappingObserver* observer_ {nullptr};
154 IpAddr hostAddress_ {};
155
156 // Calls from other threads that does not need synchronous access are
157 // rescheduled on the NatPmp private queue. This will avoid the need to
158 // protect most of the data members of this class.
159 // For some internal members (such as the igd instance and the host
160 // address) that need to be synchronously accessed, are protected by
161 // this mutex.
162 mutable std::mutex natpmpMutex_;
163
164 // Shutdown synchronization
165 bool shutdownComplete_ {false};
166};
167
168} // namespace upnp
Sébastien Blin464bdff2023-07-19 08:02:53 -0400169} // namespace dhtnet