diff --git a/Makefile b/Makefile index 494efb0..fbba7f3 100644 --- a/Makefile +++ b/Makefile @@ -86,62 +86,62 @@ dist: all IPXWRAPPER_OBJS := src/ipxwrapper.o src/winsock.o src/ipxwrapper_stubs.o src/log.o src/common.o \ src/interface.o src/interface2.o src/router.o src/ipxwrapper.def src/addrcache.o src/config.o src/addr.o \ - src/firewall.o src/wpcap_stubs.o src/ethernet.o + src/firewall.o src/ethernet.o src/funcprof.o ipxwrapper.dll: $(IPXWRAPPER_OBJS) echo 'const char *version_string = "$(VERSION)", *compile_time = "'`date`'";' | $(CC) -c -x c -o version.o - $(CC) $(CFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -shared -o $@ $^ version.o -liphlpapi -lversion -lole32 -loleaut32 src/ipxwrapper_stubs.s: src/ipxwrapper_stubs.txt - perl mkstubs.pl src/ipxwrapper_stubs.txt src/ipxwrapper_stubs.s 0 + perl mkstubs.pl src/ipxwrapper_stubs.txt src/ipxwrapper_stubs.s ipxwrapper.dll # # WSOCK32.DLL # -wsock32.dll: src/stubdll.o src/wsock32_stubs.o src/log.o src/common.o src/config.o src/addr.o src/wsock32.def +wsock32.dll: src/stubdll.o src/wsock32_stubs.o src/log.o src/common.o src/config.o src/addr.o src/funcprof.o src/wsock32.def $(CC) $(CFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -shared -o $@ $^ src/wsock32_stubs.s: src/wsock32_stubs.txt - perl mkstubs.pl src/wsock32_stubs.txt src/wsock32_stubs.s 1 + perl mkstubs.pl src/wsock32_stubs.txt src/wsock32_stubs.s wsock32.dll # # MSWSOCK.DLL # -mswsock.dll: src/stubdll.o src/mswsock_stubs.o src/log.o src/common.o src/config.o src/addr.o src/mswsock.def +mswsock.dll: src/stubdll.o src/mswsock_stubs.o src/log.o src/common.o src/config.o src/addr.o src/funcprof.o src/mswsock.def $(CC) $(CFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -shared -o $@ $^ src/mswsock_stubs.s: src/mswsock_stubs.txt - perl mkstubs.pl src/mswsock_stubs.txt src/mswsock_stubs.s 2 + perl mkstubs.pl src/mswsock_stubs.txt src/mswsock_stubs.s mswsock.dll # # DPWSOCKX.DLL # -dpwsockx.dll: src/directplay.o src/log.o src/dpwsockx_stubs.o src/common.o src/config.o src/addr.o src/dpwsockx.def +dpwsockx.dll: src/directplay.o src/log.o src/dpwsockx_stubs.o src/common.o src/config.o src/addr.o src/funcprof.o src/dpwsockx.def $(CC) $(CFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -shared -o $@ $^ -lwsock32 src/dpwsockx_stubs.s: src/dpwsockx_stubs.txt - perl mkstubs.pl src/dpwsockx_stubs.txt src/dpwsockx_stubs.s 3 + perl mkstubs.pl src/dpwsockx_stubs.txt src/dpwsockx_stubs.s dpwsockx.dll # # IPXCONFIG.EXE # IPXCONFIG_OBJS := src/ipxconfig.o icons/ipxconfig.o src/addr.o src/interface2.o src/common.o \ - src/config.o src/wpcap_stubs.o + src/config.o src/ipxconfig_stubs.o src/funcprof.o ipxconfig.exe: $(IPXCONFIG_OBJS) $(CXX) $(CXXFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -static-libstdc++ -mwindows -o $@ $^ -liphlpapi -lcomctl32 -lws2_32 +src/ipxconfig_stubs.s: src/ipxwrapper_stubs.txt + perl mkstubs.pl src/ipxconfig_stubs.txt src/ipxconfig_stubs.s ipxconfig.exe + # # SHARED TARGETS # -src/wpcap_stubs.s: src/wpcap_stubs.txt - perl mkstubs.pl src/wpcap_stubs.txt src/wpcap_stubs.s 5 - icons/%.o: icons/%.rc icons/%.ico $(WINDRES) $< -O coff -o $@ diff --git a/mkstubs.pl b/mkstubs.pl index cc5e046..db84ce1 100644 --- a/mkstubs.pl +++ b/mkstubs.pl @@ -1,5 +1,5 @@ # IPXWrapper - Generate assembly stub functions -# Copyright (C) 2008-2011 Daniel Collins +# Copyright (C) 2008-2023 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 @@ -18,74 +18,268 @@ use strict; use warnings; if(@ARGV != 3) { - print STDERR "Usage: mkdll.pl \n"; + print STDERR "Usage: mkdll.pl \n"; exit(1); } -my $stub_file = $ARGV[0]; -my $asm_file = $ARGV[1]; -my $dllnum = $ARGV[2]; -my $do_logging = ($dllnum != 0); +# Must be kept in sync with dll_names in common.c! +my %DLL_INDICES = ( + "ipxwrapper.dll" => 0, + "wsock32.dll" => 1, + "mswsock.dll" => 2, + "dpwsockx.dll" => 3, + "ws2_32.dll" => 4, + "wpcap.dll" => 5, + "ipxconfig.exe" => 6, +); + +my ($stub_file, $asm_file, $dll_name) = @ARGV; + +my $dll_index = $DLL_INDICES{$dll_name} + // die "Unknown DLL name: $dll_name"; open(STUBS, "<$stub_file") or die("Cannot open $stub_file: $!"); open(CODE, ">$asm_file") or die("Cannot open $asm_file: $!"); my @stubs = (); -my @stubs_dll = (); -foreach my $line() { +# Skip over header +(scalar ); +(scalar ); + +# Read in stub definitions +foreach my $line() +{ $line =~ s/[\r\n]//g; if($line ne "") { - my ($func, $dn) = split(/:/, $line); - $dn = $dllnum if(!defined($dn)); + my ($name, $target_dll, $target_func, $params) = split(/\s+/, $line); - my $sym = $func; - $sym =~ s/^r_//; + my $target_dll_index = $DLL_INDICES{$target_dll} + // die "Unknown DLL: $target_dll\n"; - push(@stubs, {"name" => $func, "sym" => $sym, "dllnum" => $dn}); + push(@stubs, { + name => $name, + target_dll => $target_dll, + target_dll_index => $target_dll_index, + target_func => $target_func, + params => $params, + }); } } -print CODE "section .rdata:\n"; +print CODE <<"END"; +extern _QueryPerformanceCounter\@4 -foreach my $func(@stubs) { - print CODE "\t".$func->{"name"}."_sym:\tdb\t'".$func->{"sym"}."', 0\n"; +extern _find_sym +extern _log_call +extern _fprof_record_timed +extern _fprof_record_untimed + +struc FuncStats + .func_name: resd 1 + .min_time: resd 1 + .max_time: resd 1 + .total_time: resd 1 + .n_calls: resd 1 + + .cs: resb 24 +endstruc +END + +print CODE <<"END"; +section .rdata +END + +foreach my $func(@stubs) +{ + print CODE <<"END"; + $func->{name}_name: db '$func->{name}', 0 + $func->{name}_target_func: db '$func->{target_func}', 0 +END } -print CODE "\nsection .data\n"; +my $num_funcs = (scalar @stubs); -foreach my $func(@stubs) { - print CODE "\t".$func->{"name"}."_addr:\tdd\t0\n"; +print CODE <<"END"; +global _NUM_STUBS +_NUM_STUBS: dd $num_funcs + +DLL_NAME: db '$dll_name', 0 +global _STUBS_DLL_NAME +_STUBS_DLL_NAME: dd DLL_NAME +END + +print CODE <<"END"; +section .data + +global _stubs_enable_profile +_stubs_enable_profile: db 0 + +END + +foreach my $func(@stubs) +{ + print CODE <<"END"; + $func->{name}_addr: dd 0 +END } -print CODE "\nsection .text\n"; -print CODE "\textern\t_find_sym\n"; -print CODE "\textern\t_log_call\n" if($do_logging); +print CODE <<"END"; +global _stub_fstats +_stub_fstats: +END -foreach my $func(@stubs) { - my $f_name = $func->{"name"}; - - print CODE "\nglobal\t_$f_name\n"; - print CODE "_$f_name:\n"; - - if($do_logging) { - print CODE "\tpush\tdword ".$func->{"dllnum"}."\n"; - print CODE "\tpush\t$f_name\_sym\n"; - print CODE "\tpush\tdword $dllnum\n"; - print CODE "\tcall\t_log_call\n"; +foreach my $func(@stubs) +{ + print CODE <<"END"; + $func->{name}_fstats: + istruc FuncStats + at FuncStats.func_name, dd $func->{name}_name + iend +END +} + +print CODE <<"END"; +section .text +END + +foreach my $func(@stubs) +{ + if(defined $func->{params}) + { + my $to_copy = $func->{params}; + + print CODE <<"END"; + global _$func->{name} + _$func->{name}: + ; Log the call + push dword $func->{target_dll_index} + push $func->{name}_target_func + push dword $dll_index + call _log_call + + ; Check if we have address cached + cmp dword [$func->{name}_addr], 0 + jne $func->{name}_go + + ; Fetch target function address + push $func->{name}_target_func + push dword $func->{target_dll_index} + call _find_sym + mov dword [$func->{name}_addr], eax + + $func->{name}_go: + + ; Bypass the profiling code and jump straight into the taget + ; function when not profiling. + cmp byte [_stubs_enable_profile], 0 + je $func->{name}_skip + + push ebp + mov ebp, esp + + ; Push tick count onto stack (ebp - 8) + sub esp, 8 + push esp + call _QueryPerformanceCounter\@4 + + ; Copy original arguments ($to_copy bytes) +END + + for(; $to_copy >= 4;) + { + $to_copy -= 4; + print CODE <<"END"; + push dword [ebp + 4 + 4 + $to_copy] +END + } + + for(; $to_copy >= 2;) + { + $to_copy -= 2; + print CODE <<"END"; + push word [ebp + 4 + 4 + $to_copy] +END + } + + for(; $to_copy >= 1;) + { + $to_copy -= 1; + print CODE <<"END"; + push byte [ebp + 4 + 4 + $to_copy] +END + } + + print CODE <<"END"; + ; Call target function + call [$func->{name}_addr] + + ; Push target function return value onto stack (ebp - 12) + push eax + + ; Push tick count onto stack (ebp - 20) + sub esp, 8 + push esp + call _QueryPerformanceCounter\@4 + + ; End tick parameter to _fprof_record_timed + push dword ebp + sub dword [esp], 20 + + ; Start tick parameter to _fprof_record_timed + push dword ebp + sub dword [esp], 8 + + ; FuncStats parameter to _fprof_record_timed + push dword $func->{name}_fstats + + ; Record profiling data + call _fprof_record_timed + + add esp, 8 ; Pop end tick count + pop eax ; Pop return value + add esp, 8 ; Pop start tick count + + pop ebp ; Restore caller's ebp + + ret $func->{params} + + $func->{name}_skip: + jmp [$func->{name}_addr] +END + } + else{ + print CODE <<"END"; + global _$func->{name} + _$func->{name}: + ; Log the call + push dword $func->{target_dll_index} + push $func->{name}_target_func + push dword $dll_index + call _log_call + + ; Check if we have address cached + cmp dword [$func->{name}_addr], 0 + jne $func->{name}_go + + ; Fetch target function address + push $func->{name}_target_func + push dword $func->{target_dll_index} + call _find_sym + mov dword [$func->{name}_addr], eax + + $func->{name}_go: + + ; Record that we were called + push dword $func->{name}_fstats + call _fprof_record_untimed + + ; Jump into target function. We have left the stack as we found it + ; so it can take over our frame. + jmp [$func->{name}_addr] +END } - - print CODE "\tcmp\tdword [$f_name\_addr], 0\n"; - print CODE "\tjne\t$f_name\_jmp\n"; - - print CODE "\tpush\t$f_name\_sym\n"; - print CODE "\tpush\tdword ".$func->{"dllnum"}."\n"; - print CODE "\tcall\t_find_sym\n"; - print CODE "\tmov\t[$f_name\_addr], eax\n"; - - print CODE "\t$f_name\_jmp:\n"; - print CODE "\tjmp\t[$f_name\_addr]\n"; } close(CODE); diff --git a/src/common.c b/src/common.c index b06cb01..32a3c4b 100644 --- a/src/common.c +++ b/src/common.c @@ -1,5 +1,5 @@ /* IPXWrapper - Common functions - * Copyright (C) 2011-2021 Daniel Collins + * Copyright (C) 2011-2023 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 @@ -23,6 +23,7 @@ enum ipx_log_level min_log_level = LOG_INFO; +/* Must be kept in sync with DLL_INDICES in mkstubs.pl! */ static const char *dll_names[] = { "ipxwrapper.dll", "wsock32.dll", @@ -30,6 +31,7 @@ static const char *dll_names[] = { "dpwsockx.dll", "ws2_32.dll", "wpcap.dll", + "ipxconfig.exe", NULL }; diff --git a/src/common.h b/src/common.h index e56d569..69e88bd 100644 --- a/src/common.h +++ b/src/common.h @@ -24,6 +24,7 @@ #include #include "addr.h" +#include "funcprof.h" #ifdef __cplusplus extern "C" { @@ -39,6 +40,12 @@ enum ipx_log_level { extern enum ipx_log_level min_log_level; +/* Defined by stubs */ +extern struct FuncStats stub_fstats[]; +extern const unsigned int NUM_STUBS; +extern const char *STUBS_DLL_NAME; +extern unsigned char stubs_enable_profile; + const char *w32_error(DWORD errnum); HKEY reg_open_main(bool readwrite); diff --git a/src/config.c b/src/config.c index 296cfe0..15e6e21 100644 --- a/src/config.c +++ b/src/config.c @@ -33,6 +33,7 @@ main_config_t get_main_config(void) config.encap_type = ENCAP_TYPE_IPXWRAPPER; config.frame_type = FRAME_TYPE_ETH_II; config.log_level = LOG_INFO; + config.profile = false; config.dosbox_server_addr = NULL; config.dosbox_server_port = 213; @@ -59,6 +60,7 @@ main_config_t get_main_config(void) config.encap_type = reg_get_dword(reg, "use_pcap", config.encap_type); config.frame_type = reg_get_dword(reg, "frame_type", config.frame_type); config.log_level = reg_get_dword(reg, "log_level", config.log_level); + config.profile = reg_get_dword(reg, "profile", config.profile); config.dosbox_server_addr = reg_get_string(reg, "dosbox_server_addr", ""); config.dosbox_server_port = reg_get_dword(reg, "dosbox_server_port", config.dosbox_server_port); @@ -91,6 +93,7 @@ bool set_main_config(const main_config_t *config) && reg_set_dword(reg, "use_pcap", config->encap_type) && reg_set_dword(reg, "frame_type", config->frame_type) && reg_set_dword(reg, "log_level", config->log_level) + && reg_set_dword(reg, "profile", config->profile) && reg_set_string(reg, "dosbox_server_addr", config->dosbox_server_addr) && reg_set_dword(reg, "dosbox_server_port", config->dosbox_server_port); diff --git a/src/config.h b/src/config.h index 2b67d67..b815f31 100644 --- a/src/config.h +++ b/src/config.h @@ -52,6 +52,7 @@ typedef struct main_config { uint16_t dosbox_server_port; enum ipx_log_level log_level; + bool profile; } main_config_t; struct v1_global_config { diff --git a/src/directplay.c b/src/directplay.c index 5f95df3..3cf2033 100644 --- a/src/directplay.c +++ b/src/directplay.c @@ -1,5 +1,5 @@ /* ipxwrapper - DirectPlay service provider - * Copyright (C) 2011 Daniel Collins + * Copyright (C) 2011-2019 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 @@ -725,6 +725,8 @@ HRESULT WINAPI SPInit(LPSPINITDATA data) { BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { if(fdwReason == DLL_PROCESS_ATTACH) { + fprof_init(stub_fstats, NUM_STUBS); + log_open("ipxwrapper.log"); min_log_level = get_main_config().log_level; @@ -743,6 +745,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { unload_dlls(); log_close(); + + fprof_cleanup(stub_fstats, NUM_STUBS); } return TRUE; diff --git a/src/dpwsockx_stubs.txt b/src/dpwsockx_stubs.txt index d179ac0..ef627aa 100644 --- a/src/dpwsockx_stubs.txt +++ b/src/dpwsockx_stubs.txt @@ -1,9 +1,10 @@ -r_SPInit -DPWS_GetEnumPort -DPWS_BuildIPMessageHeader - -WSACreateEvent:4 -WSACloseEvent:4 -WSAEventSelect:4 -WSAResetEvent:4 -WSASetEvent:4 +Function name Target DLL Target function +------------------------------------------------------------ +r_SPInit dpwsockx.dll SPInit +DPWS_GetEnumPort dpwsockx.dll DPWS_GetEnumPort +DPWS_BuildIPMessageHeader dpwsockx.dll DPWS_BuildIPMessageHeader +WSACreateEvent ws2_32.dll WSACreateEvent +WSACloseEvent ws2_32.dll WSACloseEvent +WSAEventSelect ws2_32.dll WSAEventSelect +WSAResetEvent ws2_32.dll WSAResetEvent +WSASetEvent ws2_32.dll WSASetEvent diff --git a/src/funcprof.c b/src/funcprof.c new file mode 100644 index 0000000..545252f --- /dev/null +++ b/src/funcprof.c @@ -0,0 +1,129 @@ +/* IPXWrapper - Function profiling functions + * Copyright (C) 2019 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 + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include + +#include "common.h" +#include "funcprof.h" + +void fprof_init(struct FuncStats *fstats, size_t n_fstats) +{ + for(size_t i = 0; i < n_fstats; ++i) + { + fstats[i].min_time = 0.0; + fstats[i].max_time = 0.0; + fstats[i].total_time = 0.0; + + fstats[i].n_calls = 0; + + InitializeCriticalSectionAndSpinCount(&(fstats[i].cs), 0x80000000); + } +} + +void fprof_cleanup(struct FuncStats *fstats, size_t n_fstats) +{ + for(size_t i = 0; i < n_fstats; ++i) + { + DeleteCriticalSection(&(fstats[i].cs)); + } +} + +__stdcall void fprof_record_timed(struct FuncStats *fstats, const LARGE_INTEGER *start, const LARGE_INTEGER *end) +{ + EnterCriticalSection(&(fstats->cs)); + + float this_time = end->QuadPart - start->QuadPart; + + if(fstats->n_calls == 0) + { + fstats->min_time = this_time; + fstats->max_time = this_time; + fstats->total_time = this_time; + } + else{ + if(fstats->min_time > this_time) + { + fstats->min_time = this_time; + } + + if(fstats->max_time < this_time) + { + fstats->max_time = this_time; + } + + fstats->total_time += this_time; + } + + ++(fstats->n_calls); + + LeaveCriticalSection(&(fstats->cs)); +} + +__stdcall void fprof_record_untimed(struct FuncStats *fstats) +{ + EnterCriticalSection(&(fstats->cs)); + + ++(fstats->n_calls); + + LeaveCriticalSection(&(fstats->cs)); +} + +void fprof_report(const char *dll_name, struct FuncStats *fstats, size_t n_fstats) +{ + LARGE_INTEGER freq; /* TODO: Cache somewhere */ + QueryPerformanceFrequency(&freq); + + const float TICKS_PER_USEC = freq.QuadPart / 1000000.0; + + for(size_t i = 0; i < n_fstats; ++i) + { + EnterCriticalSection(&(fstats[i].cs)); + + float min_time = fstats[i].min_time; + float max_time = fstats[i].max_time; + float total_time = fstats[i].total_time; + + unsigned int n_calls = fstats[i].n_calls; + + fstats[i].n_calls = 0; + + LeaveCriticalSection(&(fstats[i].cs)); + + if(n_calls > 0) + { + if(total_time > 0.0) + { + log_printf(LOG_INFO, + "%s:%s was called %u times duration total %fus min %fus max %fus avg %fus", + dll_name, + fstats[i].func_name, + n_calls, + (total_time / TICKS_PER_USEC), + (min_time / TICKS_PER_USEC), + (max_time / TICKS_PER_USEC), + ((total_time / (float)(n_calls)) / TICKS_PER_USEC)); + } + else{ + log_printf(LOG_INFO, + "%s:%s was called %u times", + dll_name, + fstats[i].func_name, + n_calls); + } + } + } +} diff --git a/src/funcprof.h b/src/funcprof.h new file mode 100644 index 0000000..5790d9a --- /dev/null +++ b/src/funcprof.h @@ -0,0 +1,64 @@ +/* IPXWrapper - Function profiling functions + * Copyright (C) 2019 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 + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef IPXWRAPPER_FUNCPROF_H +#define IPXWRAPPER_FUNCPROF_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct FuncStats +{ + const char *func_name; + float min_time, max_time, total_time; + unsigned int n_calls; + CRITICAL_SECTION cs; +}; + +void fprof_init(struct FuncStats *fstats, size_t n_fstats); +void fprof_cleanup(struct FuncStats *fstats, size_t n_fstats); + +__stdcall void fprof_record_timed(struct FuncStats *fstats, const LARGE_INTEGER *start, const LARGE_INTEGER *end); +__stdcall void fprof_record_untimed(struct FuncStats *fstats); + +void fprof_report(const char *dll_name, struct FuncStats *fstats, size_t n_fstats); + +#define FPROF_RECORD_SCOPE(fstats) \ + __attribute__((cleanup (_fprof_record_scope_exit))) struct _fprof_record_scope_ctx fstats_scoped_ctx = { fstats }; \ + QueryPerformanceCounter(&(fstats_scoped_ctx.enter_time)); + +struct _fprof_record_scope_ctx { + struct FuncStats *fstats; + LARGE_INTEGER enter_time; +}; + +static inline void _fprof_record_scope_exit(struct _fprof_record_scope_ctx *ctx) +{ + LARGE_INTEGER leave_time; + QueryPerformanceCounter(&leave_time); + + fprof_record_timed(ctx->fstats, &(ctx->enter_time), &leave_time); +} + +#ifdef __cplusplus +} +#endif + +#endif /* !IPXWRAPPER_FUNCPROF_H */ diff --git a/src/ipxconfig.cpp b/src/ipxconfig.cpp index 3df38b3..e70da19 100644 --- a/src/ipxconfig.cpp +++ b/src/ipxconfig.cpp @@ -1,5 +1,5 @@ /* IPXWrapper - Configuration tool - * Copyright (C) 2011-2022 Daniel Collins + * Copyright (C) 2011-2023 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 @@ -41,6 +41,7 @@ enum { ID_OPT_W95 = 22, ID_OPT_LOG_DEBUG = 25, ID_OPT_LOG_TRACE = 26, + ID_OPT_PROFILE = 27, ID_OK = 31, ID_CANCEL = 32, @@ -142,6 +143,7 @@ static struct { HWND opt_w95; HWND opt_log_debug; HWND opt_log_trace; + HWND opt_profile; HWND ok_btn; HWND can_btn; @@ -257,6 +259,8 @@ static LRESULT CALLBACK groupbox_wproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp int main() { + fprof_init(stub_fstats, NUM_STUBS); + INITCOMMONCONTROLSEX common_controls; common_controls.dwSize = sizeof(common_controls); common_controls.dwICC = ICC_LISTVIEW_CLASSES; @@ -316,6 +320,8 @@ int main() } } + fprof_cleanup(stub_fstats, NUM_STUBS); + return msg.wParam; } @@ -584,6 +590,8 @@ static bool save_config() } } + main_config.profile = get_checkbox(wh.opt_profile); + if(main_config.encap_type == ENCAP_TYPE_IPXWRAPPER || main_config.encap_type == ENCAP_TYPE_PCAP) { for(auto i = nics.begin(); i != nics.end(); i++) @@ -792,6 +800,7 @@ static void main_window_init() * | □ Enable Windows 95 SO_BROADCAST bug | * | □ Log debugging messages | * | □ Log WinSock API calls | + * | □ Log profiling counters | * +---------------------------------------------------------+ */ @@ -801,10 +810,12 @@ static void main_window_init() wh.opt_w95 = create_checkbox(wh.box_options, "Enable Windows 95 SO_BROADCAST bug", ID_OPT_W95); wh.opt_log_debug = create_checkbox(wh.box_options, "Log debugging messages", ID_OPT_LOG_DEBUG); wh.opt_log_trace = create_checkbox(wh.box_options, "Log WinSock API calls", ID_OPT_LOG_TRACE); + wh.opt_profile = create_checkbox(wh.box_options, "Log profiling counters", ID_OPT_PROFILE); set_checkbox(wh.opt_w95, main_config.w95_bug); set_checkbox(wh.opt_log_debug, main_config.log_level <= LOG_DEBUG); set_checkbox(wh.opt_log_trace, main_config.log_level <= LOG_CALL); + set_checkbox(wh.opt_profile, main_config.profile); } wh.ok_btn = create_child(wh.main, "BUTTON", "OK", BS_PUSHBUTTON | WS_TABSTOP, 0, ID_OK); @@ -978,6 +989,9 @@ static void main_window_init() MoveWindow(wh.opt_log_trace, BOX_SIDE_PAD, box_options_y, BOX_INNER_WIDTH, text_h, TRUE); box_options_y += text_h + 2; + MoveWindow(wh.opt_profile, BOX_SIDE_PAD, box_options_y, BOX_INNER_WIDTH, text_h, TRUE); + box_options_y += text_h + 2; + int box_options_h = box_options_y + BOX_BOTTOM_PAD; MoveWindow(wh.box_options, BOX_SIDE_MARGIN, 0, BOX_WIDTH, box_options_h, TRUE); diff --git a/src/ipxconfig_stubs.txt b/src/ipxconfig_stubs.txt new file mode 100644 index 0000000..ddaf9af --- /dev/null +++ b/src/ipxconfig_stubs.txt @@ -0,0 +1,10 @@ +Function name Target DLL Target function Parameters (bytes) +----------------------------------------------------------------------------- +pcap_open wpcap.dll pcap_open +pcap_close wpcap.dll pcap_close +pcap_findalldevs_ex wpcap.dll pcap_findalldevs_ex +pcap_freealldevs wpcap.dll pcap_freealldevs +pcap_getevent wpcap.dll pcap_getevent +pcap_dispatch wpcap.dll pcap_dispatch +pcap_geterr wpcap.dll pcap_geterr +pcap_sendpacket wpcap.dll pcap_sendpacket diff --git a/src/ipxwrapper.c b/src/ipxwrapper.c index 4c10bfb..11070c0 100644 --- a/src/ipxwrapper.c +++ b/src/ipxwrapper.c @@ -30,6 +30,7 @@ #include "ipxwrapper.h" #include "common.h" +#include "funcprof.h" #include "interface.h" #include "router.h" #include "addrcache.h" @@ -50,6 +51,17 @@ static CRITICAL_SECTION sockets_cs; typedef ULONGLONG WINAPI (*GetTickCount64_t)(void); static HMODULE kernel32 = NULL; +struct FuncStats ipxwrapper_fstats[] = { + #define FPROF_DECL(func) { #func }, + #include "ipxwrapper_prof_defs.h" + #undef FPROF_DECL +}; + +const unsigned int ipxwrapper_fstats_size = sizeof(ipxwrapper_fstats) / sizeof(*ipxwrapper_fstats); + +unsigned int send_packets = 0, send_bytes = 0; /* Sent from emulated socket */ +unsigned int recv_packets = 0, recv_bytes = 0; /* Forwarded to emulated socket */ + static void init_cs(CRITICAL_SECTION *cs) { if(!InitializeCriticalSectionAndSpinCount(cs, 0x80000000)) @@ -59,10 +71,42 @@ static void init_cs(CRITICAL_SECTION *cs) } } +static HANDLE prof_thread_handle = NULL; +static HANDLE prof_thread_exit = NULL; + +static void report_packet_stats(void) +{ + unsigned int my_send_packets = __atomic_exchange_n(&send_packets, 0, __ATOMIC_RELAXED); + unsigned int my_send_bytes = __atomic_exchange_n(&send_bytes, 0, __ATOMIC_RELAXED); + + unsigned int my_recv_packets = __atomic_exchange_n(&recv_packets, 0, __ATOMIC_RELAXED); + unsigned int my_recv_bytes = __atomic_exchange_n(&recv_bytes, 0, __ATOMIC_RELAXED); + + log_printf(LOG_INFO, "IPX sockets sent %u packets (%u bytes)", my_send_packets, my_send_bytes); + log_printf(LOG_INFO, "IPX sockets received %u packets (%u bytes)", my_recv_packets, my_recv_bytes); +} + +static DWORD WINAPI prof_thread_main(LPVOID lpParameter) +{ + static const int PROF_INTERVAL_MS = 10000; + + while(WaitForSingleObject(prof_thread_exit, PROF_INTERVAL_MS) == WAIT_TIMEOUT) + { + fprof_report(STUBS_DLL_NAME, stub_fstats, NUM_STUBS); + fprof_report("ipxwrapper.dll", ipxwrapper_fstats, ipxwrapper_fstats_size); + report_packet_stats(); + } + + return 0; +} + BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { if(fdwReason == DLL_PROCESS_ATTACH) { + fprof_init(stub_fstats, NUM_STUBS); + fprof_init(ipxwrapper_fstats, ipxwrapper_fstats_size); + log_open("ipxwrapper.log"); log_printf(LOG_INFO, "IPXWrapper %s", version_string); @@ -104,6 +148,35 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) } router_init(); + + if(main_config.profile) + { + stubs_enable_profile = true; + + prof_thread_exit = CreateEvent(NULL, FALSE, FALSE, NULL); + if(prof_thread_exit != NULL) + { + prof_thread_handle = CreateThread( + NULL, /* lpThreadAttributes */ + 0, /* dwStackSize */ + &prof_thread_main, /* lpStartAddress */ + NULL, /* lpParameter */ + 0, /* dwCreationFlags */ + NULL); /* lpThreadId */ + + if(prof_thread_handle == NULL) + { + log_printf(LOG_ERROR, + "Unable to create prof_thread_main thread: %s", + w32_error(GetLastError())); + } + } + else{ + log_printf(LOG_ERROR, + "Unable to create prof_thread_exit event object: %s", + w32_error(GetLastError())); + } + } } else if(fdwReason == DLL_PROCESS_DETACH) { @@ -117,6 +190,22 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) return TRUE; } + if(prof_thread_exit != NULL) + { + SetEvent(prof_thread_exit); + + if(prof_thread_handle != NULL) + { + WaitForSingleObject(prof_thread_handle, INFINITE); + + CloseHandle(prof_thread_handle); + prof_thread_handle = NULL; + } + + CloseHandle(prof_thread_exit); + prof_thread_exit = NULL; + } + router_cleanup(); WSACleanup(); @@ -129,6 +218,14 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) unload_dlls(); + if(main_config.profile) + { + fprof_report(STUBS_DLL_NAME, stub_fstats, NUM_STUBS); + fprof_report("ipxwrapper.dll", ipxwrapper_fstats, ipxwrapper_fstats_size); + + report_packet_stats(); + } + log_close(); if(kernel32) @@ -136,6 +233,9 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) FreeLibrary(kernel32); kernel32 = NULL; } + + fprof_cleanup(ipxwrapper_fstats, ipxwrapper_fstats_size); + fprof_cleanup(stub_fstats, NUM_STUBS); } return TRUE; @@ -181,6 +281,7 @@ ipx_socket *get_socket_wait_for_ready(SOCKET sockfd, int timeout_ms) /* Lock the mutex */ void lock_sockets(void) { + FPROF_RECORD_SCOPE(&(ipxwrapper_fstats[IPXWRAPPER_FSTATS_lock_sockets])); EnterCriticalSection(&sockets_cs); } diff --git a/src/ipxwrapper.h b/src/ipxwrapper.h index 91fe6ab..1b7e17c 100644 --- a/src/ipxwrapper.h +++ b/src/ipxwrapper.h @@ -27,6 +27,7 @@ #include #include "config.h" +#include "funcprof.h" #include "router.h" /* The standard Windows driver (in XP) only allows 1467 bytes anyway */ @@ -188,6 +189,17 @@ struct spxinit extern ipx_socket *sockets; extern main_config_t main_config; +extern struct FuncStats ipxwrapper_fstats[]; + +enum { + #define FPROF_DECL(func) IPXWRAPPER_FSTATS_ ## func, + #include "ipxwrapper_prof_defs.h" + #undef FPROF_DECL +}; + +extern unsigned int send_packets, send_bytes; /* Sent from emulated socket */ +extern unsigned int recv_packets, recv_bytes; /* Forwarded to emulated socket */ + ipx_socket *get_socket(SOCKET sockfd); ipx_socket *get_socket_wait_for_ready(SOCKET sockfd, int timeout_ms); void lock_sockets(void); diff --git a/src/ipxwrapper_prof_defs.h b/src/ipxwrapper_prof_defs.h new file mode 100644 index 0000000..052f52a --- /dev/null +++ b/src/ipxwrapper_prof_defs.h @@ -0,0 +1,5 @@ +FPROF_DECL(_deliver_packet) +FPROF_DECL(_handle_udp_recv) +FPROF_DECL(_handle_dosbox_recv) +FPROF_DECL(_handle_pcap_frame) +FPROF_DECL(lock_sockets) diff --git a/src/ipxwrapper_stubs.txt b/src/ipxwrapper_stubs.txt index e4acacb..9471f51 100644 --- a/src/ipxwrapper_stubs.txt +++ b/src/ipxwrapper_stubs.txt @@ -1,38 +1,49 @@ -inet_addr:4 -WSAStartup:4 -WSACleanup:4 -WSASetLastError:4 -WSAGetLastError:4 -htonl:4 -ntohl:4 -htons:4 -ntohs:4 -r_select:4 -r_listen:4 -r_accept:4 -WSACreateEvent:4 -WSAEventSelect:4 -WSACloseEvent:4 -WSAResetEvent:4 -WSASetEvent:4 -r_EnumProtocolsA:2 -r_EnumProtocolsW:2 -r_WSARecvEx:2 -r_bind:4 -r_closesocket:4 -r_getsockname:4 -r_getsockopt:4 -r_recv:4 -r_recvfrom:4 -r_sendto:4 -r_setsockopt:4 -r_shutdown:4 -r_socket:4 -r_ioctlsocket:4 -r_connect:4 -r_send:4 -r_getpeername:4 -inet_ntoa:4 -__WSAFDIsSet:4 -r_WSAAsyncSelect:4 -gethostbyname:4 +Function name Target DLL Target function Parameters (bytes) +------------------------------------------------------------------------------- +inet_addr ws2_32.dll inet_addr 4 +WSAStartup ws2_32.dll WSAStartup 8 +WSACleanup ws2_32.dll WSACleanup 0 +WSASetLastError ws2_32.dll WSASetLastError 4 +WSAGetLastError ws2_32.dll WSAGetLastError 0 +htonl ws2_32.dll htonl 4 +ntohl ws2_32.dll ntohl 4 +htons ws2_32.dll htons 4 +ntohs ws2_32.dll ntohs 4 +r_select ws2_32.dll select 20 +r_listen ws2_32.dll listen 8 +r_accept ws2_32.dll accept 12 +WSACreateEvent ws2_32.dll WSACreateEvent 0 +WSAEventSelect ws2_32.dll WSAEventSelect 12 +WSACloseEvent ws2_32.dll WSACloseEvent 4 +WSAResetEvent ws2_32.dll WSAResetEvent 4 +WSASetEvent ws2_32.dll WSASetEvent 4 +r_EnumProtocolsA mswsock.dll EnumProtocolsA 12 +r_EnumProtocolsW mswsock.dll EnumProtocolsW 12 +r_WSARecvEx mswsock.dll WSARecvEx 16 +r_bind ws2_32.dll bind 12 +r_closesocket ws2_32.dll closesocket 4 +r_getsockname ws2_32.dll getsockname 12 +r_getsockopt ws2_32.dll getsockopt 20 +r_recv ws2_32.dll recv 16 +r_recvfrom ws2_32.dll recvfrom 24 +r_sendto ws2_32.dll sendto 24 +r_setsockopt ws2_32.dll setsockopt 20 +r_shutdown ws2_32.dll shutdown 8 +r_socket ws2_32.dll socket 12 +r_ioctlsocket ws2_32.dll ioctlsocket 12 +r_connect ws2_32.dll connect 12 +r_send ws2_32.dll send 16 +r_getpeername ws2_32.dll getpeername 12 +inet_ntoa ws2_32.dll inet_ntoa 4 +__WSAFDIsSet ws2_32.dll __WSAFDIsSet 8 +r_WSAAsyncSelect ws2_32.dll WSAAsyncSelect 16 +gethostbyname ws2_32.dll gethostbyname 4 + +pcap_open wpcap.dll pcap_open +pcap_close wpcap.dll pcap_close +pcap_findalldevs_ex wpcap.dll pcap_findalldevs_ex +pcap_freealldevs wpcap.dll pcap_freealldevs +pcap_getevent wpcap.dll pcap_getevent +pcap_dispatch wpcap.dll pcap_dispatch +pcap_geterr wpcap.dll pcap_geterr +pcap_sendpacket wpcap.dll pcap_sendpacket diff --git a/src/mswsock_stubs.txt b/src/mswsock_stubs.txt index a0e474b..56d2ef6 100644 --- a/src/mswsock_stubs.txt +++ b/src/mswsock_stubs.txt @@ -1,35 +1,37 @@ -ServiceMain -SvchostPushServiceGlobals -AcceptEx -EnumProtocolsA:0 -EnumProtocolsW:0 -GetAcceptExSockaddrs -GetAddressByNameA -GetAddressByNameW -GetNameByTypeA -GetNameByTypeW -GetServiceA -GetServiceW -GetTypeByNameA -GetTypeByNameW -MigrateWinsockConfiguration -NPLoadNameSpaces -NSPStartup -SetServiceA -SetServiceW -StartWsdpService -StopWsdpService -TransmitFile -WSARecvEx:0 -WSPStartup -dn_expand -getnetbyname -inet_network -rcmd -rexec -rresvport -s_perror -sethostname -inet_addr -WSHEnumProtocols:0 -ntohs:1 +Function name Target DLL Target function Parameters (bytes) +-------------------------------------------------------------------------------------------------- +ServiceMain mswsock.dll ServiceMain +SvchostPushServiceGlobals mswsock.dll SvchostPushServiceGlobals +AcceptEx mswsock.dll AcceptEx 32 +EnumProtocolsA ipxwrapper.dll EnumProtocolsA 12 +EnumProtocolsW ipxwrapper.dll EnumProtocolsW 12 +GetAcceptExSockaddrs mswsock.dll GetAcceptExSockaddrs 32 +GetAddressByNameA mswsock.dll GetAddressByNameA 40 +GetAddressByNameW mswsock.dll GetAddressByNameW 40 +GetNameByTypeA mswsock.dll GetNameByTypeA 12 +GetNameByTypeW mswsock.dll GetNameByTypeW 12 +GetServiceA mswsock.dll GetServiceA 28 +GetServiceW mswsock.dll GetServiceW 28 +GetTypeByNameA mswsock.dll GetTypeByNameA 8 +GetTypeByNameW mswsock.dll GetTypeByNameW 8 +MigrateWinsockConfiguration mswsock.dll MigrateWinsockConfiguration +NPLoadNameSpaces mswsock.dll NPLoadNameSpaces +NSPStartup mswsock.dll NSPStartup 8 +SetServiceA mswsock.dll SetServiceA 24 +SetServiceW mswsock.dll SetServiceW 24 +StartWsdpService mswsock.dll StartWsdpService +StopWsdpService mswsock.dll StopWsdpService +TransmitFile mswsock.dll TransmitFile 28 +WSARecvEx ipxwrapper.dll WSARecvEx 16 +WSPStartup mswsock.dll WSPStartup 76 +dn_expand mswsock.dll dn_expand +getnetbyname mswsock.dll getnetbyname +inet_network mswsock.dll inet_network +rcmd mswsock.dll rcmd +rexec mswsock.dll rexec +rresvport mswsock.dll rresvport +s_perror mswsock.dll s_perror +sethostname mswsock.dll sethostname +inet_addr mswsock.dll inet_addr 4 +WSHEnumProtocols ipxwrapper.dll WSHEnumProtocols 16 +ntohs wsock32.dll ntohs 4 diff --git a/src/router.c b/src/router.c index e14499e..53c660b 100644 --- a/src/router.c +++ b/src/router.c @@ -26,6 +26,7 @@ #include "router.h" #include "common.h" +#include "funcprof.h" #include "ipxwrapper.h" #include "interface.h" #include "addrcache.h" @@ -230,6 +231,8 @@ static void _deliver_packet( const void *data, size_t data_size) { + FPROF_RECORD_SCOPE(&(ipxwrapper_fstats[IPXWRAPPER_FSTATS__deliver_packet])); + { IPX_STRING_ADDR(src_addr, src_net, src_node, src_socket); IPX_STRING_ADDR(dest_addr, dest_net, dest_node, dest_socket); @@ -344,6 +347,10 @@ static void _deliver_packet( { log_printf(LOG_ERROR, "Error relaying packet: %s", w32_error(WSAGetLastError())); } + else{ + __atomic_add_fetch(&recv_packets, 1, __ATOMIC_RELAXED); + __atomic_add_fetch(&recv_bytes, data_size, __ATOMIC_RELAXED); + } free(packet); } @@ -353,6 +360,8 @@ static void _deliver_packet( static void _handle_udp_recv(ipx_packet *packet, size_t packet_size, struct sockaddr_in src_ip) { + FPROF_RECORD_SCOPE(&(ipxwrapper_fstats[IPXWRAPPER_FSTATS__handle_udp_recv])); + size_t data_size = ntohs(packet->size); if(packet_size < sizeof(ipx_packet) - 1 || data_size > MAX_DATA_SIZE || data_size + sizeof(ipx_packet) - 1 != packet_size) @@ -536,6 +545,8 @@ static void _handle_dosbox_registration_response(novell_ipx_packet *packet, size static void _handle_dosbox_recv(novell_ipx_packet *packet, size_t packet_size) { + FPROF_RECORD_SCOPE(&(ipxwrapper_fstats[IPXWRAPPER_FSTATS__handle_dosbox_recv])); + if(packet_size < sizeof(novell_ipx_packet) || ntohs(packet->length) != packet_size) { /* Doesn't look valid. */ @@ -617,6 +628,8 @@ static bool _do_udp_recv(int fd) static void _handle_pcap_frame(u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data) { + FPROF_RECORD_SCOPE(&(ipxwrapper_fstats[IPXWRAPPER_FSTATS__handle_pcap_frame])); + ipx_interface_t *iface = (ipx_interface_t*)(user); const novell_ipx_packet *ipx; diff --git a/src/stubdll.c b/src/stubdll.c index 19074a5..05914e6 100644 --- a/src/stubdll.c +++ b/src/stubdll.c @@ -1,5 +1,5 @@ /* IPXWrapper - Stub DLL functions - * Copyright (C) 2008-2011 Daniel Collins + * Copyright (C) 2008-2023 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 @@ -21,13 +21,52 @@ #include "common.h" #include "config.h" +#include "funcprof.h" + +static DWORD WINAPI prof_thread_main(LPVOID lpParameter); + +static HANDLE prof_thread_handle = NULL; +static HANDLE prof_thread_exit = NULL; BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { if(fdwReason == DLL_PROCESS_ATTACH) { + fprof_init(stub_fstats, NUM_STUBS); + log_open("ipxwrapper.log"); - min_log_level = get_main_config().log_level; + main_config_t config = get_main_config(); + + min_log_level = config.log_level; + + if(config.profile) + { + stubs_enable_profile = true; + + prof_thread_exit = CreateEvent(NULL, FALSE, FALSE, NULL); + if(prof_thread_exit != NULL) + { + prof_thread_handle = CreateThread( + NULL, /* lpThreadAttributes */ + 0, /* dwStackSize */ + &prof_thread_main, /* lpStartAddress */ + NULL, /* lpParameter */ + 0, /* dwCreationFlags */ + NULL); /* lpThreadId */ + + if(prof_thread_handle == NULL) + { + log_printf(LOG_ERROR, + "Unable to create prof_thread_main thread: %s", + w32_error(GetLastError())); + } + } + else{ + log_printf(LOG_ERROR, + "Unable to create prof_thread_exit event object: %s", + w32_error(GetLastError())); + } + } } else if(fdwReason == DLL_PROCESS_DETACH) { @@ -41,9 +80,45 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { return TRUE; } + if(prof_thread_exit != NULL) + { + SetEvent(prof_thread_exit); + + if(prof_thread_handle != NULL) + { + WaitForSingleObject(prof_thread_handle, INFINITE); + + CloseHandle(prof_thread_handle); + prof_thread_handle = NULL; + } + + CloseHandle(prof_thread_exit); + prof_thread_exit = NULL; + } + unload_dlls(); + + if(stubs_enable_profile) + { + fprof_report(STUBS_DLL_NAME, stub_fstats, NUM_STUBS); + } + log_close(); + + fprof_cleanup(stub_fstats, NUM_STUBS); } return TRUE; } + +static DWORD WINAPI prof_thread_main(LPVOID lpParameter) +{ + static const int PROF_INTERVAL_MS = 10000; + + while(WaitForSingleObject(prof_thread_exit, PROF_INTERVAL_MS) == WAIT_TIMEOUT) + { + fprof_report(STUBS_DLL_NAME, stub_fstats, NUM_STUBS); + } + + return 0; +} diff --git a/src/winsock.c b/src/winsock.c index b1a9ba3..3bb3fac 100644 --- a/src/winsock.c +++ b/src/winsock.c @@ -1475,6 +1475,9 @@ static DWORD ipx_send_packet( if(pcap_sendpacket(iface->pcap, (void*)(frame), frame_size) == 0) { + __atomic_add_fetch(&send_packets, 1, __ATOMIC_RELAXED); + __atomic_add_fetch(&send_bytes, data_size, __ATOMIC_RELAXED); + free(frame); return ERROR_SUCCESS; } @@ -1531,6 +1534,10 @@ static DWORD ipx_send_packet( error = WSAGetLastError(); log_printf(LOG_ERROR, "Error sending DOSBox IPX packet: %s", w32_error(error)); } + else{ + __atomic_add_fetch(&send_packets, 1, __ATOMIC_RELAXED); + __atomic_add_fetch(&send_bytes, data_size, __ATOMIC_RELAXED); + } free(packet); @@ -1635,6 +1642,12 @@ static DWORD ipx_send_packet( free(packet); + if(send_ok) + { + __atomic_add_fetch(&send_packets, 1, __ATOMIC_RELAXED); + __atomic_add_fetch(&send_bytes, data_size, __ATOMIC_RELAXED); + } + return send_ok ? ERROR_SUCCESS : send_error; diff --git a/src/wpcap_stubs.txt b/src/wpcap_stubs.txt deleted file mode 100644 index 68fdf0e..0000000 --- a/src/wpcap_stubs.txt +++ /dev/null @@ -1,8 +0,0 @@ -pcap_open -pcap_close -pcap_findalldevs_ex -pcap_freealldevs -pcap_getevent -pcap_dispatch -pcap_geterr -pcap_sendpacket diff --git a/src/wsock32_stubs.txt b/src/wsock32_stubs.txt index 6131143..d7d26c7 100644 --- a/src/wsock32_stubs.txt +++ b/src/wsock32_stubs.txt @@ -1,76 +1,78 @@ -accept:0 -bind:0 -closesocket:0 -connect:0 -getpeername:0 -getsockname:0 -getsockopt:0 -htonl -htons -inet_addr -inet_ntoa -ioctlsocket:0 -listen:0 -ntohl -ntohs -recv:0 -recvfrom:0 -select:0 -send:0 -sendto:0 -setsockopt:0 -shutdown:0 -socket:0 -MigrateWinsockConfiguration -gethostbyaddr -gethostbyname -getprotobyname -getprotobynumber -getservbyname -getservbyport -gethostname -WSAAsyncSelect:0 -WSAAsyncGetHostByAddr -WSAAsyncGetHostByName -WSAAsyncGetProtoByNumber -WSAAsyncGetProtoByName -WSAAsyncGetServByPort -WSAAsyncGetServByName -WSACancelAsyncRequest -WSASetBlockingHook -WSAUnhookBlockingHook -WSAGetLastError -WSASetLastError -WSACancelBlockingCall -WSAIsBlocking -WSAStartup -WSACleanup -__WSAFDIsSet -WEP -WSApSetPostRoutine -inet_network -getnetbyname -rcmd -rexec -rresvport -sethostname -dn_expand -WSARecvEx:0 -s_perror -GetAddressByNameA -GetAddressByNameW -EnumProtocolsA:0 -EnumProtocolsW:0 -GetTypeByNameA -GetTypeByNameW -GetNameByTypeA -GetNameByTypeW -SetServiceA -SetServiceW -GetServiceA -GetServiceW -NPLoadNameSpaces -TransmitFile -AcceptEx -GetAcceptExSockaddrs -WSHEnumProtocols:0 +Function name Target DLL Target function Parameters (bytes) +-------------------------------------------------------------------------------------------------- +accept ipxwrapper.dll accept 12 +bind ipxwrapper.dll bind 12 +closesocket ipxwrapper.dll closesocket 4 +connect ipxwrapper.dll connect 12 +getpeername ipxwrapper.dll getpeername 12 +getsockname ipxwrapper.dll getsockname 12 +getsockopt ipxwrapper.dll getsockopt 20 +htonl wsock32.dll htonl 4 +htons wsock32.dll htons 4 +inet_addr wsock32.dll inet_addr 4 +inet_ntoa wsock32.dll inet_ntoa 4 +ioctlsocket ipxwrapper.dll ioctlsocket 12 +listen ipxwrapper.dll listen 8 +ntohl wsock32.dll ntohl 4 +ntohs wsock32.dll ntohs 4 +recv ipxwrapper.dll recv 16 +recvfrom ipxwrapper.dll recvfrom 24 +select ipxwrapper.dll select 20 +send ipxwrapper.dll send 16 +sendto ipxwrapper.dll sendto 24 +setsockopt ipxwrapper.dll setsockopt 20 +shutdown ipxwrapper.dll shutdown 8 +socket ipxwrapper.dll socket 12 +MigrateWinsockConfiguration wsock32.dll MigrateWinsockConfiguration +gethostbyaddr wsock32.dll gethostbyaddr 12 +gethostbyname wsock32.dll gethostbyname 4 +getprotobyname wsock32.dll getprotobyname 4 +getprotobynumber wsock32.dll getprotobynumber 4 +getservbyname wsock32.dll getservbyname 8 +getservbyport wsock32.dll getservbyport 8 +gethostname wsock32.dll gethostname 8 +WSAAsyncSelect ipxwrapper.dll WSAAsyncSelect 16 +WSAAsyncGetHostByAddr wsock32.dll WSAAsyncGetHostByAddr 28 +WSAAsyncGetHostByName wsock32.dll WSAAsyncGetHostByName 20 +WSAAsyncGetProtoByNumber wsock32.dll WSAAsyncGetProtoByNumber 20 +WSAAsyncGetProtoByName wsock32.dll WSAAsyncGetProtoByName 20 +WSAAsyncGetServByPort wsock32.dll WSAAsyncGetServByPort 24 +WSAAsyncGetServByName wsock32.dll WSAAsyncGetServByName 24 +WSACancelAsyncRequest wsock32.dll WSACancelAsyncRequest 4 +WSASetBlockingHook wsock32.dll WSASetBlockingHook 4 +WSAUnhookBlockingHook wsock32.dll WSAUnhookBlockingHook 0 +WSAGetLastError wsock32.dll WSAGetLastError 0 +WSASetLastError wsock32.dll WSASetLastError 4 +WSACancelBlockingCall wsock32.dll WSACancelBlockingCall 0 +WSAIsBlocking wsock32.dll WSAIsBlocking 0 +WSAStartup wsock32.dll WSAStartup 8 +WSACleanup wsock32.dll WSACleanup 0 +__WSAFDIsSet wsock32.dll __WSAFDIsSet 8 +WEP wsock32.dll WEP +WSApSetPostRoutine wsock32.dll WSApSetPostRoutine +inet_network wsock32.dll inet_network +getnetbyname wsock32.dll getnetbyname +rcmd wsock32.dll rcmd +rexec wsock32.dll rexec +rresvport wsock32.dll rresvport +sethostname wsock32.dll sethostname +dn_expand wsock32.dll dn_expand +WSARecvEx ipxwrapper.dll WSARecvEx 16 +s_perror wsock32.dll s_perror +GetAddressByNameA wsock32.dll GetAddressByNameA 40 +GetAddressByNameW wsock32.dll GetAddressByNameW 40 +EnumProtocolsA ipxwrapper.dll EnumProtocolsA 12 +EnumProtocolsW ipxwrapper.dll EnumProtocolsW 12 +GetTypeByNameA wsock32.dll GetTypeByNameA 8 +GetTypeByNameW wsock32.dll GetTypeByNameW 8 +GetNameByTypeA wsock32.dll GetNameByTypeA 12 +GetNameByTypeW wsock32.dll GetNameByTypeW 12 +SetServiceA wsock32.dll SetServiceA 24 +SetServiceW wsock32.dll SetServiceW 24 +GetServiceA wsock32.dll GetServiceA 28 +GetServiceW wsock32.dll GetServiceW 28 +NPLoadNameSpaces wsock32.dll NPLoadNameSpaces +TransmitFile wsock32.dll TransmitFile 28 +AcceptEx wsock32.dll AcceptEx 32 +GetAcceptExSockaddrs wsock32.dll GetAcceptExSockaddrs 32 +WSHEnumProtocols ipxwrapper.dll WSHEnumProtocols 16