Commit Graph
88 Commits
Author SHA1 Message Date
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å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
Henrik RydgårdandClaude Opus 5.5 3ee22fbd3d sceNetInet: TCP socket states and bind's port sharing
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>
2026-10-28 13:09:28 +01:00
Henrik RydgårdandClaude Opus 5.5 d76e1a4496 sceNetInet: Recvmsg, Sendmsg rewritten, and sendto without an address
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>
2026-10-28 12:25:39 +01:00
Henrik RydgårdandClaude Opus 5.5 cc1fad6e2a sceNetInet: Check up to 64 sockets at once on Windows, as before
Splitting larger checks into groups of 64 for Winsock's select() was
untested, and no game is known to poll more sockets than that. Past 64,
it now logs an error and checks the first 64, as the old code did.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 11:42:58 +01:00
Henrik RydgårdandClaude Opus 5.5 759c9e590a sceNetInet: Poll and select as on hardware, and host sockets past FD_SETSIZE
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>
2026-10-28 11:37:32 +01:00
Henrik RydgårdandClaude Opus 5.5 59e9d889e1 sceNetInet: Socket options as the PSP keeps them
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>
2026-10-28 10:59:24 +01:00
Henrik RydgårdandClaude Opus 5.5 0a86a248da sceNetInet: Addresses in and out like the PSP
- 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>
2026-10-28 10:29:23 +01:00
Henrik RydgårdandClaude Opus 5.5 79537d18bd sceNetInet: errno per thread as on hardware, and the socket table
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>
2026-10-28 09:50:48 +01:00
Henrik RydgårdandClaude Opus 5.5 5610c9ff9b sceNetInet: Validate arguments, failing with errno set
Bad arguments now fail the way the PSP fails them, with -1 and errno
set, rather than reaching the host or returning something else:
- A descriptor that isn't open is EBADF. The result used to be EBADF's
  number, 9, which looks like success (pspautotests net/inet/errors).
- Buffers and addresses the host reads or writes directly are checked to
  lie in game memory, failing with EFAULT, rather than letting a host
  recv or send run past the end of it.
- socket() with anything but an AF_INET TCP, UDP or raw socket, with a
  protocol that fits, is EPROTONOSUPPORT (net/inet/errors).
- bind with an address shorter than 16 bytes is EINVAL, and with another
  family than AF_INET EADDRNOTAVAIL (net/inet/errors).
- shutdown with a how other than 0-2 is EINVAL (net/inet/states).
- sendto with an address shorter than 16 bytes is EINVAL, which Winsock
  calls EFAULT, and Sendmsg with any control data, or a short address,
  EINVAL (net/inet/msg).
- poll reports a negative fd as POLLNVAL like any other that isn't open,
  rather than failing (net/inet/polledge).

The pspautotests update brings in the new net/inet tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 09:02:20 +01:00
Henrik RydgårdandClaude Opus 5.5 bd56e07bb0 sceNetInet: Fix the blocking socket waits on Windows
Headless only started Winsock (net::Init) for the debugger, so on Windows
every socket call failed with WSANOTINITIALISED. Start it always.

Winsock's select() fails on empty sets, where POSIX waits out the timeout, so
a select() used as a sleep (the VSH's Skype) returned an error at once. With
no host sockets to check, select and poll now just report nothing ready.

Look up host sockets without GetHostSocketFromInetSocket, which asserts on a
socket closed while a call waits for it, and whose -1 can't be caught with
< 0 on Windows, where SOCKET is unsigned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:04:09 +01:00
Henrik RydgårdandClaude Opus 5.5 be9383c08f sceNetInetPoll: The timeout is in milliseconds
Like POSIX poll(), as pspautotests net/inet/blocking shows. We took it as
microseconds, so every poll timeout was a thousand times too short.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:03:59 +01:00
Henrik RydgårdandClaude Opus 5.5 22e0a1a536 sceNetInet: Wait for blocking socket calls in emulated time
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>
2026-10-27 17:03:59 +01:00
Henrik RydgårdandClaude Opus 5.5 72a0cd1879 sceNetInetSelect: Wait in emulated time instead of blocking the host
select() ran on the CPU thread with the guest's timeout (5.5 seconds when it
gave none), so the whole emulator stopped for as long as it waited. The VSH's
Skype uses select() with no sockets as a sleep, 0.65-0.95 s at a time, and ran
at a crawl: almost no emulated time passed, and the UI barely moved.

