Commit Graph
16447 Commits
Author SHA1 Message Date
Henrik RydgårdandClaude Opus 5.5 214b14fe63 Add --nickname, and give each adhoc_session.py instance its own
Games that show the system nickname in their lobbies can then tell the
instances apart. Also: press --times N --every S for menus that need
several presses, and start clears the last session's screenshots, which
could otherwise pass for this one's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 10:08:10 +01:00
Henrik RydgårdandClaude Opus 5.5 96e31f8c47 WebSocket debugger: Enabling a log channel turns logging on
Headless turns logging as a whole off without --log, so a channel
enabled with log.channel.set still logged nothing, and a client
watching the log events saw none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 10:07:57 +01:00
Henrik RydgårdandClaude Opus 5.5 f449129dec sceNetAdhoc: Time a vanished peer's timeouts as a PSP does
A PSP checks a PTP connection's oldest unacknowledged data every
rexmt_int, counting from when the connection was established, and drops
the connection at the first check where that data is older than
(rexmt_cnt + 1) * rexmt_int. A matching peer times out keepalive_int *
init_count after its last keepalive, checked all the time instead of on
the console's own keepalive tick, which could add up to an interval.
Both measured with several settings in pspautotests
net/adhoc/pair/vanishtiming; DATA_TIMEOUT already matched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:07 +01:00
Henrik RydgårdandClaude Opus 5.5 ee86058ec7 sceNetAdhocctl: Leave the console out of its own peer lookups; give groups their own BSSID
From the basic and lifecycle pair tests, recorded on two PSPs:

- GetNameByAddr for the console's own MAC gives NO_ENTRY, and
  GetAddrByName doesn't find the console itself.
- GetPeerInfo with a size too small for the entry gives INVALID_BUFLEN.
- A PTP connection accepted over the relay reports the peer's port as
  the game sees it, not the relay's offset port.
- The built-in server makes up a locally administered BSSID for each
  group, which stays when the creator leaves. It was the MAC of the
  oldest member.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:07 +01:00
Henrik RydgårdandClaude Opus 5.5 4197f2326a sceNetAdhoc: A console that leaves the network goes quiet, as on a PSP
The vanish pair test (recorded on two PSPs) now passes on both sides,
over the relay:

- From the Disconnect call, a console's PDP and PTP sends succeed and go
  nowhere, and nothing reaches it.
- A PTP connection to a peer that has left the group fails with
  DISCONNECTED after rexmt_int * rexmt_cnt. Relay sockets now get their
  retry settings (and are zeroed), and an accepted one counts as
  connected.
- Matching data to a peer that has left gets DATA_TIMEOUT after the
  retransmissions instead of a DATA_ACK.
- The matching timeout for a silent peer is keepalive_int * init_count,
  plus MATCHING_TIMEOUT_EXTRA_US (0) to tune for internet latency. It
  was (keepalive + rexmt) * count + 500ms, later than a PSP's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:07 +01:00
Henrik RydgårdandClaude Opus 5.5 fa51700d58 sceNetAdhocctl: Fail entering game mode the way a PSP does
On a PSP (pspautotests net/adhoc/gamemode):
- a JoinEnterGameMode whose host never shows up gets ERROR with TIMEOUT
  when its timeout runs out, and is out of the group afterwards. The
  joiner's GAMEMODE, queued as soon as the server answered and held
  until the host appeared, came after 5 s anyway;
- a CreateEnterGameMode whose first member isn't this console returns
  0 and reports INVALID_ADDR;
- in a normal group, CreateEnterGameMode reports ALREADY_CONNECTED and
  stays in the group, and ExitGameMode returns INVALID_IBSS;
