mirror of
https://github.com/solemnwarning/ipxwrapper
synced 2024-12-30 16:45:37 +01:00
Merge branch 'profiling'
This commit is contained in:
commit
bbe0dbd4e1
24
Makefile
24
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 $@
|
||||
|
||||
|
282
mkstubs.pl
282
mkstubs.pl
@ -1,5 +1,5 @@
|
||||
# IPXWrapper - Generate assembly stub functions
|
||||
# Copyright (C) 2008-2011 Daniel Collins <solemnwarning@solemnwarning.net>
|
||||
# Copyright (C) 2008-2023 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
|
||||
@ -18,74 +18,268 @@ use strict;
|
||||
use warnings;
|
||||
|
||||
if(@ARGV != 3) {
|
||||
print STDERR "Usage: mkdll.pl <function list> <output file> <dll number>\n";
|
||||
print STDERR "Usage: mkdll.pl <stub definitions file> <asm output file> <dll name>\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(<STUBS>) {
|
||||
# Skip over header
|
||||
(scalar <STUBS>);
|
||||
(scalar <STUBS>);
|
||||
|
||||
# Read in stub definitions
|
||||
foreach my $line(<STUBS>)
|
||||
{
|
||||
$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);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* IPXWrapper - Common functions
|
||||
* Copyright (C) 2011-2021 Daniel Collins <solemnwarning@solemnwarning.net>
|
||||
* Copyright (C) 2011-2023 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
|
||||
@ -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
|
||||
};
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#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);
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ipxwrapper - DirectPlay service provider
|
||||
* Copyright (C) 2011 Daniel Collins <solemnwarning@solemnwarning.net>
|
||||
* Copyright (C) 2011-2019 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
|
||||
@ -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;
|
||||
|
@ -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
|
||||
|
129
src/funcprof.c
Normal file
129
src/funcprof.c
Normal file
@ -0,0 +1,129 @@
|
||||
/* IPXWrapper - Function profiling functions
|
||||
* Copyright (C) 2019 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
|
||||
* 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 <windows.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
64
src/funcprof.h
Normal file
64
src/funcprof.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* IPXWrapper - Function profiling functions
|
||||
* Copyright (C) 2019 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
|
||||
* 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 <windows.h>
|
||||
|
||||
#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 */
|
@ -1,5 +1,5 @@
|
||||
/* IPXWrapper - Configuration tool
|
||||
* Copyright (C) 2011-2022 Daniel Collins <solemnwarning@solemnwarning.net>
|
||||
* Copyright (C) 2011-2023 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
|
||||
@ -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);
|
||||
|
10
src/ipxconfig_stubs.txt
Normal file
10
src/ipxconfig_stubs.txt
Normal file
@ -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
|
101
src/ipxwrapper.c
101
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);
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <uthash.h>
|
||||
|
||||
#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);
|
||||
|
5
src/ipxwrapper_prof_defs.h
Normal file
5
src/ipxwrapper_prof_defs.h
Normal file
@ -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)
|
@ -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
|
||||
|
@ -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
|
||||
|
13
src/router.c
13
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;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* IPXWrapper - Stub DLL functions
|
||||
* Copyright (C) 2008-2011 Daniel Collins <solemnwarning@solemnwarning.net>
|
||||
* Copyright (C) 2008-2023 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
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -1,8 +0,0 @@
|
||||
pcap_open
|
||||
pcap_close
|
||||
pcap_findalldevs_ex
|
||||
pcap_freealldevs
|
||||
pcap_getevent
|
||||
pcap_dispatch
|
||||
pcap_geterr
|
||||
pcap_sendpacket
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user