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
* 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
* 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 */
void addr_cache_init(void)
{
if(!InitializeCriticalSectionAndSpinCount(&host_table_cs, 0x80000000))
{
log_printf(LOG_ERROR, "Failed to initialise critical section: %s", w32_error(GetLastError()));
abort();
}
init_critical_section(&host_table_cs);
}
/* 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++) {
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;
}
}
@ -419,3 +429,51 @@ wchar_t *get_module_relative_path(HMODULE module, const wchar_t *relative_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_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_open(const char *file);
void log_close();

View File

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

View File

@ -1,5 +1,5 @@
/* 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
* 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;
InitializeCriticalSectionAndSpinCount(&(fstats[i].cs), 0x80000000);
init_critical_section(&(fstats[i].cs));
}
}

View File

@ -1,5 +1,5 @@
/* 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
* 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_ctime = 0;
if(!InitializeCriticalSectionAndSpinCount(&interface_cache_cs, 0x80000000))
{
log_printf(LOG_ERROR, "Failed to initialise critical section: %s", w32_error(GetLastError()));
abort();
}
init_critical_section(&interface_cache_cs);
/* 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 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_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, "Performance counter: %lld Hz", perf_counter_freq);
#if 0
if(!getenv("SystemRoot"))
{
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);
_putenv(env);
}
#endif
if(main_config.fw_except)
{
@ -158,7 +151,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
ipx_interfaces_init();
init_cs(&sockets_cs);
init_critical_section(&sockets_cs);
WSADATA 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);
if(prof_thread_exit != NULL)
{
DWORD prof_thread_id;
prof_thread_handle = CreateThread(
NULL, /* lpThreadAttributes */
0, /* dwStackSize */
&prof_thread_main, /* lpStartAddress */
NULL, /* lpParameter */
0, /* dwCreationFlags */
NULL); /* lpThreadId */
&prof_thread_id); /* lpThreadId */
if(prof_thread_handle == NULL)
{

View File

@ -36,10 +36,16 @@ void log_init()
}
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(
file,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
log_share_mode,
NULL,
OPEN_ALWAYS,
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());
OVERLAPPED off;
off.Offset = 0;
off.OffsetHigh = 0;
off.hEvent = 0;
/* File locking isn't implemented on Windows 98, so we just skip it and
* hope we don't wind up with any interleaves writes from parallel
* threads (not much chance of an SMP Windows 98 machine anyway).
*/
bool use_locking = windows_at_least_2000();
if(!LockFileEx(log_fh, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &off)) {
ReleaseMutex(log_mutex);
return;
if(use_locking)
{
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) {
@ -108,7 +124,10 @@ void log_printf(enum ipx_log_level level, const char *fmt, ...) {
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);
}

View File

@ -174,7 +174,9 @@ void router_init(void)
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()));
abort();

View File

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

View File

@ -1,5 +1,5 @@
/* 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
* 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;
}
if(!InitializeCriticalSectionAndSpinCount(&(recv_queue->refcount_lock), 0x80000000))
{
log_printf(LOG_ERROR, "Failed to initialise critical section: %s", w32_error(GetLastError()));
WSASetLastError(GetLastError());
free(recv_queue);
free(nsock);
return -1;
}
init_critical_section(&(recv_queue->refcount_lock));
recv_queue->refcount = 1;
recv_queue->n_ready = 0;

View File

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

View File

@ -76,3 +76,8 @@ TransmitFile wsock32.dll TransmitFile
AcceptEx wsock32.dll AcceptEx 32
GetAcceptExSockaddrs wsock32.dll GetAcceptExSockaddrs 32
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
* 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
* 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);
}
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);
char line[1024];

View File

@ -1,5 +1,5 @@
/* 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
* 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);
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);
{

View File

@ -1,5 +1,5 @@
/* 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
* 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]);
}
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);
printf("Ready\n");

View File

@ -1,5 +1,5 @@
/* 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
* 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]);
}
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);
printf("Ready\n");