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:
parent
26f6511dee
commit
623d2c3df4
@ -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 */
|
||||
|
60
src/common.c
60
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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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()));
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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... */
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
37
src/log.c
37
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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
||||
{
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user