Repository navigation
Wii: fix hang after connect and failure on large replies in net_read/… - #2
TeleTubby666 wants to merge 18 commits into
Conversation
…net_write On the Wii, connecting to an SMB share hangs after the tree connect, and opening a directory with many entries fails (the share root works, a large subfolder does not). A packet capture shows the server side is fine. - smb2_net_read(): libsmb2 reads in a loop until the socket reports EAGAIN, but net_read() does not return EAGAIN when no data is waiting, so smb2_service() never returns. Only read when select() reports data, otherwise return EAGAIN. - smb2_net_read()/smb2_net_write(): libogc's net_read()/net_write() copy the whole buffer through a fixed 64 KB IOS heap. A large reply (a directory listing is up to ~64 KB) fails with IPC_ENOMEM and breaks the connection. Cap a single call to 8 KB; libsmb2 resumes partial reads and writes. Only affects __wii__.
|
I think this is fixing this at the wrong layer. libsmb2 shouldn't need to work around this. I've submitted a PR for libogc2 - extremscorner/libogc2#31 |
|
Following up on this: I tested libogc2 PR 31 (block splitting) together with After the last PDU of the connect handshake has been read successfully net_read(len=16) calling That part is independent of the 64 KB heap limit, so it will remain even if |
|
Got it. So with the large reply case handled, yes let's split off this to the remainder. |
|
Let me update - any libsmb2 changes need to be tested on and also work for libogc too - not just libogc2. |
The size limit for large replies is handled in libogc2 (net_recvfrom/net_sendto in blocks). What remains is the hang: net_read() blocks instead of returning EAGAIN when nothing is pending, so libsmb2's read loop never ends. Only read when select() reports data.
77511a2 to
5f9ce8e
Compare
Added an exception set for error handling in smb2_net_read on Wii.
|
The select-before-read check is a reasonable Wii-only workaround. But as written, a hangup or error that IOS reports without POLLIN becomes EAGAIN forever and the dead connection never surfaces. Watching the exception set as well fixes that. It costs one extra IOS call per read. I've added that change. Before merging though (and submitting upstream to libsmb2) - to find the real cause, log what net_ioctl(fd, FIONBIO, &one) returns, what net_fcntl(fd, F_GETFL, 0) returns afterwards, and how long a net_read takes on an idle connected socket. If it blocks with the flag set, the fix belongs in libogc2 and this libsmb2 workaround can go. |
|
Thanks for the pointers. I tested on real Wii hardware (libogc2 master incl. 8cad2e7 + libsmb2 with the change below, stock snes9xgx otherwise). Root cause of the hang: with the toolchain I use, FIONBIO evaluates to 0x1 in libsmb2, but libogc2's net_ioctl() only accepts its own _IOW('f', 126, unsigned long) = 0x8004667e. So net_ioctl(fd, FIONBIO, &one) in set_nonblocking() returns -22 (EINVAL). The return value is ignored, the socket stays blocking, and net_read() blocks as soon as nothing is pending. Trace (before): F_GETFL = 0x0, IOS_O_NONBLOCK (0x04) not set, read blocks -> hang at "connecting". With that change connect works, a large directory listing works (a 65424-byte read comes back as 32696 + 32728 thanks to 8cad2e7), loading a ROM works, and so do mkdir, stat and writes (8 KB, 32 KB and 48 KB writes all return the full length). The select-before-read workaround is not needed on this setup. Change: TeleTubby666@b0ca245 (branch wii-fionbio-fix, based on current master). Caveats: Wii only (Wii U is not affected). I have no GameCube to test. For libogc I could only check that it compiles in CI; I haven't verified what FIONBIO expands to there, so you may want to guard the constant accordingly. Should I turn PR #2 into this change, or open a new PR from wii-fionbio-fix? |
socket.c includes <sys/ioctl.h> before compat.h pulls in libogc's
<network.h>. The toolchain header defines FIONBIO (as 0x1 on the Wii),
so network.h's "#ifndef FIONBIO" definition, _IOW('f', 126, unsigned
long) = 0x8004667e, is skipped. net_ioctl() only accepts its own value,
returns EINVAL, the result is ignored, and the socket stays blocking:
net_read() then blocks when nothing is pending and connecting hangs.
Don't include <sys/ioctl.h> on __wii__/__gamecube__ so <network.h>
provides FIONBIO, instead of hardcoding the constant.
Reported and diagnosed on hardware by TeleTubby666 (#2).
Co-authored-by: TeleTubby666 <80608448+TeleTubby666@users.noreply.github.com>
socket.c includes <sys/ioctl.h> before compat.h pulls in libogc's
<network.h>. The toolchain header defines FIONBIO (as 0x1 on the Wii),
so network.h's "#ifndef FIONBIO" definition, _IOW('f', 126, unsigned
long) = 0x8004667e, is skipped. net_ioctl() only accepts its own value,
returns EINVAL, the result is ignored, and the socket stays blocking:
net_read() then blocks when nothing is pending and connecting hangs.
Don't include <sys/ioctl.h> on __wii__/__gamecube__ so <network.h>
provides FIONBIO, instead of hardcoding the constant.
Reported and diagnosed on hardware by TeleTubby666 (#2).
Co-authored-by: TeleTubby666 <80608448+TeleTubby666@users.noreply.github.com>
|
good job. it's the right problem, wrong solution. I've refined it for you and submitted it directly to sahlberg#495 you can test https://github.com/dborth/libsmb2 again and see if it's fixed. I've updated the changelog on the emulators which should kick off builds that include the libogc2 + libsmb2 changes |
) socket.c includes <sys/ioctl.h> before compat.h pulls in libogc's <network.h>. The toolchain header defines FIONBIO (as 0x1 on the Wii), so network.h's "#ifndef FIONBIO" definition, _IOW('f', 126, unsigned long) = 0x8004667e, is skipped. net_ioctl() only accepts its own value, returns EINVAL, the result is ignored, and the socket stays blocking: net_read() then blocks when nothing is pending and connecting hangs. Don't include <sys/ioctl.h> on __wii__/__gamecube__ so <network.h> provides FIONBIO, instead of hardcoding the constant. Reported and diagnosed on hardware by TeleTubby666 (dborth#2). Co-authored-by: TeleTubby666 <80608448+TeleTubby666@users.noreply.github.com>
…net_write
On the Wii, connecting to an SMB share hangs after the tree connect, and opening a directory with many entries fails (the share root works, a large subfolder does not). A packet capture shows the server side is fine.
Only affects wii