1
0
mirror of https://github.com/solemnwarning/ipxwrapper synced 2024-12-30 16:45:37 +01:00

Work around some bugs on Windows 98

- Call CreateThread() with non-NULL lpThreadId pointers.

- Ignore InitializeCriticalSectionAndSpinCount() return values.

- Skip log file locking when unimplemented.

- Add missing wsock32.dll entry points.
This commit is contained in:
Daniel Collins 2024-06-26 00:37:43 +01:00
parent 26f6511dee
commit 623d2c3df4
17 changed files with 134 additions and 60 deletions

View File

@ -1,5 +1,5 @@
/* IPXWrapper - Address cache /* IPXWrapper - Address cache
* Copyright (C) 2008-2023 Daniel Collins <solemnwarning@solemnwarning.net> * Copyright (C) 2008-2024 Daniel Collins <solemnwarning@solemnwarning.net>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by * under the terms of the GNU General Public License version 2 as published by
@ -101,11 +101,7 @@ static void host_table_delete(host_table_t *host)
/* Initialise the address cache */ /* Initialise the address cache */
void addr_cache_init(void) void addr_cache_init(void)
{ {
if(!InitializeCriticalSectionAndSpinCount(&host_table_cs, 0x80000000)) init_critical_section(&host_table_cs);
{
log_printf(LOG_ERROR, "Failed to initialise critical section: %s", w32_error(GetLastError()));
abort();
}
} }
/* Free all resources used by the address cache */ /* Free all resources used by the address cache */

View File

@ -345,7 +345,17 @@ void unload_dlls(void) {
for(i = 0; dll_names[i]; i++) { for(i = 0; dll_names[i]; i++) {
if(dll_handles[i]) { if(dll_handles[i]) {
FreeLibrary(dll_handles[i]); DWORD flt_id;
HANDLE flt_thread = CreateThread(NULL, 0, &FreeLibrary, dll_handles[i], 0, &flt_id);
if(flt_thread == NULL)
{
log_printf(LOG_ERROR, "FreeLibrary thread creation failed (%s) - %s will not be unloaded!\n", w32_error(GetLastError()), dll_names[i]);
}
else{
/* Detatch thread. */
CloseHandle(flt_thread);
}
dll_handles[i] = NULL; dll_handles[i] = NULL;
} }
} }
@ -419,3 +429,51 @@ wchar_t *get_module_relative_path(HMODULE module, const wchar_t *relative_path)
return path; return path;
} }
void init_critical_section(CRITICAL_SECTION *critical_section)
{
/* > If the function succeeds, the return value is nonzero. If the
* > function fails, the return value is zero. To get extended error
* > information, call GetLastError(). For Windows Me/98/95: This
* > function has no return value. If the function fails, it will
* > raise an exception.
*
* - https://www.tenouk.com/crstufunction3.html
*
* The above goes against what the documentation (MSDN '98) says, but
* in testing, it returns FALSE on Windows 98 and GetLastError() yields
* nonsensical error codes, so its probably right and we ignore the
* result when running on pre-Windows 2000 systems.
*/
if(!InitializeCriticalSectionAndSpinCount(critical_section, 0x80000000) && windows_at_least_2000())
{
log_printf(LOG_ERROR, "Failed to initialise critical section: %s", w32_error(GetLastError()));
abort();
}
}
bool windows_at_least_2000()
{
static int result = 0;
int result_view = __atomic_load_n(&result, __ATOMIC_SEQ_CST);
if(result_view == 0)
{
OSVERSIONINFO osver;
osver.dwOSVersionInfoSize = sizeof(osver);
GetVersionEx(&osver);
if(osver.dwMajorVersion >= 5)
{
__atomic_store_n(&result, 1, __ATOMIC_SEQ_CST);
return true;
}
else{
__atomic_store_n(&result, -1, __ATOMIC_SEQ_CST);
return false;
}
}
return result_view > 0;
}

View File