- ExitGameMode outside game mode returns 0 with no event.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:07 +01:00
Henrik RydgårdandClaude Opus 5.5 1e3e9c7251 sceNetAdhocctl: Send Create, Connect and Scan without the 10 ms wait
On a PSP they return within about 30 µs (pspautotests net/adhoc/timing).
They waited 10 ms before trying to send the request; now the first try is
right away, and the call returns once it's sent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:07 +01:00
Henrik RydgårdandClaude Opus 5.5 a2897c5b65 sceNetAdhocctl: Deliver CONNECT, SCAN and DISCONNECT at the PSP's times
A PSP delivers CONNECT 1.1 s after a Create, 0.53 s after a Join and
3.5-4 s after a Connect (which looks for the group first), SCAN 1.0 s
after a Scan and DISCONNECT 105 ms after a Disconnect, and the state
changes along with the event (pspautotests net/adhoc/timing and
net/adhoc/pair/timing). Deliver them then, counting from the request in
emulated time, or later if the server's answer takes longer. This
replaces the delays tuned for Dissidia 012, GTA: VCS and Tekken 5, and
Disconnect no longer blocks for 16.7 ms (Tekken 6): it returns at once,
as on a PSP.

Since the state now changes later, a Disconnect can come while a Create
is still pending. Keep track of whether the server has us in a group, so
the Disconnect still reaches it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:07 +01:00
Henrik RydgårdandClaude Opus 5.5 b58368405b proAdhoc: Keep pinging the server while emulation is paused
The adhocctl poll only runs while emulation does, so with the pause menu
open, or stopped in a debugger, for 15 s the server dropped the client,
and a game in a lobby lost its peers until it rejoined. A small thread
pings when the poll hasn't, as the friendFinder thread used to.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:07 +01:00
Henrik RydgårdandClaude Opus 5.5 5021e3ccc1 sceNetAdhocctlInit: Don't wait for the login to the server
On a PSP, Init returns at once and a Create, Connect or Scan right after
it works (pspautotests net/adhoc/ctlinit). The login now runs on in the
background, and those requests wait for it, as they already did when it
was lost. The first login no longer resets the busy flag, which would
have cleared it for a request already waiting on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:07 +01:00
Henrik RydgårdandClaude Opus 5.5 a276f00dd0 proAdhoc: Run the adhocctl client from a CoreTiming event
The friendFinder thread is replaced by friendFinderPoll(), which a
CoreTiming event calls every millisecond of emulated time on the CPU
thread. It handles everything the server has sent since the last poll,
instead of one event every 10 ms, and pings it at the same real-time
interval. Resolving the server and logging in, which can take seconds,
run on a thread of their own; the poll starts it and takes over the
session when it's done.

Everything else about the client is unchanged, including sceNetAdhocctlInit
waiting for the login. The savestate section goes to version 11 for the
poll event; older states get it scheduled on load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:07 +01:00
Henrik RydgårdandClaude Opus 5.5 e5bafd423d sceNetAdhocMatching: Report every join request, after SetHelloOpt too
The rule that dropped the first join after the hello data changed came
from a race in pspautotests net/adhoc/pair/matching2, where the host
started looking for the REQUEST after it had come. A PSP reports the
join at once however soon after SetHelloOpt it arrives, also when the
host changes its hello data every second (net/adhoc/pair/matchingjoin).
Ridge Racer does that every 5 seconds, so its clients could never enter
a race.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:06 +01:00
Henrik RydgårdandClaude Opus 5.5 5cc3554667 sceNetAdhocMatching: Pass the pair matching tests
The matching, matching2 and matching3 pair tests (recorded on two PSPs)
now pass on both sides:

- Event and input messages are queued in order. They were stacks, so a
  burst came out reversed (PONG and PANG crossed), and two places spawned
  their messages backwards to compensate.
- A peer stays busy until its DATA_ACK is delivered (DATA_BUSY), and
  AbortSendData discards that DATA_ACK.
- A host's SelectTarget while its accept is in progress gives
  REQUEST_IN_PROGRESS.
