From 36693ee9e0d9985de096f6b3017c337b9f01cac3 Mon Sep 17 00:00:00 2001 From: Daniel Collins Date: Tue, 5 Sep 2023 18:19:30 +0100 Subject: [PATCH] Block certain calls momentarily when connecting to a DOSBox server. Normally calls like bind() will immediately succeed or fail depending on what address was requested and what addresses are assigned to the machine, but when using a DOSBox IPX server we don't know our address until it gets assigned to us, so block functions impacted by that to avoid spurious errors when starting up. If the server is down or slow then the calls will fail after a few seconds rather than hanging indefinitely. --- src/ipxwrapper.h | 7 +++++++ src/router.c | 18 ++++++++++++++++++ src/router.h | 2 ++ src/winsock.c | 6 ++++++ 4 files changed, 33 insertions(+) diff --git a/src/ipxwrapper.h b/src/ipxwrapper.h index ea34dec..3dde11b 100644 --- a/src/ipxwrapper.h +++ b/src/ipxwrapper.h @@ -36,6 +36,13 @@ #define IPX_CONNECT_TIMEOUT 6 #define IPX_CONNECT_TRIES 3 +/* Maximum number of milliseconds to block waiting for IPX networking to be ready. + * + * This blocks functions which usually don't block (e.g. bind()) so that they don't fail right as + * the process is starting up because we are still connecting to a DOSBox IPX server. +*/ +#define IPX_READY_TIMEOUT 3000 + #define IPX_FILTER (int)(1<<0) #define IPX_BOUND (int)(1<<1) #define IPX_BROADCAST (int)(1<<2) diff --git a/src/router.c b/src/router.c index e5340d0..8fca7a0 100644 --- a/src/router.c +++ b/src/router.c @@ -61,6 +61,7 @@ SOCKET private_socket = -1; struct sockaddr_in dosbox_server_addr; static time_t dosbox_connect_begin; +static HANDLE dosbox_ready_event = NULL; static void _send_dosbox_registration_request(void); static DWORD router_main(void *arg); @@ -141,6 +142,13 @@ void router_init(void) } else if(ipx_encap_type == ENCAP_TYPE_DOSBOX) { + dosbox_ready_event = CreateEvent(NULL, TRUE, FALSE, NULL); + if(dosbox_ready_event == NULL) + { + log_printf(LOG_ERROR, "Error creating event object: %s", w32_error(GetLastError())); + abort(); + } + /* TODO: Support DNS. Do this async somewhere within router_main. */ _init_socket(&private_socket, 0, FALSE, FALSE); @@ -522,6 +530,8 @@ static void _handle_dosbox_registration_response(novell_ipx_packet *packet, size addr48_string(local_nodenum_s, dosbox_local_nodenum); log_printf(LOG_INFO, "Connected to DOSBox server, local address: %s/%s", local_netnum_s, local_nodenum_s); + + SetEvent(dosbox_ready_event); } static void _handle_dosbox_recv(novell_ipx_packet *packet, size_t packet_size) @@ -787,3 +797,11 @@ static DWORD router_main(void *arg) return exit_status; } + +void wait_for_ready(DWORD timeout) +{ + if(dosbox_ready_event != NULL) + { + WaitForSingleObject(dosbox_ready_event, timeout); + } +} diff --git a/src/router.h b/src/router.h index 1ee5360..6162221 100644 --- a/src/router.h +++ b/src/router.h @@ -31,4 +31,6 @@ extern struct sockaddr_in dosbox_server_addr; void router_init(void); void router_cleanup(void); +void wait_for_ready(DWORD timeout); + #endif /* !IPXWRAPPER_ROUTER_H */ diff --git a/src/winsock.c b/src/winsock.c index 9e086cd..2807cf0 100644 --- a/src/winsock.c +++ b/src/winsock.c @@ -542,6 +542,8 @@ int WSAAPI bind(SOCKET fd, const struct sockaddr *addr, int addrlen) if(sock) { + wait_for_ready(IPX_READY_TIMEOUT); + struct sockaddr_ipx ipxaddr; if(addrlen < sizeof(ipxaddr) || addr->sa_family != AF_IPX) @@ -940,6 +942,8 @@ int WSAAPI getsockopt(SOCKET fd, int level, int optname, char FAR *optval, int F if(sock) { + wait_for_ready(IPX_READY_TIMEOUT); + if(level == NSPROTO_IPX) { if(optname == IPX_PTYPE) @@ -1477,6 +1481,8 @@ int WSAAPI sendto(SOCKET fd, const char *buf, int len, int flags, const struct s if(sock) { + wait_for_ready(IPX_READY_TIMEOUT); + if(sock->flags & IPX_IS_SPX) { unlock_sockets();