Now the sockets are checked without blocking. If none is ready, the thread
waits and a CoreTiming event polls again every millisecond until one is, or
the timeout runs out in emulated time. A null timeout now waits for as long as
it takes. Pending waits are saved in savestates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:02:03 +01:00
Henrik RydgårdandClaude Opus 5.5 455209b43e Net: Fix use-after-pop, the resolver after loads, inet sockaddr/poll
- 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>
2026-10-27 08:43:28 +01:00
Henrik RydgårdandClaude Opus 5.5 7dd1475ed7 HLE: Pass the MIPSState to syscalls and their implementations
HLEFunc and ReplaceFunc now take the MIPSState they run on. The dispatch
paths (both interpreters and every JIT backend) pass in the state they
belong to, and CallSyscall*, hleFinishSyscall and the HLE mips call
machinery use it instead of currentMIPS.

The wrappers in FunctionWrappers.h take the function as `auto` and call it
through HLECall, which also accepts an implementation with an extra leading
MIPSState * parameter and passes the state to it. Any other signature still
fails to compile, as before. PARAM/RETURN now refer to a local `mips`.

The HLE functions (and replacement functions) that used currentMIPS now take
the state that way. Callers outside a syscall's own frame - CoreTiming
events, the adhoc matching thread, dialogs, PPGe, the debugger UIs - pass
currentMIPS or &mipsr4k explicitly. The kernel's thread internals still use
currentMIPS.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-20 15:45:14 +02:00
Henrik RydgårdandClaude Opus 5.5 5080cb23b6 sceNetInet: Only let the ad hoc settings change bind addresses during ad hoc
- Fixes #22647

sceNetInetBind rewrote the address whenever the ad hoc server was set to
localhost (to 127.0.0.x, even an explicit address) or the built-in ad hoc
server was enabled (INADDR_ANY to the address facing the ad hoc server),
breaking infrastructure sockets. Both rewrites now only apply while
adhocctl is initialized, which keeps ad hoc as it was.

sceNetApctlGetInfo reported its IP from the same ad hoc-relative
getLocalIp(), so a localhost ad hoc server told infrastructure games their
IP was 127.0.0.x. It now uses the host interface's IP (getHostLocalIp(),
split out of getLocalIp()).