- A child that leaves, a cancelled request and a denied request (client
  and P2P) go back to a known non-member peer: no TIMEOUT, hellos keep
  coming, and it can ask again; a cancelled request gives
  TARGET_NOT_READY. A client says BYE to a host it has left.
- After SetHelloOpt the next join from an unknown peer reaches the host
  without a REQUEST.
- GetMembers lists the console itself first, also on a client.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:05 +01:00
Henrik RydgårdandClaude Opus 5.5 e94ae7f190 sceNetAdhocMatchingStart2: Check the stack sizes and partitions
A stack size too small to be one (where a partition was passed) gives
STACKSIZE_TOO_SHORT, and a partition outside 1-6 then INVALID_ID
(pspautotests net/adhoc/matching). How small a stack still works isn't
known, so only sizes below 0x100 are refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:05 +01:00
Henrik RydgårdandClaude Opus 5.5 25ee41f135 sceNetAdhocMatching: Hand out context IDs in increasing order
A PSP numbers matching contexts 1 to 15 in increasing order and then
starts over, instead of reusing the lowest free ID (pspautotests
net/adhoc/matching).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:05 +01:00
Henrik RydgårdandClaude Opus 5.5 ce81c07a69 sceNetAdhocMatching: Start returns 0, not the matching thread's ID
The fake matching thread was started through sceKernelStartThread,
which switched threads inside the call, and the game got the new
thread's ID back. On a PSP, Start returns 0 (pspautotests
net/adhoc/matching). Create and start it like adhocctl's thread instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:05 +01:00
Henrik RydgårdandClaude Opus 5.5 ae906cb292 sceNetAdhocMatching: Don't list a member twice
A child the host accepts right after another one learns about that one
twice: from the sibling list in its accept packet, and from the BIRTH
packet the host sends about it. It added it both times, so with three or
four players the last one to join had an extra member (pspautotests
net/adhoc/group/matching, not recorded on PSPs yet).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:05 +01:00
Henrik RydgårdandClaude Opus 5.5 db7c9ede34 sceNetAdhocctlGetPeerInfo: NO_ENTRY for the local MAC
The console itself isn't in its peer list, and a PSP returns NO_ENTRY
for it (pspautotests net/adhoc/adhocctl).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:05 +01:00
Henrik RydgårdandClaude Opus 5.5 874080ced2 sceNetAdhocDiscover: Go through the states a PSP goes through
With nobody to find (pspautotests net/adhoc/discover): InitStart leaves
the result field alone and fails with 0x80411301 while running,
adhocctl enters the DISCOVER state after the first Update, and after a
Stop adhocctl goes back to DISCONNECTED with a DISCONNECT event, then
the status becomes COMPLETED with the result cancelled. RequestSuspend
while discovering fails with 0x80411303 instead of cancelling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:05 +01:00
Henrik RydgårdandClaude Opus 5.5 48c9bf9988 sceNetAdhocPdpRecv: Don't copy a datagram that doesn't fit
With a buffer smaller than the next datagram, a PSP returns
NOT_ENOUGH_SPACE with the datagram's size, copies nothing, and keeps
the datagram for the next call (pspautotests net/adhoc/pdp). The first
bytes were copied into the buffer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:05 +01:00
Henrik RydgårdandClaude Opus 5.5 d9ac972915 sceNetAdhocPtpSend, PtpRecv: DISCONNECTED once the peer has gone
After a Recv has found the peer gone, a PSP keeps returning
DISCONNECTED for Send and Recv on that socket, not NOT_CONNECTED
(pspautotests net/adhoc/ptp).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:05 +01:00
Henrik RydgårdandClaude Opus 5.5 1649bd2072 sceNetAdhocPtpOpen: Accept the broadcast address as the destination
A PSP creates the socket (pspautotests net/adhoc/ptp); connecting it
just never succeeds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:05 +01:00
Henrik RydgårdandClaude Opus 5.5 dc450f79b3 sceNetAdhoc: Hand out socket IDs in increasing order, like the PSP
A PSP numbers adhoc sockets in increasing order instead of reusing the
lowest free ID, and a PDP or PTP create that fails its address or port
check, or finds the PDP port in use, uses up an ID too (pspautotests
net/adhoc/pdp and net/adhoc/ptp). Find free slots starting after the last
one handed out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:05 +01:00
Henrik RydgårdandClaude Opus 5.5 97b18b95bb sceNetAdhocPollSocket: Report what a PSP reports
On a PSP (pspautotests net/adhoc/poll):
- a PTP listener reports SEND and FLUSH, and ACCEPT with a connection
  waiting;
