14 Commits
Author SHA1 Message Date
Henrik RydgårdandClaude Opus 5 2cb0be1bc4 UPnP: fix the exit hang and the CPU spin, and only run the thread when enabled
The two long-standing bug reports had a shared root: the service loop could
end up in a state it never left.

- Exit hang: UPNP_CMD_EXIT was queued alongside port requests and only acted
  on when it reached the front. A request that couldn't complete was never
  popped, so exit sat behind it forever and join() blocked indefinitely.
  Exit is a flag now, checked before anything else.
- CPU spin: wait_for() with a predicate returns immediately when the predicate
  already holds, so a stuck queue head meant a tight loop. sceNetInet's bind()
  queues UPnP_Add regardless of the setting, so this hit whenever UPnP was off
  and a game used sockets. The loop always blocks now, and requests are dropped
  while UPnP is off.
- Failed discovery was retried every 5s forever, each time a full 2s SSDP round
  plus an error toast. Now backs off 5s -> 300s and reports once.

Other things found while in here:

- Every failed Initialize() leaked a UPNPUrls + IGDdatas, so ~every 5 seconds
  for anyone with UPnP on and no router. The manual miniwget/parserootdesc/
  GetUPNPUrls block was also redundant - UPNP_GetValidIGD does all of it and
  memsets over the result, leaking the URLs and costing an extra HTTP round
  trip per attempt.
- UPNP_GetValidIGD's status was never checked, so we could go DONE with no
  usable IGD and hand a NULL controlURL to UPNP_GetConnectionTypeInfo.
- miniupnpc's strncpy into the port-mapping-entry buffers doesn't guarantee a
  terminator; an 80-char description ran std::string off the end of desc[80].
- Add() marked another app's port "taken" only after our own add succeeded, so
  a failed add left their mapping deleted and never restored.
- Clear() walked the router's entire table at exit, one HTTP round trip per
  index. It now deletes only what we know we mapped, and the exit cleanup has
  a time budget so an unreachable router can't stall shutdown.
- The in-flight request stayed in the queue during the router call, so a
  same-port request arriving concurrently could erase it and be dropped
  unexecuted.
- The queue is bounded, and last-write-wins per port collapses the churn from
  games that rebind in a loop.
- The mapping description is built when the request is queued rather than read
  off g_paramSFO from the UPnP thread later.

The thread now only exists while the setting is on - turning it off makes it
remove its mappings and exit, turning it on starts one. That means __UPnPInit()
has to run after the config is actually loaded; g_Config.Init() only builds a
lookup table. QueueRequest() reconciles too, so a per-game config or a libretro
core option enabling UPnP works without a notify at every call site.

The settings checkbox is disabled in-game, since sceNet latches related
settings at boot and a game that already mapped its ports wouldn't cope with
them disappearing.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01DCPmm7FoQUoqrbMdhfqhQ2
2026-08-30 00:37:05 +02:00
Henrik Rydgård c1310ae4a5 Rework UPnP service thread sync
No longer waking up twice per second. Instead a slow 5s poll plus
wakeups if needed.
2026-08-07 11:24:22 +02:00
Kevin Reinholz 795c8678a6 Fixed build with system libzip and miniupnpc 2025-05-31 16:03:57 -07:00
Henrik Rydgård 370a521381 Move UPnP init/shutdown to app init/shutdown instead of game init/shutdown 2025-04-07 16:46:04 +02:00
Henrik Rydgård ab257e335f Ugprade miniupnp submodule to latest
Maybe will help #19246, but no idea really.

Windows buildfix

UWP buildfix

miniupnpc path fixes

libretro buildfix attempt, android.mk
2024-06-05 00:18:00 +02:00
Henrik Rydgård 779a156251 PortManager warning fix. The #pragma pack stuff was redundant anyway 2023-08-10 17:15:57 +02:00
Henrik Rydgård 9decdd198e Address more feedback, minor cleanup 2023-07-21 10:30:06 +02:00
Henrik Rydgård b54d5ab8e6 Cleanup the g_PortManager shutdown process
Following up comment by @ANR2ME in #17744, to be merged before that one.
2023-07-20 23:55:35 +02:00
李通洲 17171bc9dc Use system headers when building with system miniupnpc
Fixes https://github.com/hrydgard/ppsspp/pull/15185
2021-12-07 15:36:30 +08:00
ANR2ME bd36fdda0e Do UPnP stuff on it's own thread to prevent causing stutters/lags during multiplayer game due to blocking socket behavior on miniUPnP 2020-07-23 12:41:13 +02:00
ANR2ME 68fa15784c Fixed UPnP port opened by PPSSPP detection, and Updated PortManager to be compliant to general purpose usage 2020-07-22 23:13:41 +02:00
ANR2ME b9025b50bd Added a UPnP option to use original port for external port instead of using the shifted port by port offset, to be compatible with real PSP or other PSP emulators 2020-07-22 23:13:41 +02:00
ANR2ME 088e489c91 Fix UPnP error detection
Fix Local IP detection on non-Windows system
2020-07-21 23:03:04 +02:00
ANR2ME 33d3ac28de Added UPnP Support
Fix i18n type
2020-07-21 23:02:58 +02:00