@@ -40,7 +40,8 @@ static_assert(MINIUPNPC_API_VERSION >= 10, "miniUPnPc API version >= 10 assumed"
40
40
#if defined(USE_NATPMP) || defined(USE_UPNP)
41
41
static CThreadInterrupt g_mapport_interrupt;
42
42
static std::thread g_mapport_thread;
43
- static std::atomic_uint g_mapport_target_proto{MapPortProtoFlag::NONE};
43
+ static std::atomic_uint g_mapport_enabled_protos{MapPortProtoFlag::NONE};
44
+ static std::atomic<MapPortProtoFlag> g_mapport_current_proto{MapPortProtoFlag::NONE};
44
45
45
46
using namespace std ::chrono_literals;
46
47
static constexpr auto PORT_MAPPING_REANNOUNCE_PERIOD{20min};
@@ -220,9 +221,34 @@ static bool ProcessUpnp()
220
221
221
222
static void ThreadMapPort ()
222
223
{
224
+ bool ok;
223
225
do {
224
- if (ProcessUpnp ()) return ;
225
- } while (g_mapport_interrupt.sleep_for (PORT_MAPPING_RETRY_PERIOD));
226
+ ok = false ;
227
+
228
+ #ifdef USE_UPNP
229
+ // High priority protocol.
230
+ if (g_mapport_enabled_protos & MapPortProtoFlag::UPNP) {
231
+ g_mapport_current_proto = MapPortProtoFlag::UPNP;
232
+ ok = ProcessUpnp ();
233
+ if (ok) continue ;
234
+ }
235
+ #endif // USE_UPNP
236
+
237
+ #ifdef USE_NATPMP
238
+ // Low priority protocol.
239
+ if (g_mapport_enabled_protos & MapPortProtoFlag::NAT_PMP) {
240
+ g_mapport_current_proto = MapPortProtoFlag::NAT_PMP;
241
+ ok = ProcessNatpmp ();
242
+ if (ok) continue ;
243
+ }
244
+ #endif // USE_NATPMP
245
+
246
+ g_mapport_current_proto = MapPortProtoFlag::NONE;
247
+ if (g_mapport_enabled_protos == MapPortProtoFlag::NONE) {
248
+ return ;
249
+ }
250
+
251
+ } while (ok || g_mapport_interrupt.sleep_for (PORT_MAPPING_RETRY_PERIOD));
226
252
}
227
253
228
254
void StartThreadMapPort ()
@@ -235,20 +261,39 @@ void StartThreadMapPort()
235
261
236
262
static void DispatchMapPort ()
237
263
{
238
- if (g_mapport_target_proto == MapPortProtoFlag::UPNP) {
264
+ if (g_mapport_current_proto == MapPortProtoFlag::NONE && g_mapport_enabled_protos == MapPortProtoFlag::NONE) {
265
+ return ;
266
+ }
267
+
268
+ if (g_mapport_current_proto == MapPortProtoFlag::NONE && g_mapport_enabled_protos != MapPortProtoFlag::NONE) {
239
269
StartThreadMapPort ();
240
- } else {
270
+ return ;
271
+ }
272
+
273
+ if (g_mapport_current_proto != MapPortProtoFlag::NONE && g_mapport_enabled_protos == MapPortProtoFlag::NONE) {
241
274
InterruptMapPort ();
242
275
StopMapPort ();
276
+ return ;
277
+ }
278
+
279
+ if (g_mapport_enabled_protos & g_mapport_current_proto) {
280
+ // Enabling another protocol does not cause switching from the currently used one.
281
+ return ;
243
282
}
283
+
284
+ assert (g_mapport_thread.joinable ());
285
+ assert (!g_mapport_interrupt);
286
+ // Interrupt a protocol-specific loop in the ThreadUpnp() or in the ThreadNatpmp()
287
+ // to force trying the next protocol in the ThreadMapPort() loop.
288
+ g_mapport_interrupt ();
244
289
}
245
290
246
291
static void MapPortProtoSetEnabled (MapPortProtoFlag proto, bool enabled)
247
292
{
248
293
if (enabled) {
249
- g_mapport_target_proto |= proto;
294
+ g_mapport_enabled_protos |= proto;
250
295
} else {
251
- g_mapport_target_proto &= ~proto;
296
+ g_mapport_enabled_protos &= ~proto;
252
297
}
253
298
}
254
299
@@ -260,6 +305,7 @@ void StartMapPort(bool use_upnp)
260
305
261
306
void InterruptMapPort ()
262
307
{
308
+ g_mapport_enabled_protos = MapPortProtoFlag::NONE;
263
309
if (g_mapport_thread.joinable ()) {
264
310
g_mapport_interrupt ();
265
311
}
0 commit comments