diff --git a/src/addrcache.c b/src/addrcache.c index 122b2e8..de73593 100644 --- a/src/addrcache.c +++ b/src/addrcache.c @@ -1,5 +1,5 @@ /* IPXWrapper - Address cache - * Copyright (C) 2008-2023 Daniel Collins + * Copyright (C) 2008-2024 Daniel Collins * * 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 */ diff --git a/src/common.c b/src/common.c index 43b7547..ca00218 100644 --- a/src/common.c +++ b/src/common.c @@ -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; +} diff --git a/src/common.h b/src/common.h index 41cb5c8..7cdb589 100644 --- a/src/common.h +++ b/src/common.h @@ -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(); diff --git a/src/directplay.c b/src/directplay.c index 59b5453..831c424 100644 --- a/src/directplay.c +++ b/src/directplay.c @@ -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())); diff --git a/src/funcprof.c b/src/funcprof.c index 545252f..541ab58 100644 --- a/src/funcprof.c +++ b/src/funcprof.c @@ -1,5 +1,5 @@ /* IPXWrapper - Function profiling functions - * Copyright (C) 2019 Daniel Collins + * Copyright (C) 2019-2024 Daniel Collins * * 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)); } } diff --git a/src/interface.c b/src/interface.c index 1b474d4..b8e78d6 100644 --- a/src/interface.c +++ b/src/interface.c @@ -1,5 +1,5 @@ /* IPXWrapper - Interface functions - * Copyright (C) 2011-2023 Daniel Collins + * Copyright (C) 2011-2024 Daniel Collins * * 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... */ diff --git a/src/ipxwrapper.c b/src/ipxwrapper.c index 2c50db6..f16aa0e 100644 --- a/src/ipxwrapper.c +++ b/src/ipxwrapper.c @@ -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) { diff --git a/src/log.c b/src/log.c index 75d4f4f..bacce55 100644 --- a/src/log.c +++ b/src/log.c @@ -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); } diff --git a/src/router.c b/src/router.c index 0bec648..8feb86d 100644 --- a/src/router.c +++ b/src/router.c @@ -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(); diff --git a/src/stubdll.c b/src/stubdll.c index 8607282..e6da58a 100644 --- a/src/stubdll.c +++ b/src/stubdll.c @@ -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) { diff --git a/src/winsock.c b/src/winsock.c index 1cafaed..d31b329 100644 --- a/src/winsock.c +++ b/src/winsock.c @@ -1,5 +1,5 @@ /* ipxwrapper - Winsock functions - * Copyright (C) 2008-2023 Daniel Collins + * Copyright (C) 2008-2024 Daniel Collins * * 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; diff --git a/src/wsock32.def b/src/wsock32.def index 0dd5187..812617a 100644 --- a/src/wsock32.def +++ b/src/wsock32.def @@ -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 diff --git a/src/wsock32_stubs.txt b/src/wsock32_stubs.txt index d7d26c7..cdd42a2 100644 --- a/src/wsock32_stubs.txt +++ b/src/wsock32_stubs.txt @@ -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 diff --git a/tools/dptool.c b/tools/dptool.c index b54f244..5b19846 100644 --- a/tools/dptool.c +++ b/tools/dptool.c @@ -1,5 +1,5 @@ /* IPXWrapper test tools - * Copyright (C) 2015 Daniel Collins + * Copyright (C) 2015-2024 Daniel Collins * * 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]; diff --git a/tools/ipx-isr.c b/tools/ipx-isr.c index 9d56289..be78bd4 100644 --- a/tools/ipx-isr.c +++ b/tools/ipx-isr.c @@ -1,5 +1,5 @@ /* IPXWrapper test tools - * Copyright (C) 2014-2023 Daniel Collins + * Copyright (C) 2014-2024 Daniel Collins * * 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); { diff --git a/tools/ipx-recv.c b/tools/ipx-recv.c index 0904067..ed14fb9 100644 --- a/tools/ipx-recv.c +++ b/tools/ipx-recv.c @@ -1,5 +1,5 @@ /* IPXWrapper test tools - * Copyright (C) 2014 Daniel Collins + * Copyright (C) 2014-2024 Daniel Collins * * 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"); diff --git a/tools/spx-server.c b/tools/spx-server.c index ffa87cb..5854850 100644 --- a/tools/spx-server.c +++ b/tools/spx-server.c @@ -1,5 +1,5 @@ /* IPXWrapper test tools - * Copyright (C) 2014 Daniel Collins + * Copyright (C) 2014-2024 Daniel Collins * * 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");