@ -78,6 +78,10 @@ void __stdcall log_call(unsigned int entry, const char *symbol, unsigned int tar
wchar_t *get_module_path(HMODULE module); wchar_t *get_module_path(HMODULE module);
wchar_t *get_module_relative_path(HMODULE module, const wchar_t *relative_path); wchar_t *get_module_relative_path(HMODULE module, const wchar_t *relative_path);
void init_critical_section(CRITICAL_SECTION *critical_section);
bool windows_at_least_2000();
void log_init(); void log_init();
void log_open(const char *file); void log_open(const char *file);
void log_close(); void log_close();

View File

@ -158,7 +158,8 @@ static BOOL init_worker(IDirectPlaySP *sp, struct sp_data *sp_data)
return TRUE; return TRUE;
} }
sp_data->worker_thread = CreateThread(NULL, 0, &worker_main, sp, 0, NULL); DWORD worker_thread_id;
sp_data->worker_thread = CreateThread(NULL, 0, &worker_main, sp, 0, &worker_thread_id);
if(!sp_data->worker_thread) if(!sp_data->worker_thread)
{ {
log_printf(LOG_ERROR, "Failed to create worker thread"); log_printf(LOG_ERROR, "Failed to create worker thread");
@ -676,10 +677,7 @@ HRESULT WINAPI SPInit(LPSPINITDATA data) {
struct sp_data sp_data; struct sp_data sp_data;
if(!InitializeCriticalSectionAndSpinCount(&(sp_data.lock), 0x80000000)) { init_critical_section(&(sp_data.lock));
log_printf(LOG_ERROR, "Error initialising critical section: %s", w32_error(GetLastError()));
goto FAIL2;
}
if((sp_data.event = WSACreateEvent()) == WSA_INVALID_EVENT) { if((sp_data.event = WSACreateEvent()) == WSA_INVALID_EVENT) {
log_printf(LOG_ERROR, "Error creating WSA event object: %s", w32_error(WSAGetLastError())); log_printf(LOG_ERROR, "Error creating WSA event object: %s", w32_error(WSAGetLastError()));

View File

@ -1,5 +1,5 @@
/* IPXWrapper - Function profiling functions /* IPXWrapper - Function profiling functions
* Copyright (C) 2019 Daniel Collins <solemnwarning@solemnwarning.net> * Copyright (C) 2019-2024 Daniel Collins <solemnwarning@solemnwarning.net>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by * under the terms of the GNU General Public License version 2 as published by
@ -30,7 +30,7 @@ void fprof_init(struct FuncStats *fstats, size_t n_fstats)
fstats[i].n_calls = 0; fstats[i].n_calls = 0;
InitializeCriticalSectionAndSpinCount(&(fstats[i].cs), 0x80000000); init_critical_section(&(fstats[i].cs));
} }
} }

View File

@ -1,5 +1,5 @@
/* IPXWrapper - Interface functions /* IPXWrapper - Interface functions
* Copyright (C) 2011-2023 Daniel Collins <solemnwarning@solemnwarning.net> * Copyright (C) 2011-2024 Daniel Collins <solemnwarning@solemnwarning.net>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by * under the terms of the GNU General Public License version 2 as published by
@ -399,11 +399,7 @@ void ipx_interfaces_init(void)
interface_cache = NULL; interface_cache = NULL;
interface_cache_ctime = 0; interface_cache_ctime = 0;
if(!InitializeCriticalSectionAndSpinCount(&interface_cache_cs, 0x80000000)) init_critical_section(&interface_cache_cs);
{
log_printf(LOG_ERROR, "Failed to initialise critical section: %s", w32_error(GetLastError()));
abort();
}
/* Dump the interface lists for debugging... */ /* Dump the interface lists for debugging... */

View File

@ -67,15 +67,6 @@ unsigned int recv_packets = 0, recv_bytes = 0; /* Forwarded to emulated socket
unsigned int send_packets_udp = 0, send_bytes_udp = 0; /* Sent over UDP transport */ unsigned int send_packets_udp = 0, send_bytes_udp = 0; /* Sent over UDP transport */
unsigned int recv_packets_udp = 0, recv_bytes_udp = 0; /* Received over UDP transport */ unsigned int recv_packets_udp = 0, recv_bytes_udp = 0; /* Received over UDP transport */
static void init_cs(CRITICAL_SECTION *cs)
{
if(!InitializeCriticalSectionAndSpinCount(cs, 0x80000000))
{
log_printf(LOG_ERROR, "Failed to initialise critical section: %s", w32_error(GetLastError()));
abort();
}
}
static HANDLE prof_thread_handle = NULL; static HANDLE prof_thread_handle = NULL;
static HANDLE prof_thread_exit = NULL; static HANDLE prof_thread_exit = NULL;
@ -137,6 +128,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
log_printf(LOG_INFO, "Compiled at %s", compile_time); log_printf(LOG_INFO, "Compiled at %s", compile_time);
log_printf(LOG_INFO, "Performance counter: %lld Hz", perf_counter_freq); log_printf(LOG_INFO, "Performance counter: %lld Hz", perf_counter_freq);
#if 0
if(!getenv("SystemRoot")) if(!getenv("SystemRoot"))
{ {
log_printf(LOG_WARNING, "SystemRoot is not set in the environment"); log_printf(LOG_WARNING, "SystemRoot is not set in the environment");
@ -147,6 +139,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
log_printf(LOG_INFO, "Setting SystemRoot to '%s'", env+11); log_printf(LOG_INFO, "Setting SystemRoot to '%s'", env+11);
_putenv(env); _putenv(env);
} }
#endif
if(main_config.fw_except) if(main_config.fw_except)
{ {
@ -158,7 +151,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
ipx_interfaces_init(); ipx_interfaces_init();
init_cs(&sockets_cs); init_critical_section(&sockets_cs);
WSADATA wsdata; WSADATA wsdata;
int err = WSAStartup(MAKEWORD(1,1), &wsdata); int err = WSAStartup(MAKEWORD(1,1), &wsdata);
@ -177,13 +170,14 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
prof_thread_exit = CreateEvent(NULL, FALSE, FALSE, NULL); prof_thread_exit = CreateEvent(NULL, FALSE, FALSE, NULL);
if(prof_thread_exit != NULL) if(prof_thread_exit != NULL)
{ {
DWORD prof_thread_id;
prof_thread_handle = CreateThread( prof_thread_handle = CreateThread(
NULL, /* lpThreadAttributes */ NULL, /* lpThreadAttributes */
0, /* dwStackSize */ 0, /* dwStackSize */
&prof_thread_main, /* lpStartAddress */ &prof_thread_main, /* lpStartAddress */
NULL, /* lpParameter */ NULL, /* lpParameter */
0, /* dwCreationFlags */ 0, /* dwCreationFlags */
NULL); /* lpThreadId */ &prof_thread_id); /* lpThreadId */
if(prof_thread_handle == NULL) if(prof_thread_handle == NULL)
{ {

View File

@ -36,10 +36,16 @@ void log_init()
} }
void log_open(const char *file) { void log_open(const char *file) {
DWORD log_share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
if(windows_at_least_2000())
{
log_share_mode |= FILE_SHARE_DELETE;
}
log_fh = CreateFile( log_fh = CreateFile(
file, file,
GENERIC_READ | GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, log_share_mode,
NULL, NULL,
OPEN_ALWAYS, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
@ -90,14 +96,24 @@ void log_printf(enum ipx_log_level level, const char *fmt, ...) {
mirtoto_snprintf(tstr, 64, "[%u.%02u, thread %u] ", (unsigned int)(called/1000), (unsigned int)((called % 1000) / 10), (unsigned int)GetCurrentThreadId()); mirtoto_snprintf(tstr, 64, "[%u.%02u, thread %u] ", (unsigned int)(called/1000), (unsigned int)((called % 1000) / 10), (unsigned int)GetCurrentThreadId());
OVERLAPPED off; /* File locking isn't implemented on Windows 98, so we just skip it and
off.Offset = 0; * hope we don't wind up with any interleaves writes from parallel
off.OffsetHigh = 0; * threads (not much chance of an SMP Windows 98 machine anyway).
off.hEvent = 0; */
bool use_locking = windows_at_least_2000();
if(!LockFileEx(log_fh, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &off)) { if(use_locking)
ReleaseMutex(log_mutex); {
return; OVERLAPPED off;
off.Offset = 0;
off.OffsetHigh = 0;
off.hEvent = 0;
// ERROR_CALL_NOT_IMPLEMENTED
if(!LockFileEx(log_fh, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &off)) {
ReleaseMutex(log_mutex);
return;
}
} }
if(SetFilePointer(log_fh, 0, NULL, FILE_END) != INVALID_SET_FILE_POINTER) { if(SetFilePointer(log_fh, 0, NULL, FILE_END) != INVALID_SET_FILE_POINTER) {
@ -108,7 +124,10 @@ void log_printf(enum ipx_log_level level, const char *fmt, ...) {
WriteFile(log_fh, "\r\n", 2, &written, NULL); WriteFile(log_fh, "\r\n", 2, &written, NULL);
} }
UnlockFile(log_fh, 0, 0, 1, 0); if(use_locking)
{
UnlockFile(log_fh, 0, 0, 1, 0);
}
ReleaseMutex(log_mutex); ReleaseMutex(log_mutex);
} }

View File

@ -174,7 +174,9 @@ void router_init(void)
router_running = true; router_running = true;
if(!(router_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(&router_main), NULL, 0, NULL))) DWORD router_thread_id;
if(!(router_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(&router_main), NULL, 0, &router_thread_id)))
{ {
log_printf(LOG_ERROR, "Cannot create router worker thread: %s", w32_error(GetLastError())); log_printf(LOG_ERROR, "Cannot create router worker thread: %s", w32_error(GetLastError()));
abort(); abort();

View File

@ -46,13 +46,14 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
prof_thread_exit = CreateEvent(NULL, FALSE, FALSE, NULL); prof_thread_exit = CreateEvent(NULL, FALSE, FALSE, NULL);
if(prof_thread_exit != NULL) if(prof_thread_exit != NULL)
{ {
DWORD prof_thread_id;
prof_thread_handle = CreateThread( prof_thread_handle = CreateThread(
NULL, /* lpThreadAttributes */ NULL, /* lpThreadAttributes */
0, /* dwStackSize */ 0, /* dwStackSize */
&prof_thread_main, /* lpStartAddress */ &prof_thread_main, /* lpStartAddress */
NULL, /* lpParameter */ NULL, /* lpParameter */
0, /* dwCreationFlags */ 0, /* dwCreationFlags */
NULL); /* lpThreadId */ &prof_thread_id); /* lpThreadId */
if(prof_thread_handle == NULL) if(prof_thread_handle == NULL)
{ {

View File

@ -1,5 +1,5 @@
/* ipxwrapper - Winsock functions /* ipxwrapper - Winsock functions
* Copyright (C) 2008-2023 Daniel Collins <solemnwarning@solemnwarning.net> * Copyright (C) 2008-2024 Daniel Collins <solemnwarning@solemnwarning.net>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by * under the terms of the GNU General Public License version 2 as published by
@ -344,15 +344,7 @@ SOCKET WSAAPI socket(int af, int type, int protocol)
return -1; return -1;
} }
if(!InitializeCriticalSectionAndSpinCount(&(recv_queue->refcount_lock), 0x80000000)) init_critical_section(&(recv_queue->refcount_lock));
{
log_printf(LOG_ERROR, "Failed to initialise critical section: %s", w32_error(GetLastError()));
WSASetLastError(GetLastError());
free(recv_queue);
free(nsock);
return -1;
}
recv_queue->refcount = 1; recv_queue->refcount = 1;
recv_queue->n_ready = 0; recv_queue->n_ready = 0;

View File

@ -50,6 +50,10 @@ EXPORTS
__WSAFDIsSet @151 __WSAFDIsSet @151
WEP @500 WEP @500
WSApSetPostRoutine @1000 WSApSetPostRoutine @1000
WsControl @1001
closesockinfo @1002
Arecv @1003
Asend @1004
WSHEnumProtocols @1005 WSHEnumProtocols @1005
inet_network @1100 inet_network @1100
getnetbyname @1101 getnetbyname @1101
@ -73,6 +77,7 @@ EXPORTS
GetServiceA @1119 GetServiceA @1119
GetServiceW @1120 GetServiceW @1120
NPLoadNameSpaces @1130 NPLoadNameSpaces @1130
NSPStartup @1131
TransmitFile @1140 TransmitFile @1140
AcceptEx @1141 AcceptEx @1141
GetAcceptExSockaddrs @1142 GetAcceptExSockaddrs @1142

View File

@ -76,3 +76,8 @@ TransmitFile wsock32.dll TransmitFile
AcceptEx wsock32.dll AcceptEx 32 AcceptEx wsock32.dll AcceptEx 32
GetAcceptExSockaddrs wsock32.dll GetAcceptExSockaddrs 32 GetAcceptExSockaddrs wsock32.dll GetAcceptExSockaddrs 32
WSHEnumProtocols ipxwrapper.dll WSHEnumProtocols 16 WSHEnumProtocols ipxwrapper.dll WSHEnumProtocols 16
Arecv wsock32.dll Arecv
Asend wsock32.dll Asend
NSPStartup wsock32.dll NSPStartup
WsControl wsock32.dll WsControl
closesockinfo wsock32.dll closesockinfo

View File

@ -1,5 +1,5 @@
/* IPXWrapper test tools /* IPXWrapper test tools
* Copyright (C) 2015 Daniel Collins <solemnwarning@solemnwarning.net> * Copyright (C) 2015-2024 Daniel Collins <solemnwarning@solemnwarning.net>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by * under the terms of the GNU General Public License version 2 as published by
@ -199,7 +199,8 @@ int main(int argc, char **argv)
free(conn); free(conn);
} }
HANDLE recv_thread = CreateThread(NULL, 0, &recv_thread_main, dp, 0, NULL); DWORD recv_thread_id;
HANDLE recv_thread = CreateThread(NULL, 0, &recv_thread_main, dp, 0, &recv_thread_id);
assert(recv_thread); assert(recv_thread);
char line[1024]; char line[1024];

View File

@ -1,5 +1,5 @@
/* IPXWrapper test tools /* IPXWrapper test tools
* Copyright (C) 2014-2023 Daniel Collins <solemnwarning@solemnwarning.net> * Copyright (C) 2014-2024 Daniel Collins <solemnwarning@solemnwarning.net>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by * under the terms of the GNU General Public License version 2 as published by
@ -96,7 +96,8 @@ int main(int argc, char **argv)
assert(bind(sock, (struct sockaddr*)(&local_addr), sizeof(local_addr)) == 0); assert(bind(sock, (struct sockaddr*)(&local_addr), sizeof(local_addr)) == 0);
HANDLE send_thread_h = CreateThread(NULL, 0, &send_thread, &sock, 0, NULL); DWORD send_thread_id;
HANDLE send_thread_h = CreateThread(NULL, 0, &send_thread, &sock, 0, &send_thread_id);
assert(send_thread_h != NULL); assert(send_thread_h != NULL);
{ {

View File

@ -1,5 +1,5 @@
/* IPXWrapper test tools /* IPXWrapper test tools
* Copyright (C) 2014 Daniel Collins <solemnwarning@solemnwarning.net> * Copyright (C) 2014-2024 Daniel Collins <solemnwarning@solemnwarning.net>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by * under the terms of the GNU General Public License version 2 as published by
@ -134,7 +134,8 @@ int main(int argc, char **argv)
usage(argv[0]); usage(argv[0]);
} }
HANDLE getchar_thread = CreateThread(NULL, 0, &getchar_thread_main, NULL, 0, NULL); DWORD getchar_thread_id;
HANDLE getchar_thread = CreateThread(NULL, 0, &getchar_thread_main, NULL, 0, &getchar_thread_id);
assert(getchar_thread != NULL); assert(getchar_thread != NULL);
printf("Ready\n"); printf("Ready\n");

View File

@ -1,5 +1,5 @@
/* IPXWrapper test tools /* IPXWrapper test tools
* Copyright (C) 2014 Daniel Collins <solemnwarning@solemnwarning.net> * Copyright (C) 2014-2024 Daniel Collins <solemnwarning@solemnwarning.net>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by * under the terms of the GNU General Public License version 2 as published by
@ -122,7 +122,8 @@ int main(int argc, char **argv)
usage(argv[0]); usage(argv[0]);
} }
HANDLE getchar_thread = CreateThread(NULL, 0, &getchar_thread_main, NULL, 0, NULL); DWORD getchar_thread_id;
HANDLE getchar_thread = CreateThread(NULL, 0, &getchar_thread_main, NULL, 0, &getchar_thread_id);
assert(getchar_thread != NULL); assert(getchar_thread != NULL);
printf("Ready\n"); printf("Ready\n");