Skip to content

libkernel: connect() on a listening TCP socket returns the host error instead of EOPNOTSUPP; fix branch ready #6923

Closed

Description

@husseinkad

connect() on a listening TCP socket returns the host error (EINVAL on Windows, EISCONN on Linux) instead of EOPNOTSUPP (45). FreeBSD 11.4 soconnectat fails any socket that has SO_ACCEPTCONN set with EOPNOTSUPP. A program that connects its own listener (a probe, or a retry loop that reuses the descriptor) tests for 45 on the console and sees a different number here.

Fix branch: https://github.com/husseinkad/AnyPS5/tree/fix/socket-connect-listener-eopnotsupp (two commits; it merges cleanly into current main; libkernel/Socket/src/Udp.cpp, the new test tests/GuestSocketConnectListening.cpp registered in the libkernel CMakeLists.txt). For stream sockets, connect now queries SO_ACCEPTCONN after the address has been read and validated (FreeBSD's kern_connect copies the address in before soconnect, so a null or short address still fails first) and returns EOPNOTSUPP for a listener, before the family check.

Checks:

  • The new test fails on main (abort, errno 22) and passes with the change; the 18-test socket group passes.
  • Probed against main on loopback: a valid address on a listener gives 45 for IPv4, IPv6 on an IPv6 listener, an IPv6 address on an IPv4 listener, a nonblocking listener, and after shutdown; connect(listener, NULL, 16) gives 14 and a one-byte address gives the same error as a plain socket, as in FreeBSD's order. Non-listening TCP is unchanged (NULL gives 14, a refused connect gives 61, a second connect gives 56, and a connect to the listener from another socket works), and UDP is unchanged. accept keeps working after every failed connect on the listener. In a 3,000-sequence fuzz, 351 connect results changed from main (156 from 22, 147 from 47, 48 from 14), all on listeners.
  • Three independent reviews. The first found the check ran before address validation (null address gave 45), fixed in the second commit. check_conventions.py is clean and pr_overlap.py found no overlap; it conflicts only textually (adjacent insertions) with my listen auto-bind fix and the port-zero fix, and keeping both sides resolves it.

Not covered: addresses that Address() rejects with 47 (an AF_UNIX family byte, family 0 or 255, a 4-byte-long IPv4 address) still return 47 on a listener where FreeBSD would return 45; a length of 1 returns 14 for plain and listening sockets where FreeBSD gives EINVAL (22), which the sockaddr length checks in #4920 would change. The Linux error code was read from the kernel source, not run. Only Windows was built and run.

AI-assisted: yes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions