blob: 0468352e08776488041f99142b5b6b34bb72692e [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érauddbb06862023-07-08 09:18:39 -040019#include "../ip_utils.h"
Adrien Béraud612b55b2023-05-29 10:42:04 -040020
21#include <map>
22#include <string>
23#include <chrono>
24#include <functional>
25#include <mutex>
Morteza Namvar5f639522023-07-04 17:08:58 -040026#include <memory>
Adrien Béraud612b55b2023-05-29 10:42:04 -040027
Adrien Béraud1ae60aa2023-07-07 09:55:09 -040028namespace dhtnet {
Adrien Béraud612b55b2023-05-29 10:42:04 -040029namespace upnp {
30
31using sys_clock = std::chrono::system_clock;
32
33enum class PortType { TCP, UDP };
Amna43448f62024-09-11 17:20:13 -040034
35/**
36 * State Machine:
37 *
38 * - PENDING: Initial state when a mapping is requested by the client.
39 * - IN_PROGRESS: Intermediate state while the mapping is being requested from an IGD.
40 * - OPEN: State when the mapping is successfully established.
41 * - FAILED: State when the mapping fails or is invalidated.
42 *
43 * State Transitions:
44 *
45 * - PENDING -> IN_PROGRESS: When the mapping request is sent to the IGD.
46 * - PENDING -> FAILED: When there is no valid IGD and it's not during the IGD discovery phase.
47 * - IN_PROGRESS -> OPEN: When the mapping is successfully established.
48 * - IN_PROGRESS -> FAILED: When the mapping fails.
49 * - OPEN -> FAILED: When the IGD becomes invalid or the mapping is removed.
50 * - FAILED -> PENDING: When auto-update is enabled and there is no valid IGD.
51 * - FAILED -> unregistered: When auto-update is disabled.
52 *
53 * If auto-update is enabled but there is a valid IGD, the mapping will be unregistered and a new mapping of the same type will be requested.
54 */
Adrien Béraud612b55b2023-05-29 10:42:04 -040055enum class MappingState { PENDING, IN_PROGRESS, FAILED, OPEN };
56
57enum class NatProtocolType;
58class IGD;
59
Adrien Béraud56740312023-08-23 08:38:28 -040060class Mapping
Adrien Béraud612b55b2023-05-29 10:42:04 -040061{
62 friend class UPnPContext;
63 friend class NatPmp;
64 friend class PUPnP;
65
66public:
67 using key_t = uint64_t;
68 using sharedPtr_t = std::shared_ptr<Mapping>;
69 using NotifyCallback = std::function<void(sharedPtr_t)>;
70
71 static constexpr char const* MAPPING_STATE_STR[4] {"PENDING", "IN_PROGRESS", "FAILED", "OPEN"};
72 static constexpr char const* UPNP_MAPPING_DESCRIPTION_PREFIX {"JAMI"};
73
74 Mapping(PortType type,
75 uint16_t portExternal = 0,
76 uint16_t portInternal = 0,
77 bool available = true);
78 Mapping(const Mapping& other);
79 Mapping(Mapping&& other) = delete;
80 ~Mapping() = default;
81
82 // Delete operators with confusing semantic.
83 Mapping& operator=(Mapping&& other) = delete;
84 bool operator==(const Mapping& other) = delete;
85 bool operator!=(const Mapping& other) = delete;
86 bool operator<(const Mapping& other) = delete;
87 bool operator>(const Mapping& other) = delete;
88 bool operator<=(const Mapping& other) = delete;
89 bool operator>=(const Mapping& other) = delete;
90
91 inline explicit operator bool() const { return isValid(); }
92
93 void updateFrom(const Mapping& other);
94 void updateFrom(const Mapping::sharedPtr_t& other);
95 std::string getExternalAddress() const;
96 uint16_t getExternalPort() const;
97 std::string getExternalPortStr() const;
98 std::string getInternalAddress() const;
99 uint16_t getInternalPort() const;
100 std::string getInternalPortStr() const;
101 PortType getType() const;
102 const char* getTypeStr() const;
103 static const char* getTypeStr(PortType type) { return type == PortType::UDP ? "UDP" : "TCP"; }
104 std::shared_ptr<IGD> getIgd() const;
105 NatProtocolType getProtocol() const;
Adrien Berauda8731ac2023-08-17 12:19:39 -0400106 std::string_view getProtocolName() const;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400107 bool isAvailable() const;
108 MappingState getState() const;
109 const char* getStateStr() const;
110 static const char* getStateStr(MappingState state)
111 {
112 return MAPPING_STATE_STR[static_cast<int>(state)];
113 }
114 std::string toString(bool extraInfo = false) const;
115 bool isValid() const;
116 bool hasValidHostAddress() const;
117 bool hasPublicAddress() const;
118 void setNotifyCallback(NotifyCallback cb);
119 void enableAutoUpdate(bool enable);
120 bool getAutoUpdate() const;
121 key_t getMapKey() const;
122 static PortType getTypeFromMapKey(key_t key);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400123 sys_clock::time_point getRenewalTime() const;
François-Simon Fauteux-Chapleaufd29c1d2024-05-30 16:48:26 -0400124 sys_clock::time_point getExpiryTime() const;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400125
126private:
127 NotifyCallback getNotifyCallback() const;
128 void setInternalAddress(const std::string& addr);
129 void setExternalPort(uint16_t port);
130 void setInternalPort(uint16_t port);
131
132 void setIgd(const std::shared_ptr<IGD>& igd);
133 void setAvailable(bool val);
134 void setState(const MappingState& state);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400135 void setRenewalTime(sys_clock::time_point time);
François-Simon Fauteux-Chapleaufd29c1d2024-05-30 16:48:26 -0400136 void setExpiryTime(sys_clock::time_point time);
Adrien Béraud612b55b2023-05-29 10:42:04 -0400137
138 mutable std::mutex mutex_;
139 PortType type_ {PortType::UDP};
140 uint16_t externalPort_ {0};
141 uint16_t internalPort_ {0};
142 std::string internalAddr_;
143 // Protocol and
144 std::shared_ptr<IGD> igd_;
145 // Track if the mapping is available to use.
146 bool available_;
147 // Track the state of the mapping
148 MappingState state_;
149 NotifyCallback notifyCb_;
François-Simon Fauteux-Chapleaufd29c1d2024-05-30 16:48:26 -0400150 // If true, a new mapping will be requested on behalf of the mapping
Adrien Béraud612b55b2023-05-29 10:42:04 -0400151 // owner when the mapping state changes from "OPEN" to "FAILED".
152 bool autoUpdate_;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400153 sys_clock::time_point renewalTime_;
François-Simon Fauteux-Chapleaufd29c1d2024-05-30 16:48:26 -0400154 sys_clock::time_point expiryTime_;
Adrien Béraud612b55b2023-05-29 10:42:04 -0400155};
156
François-Simon Fauteux-Chapleau826f0ba2024-05-29 15:22:21 -0400157struct MappingInfo
158{
159 std::string remoteHost;
160 std::string protocol;
161 std::string internalClient;
162 std::string enabled;
163 std::string description;
164 uint16_t externalPort;
165 uint16_t internalPort;
166 uint32_t leaseDuration;
167};
168
Adrien Béraud612b55b2023-05-29 10:42:04 -0400169} // namespace upnp
Sébastien Blin464bdff2023-07-19 08:02:53 -0400170} // namespace dhtnet