Adds the net/inet/bind test, which failed every bind under headless (whose
ad hoc server is localhost).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-20 08:59:03 +02:00
Henrik Rydgård 86fcfdc60a Add some new function names that were cracked from NIDs by zecoxao
He used Claude, never thought of this use case, but it's logical - it
can go reverse engineer the functions to come up with likely names,
making it easier to match the SHA1 hash. (NIDs are truncated SHA1 hashes
of names, except in firmwares later than around 3.50).
2026-09-10 15:52:53 -06:00
Henrik Rydgård c5e4d0d90d Rename the get-memory-pointer functions to make it clear where CPU exceptions can happen. 2026-08-12 14:06:16 +02:00
Henrik Rydgård 3c81d6b121 More manual Read_U32 cleanup
Buildfix
2026-08-11 10:28:36 +02:00
Henrik Rydgård cf8afb9490 Safety check in sceNetInetSelect 2026-03-13 10:36:59 +01:00
Henrik Rydgård a08b6c1340 More error code cleanup 2025-08-06 17:44:54 +02:00
Adam.N 0aa8e39b50 Reduce the number of lines a little bit. 2025-05-06 23:08:14 +07:00
Adam.N 4e2d5ca6de Only enforce blocking-mode on games that use blocking-mode. 2025-05-06 00:49:06 +07:00
Henrik Rydgård da7c99a585 sceNetInet: Implement per-thread errno. Reduce some log levels 2025-04-08 08:31:09 +02:00
Henrik Rydgård ebcf6be42c When (successfully) using dyn_dns, remove fixed lookups.
Additionally some various cleanup.
2025-04-08 00:32:40 +02:00
Henrik Rydgård 4e25f44eef Rename some module-related functions to include HLE where appropriate 2025-03-31 11:17:50 +02:00
Henrik Rydgård 28b2c7f540 HLE log rename part 1: Remove duplicate log functions. Return type should be determined by metadata. 2025-01-29 09:45:39 +01:00
Henrik Rydgård 57b6850ea0 Pause screen improvements 2025-01-22 11:50:01 +01:00
Henrik Rydgård e4de9dbfb5 Add some socket data in the debugger 2025-01-22 10:12:56 +01:00
Henrik Rydgård 2523690584 Flip around so sceDelayResult is always outermost. Start using HLECall. 2025-01-20 12:20:18 +01:00
Henrik Rydgård 86b3eadc16 Warning fixes, maybe test fix 2025-01-19 16:33:40 +01:00
Henrik Rydgård 9165711cef Convert more HLE logging to the hleLog system 2025-01-19 15:53:20 +01:00
Henrik Rydgård 5316ec7ef7 Fix more misuse of the hleLog* functions 2025-01-19 13:09:30 +01:00
Henrik Rydgård 7a0ec74c32 Merge pull request #19855 from oltolm/cmake
make compile with Clang/GCC on Windows
2025-01-17 15:13:52 +01:00
Henrik Rydgård 6c6ea2a355 Sockopt: Ignore case we can't support (SO_ONESBCAST) 2025-01-17 12:28:09 +01:00
Henrik Rydgård bfcef44c48 setsockopt refactor part #2 2025-01-17 09:31:38 +01:00
Henrik Rydgård 852c41d124 sockopt refactor part #1 2025-01-17 09:31:09 +01:00
Henrik Rydgård 1013be090c sceNetInet: Refactor errno handling and logging, so we always see how it changes 2025-01-12 14:57:51 +01:00
Henrik Rydgård c901486791 Removes another hacky behavior in sceNetInetGetErrno 2025-01-12 12:50:32 +01:00
Henrik Rydgård 016d66f866 sceNetInet: Stop resetting inetLastErrno to 0 in sceNetInetGetErrno()
This fixes MOHH on Windows.
2025-01-12 12:38:47 +01:00
Henrik Rydgård 364fc2ed6a More sceNetInet logging cleanup 2025-01-11 10:22:23 +01:00
Henrik Rydgård 54581441ea Start cleaning up logging in sceNetInet 2025-01-11 10:22:21 +01:00
AdamN c5e1ea71e0 oops 2025-01-11 09:24:39 +07:00
oltolm 9566065455 make compile on mingw-w64 2025-01-11 01:25:27 +01:00
AdamN ec99cb47bd Fix potential buffer size issue on sceNetInetGetsockname 2025-01-10 22:38:30 +07:00
AdamN cbe8c922a4 Fix potential buffer size issue on sceNetInetGetpeername 2025-01-10 22:25:25 +07:00
Henrik Rydgård 885724db83 Add comments (checked that no other host socket numbers leak to the game) 2025-01-10 14:54:45 +01:00
Henrik Rydgård e79fdaca57 Fix bug in sceNetInetPoll, similar to the previous select bug 2025-01-10 11:24:12 +01:00
AdamN e8bf2effc6 Changed Address Replacement log channel to WARN, because apparently Debug channel being disabled on non-Windows 2025-01-10 07:10:27 +07:00