- a connected PTP socket reports SEND, CONNECT and FLUSH, and RECV with
  data waiting;
- a connection whose peer has closed reports DISCONNECT alone, and the
  call returns EXCEPTION_EVENT;
- an unknown ID puts INVALID in the first entry;
- a blocking poll with nothing to report by its timeout returns TIMEOUT,
  and one that hits a disconnected socket or the poll alert returns at
  once.

A connection PtpOpen started counts as connected once it's up. Sockets
still connecting keep PPSSPP's own events (Fate Unlimited Codes,
Bleach), and a refused connect still isn't reported, since PPSSPP keeps
retrying it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:05 +01:00
Henrik RydgårdandClaude Opus 5.5 0d089972a3 sceNetAdhoc: Socket alerts don't stop calls that can complete at once
On a PSP (pspautotests net/adhoc/alerts), PtpConnect on a connected
socket and PtpFlush with nothing left to send return 0 with their alerts
set, and the poll alert reports ALERT alone in revents. A connection
PtpOpen started counts as connected once it's up, even if no call has
looked at it since.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:05 +01:00
Henrik RydgårdandClaude Opus 5.5 7e44dc7e8d sceNetAdhocPdpCreate: Give port 0 a port in 0x1000-0x7FFF
On a PSP, a PDP socket created on port 0 gets a free port between
0x1000 and 0x7FFF (pspautotests net/adhoc/limits). The host picked
one instead, usually 0x8000 or above once the port offset was taken
off. Pick it the way PtpOpen already does for PTP, and try another if
the host port is taken. Port 0 still doesn't become the fixed port the
offset alone would give (Phantasy Star Portable 2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:39:05 +01:00
Henrik Rydgård 9c5f87f33d Allow picking 2 frames to buffer again. 2026-10-29 15:25:34 +01:00
Henrik Rydgård 37fa5896c1 Merge pull request #22839 from hrydgard/play-crash-fixes-4
Play crash fixes: vertex range, interrupt and vtimer edge cases, GL push buffer
2026-10-29 09:17:42 +01:00
Henrik Rydgård 1ed60bb835 Merge pull request #22836 from hrydgard/headless-ppge-slots
Headless/debugger fixes, and a crash loading states after a system dialog
2026-10-29 09:17:17 +01:00
Henrik RydgårdandClaude Opus 5.5 d5503978e7 Interrupts: Check whether a sub-interrupt is enabled when its turn comes
All the enabled sub-interrupt handlers were queued when the interrupt fired,
so a handler disabled by an earlier one in the same VBLANK still ran, and one
an earlier handler enabled waited for the next VBLANK. The PSP checks each
handler as it gets to it (intr/disablepending): skip a disabled one, and
queue a newly enabled one if it comes after the handler that's running.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 08:58:33 +01:00
Henrik RydgårdandClaude Opus 5.5 0987fdb169 VTimers: Don't run a pending timer that was cancelled, stopped or given a new handler
The interrupt ran it anyway, and after sceKernelCancelVTimerHandler or
sceKernelSetVTimerHandler with no handler that meant jumping to address 0.
This happens when one timer's handler cancels another timer that came due
together with it, or when a timer comes due while interrupts are suspended.
On the PSP none of these run (threads/vtimers/pending/cancelpending). The
pending entry becomes an invalid id, which the interrupt pops and skips, as
with deleted timers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 08:58:32 +01:00
Henrik RydgårdandClaude Opus 5.5 b566634318 Add --lag-sync, and let it pace headless --realtime
The JIT cores only return from the run loop at the end of a frame, so
--realtime paces once per frame, like the app. With --lag-sync, lag
sync paces every emulated millisecond instead and --realtime's own
sleep stays out of its way. Two instances measuring round trips over
the relay (pspautotests net/adhoc/pair/timing) go from 15-31 ms to
3 ms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 07:33:14 +01:00
Henrik RydgårdandClaude Opus 5.5 d40290b30d sceDisplay: Keep lag sync from drifting, and let it pace alone
Lag sync ("Force real clock sync") waited for 1 ms after the end of the
previous sync, so every sync's oversleep added up: GTA VCS lost 0.4 s
per minute against the wall clock. Wait instead for a fixed base plus
the emulated time since, which can't drift, and start over from now
only when more than 100 ms behind (a pause, or loading).

While it runs, the frame throttle's own waits are skipped. They were out
of phase with lag sync, which then ran flat out to catch up, so frames
were bursts again. The wait itself is the precise one the frame
throttle uses, instead of a yield() spin on Windows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 07:33:14 +01:00
Henrik RydgårdandClaude Opus 5.5 b40c427807 Built-in relay: Pump every millisecond
Every message through the relay waited for the next pump, every 8 ms,
or 100 ms while nobody was connected, which is when a game's first
connection comes in. That was most of what a round trip took once the
emulators stopped running in frame bursts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 07:33:14 +01:00
Henrik RydgårdandClaude Opus 5.5 06a504c9d0 Interrupts: Don't drop the running entry when a handler releases itself
__ReleaseSubIntrHandler erased every pending entry for the sub-interrupt,
including the one at the front, which is the handler that's running. A
handler releasing its own sub-interrupt then left
__KernelReturnFromInterrupt popping an empty list (or the next entry),
which is undefined behaviour and fits Play reports crashing in free under
it on 32-bit. Skip the front entry while in an interrupt, as
__CancelRaisedInterrupts already does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 01:58:13 +01:00
Henrik RydgårdandClaude Opus 5.5 8f6d7fcf94 Log CPU exception reports in headless too
Headless sets a debug output listener, which only passes the output on
when collecting a test's output, so a game crashing in headless left
nothing in the log.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 00:21:49 +01:00
Henrik RydgårdandClaude Opus 5.5 93b7dacc1e WebSocket debugger: runUntilTime that's already there, and across loads
A target time that had already passed, relativeUs 0 for one, failed
without a stop event, so a client waiting for cpu.stepping waited until
its own timeout. Now it doesn't run, and reports the stop right away.

A savestate loaded during the run kept the deadline's absolute time,
which belongs to the timeline the load replaced: a state from later in
the game stopped the run at once, one from earlier ran it for as long
as the gap. Now the deadline keeps the time it had left.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 00:21:49 +01:00
Henrik RydgårdandClaude Opus 5.5 df72f3be81 WebSocket debugger: Any savestate slot in headless
game.state.save and game.state.load with a slot were limited to the
app's slot count (5 by default), which only means how many the UI shows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 00:20:14 +01:00
Henrik RydgårdandClaude Opus 5.5 b719c7e027 PPGe: Load the atlas in headless too
Headless skipped it, so system dialogs (savedata messages, the network
dialogs) had no text, which made driving a game through them blind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 00:20:14 +01:00
Henrik RydgårdandClaude Opus 5.5 f865361c8d sceNetResolver: A lookup takes 5 ms, as on hardware
sceNetResolverStartNtoA returned at once, but on a PSP a lookup through
the access point takes 4-18 ms (pspautotests net/inet/timing), with the
thread asleep waiting for the answer, so the game's other threads run.
It now takes 5 ms and lets them.

The host lookup itself is still synchronous, and stops the emulator
while it waits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 20:30:07 +01:00
Henrik RydgårdandClaude Opus 5.5 8583d3beaa sceNetInet, sceNetApctl: Quicker access point connection, and no busy waits
pspautotests net/inet/timing measures, on a PSP that has connected to
an open network before: JOINING 11 ms after sceNetApctlConnect,
GETTING_IP after about 2.6 s, GOT_IP after about 3.6 s (6.6 s the first
time), and DISCONNECTED 1.1 s after a disconnect. We took 2 s to get to
each of the three, 6 s in all, and 10 ms to disconnect. Games have to
wait for the connection anyway, so it's now quicker than hardware:
JOINING after 10 ms, GETTING_IP 1.25 s later and GOT_IP 0.5 s after
that, with the delays in named constants. Disconnecting takes 0.5 s,
the state staying as it was until then.

The handlers also got 0 as the old state of every step but the first.
Each step now starts from the state the one before ended in.

recv, recvfrom, select and poll still added a 500 us or 1 ms delay to
every call, a workaround from before blocking calls waited for real.
They now take what they take on the PSP when they return at once,
4-15 us (net/inet/timing).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 20:30:07 +01:00
Henrik Rydgård 7aecf86c4d Merge pull request #22830 from hrydgard/inet-8-stack
sceNetInet: The firmware's stack check, and GetPspError as it computes it
2026-10-28 19:00:09 +01:00
Henrik RydgårdandClaude Opus 5.5 fc9a3d3a39 sceNetAdhoc: Give the built-in relay the port its client connects to
aemu_postoffice's default happens to match, but nothing tied the two.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 14:48:47 +01:00
Henrik RydgårdandClaude Opus 5.5 d293cd59b5 proAdhocServer: Let players log in from an IP that's already in use
The relay tells players apart by MAC, so players behind one NAT, or
several instances on one machine, can all play through it. The second
login used to be dropped without an answer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 13:56:56 +01:00
Henrik RydgårdandClaude Opus 5.5 5e92e0e02a sceNetAdhoc: Fix the built-in relay's thread
Join the old relay thread before starting a new one (assigning to a
joinable std::thread terminates), don't map the UPnP port when another
relay already has it, sleep the intended interval (the elapsed time was
subtracted the wrong way round), use one worker per pool, and guard the
log helper against empty messages. Drop the warning that the built-in
server doesn't support relay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 13:56:56 +01:00
Katharine Chui 92b00eb28a fix code formatting 2026-10-28 13:56:56 +01:00
Katharine Chui 7af6661cf0 add upnp call around relay server loop 2026-10-28 13:56:56 +01:00
Katharine Chui c8a9ed025a start aemu_postoffice relay with built-in adhoc server 2026-10-28 13:56:56 +01:00
Katharine Chui 4791043e8d build aemu_postoffice relay server module in cmake 2026-10-28 13:56:56 +01:00
Henrik RydgårdandClaude Opus 5.5 fdbce5fbf2 sceNetInet: The firmware's stack check, and GetPspError as it computes it
Every export of pspnet_inet.prx but the address conversions starts with
sceKernelCheckThreadStack(), and fails without doing anything if the
thread has less than 0x1000 bytes of stack free (0xFE0 for socket()):
the socket calls with -1, without setting errno, and Init, Term,
GetErrno, GetPspError and SocketAbort with 0x80410005. Each function's
limit plus its own stack frame comes to that. pspautotests
net/inet/errnothread shows it on a thread with a 4 KB stack.

GetPspError is 0x80010000 | errno, and 0 for no error, rather than a
table of guesses, so 0x80010001 on a thread with no errno record yet
(net/inet/errnothread).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 13:41:44 +01:00