mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-25 18:05:12 -04:00
c1a9e52894
A failed start printed "built without recomp-net, or bind/peer invalid" for every cause. A player whose system held the UDP port read first that the build had no netplay. The library answers a refused bind, a listen address it cannot read and a peer address it cannot use with the same -1. main.cpp now does those steps again (it reads the listen address as the library does, looks up a name, binds without address reuse) and reports the system's answer. The sentence names a cause only when the system does: address in use, access denied (a port range Windows keeps for Hyper-V or WSL, a port below 1024 elsewhere), address not available. Any other error gets the number and the system's text. The peer address is named only when the listen address opened and the peer address cannot be read. The build is named only when it has no netplay. The sentences are in netplay_exit_reason.c with unit cases; a source guard checks the wiring in main.cpp.
197 lines
12 KiB
C
197 lines
12 KiB
C
/* Netplay exit reasons and the boot-mismatch deadline.
|
|
* Plain checks, not assert(): Release test builds define NDEBUG. */
|
|
#include "netplay_exit_reason.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
static int failures;
|
|
#define CHECK(cond) do { if (!(cond)) { \
|
|
fprintf(stderr, "%s:%d: CHECK failed: %s\n", __FILE__, __LINE__, #cond); \
|
|
++failures; } } while (0)
|
|
|
|
int main(void)
|
|
{
|
|
static const char *const ended[] = {
|
|
"netplay_boot_mismatch", "netplay_peer_disconnect", "netplay_load_failed",
|
|
"netplay_load_stall", "netplay_link_stall", "netplay_admit_stall",
|
|
};
|
|
size_t i;
|
|
|
|
/* Every origin netplay_soft_exit uses for a failure has a sentence, and it
|
|
* fits the lobby client's last_error (192 bytes). */
|
|
for (i = 0; i < sizeof(ended) / sizeof(ended[0]); ++i) {
|
|
const char *t = netplay_exit_reason_text(ended[i]);
|
|
CHECK(t != NULL);
|
|
CHECK(t && strlen(t) > 20 && strlen(t) < 192);
|
|
}
|
|
CHECK(strstr(netplay_exit_reason_text("netplay_boot_mismatch"), "BIOS") != NULL);
|
|
|
|
/* A player who closed the window or pressed Escape needs no reason. */
|
|
CHECK(netplay_exit_reason_text("sdl_window_close") == NULL);
|
|
CHECK(netplay_exit_reason_text("netplay_escape") == NULL);
|
|
CHECK(netplay_exit_reason_text("netplay_barrier_escape") == NULL);
|
|
CHECK(netplay_exit_reason_text("") == NULL);
|
|
CHECK(netplay_exit_reason_text(NULL) == NULL);
|
|
|
|
/* A start that failed says what failed. */
|
|
{
|
|
char why[NETPLAY_START_FAILURE_CAP];
|
|
static const char long_text[] =
|
|
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234";
|
|
/* The port is in use: the port, the address and the system's error
|
|
* are named, the player is told what to do, and the build is not
|
|
* blamed. */
|
|
netplay_start_failure_text(-3, 1, "127.0.0.1:47810", "127.0.0.1:47811",
|
|
NETPLAY_BIND_FAILED, 10048, "in use", why, sizeof(why));
|
|
CHECK(strstr(why, "UDP port 47810 on 127.0.0.1") != NULL);
|
|
CHECK(strstr(why, "system error 10048") != NULL);
|
|
CHECK(strstr(why, "Another program or the operating system holds that port") != NULL);
|
|
CHECK(strstr(why, "Choose another port") != NULL);
|
|
CHECK(strstr(why, "built without") == NULL && strstr(why, "recomp-net") == NULL);
|
|
CHECK(strlen(why) < 192);
|
|
/* The same cause has another number on Linux (98) and on macOS (48).
|
|
* The longest port and address still fit last_error. */
|
|
{
|
|
static const int in_use[] = { 10048, 98, 48 };
|
|
size_t k;
|
|
for (k = 0; k < sizeof(in_use) / sizeof(in_use[0]); ++k) {
|
|
netplay_start_failure_text(-3, 1, "255.255.255.255:65535", "", NETPLAY_BIND_FAILED,
|
|
in_use[k], "", why, sizeof(why));
|
|
CHECK(strstr(why, "UDP port 65535 on 255.255.255.255 (system error ") != NULL);
|
|
CHECK(strstr(why, "holds that port. Choose another port and start again.") != NULL);
|
|
CHECK(strlen(why) < 192);
|
|
}
|
|
}
|
|
/* A LAN host's own port, any address; no address means any address. */
|
|
netplay_start_failure_text(-3, 1, "0.0.0.0:7777", "", NETPLAY_BIND_FAILED, 98, NULL, why, sizeof(why));
|
|
CHECK(strstr(why, "UDP port 7777 on 0.0.0.0 (system error 98)") != NULL);
|
|
CHECK(strstr(why, "holds that port") != NULL);
|
|
netplay_start_failure_text(-3, 1, ":7777", "", NETPLAY_BIND_FAILED, 98, NULL, why, sizeof(why));
|
|
CHECK(strstr(why, "UDP port 7777 on 0.0.0.0 (system error 98)") != NULL);
|
|
/* A port the system does not hand out (a range Windows keeps for
|
|
* Hyper-V or WSL: 10013; a port below 1024 elsewhere: 13). The player
|
|
* is not sent looking for another program. */
|
|
{
|
|
static const int denied[] = { 10013, 13 };
|
|
size_t k;
|
|
for (k = 0; k < sizeof(denied) / sizeof(denied[0]); ++k) {
|
|
netplay_start_failure_text(-3, 1, "127.0.0.1:47810", "127.0.0.1:47811",
|
|
NETPLAY_BIND_FAILED, denied[k], "denied", why, sizeof(why));
|
|
CHECK(strstr(why, "UDP port 47810 on 127.0.0.1 (system error ") != NULL);
|
|
CHECK(strstr(why, "The operating system does not allow this port.") != NULL);
|
|
CHECK(strstr(why, "Choose another port and start again.") != NULL);
|
|
CHECK(strstr(why, "Another program") == NULL && strstr(why, "holds") == NULL);
|
|
CHECK(strstr(why, "built without") == NULL);
|
|
CHECK(strlen(why) < 192);
|
|
}
|
|
CHECK(strstr(why, "(system error 13)") != NULL);
|
|
/* The number alone does not decide: a port that could be bound is not "not allowed". */
|
|
netplay_start_failure_text(-3, 1, "127.0.0.1:47810", "x", NETPLAY_BIND_OK, 10013, "", why, sizeof(why));
|
|
CHECK(strstr(why, "does not allow") == NULL);
|
|
}
|
|
/* The listen address is not one of this computer's (Windows 10049,
|
|
* Linux 99, macOS 49). No port is held and another port does not
|
|
* help, so neither is said. */
|
|
{
|
|
static const int no_address[] = { 10049, 99, 49 };
|
|
size_t k;
|
|
for (k = 0; k < sizeof(no_address) / sizeof(no_address[0]); ++k) {
|
|
netplay_start_failure_text(-3, 1, "192.168.1.50:7777", "", NETPLAY_BIND_FAILED,
|
|
no_address[k], "not available", why, sizeof(why));
|
|
CHECK(strstr(why, "Netplay could not listen on 192.168.1.50 (system error ") != NULL);
|
|
CHECK(strstr(why, "That address is not one of this computer's addresses.") != NULL);
|
|
CHECK(strstr(why, "Check the listen address and start again.") != NULL);
|
|
CHECK(strstr(why, "holds") == NULL && strstr(why, "another port") == NULL);
|
|
CHECK(strstr(why, "does not allow") == NULL);
|
|
}
|
|
CHECK(strstr(why, "(system error 49)") != NULL);
|
|
netplay_start_failure_text(-3, 1, "255.255.255.255:65535", "", NETPLAY_BIND_FAILED,
|
|
10049, "", why, sizeof(why));
|
|
CHECK(strlen(why) < 192 && strstr(why, "start again.") != NULL);
|
|
}
|
|
/* Any other answer of the system: the number and the system's text,
|
|
* and no cause and no advice the code cannot know. */
|
|
netplay_start_failure_text(-3, 1, "10.0.0.1:7777", "", NETPLAY_BIND_FAILED, 101,
|
|
"Network is unreachable", why, sizeof(why));
|
|
CHECK(strcmp(why, "Netplay could not open UDP port 7777 on 10.0.0.1 "
|
|
"(system error 101: Network is unreachable).") == 0);
|
|
CHECK(strstr(why, "holds") == NULL && strstr(why, "Choose") == NULL && strstr(why, "does not allow") == NULL);
|
|
/* Without a text, a text in another alphabet or a long text: the number alone. */
|
|
netplay_start_failure_text(-3, 1, "10.0.0.1:7777", "", NETPLAY_BIND_FAILED, 101, NULL, why, sizeof(why));
|
|
CHECK(strcmp(why, "Netplay could not open UDP port 7777 on 10.0.0.1 (system error 101).") == 0);
|
|
netplay_start_failure_text(-3, 1, "10.0.0.1:7777", "", NETPLAY_BIND_FAILED, 10055,
|
|
"\xcc\xe7 \xe4\xe9\xe1\xe8\xdd\xf3\xe9\xec\xef", why, sizeof(why));
|
|
CHECK(strcmp(why, "Netplay could not open UDP port 7777 on 10.0.0.1 (system error 10055).") == 0);
|
|
netplay_start_failure_text(-3, 1, "10.0.0.1:7777", "", NETPLAY_BIND_FAILED, 10055, long_text, why, sizeof(why));
|
|
CHECK(strcmp(why, "Netplay could not open UDP port 7777 on 10.0.0.1 (system error 10055).") == 0);
|
|
/* The longest values with the longest text that is shown (80 letters) fit. */
|
|
netplay_start_failure_text(-3, 1, "255.255.255.255:65535", "", NETPLAY_BIND_FAILED, -2147483647,
|
|
long_text + 5, why, sizeof(why));
|
|
CHECK(strlen(why) < 192 && strstr(why, "01234).") != NULL);
|
|
/* The system made no socket: no port and no address is blamed. */
|
|
netplay_start_failure_text(-3, 1, "0.0.0.0:7777", "", NETPLAY_BIND_NO_SOCKET, 24,
|
|
"Too many open files", why, sizeof(why));
|
|
CHECK(strcmp(why, "Netplay could not open a network socket (system error 24: Too many open files).") == 0);
|
|
/* The build is named only when the build has no netplay. */
|
|
netplay_start_failure_text(-1, 0, "127.0.0.1:47810", "", NETPLAY_BIND_NOT_TRIED, 0, "", why, sizeof(why));
|
|
CHECK(strstr(why, "This build has no netplay") != NULL);
|
|
CHECK(strstr(why, "port") == NULL);
|
|
/* The listen address opened and the peer address cannot be read: the
|
|
* peer address is the cause. */
|
|
netplay_start_failure_text(-3, 1, "127.0.0.1:47810", "not an address", NETPLAY_BIND_PEER_BAD, 0, "",
|
|
why, sizeof(why));
|
|
CHECK(strstr(why, "the other player's address \"not an address\"") != NULL);
|
|
CHECK(strstr(why, "holds that port") == NULL);
|
|
/* The peer address is not blamed when nothing was tried, or when the
|
|
* listen address opened and the peer address reads well: no cause is
|
|
* known then. */
|
|
netplay_start_failure_text(-3, 1, "localhost:40010", "127.0.0.1:40011", NETPLAY_BIND_NOT_TRIED, 0, "",
|
|
why, sizeof(why));
|
|
CHECK(strcmp(why, "Netplay could not start its connection on localhost:40010.") == 0);
|
|
netplay_start_failure_text(-3, 1, "127.0.0.1:40010", "127.0.0.1:40011", NETPLAY_BIND_OK, 0, "",
|
|
why, sizeof(why));
|
|
CHECK(strcmp(why, "Netplay could not start its connection on 127.0.0.1:40010.") == 0);
|
|
CHECK(strstr(why, "other player") == NULL);
|
|
/* A listen address that is not address:port. */
|
|
netplay_start_failure_text(-3, 1, "47810", "", NETPLAY_BIND_BAD_ADDRESS, 0, "", why, sizeof(why));
|
|
CHECK(strstr(why, "\"47810\" is not an address and a port") != NULL);
|
|
/* A host waiting for the first peer (no peer address), port free. */
|
|
netplay_start_failure_text(-3, 1, "0.0.0.0:7777", "", NETPLAY_BIND_OK, 0, "", why, sizeof(why));
|
|
CHECK(strstr(why, "its connection on 0.0.0.0:7777") != NULL);
|
|
/* Online (relay): five causes share the code, so none is named and
|
|
* the player is not sent to a log a released game does not show. */
|
|
netplay_start_failure_text(-4, 1, "0.0.0.0:0", "", NETPLAY_BIND_NOT_TRIED, 0, "", why, sizeof(why));
|
|
CHECK(strcmp(why, "Netplay could not start the online connection.") == 0);
|
|
/* Any other code. */
|
|
netplay_start_failure_text(-2, 1, "", "", NETPLAY_BIND_NOT_TRIED, 0, "", why, sizeof(why));
|
|
CHECK(strstr(why, "(code -2)") != NULL);
|
|
/* Missing strings and a short buffer are safe. */
|
|
netplay_start_failure_text(-3, 1, NULL, NULL, NETPLAY_BIND_FAILED, 5, NULL, why, sizeof(why));
|
|
CHECK(strlen(why) > 20 && strlen(why) < 192);
|
|
memset(why, 'x', sizeof(why));
|
|
netplay_start_failure_text(-3, 1, "127.0.0.1:47810", "", NETPLAY_BIND_FAILED, 10048, "", why, 8);
|
|
CHECK(strlen(why) == 7 && why[8] == 'x');
|
|
netplay_start_failure_text(-3, 1, "127.0.0.1:47810", "", NETPLAY_BIND_FAILED, 10048, "", NULL, 0);
|
|
}
|
|
|
|
/* No mismatch seen: never final. */
|
|
CHECK(!netplay_boot_mismatch_final(0u, 100000u, NETPLAY_BOOT_MISMATCH_GRACE_MS));
|
|
/* Seen, grace not yet over, then over. */
|
|
CHECK(!netplay_boot_mismatch_final(1000u, 3999u, NETPLAY_BOOT_MISMATCH_GRACE_MS));
|
|
CHECK(netplay_boot_mismatch_final(1000u, 4000u, NETPLAY_BOOT_MISMATCH_GRACE_MS));
|
|
/* The 32-bit millisecond clock wraps. */
|
|
CHECK(!netplay_boot_mismatch_final(0xFFFFFF00u, 0x00000100u, NETPLAY_BOOT_MISMATCH_GRACE_MS));
|
|
CHECK(netplay_boot_mismatch_final(0xFFFFFF00u, 0x00000C00u, NETPLAY_BOOT_MISMATCH_GRACE_MS));
|
|
/* The old behaviour was a 20 s admit-stall watchdog; the grace is far
|
|
* shorter than that. */
|
|
CHECK(NETPLAY_BOOT_MISMATCH_GRACE_MS < 20000u);
|
|
|
|
if (failures) {
|
|
fprintf(stderr, "netplay_exit_reason: %d check(s) FAILED\n", failures);
|
|
return 1;
|
|
}
|
|
puts("netplay_exit_reason: PASS");
|
|
return 0;
|
|
}
|