Skip to content

Commit 4b2cbcc

Browse files
committed
C4Network2UPnP: Fix race condition in clearing the mappings
1 parent a3ac90f commit 4b2cbcc

File tree

3 files changed

+43
-56
lines changed

3 files changed

+43
-56
lines changed

src/C4Network2UPnP.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,7 @@ class C4Network2UPnP
3131

3232
public:
3333
void AddMapping(C4Network2IOProtocol protocol, std::uint16_t internalPort, std::uint16_t externalPort);
34-
void ClearMappings();
3534

3635
private:
37-
const std::unique_ptr<Impl> impl;
36+
std::unique_ptr<Impl> impl;
3837
};

src/C4Network2UPnPDummy.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,3 @@ C4Network2UPnP::C4Network2UPnP() = default;
2222
C4Network2UPnP::~C4Network2UPnP() noexcept = default;
2323

2424
void C4Network2UPnP::AddMapping(C4Network2IOProtocol, std::uint16_t, std::uint16_t) {}
25-
void C4Network2UPnP::ClearMappings() {}

src/C4Network2UPnPMiniUPnPc.cpp

Lines changed: 42 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,45 @@ struct C4Network2UPnP::Impl
7070
task = AddMappingInt(std::move(task), protocol, internalPort, externalPort);
7171
}
7272

73-
void ClearMappings()
73+
static C4Task::OneShot ClearMappings(std::unique_ptr<Impl> self)
7474
{
75-
task = ClearMappingsInt(std::move(task));
75+
co_await C4Awaiter::ResumeInGlobalThreadPool();
76+
co_await std::move(self->task);
77+
78+
if (!self->IsInitialized())
79+
{
80+
co_return;
81+
}
82+
83+
for (const auto &mapping : self->mappings)
84+
{
85+
const int result{UPNP_DeletePortMapping(
86+
self->urls.controlURL,
87+
self->igdData.first.servicetype,
88+
mapping.ExternalPort.data(),
89+
mapping.Protocol.data(),
90+
nullptr
91+
)};
92+
if (result == UPNPCOMMAND_SUCCESS)
93+
{
94+
self->logger->info("Removed port mapping {} {} -> {}:{}",
95+
mapping.Protocol.data(),
96+
mapping.ExternalPort.data(),
97+
self->lanAddress.data(),
98+
mapping.InternalPort.data()
99+
);
100+
}
101+
else
102+
{
103+
self->logger->error("Failed to remove port mapping {} {} -> {}:{}: {}",
104+
mapping.Protocol.data(),
105+
mapping.ExternalPort.data(),
106+
self->lanAddress.data(),
107+
mapping.InternalPort.data(),
108+
strupnperror(result)
109+
);
110+
}
111+
}
76112
}
77113

78114
bool IsInitialized() const
@@ -177,51 +213,6 @@ struct C4Network2UPnP::Impl
177213
}
178214
}
179215

180-
C4Task::Hot<void> ClearMappingsInt(C4Task::Hot<void> task)
181-
{
182-
co_await C4Awaiter::ResumeInGlobalThreadPool();
183-
co_await std::move(task);
184-
185-
if (!IsInitialized())
186-
{
187-
co_return;
188-
}
189-
190-
for (const auto &mapping : mappings)
191-
{
192-
const int result{UPNP_DeletePortMapping(
193-
urls.controlURL,
194-
igdData.first.servicetype,
195-
mapping.ExternalPort.data(),
196-
mapping.Protocol.data(),
197-
nullptr
198-
)};
199-
if (result == UPNPCOMMAND_SUCCESS)
200-
{
201-
logger->info("Removed port mapping {} {} -> {}:{}",
202-
mapping.Protocol.data(),
203-
mapping.ExternalPort.data(),
204-
lanAddress.data(),
205-
mapping.InternalPort.data()
206-
);
207-
208-
mappings.emplace_back(std::move(mapping));
209-
}
210-
else
211-
{
212-
logger->error("Failed to remove port mapping {} {} -> {}:{}: {}",
213-
mapping.Protocol.data(),
214-
mapping.ExternalPort.data(),
215-
lanAddress.data(),
216-
mapping.InternalPort.data(),
217-
strupnperror(result)
218-
);
219-
}
220-
}
221-
222-
mappings.clear();
223-
}
224-
225216
std::shared_ptr<spdlog::logger> logger;
226217
C4Task::Hot<void> task;
227218
UPNPUrls urls{};
@@ -240,15 +231,13 @@ C4Network2UPnP::C4Network2UPnP()
240231

241232
C4Network2UPnP::~C4Network2UPnP() noexcept
242233
{
243-
ClearMappings();
234+
if (impl)
235+
{
236+
Impl::ClearMappings(std::move(impl));
237+
}
244238
}
245239

246240
void C4Network2UPnP::AddMapping(const C4Network2IOProtocol protocol, const std::uint16_t internalPort, const std::uint16_t externalPort)
247241
{
248242
impl->AddMapping(protocol, internalPort, externalPort);
249243
}
250-
251-
void C4Network2UPnP::ClearMappings()
252-
{
253-
impl->ClearMappings();
254-
}

0 commit comments

Comments
 (0)