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