Winsock never makes a socket whose connect failed writable; the failure
shows in select's exception set, with the reason in SO_ERROR. The poll
now checks both, and SO_ERROR on a writable socket too, which is where
other systems put a refusal.
Windows still retries a refused connect for about a second before
reporting it, far longer than a PSP at the tests' 800% speed, so
pair/basic is a known P2P failure on Windows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Like the two-console tests, each runs through the built-in server's relay
and in P2P, with adhoc_known_failures for the ones that fail in one mode.
pair/basic passes in P2P now and moves to tests_good, a known failure
through the relay.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A PSP completes a connect to a listener without the game calling Accept,
so an opened PTP connection is up a few ms after PtpOpen (pspautotests
net/adhoc/pair/ptppoll). The relay only answers the connecting side once
the listening side accepts, so the relay transport now accepts pending
connections into a queue as long as the listener's backlog, from a new
per-millisecond AdhocTransport::Poll() and from polls and accepts, and
PtpAccept takes them from there. A poll reports ACCEPT while the queue
isn't empty.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Out of the group, a PSP's sends reach nobody and nothing reaches it, and
a PTP connection to a peer that has left fails once its retransmits would
have run out. Only the relay transport did this; the P2P one kept sending
over the host's sockets, so neither side ever noticed the other was gone
(pspautotests net/adhoc/pair/vanish).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
--cpu-backend-only leaves out the tests that don't depend on the CPU
backend (net/ for now, the two-console ones taking about 40 s of a 60 s
run). The Linux CI jobs run everything with the JIT and pass it for
jit-ir, ir and the interpreter.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pair tests that pass go in tests_good, and each runs twice: through
the built-in server's relay and P2P. pair_known_failures lists the ones
that fail in only one mode. A P2P test that needs a loopback address
the machine lacks (macOS has only 127.0.0.1) is skipped with a warning,
and the run fails at the end with the command that adds it. The macOS
CI runners add 127.0.0.2. Each run gets a random port offset.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Fixes#22857
PES 2009 calls sceNetApctlGetState first and only calls sceNetApctlInit
when it fails with 0x80410a0d. We returned success, so Init was never
called, apctl's state never advanced and the Netconf dialog waited on
"Connecting to the access point" forever. A PSP returns 0x80410a0d before
Init and after Term (pspautotests net/adhoc/apctlinit).
After that the game polls sceNetGetLocalEtherAddr until it succeeds, which
we only allowed in ad hoc mode. Also allow it once apctl has connected. It
still fails with apctl initialized but not connected, as the test shows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
As on a PSP (pspautotests net/adhoc/abandon): the Disconnect fails and
the join goes on to CONNECT. Before, it was accepted, and the join's late
answer from the server could still connect us afterwards.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With offsets of up to 30000, a port net/adhoc/limits listened on could
be one an outgoing connection was using, and the listen failed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
--speed=PERCENT runs a --realtime headless at an alternate speed (speed
control while connected is allowed for it), and pacing follows it. The
ad hoc tests now run at 800%, which takes their part of test.py -g from
about 71 s to 12 s; only local network round trips stay real time.
test.py also gives each ad hoc test run its own --port-offset: a
connection the previous run made with the same ports is still in TCP
TIME_WAIT, and connecting again failed with EADDRINUSE once runs came
close together.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
alerts, discover, gamemode, limits, loopback, self, socketids and term
pass, so they move to tests_good. They run in real time against the
built-in server, about 71 s together. The ad hoc tests left in
tests_next say why they don't pass yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A PSP stays in its group through sceNetAdhocTerm and sceNetAdhocInit,
and matching keeps working; only the sockets go, and calls on them
return NOT_INITIALIZED until the next init (net/adhoc/term, recorded on
a PSP). We also terminated adhocctl, so a game that restarts the adhoc
library inside a group found itself disconnected. Every other caller
already terminates adhocctl itself first.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A PSP hands out socket IDs from 1 again after sceNetAdhocTerm and
sceNetAdhocInit (net/adhoc/socketids, recorded on a PSP). We kept
counting up. Pangya: Fantasy Golf tears down the network between its
room and the round, and then keeps using socket 1 without looking at
what PdpCreate returned, so every send and receive failed with
INVALID_SOCKET_ID and each player saw the other as "Off-line".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Fixes#22331
A child's GetMembers starts with itself, then switches to the parent
first one keepalive interval after it was accepted
(net/adhoc/pair/matchingorder, recorded on two PSPs). We kept it self
first. Bomberman's client checks that the first member is the host
before it marks itself ready, so its lobby stayed empty and the host's
start failed with "failed to connect to the game".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The u64 total length made both context structs 8-aligned, while the
game's context only has to be 4-aligned (hash/hash puts it in a char
array). On ARM32, GCC then copies buf with vld1.64 [:64], which faults
on such an address - on hardware too, not just under qemu as the
known-failures entry assumed. Store the length as two words; the layout
is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
The pair tests (net/adhoc/pair) run on two headless instances through
Tools/adhoc_multi.py and the host's built-in relay. They're all in
tests_next for now. The single-console ad hoc tests get the built-in
server and real-time speed, which they need to get past creating a
group, with a timeout to match.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
Following pspautotests net/inet/errors, states and reuse:
- bind decides itself whether a port is in use, as 4.4BSD's in_pcbbind()
does with SO_REUSEADDR and SO_REUSEPORT. The host can't, since its
sockets have both on for running several instances, so any number of
sockets could bind the same port. A socket that's bound already is
EINVAL.
- Shutting down the sending side of an unconnected TCP socket, or a
failed connect, throws away its TCP state as in 4.4BSD's tcp_usrreq(),
after which bind, listen, connect, accept and shutdown fail with
EINVAL, and its port is free again. shutdown otherwise only fails for
a bad how, and still reaches the host, so a thread waiting in accept
wakes up.
- listen on an unbound TCP socket binds one, which Winsock didn't, and on
a connected one succeeds.
- connect on a listening socket is EOPNOTSUPP. Winsock's WSAEINVAL for
it looked like a connect in progress, and a blocking socket waited
forever. A second connect on a loopback connection the host hasn't
noticed finishing is EISCONN once it has.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Recvmsg was a stub that failed without setting errno. It now receives
like recvfrom, scattering into the buffers and waiting like the other
blocking calls. Sendmsg is rewritten around the same msghdr reading.
Following pspautotests net/inet/msg:
- Recvmsg truncates the address to namelen, gives TCP none and a namelen
of 0, sets MSG_TRUNC in msg_flags, and controllen to 0.
- Sendmsg with no buffers sends an empty datagram, which macOS failed.
- sendto without an address works on a connected socket. Linux failed
it, given an address of length 0.
On Windows, Sendmsg uses WSASendTo, since WSASendMsg only takes
datagram sockets, and Recvmsg WSARecvFrom.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Following pspautotests net/inet/polledge:
- poll reports only what was asked for, and never POLLHUP or POLLERR,
even for a peer that closed or reset the connection.
- select with a closed descriptor in a set fails with EBADF and leaves
the sets alone. It used to skip it.
The host side now uses poll() outside Windows, where select() can't take
a descriptor numbered FD_SETSIZE or above and FD_SET wrote past the
fd_set. macOS reports a peer that closed as POLLHUP with POLLPRI, and
the POLLPRI is ignored, as its select() shows nothing for it. Winsock's
select() has no such limit, but takes only 64 sockets a set, so it's
called on groups of 64, and poll is no longer cut short at 64 entries
there. A failing poll sets the host's errno rather than EINTR.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The PSP's getsockopt and setsockopt work like 4.4BSD's, which
pspautotests net/inet/options records in detail, and most of it didn't
match: flags read back as their bit (SO_REUSEADDR as 4, SO_NBIO as
0x80), buffer sizes have their own defaults, getsockopt copies as much
as fits and says how much, and unknown options and levels fail with
ENOPROTOOPT and EINVAL.
So the socket-level options are now kept in InetSocket, and only the
ones that change what the host socket does are passed on to it. That
also stops the timeouts reaching the host, where Winsock read the
timeval as a millisecond count. Accepted sockets copy their options from
the listener, like BSD's sonewconn(). IP_TTL is kept too, as Windows'
default is 128 and the PSP's 64.
Timeouts are set in microseconds, but kept in 10 ms clock ticks, and
one under a tick is no timeout at all (net/inet/limits). Buffers can be
up to 233016 bytes (net/inet/limits), 4.4BSD's limit with 256-byte
mbufs, where we allowed 8 MB. SO_ERROR reads as an SCE error code rather
than an errno (net/inet/tcp).
The host's TCP send buffer is capped at 64 KB, closer to the PSP's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- accept and recvfrom write only as much of the address as its length
allows, and set the length to that (pspautotests net/inet/udp and
tcp). They wrote all 16 bytes and set it to 16. They now also give the
host an address of their own, so one the game passes without a length
can't make the host fail the call with EFAULT.
- InetAton and InetAddr take the forms 4.4BSD's inet_aton() does
("1.2.3", "16909060", "0x7f.1", octal with a leading zero), which the
host's inet_pton() didn't. InetPton takes only a plain dotted quad,
and only AF_INET. All three stop at a space. InetNtop returns NULL with
ENOSPC when the string doesn't fit, leaving the buffer alone, and with
EAFNOSUPPORT for other families (net/inet/addr).
- getpeername after the peer closed is ENOTCONN rather than macOS's
EINVAL, as 4.4BSD checks for a connection first (net/inet/errors).
Coded Arms Contagion calls InetNtop with a 4-byte buffer, which now gets
NULL, as on hardware.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
errno:
- A thread that hasn't made a call yet reads 0x80410001 from GetErrno,
as the PSP has no errno record for it until then. errno is saved in
savestates now, in a new sceNet section version.
- socket(), close() and setsockopt() clear it when they succeed.
- Running out of descriptors is EMFILE, at 255 like the PSP, and an
unconnected UDP socket sending without an address EDESTADDRREQ, which
Winsock calls ENOTCONN.
- On Windows, ENOBUFS, EPROTOTYPE, ENOPROTOOPT, EMSGSIZE, ENETRESET and
EDESTADDRREQ now map to the PSP's errnos. They only did elsewhere.
All from pspautotests net/inet/errors, options and errnothread.
The socket table:
- Descriptor numbers are handed out round-robin up to 255, as on the PSP
(net/inet/states), rather than the lowest free one.
- Closing frees the slot even if the host's close fails, and Close and
CloseAll take the lock the rest of SocketManager does.
- accept no longer leaks the host socket when it runs out of numbers.
- bind no longer asks UPnP to forward port 0, and closing the socket
removes its forward, unless another socket still uses the port.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Host sockets are always non-blocking, so a game's blocking recv(), accept()
and so on came back with EAGAIN at once, and connect() and poll() blocked the
whole emulator in the host call instead. Now recv, recvfrom, send, sendto,
accept, connect, poll and select try once, and if the call would block on a
blocking socket (no SO_NBIO or MSG_DONTWAIT), the thread waits and a
CoreTiming event retries it every millisecond. It ends when the call completes
or fails, or when SO_RCVTIMEO/SO_SNDTIMEO runs out in emulated time.
Sockets accepted on Linux are made non-blocking too: unlike BSD and Windows,
Linux doesn't pass that on from the listening socket. select() rejects a
tv_usec of a second or more with EINVAL.
Hardware behaviour from pspautotests net/inet/blocking.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pspautotests audio/sceaudio/input and audio/sceaudio/routing.
- sceAudioInput fails until sceAudioInputInit, then checks that the
sample count is a nonzero multiple of 64 before checking the rate
(11025, 22050 or 44100 only). A rate of 0 now gets the PSP's error
instead of the USB mic's. Init takes about 3ms.
- A blocking mic input woke with the byte count rather than the sample
count that the non-blocking call returns.
- The routing functions are exported by both sceAudio and
sceAudioRouting, and the latter had its own copy that ignored the
stored modes. Both now share the one in sceAudio, with the ranges
checked. SetVolumeMode returns 0, not the previous mode, and both
modes start at 0.
sceAudio's savestate section goes to version 5 for the input init flag.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The apctl, NpAuth and NpMatching2 event loops kept references to the
front of their deque after popping it, so callbacks could get the
next event's arguments. NpMatching2 also dereferenced its optional
opt param when it was null.
- The resolver was left stopped after any savestate load or reboot,
which broke Outrun 2006 (it relies on it starting out running).
- Getpeername/Getsockname with a namelen under 2 copied a negative size.
They now write the PSP's 16-byte sockaddr truncated to namelen, with
sa_len 16, as pspautotests net/inet/poll shows on hardware.
- Poll handed an fd that isn't open (-1) to FD_SET. It now reports
POLLNVAL for it and counts it, as on hardware (net/inet/poll).
Setsockopt read past a local u32 for larger options, and passed a
negative optlen to the host. A zero cmsg_len looped forever.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pspautotests modules/idlist shows that sceKernelGetModuleIdList still
writes a partial entry at the end of the buffer (a size of 6 gives two
entries), which the previous commit had stopped. A NULL buffer or a
negative size returns ILLEGAL_ADDR without writing the count.
sysmem/kernel/heap shows sceKernelAllocHeapMemory returning null for
sizes near 4GB, rather than wrapping. The WithOption variant already
checked this. The plain one now does too.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Fixes#22764
pspautotests video/mpeg/cscvme shows the two luma buffers are fields, each
with its own chroma, and that the rows land as they do for
sceMpegBaseCscAvc: woven together without a second buffer, packed one per
buffer with one. The XMB's Motion JPEG player passes the second buffer
right after the first with the picture's halves as the fields, which is
why the halves model happened to work for it.
The hardware's colours match the scalar conversion exactly, so CscVme uses
that rather than swscale. Fields packed back to back now reach the GPU as
one write, so a texture over the whole picture isn't cut at the first.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
On a PSP, jr and jalr to an address with its low two bits set raise no
address error: they run from the aligned address, the PC keeps no low
bits, and jalr's link is unaffected (cpu/jump/unaligned, recorded on
firmware 6.61). This was done only for the Media Engine.
The firmware's PS1 emulator returns through such an address. The
interpreters stopped there with an invalid jump, and the JITs found the
block at the aligned address only if it was already compiled, and
otherwise compiled one at the unaligned address.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Updates the submodule for video/mp4/avchold's ref3b1hrdsplice, recorded
on a PSP, which fails without the AvcDecoder fix on this branch: the pictures after
the splice never come out.
avchold and decodeend only test anything with Sony's mpeg and mp4
modules running, which headless never does for homebrew unless asked,
and which CI doesn't have. docs/pspautotests.md now says how to run
them (--disable-hle=0x110 and a memory stick with a firmware dump).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
-i, -j, -r, -J, --ir and --jit-ir are gone. -r was also --root's short form,
and --root won, so -r took the next argument as the root path and nothing
booted (test.py -r failed every test).
-i, -j and -J now fail with an error pointing at --cpu= instead of quietly
running on the default core. Docs and test.py updated.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The audio block's FIFO, measured from the ME on a PSP-1000. In the next
set: it needs the ME on, and Sony's ME firmware to hand the ME back to.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
PMDVIS ships a kcall.prx that ends where its relocation sections begin.
On a PSP-1000 (6.61) such a module loads unrelocated if syslib is its only
export library, but with another library the load hangs the PSP
(pspautotests modules/cutrel and modules/cutrel/kernel, which leave that
case out). We loaded it unrelocated, and PMDVIS then crashed on its
garbage export table. Now the load fails with 80020148, the error
PSPLink's modload gave for that file, and PMDVIS carries on without the
ME.
Also ModuleMgrForKernel's 6.61 NID for sceKernelUnloadModule, which the
kernel test uses.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
What the ME sees at VRAM's addresses, recorded on a PSP-1000. In the
next set: it needs the ME on, and Sony's ME firmware to hand the ME back
to at the end.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The calls a PSP-2000 and later switch to their 4MB of VRAM with. We have
the PSP-1000's 2MB, and answer as it does, recorded in the new
gpu/ge/kernel/edramsize. Tanaka's Touhou ports import them in their GE4
wrapper module, and fall back to 2MB.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>