This is it, folks. Pls. let me know if I botched anything. Should be relative to CVS. LICENSE: X11 CHANGELOG: * configure; configure.ac; dlls/rpcrt4: .cvsignore, Makefile.in, rpc_binding.h, rpcrt4.spec, rpcrt4_main.c, rpc_epmap.c (new); include: rpcdce.h, rpcdcep.h, rpcndr.h, winbase.h; include/wine: rpcss_shared.h (new); programs: Makefile.in; programs/rpcss (new dir): .cvsignore (new), Makefile.in (new), README (new), atomicity.c (new), epmap_server.c (new), named_pipe_kludge_client.c (new), named_pipe_kludge_server.c (new), rpcss.h (new), rpcss_main.c (new): Greg Turner <gmturner007@ameritech.net>, Ove Kåven <ovek@transgaming.com> - a preliminary implementation of endpoint-mapping via a new on-demand server-ish process ("rpcss.exe.so") - more header fixups - (re)implement RpcEpRegisterA, RpcEpUnregister, and RpcEpResolveBinding using the new rpcss functionality - update the todo list in rpcrt4_main.c a bit -- gmt "War is an ugly thing, but not the ugliest of things; the decayed and degraded state of moral and patriotic feeling which thinks that nothing is worth war is much worse. A man who has nothing for which he is willing to fight; nothing he cares about more than his own personal safety; is a miserable creature who has no chance of being free, unless made and kept so by the exertions of better persons than himself." -- John Stuart Mill
diff -ur -x CVS -x 'bigdif*' ../wine.test/configure ./configure --- ../wine.test/configure 2002-11-12 22:00:01.000000000 -0600 +++ ./configure 2002-11-13 10:37:52.000000000 -0600 @@ -13593,7 +13593,7 @@ MAKE_PROG_RULES=programs/Makeprog.rules - ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Maketest.rules programs/Makeprog.rules Makefile dlls/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/d3d8/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dsound/Makefile dlls/gdi/Makefile dlls/gdi/tests/Makefile dlls/glu32/Makefile dlls/icmp/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msdmo/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msvcrt/Makefile dlls/msvcrt/tests/Makefile dlls/msvcrt20/Makefile dlls/msvideo/Makefile dlls/msvideo/msrle32/Makefile dlls/netapi32/Makefile dlls/netapi32/tests/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/rpcrt4/tests/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/urlmon/tests/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/version/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/tests/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/winenas/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winsock/tests/Makefile dlls/winspool/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile include/Makefile library/Makefile miscemu/Makefile ole/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/notepad/Makefile programs/osversioncheck/Makefile programs/progman/Makefile programs/regapi/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/regtest/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineconsole/Makefile programs/winedbg/Makefile programs/winefile/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/wmc/Makefile tools/wpp/Makefile tools/wrc/Makefile unicode/Makefile" + ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Maketest.rules programs/Makeprog.rules Makefile dlls/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/d3d8/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dsound/Makefile dlls/gdi/Makefile dlls/gdi/tests/Makefile dlls/glu32/Makefile dlls/icmp/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msdmo/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msvcrt/Makefile dlls/msvcrt/tests/Makefile dlls/msvcrt20/Makefile dlls/msvideo/Makefile dlls/msvideo/msrle32/Makefile dlls/netapi32/Makefile dlls/netapi32/tests/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/rpcrt4/tests/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/urlmon/tests/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/version/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/tests/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/winenas/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winsock/tests/Makefile dlls/winspool/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile include/Makefile library/Makefile miscemu/Makefile ole/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/notepad/Makefile programs/osversioncheck/Makefile programs/progman/Makefile programs/regapi/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/regtest/Makefile programs/rpcss/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineconsole/Makefile programs/winedbg/Makefile programs/winefile/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/wmc/Makefile tools/wpp/Makefile tools/wrc/Makefile unicode/Makefile" cat >confcache <<\_ACEOF @@ -14238,6 +14238,7 @@ "programs/regedit/Makefile" ) CONFIG_FILES="$CONFIG_FILES programs/regedit/Makefile" ;; "programs/regsvr32/Makefile" ) CONFIG_FILES="$CONFIG_FILES programs/regsvr32/Makefile" ;; "programs/regtest/Makefile" ) CONFIG_FILES="$CONFIG_FILES programs/regtest/Makefile" ;; + "programs/rpcss/Makefile" ) CONFIG_FILES="$CONFIG_FILES programs/rpcss/Makefile" ;; "programs/uninstaller/Makefile" ) CONFIG_FILES="$CONFIG_FILES programs/uninstaller/Makefile" ;; "programs/view/Makefile" ) CONFIG_FILES="$CONFIG_FILES programs/view/Makefile" ;; "programs/wcmd/Makefile" ) CONFIG_FILES="$CONFIG_FILES programs/wcmd/Makefile" ;; diff -ur -x CVS -x 'bigdif*' ../wine.test/configure.ac ./configure.ac --- ../wine.test/configure.ac 2002-11-12 22:00:01.000000000 -0600 +++ ./configure.ac 2002-11-13 10:34:48.000000000 -0600 @@ -1511,6 +1511,7 @@ programs/regedit/Makefile programs/regsvr32/Makefile programs/regtest/Makefile +programs/rpcss/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile diff -ur -x CVS -x 'bigdif*' ../wine.test/dlls/rpcrt4/.cvsignore ./dlls/rpcrt4/.cvsignore --- ../wine.test/dlls/rpcrt4/.cvsignore 2002-05-14 15:55:02.000000000 -0500 +++ ./dlls/rpcrt4/.cvsignore 2002-11-13 16:09:25.000000000 -0600 @@ -1,3 +1,5 @@ Makefile rpcrt4.dll.dbg.c rpcrt4.spec.c +atomicity.c +named_pipe_kludge_client.c diff -ur -x CVS -x 'bigdif*' ../wine.test/dlls/rpcrt4/Makefile.in ./dlls/rpcrt4/Makefile.in --- ../wine.test/dlls/rpcrt4/Makefile.in 2002-11-04 21:25:58.000000000 -0600 +++ ./dlls/rpcrt4/Makefile.in 2002-11-13 16:32:52.000000000 -0600 @@ -10,7 +10,12 @@ LDDLLFLAGS = @LDDLLFLAGS@ SYMBOLFILE = $(MODULE).tmp.o +C_SRC_LINKS = \ + atomicity.c \ + named_pipe_kludge_client.c + C_SRCS = \ + $(C_SRC_LINKS) \ cproxy.c \ cpsf.c \ cstub.c \ @@ -19,12 +24,29 @@ ndr_ole.c \ ndr_stubless.c \ rpc_binding.c \ + rpc_epmap.c \ rpc_message.c \ rpc_server.c \ rpcrt4_main.c +C_SRC_LINK_SRCS = $(C_SRC_LINKS:%=$(TOPSRCDIR)/programs/rpcss/%) + SUBDIRS = tests @MAKE_DLL_RULES@ +# depend steps + +depend: $(C_SRC_LINKS) + +# install steps + +clean:: + $(RM) $(C_SRC_LINKS) + +# symlink steps + +$(C_SRC_LINKS): $(C_SRC_LINK_SRCS) + $(RM) $(C_SRC_LINKS) && $(LN_S) $(C_SRC_LINK_SRCS) . + ### Dependencies: diff -ur -x CVS -x 'bigdif*' ../wine.test/dlls/rpcrt4/rpc_binding.h ./dlls/rpcrt4/rpc_binding.h --- ../wine.test/dlls/rpcrt4/rpc_binding.h 2002-10-07 16:49:49.000000000 -0500 +++ ./dlls/rpcrt4/rpc_binding.h 2002-11-13 10:34:48.000000000 -0600 @@ -21,6 +21,8 @@ #ifndef __WINE_RPC_BINDING_H #define __WINE_RPC_BINDING_H +#include "wine/rpcss_shared.h" + /* don't know what MS's structure looks like */ typedef struct _RpcBinding { @@ -57,5 +59,6 @@ RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding); RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding); RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding); +BOOL RPCRT4_SnazzyRPCSSCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPCSS_NP_REPLY reply); #endif diff -ur -x CVS -x 'bigdif*' ../wine.test/dlls/rpcrt4/rpcrt4.spec ./dlls/rpcrt4/rpcrt4.spec --- ../wine.test/dlls/rpcrt4/rpcrt4.spec 2002-11-04 21:30:27.000000000 -0600 +++ ./dlls/rpcrt4/rpcrt4.spec 2002-11-13 10:34:48.000000000 -0600 @@ -53,12 +53,12 @@ @ stub RpcCertGeneratePrincipalNameA @ stub RpcCertGeneratePrincipalNameW @ stub RpcCompleteAsyncCall -@ stub RpcEpRegisterA +@ stdcall RpcEpRegisterA(ptr ptr ptr str) RpcEpRegisterA @ stub RpcEpRegisterW @ stub RpcEpRegisterNoReplaceA @ stub RpcEpRegisterNoReplaceW -@ stub RpcEpResolveBinding -@ stub RpcEpUnregister +@ stdcall RpcEpResolveBinding(ptr ptr) RpcEpResolveBinding +@ stdcall RpcEpUnregister(ptr ptr ptr) RpcEpUnregister @ stub RpcErrorAddRecord # wxp @ stub RpcErrorClearInformation # wxp @ stub RpcErrorEndEnumeration # wxp diff -ur -x CVS -x 'bigdif*' ../wine.test/dlls/rpcrt4/rpcrt4_main.c ./dlls/rpcrt4/rpcrt4_main.c --- ../wine.test/dlls/rpcrt4/rpcrt4_main.c 2002-11-07 20:30:29.000000000 -0600 +++ ./dlls/rpcrt4/rpcrt4_main.c 2002-11-13 22:08:15.000000000 -0600 @@ -23,13 +23,11 @@ * a bit of work needs to be done here. widl currently doesn't generate stubs * for RPC invocation -- it will need to; this is tricky because the MIDL compiler * does some really wierd stuff. Then again, we don't neccesarily have to - * make widl work like MIDL, so it could be worse. + * make widl work like MIDL, so it could be worse. Lately Ove has been working on + * some widl enhancements. * - * - RPC has a quite featureful error handling mechanism; none of it is implemented - * right now. - * - * - The server portions of the patch don't seem to be getting accepted by - * Alexandre. Instead, we are working on "rpcss.exe.so" which will replace them. + * - RPC has a quite featureful error handling mechanism; basically none of this is + * implemented right now. * * - There are several different memory allocation schemes for MSRPC. * I don't even understand what they all are yet, much less have them @@ -42,13 +40,16 @@ * API's & gracefully ignore the irrelevant stuff (to a small extent we already do). * * - Some transports are not yet implemented. The existing transport implementations - * are incomplete; the various transports probably ought to be supported in a more + * are incomplete and many seem to be buggy + * + * - The various transports that we do support ought to be supported in a more * object-oriented manner, like in DCE's RPC implementation, instead of cluttering * up the code with conditionals like we do now. * * - Data marshalling: So far, only the very beginnings of an implementation * exist in wine. NDR protocol itself is documented, but the MS API's to - * convert data-types in memory into NDR are not. + * convert data-types in memory into NDR are not. This is a bit of a challenge, + * but it is at the top of Greg's queue and should be improving soon. * * - ORPC is RPC for OLE; once we have a working RPC framework, we can * use it to implement out-of-process OLE client/server communications. @@ -56,13 +57,15 @@ * and the marshalling going on here. This is a good thing, since marshalling * doesn't work yet. But once it does, obviously there will be the opportunity * to implement out-of-process OLE using wine's rpcrt4 or some derivative. + * This may require some collaboration between the RPC workers and the OLE + * workers, of course. * * - In-source API Documentation, at least for those functions which we have * implemented, but preferably for everything we can document, would be nice. * Some stuff is undocumented by Microsoft and we are guessing how to implement * (in these cases we should document the behavior we implemented, or, if there * is no implementation, at least hazard some kind of guess, and put a few - * question marks after it ;) ). + * question marks after it ;) ). * * - Stubs. Lots of stuff is defined in Microsoft's headers, including undocumented * stuff. So let's make a stub-farm and populate it with as many rpcrt4 api's as @@ -70,9 +73,9 @@ * * - Name services: this part hasn't even been started. * - * - Concurrency: right now I don't think (?) we handle more than one request at a time; + * - Concurrency: right now I have not tested more than one request at a time; * we are supposed to be able to do this, and to queue requests which exceed the - * concurrency limit. Lots of scenarios are untested. + * concurrency limit. * * - Protocol Towers: Totally unimplemented.... I think. * @@ -82,7 +85,7 @@ * * - Statistics: we are supposed to be keeping various counters. we aren't. * - * - Connectionless RPC: unimplemented. + * - Connectionless RPC: unimplemented (DNE in win9x so not a top priority) * * - XML RPC: Dunno if microsoft does it... but we'd might as well just for kicks. * @@ -157,9 +160,13 @@ { switch (fdwReason) { case DLL_PROCESS_ATTACH: + if (!RPC_GetMasterMutex()) + ERR("Failed to acquire master mutex. Not good.\n"); break; case DLL_PROCESS_DETACH: + if (!RPC_ReleaseMasterMutex()) + ERR("Failed to release master mutex.\n"); break; } @@ -673,6 +680,82 @@ HRESULT WINAPI RPCRT4_DllRegisterServer( void ) { - FIXME( "(): stub\n" ); - return S_OK; + FIXME( "(): stub\n" ); + return S_OK; +} + +BOOL RPCRT4_StartRPCSS() +{ + PROCESS_INFORMATION pi; + STARTUPINFOA si; + static char cmd[6]; + BOOL rslt; + + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&si, sizeof(STARTUPINFOA)); + si.cb = sizeof(STARTUPINFOA); + + /* apparently it's not OK to use a constant string below */ + CopyMemory(cmd, "rpcss", 6); + + /* FIXME: will this do the right thing when run as a test? */ + rslt = CreateProcessA( + NULL, /* executable */ + cmd, /* command line */ + NULL, /* process security attributes */ + NULL, /* primary thread security attributes */ + FALSE, /* inherit handles */ + 0, /* creation flags */ + NULL, /* use parent's environment */ + NULL, /* use parent's current directory */ + &si, /* STARTUPINFO pointer */ + &pi /* PROCESS_INFORMATION */ + ); + + if (rslt) { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + + return rslt; +} + +BOOL RPCRT4_SnazzyRPCSSCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPCSS_NP_REPLY reply) +{ + HANDLE client_handle; + int i, j = 0; + + TRACE("(msg == %p, vardata_payload == %p, reply == %p)\n", msg, vardata_payload, reply); + + client_handle = RPC_RpcssNPConnect(); + + while (!client_handle) { + /* start the RPCSS process */ + if (!RPCRT4_StartRPCSS()) { + ERR("Unable to start RPCSS process.\n"); + return FALSE; + } + /* wait for a connection (w/ periodic polling) */ + for (i = 0; i < 60; i++) { + Sleep(200); + client_handle = RPC_RpcssNPConnect(); + if (client_handle) break; + } + /* we are only willing to try twice */ + if (j++ >= 1) break; + } + + if (!client_handle) { + /* no dice! */ + ERR("Unable to connect to RPCSS process!\n"); + return FALSE; + } + + /* great, we're connected. now send the message */ + if (!RPC_SendReceiveNPMsg(client_handle, msg, vardata_payload, reply)) { + ERR("Something is amiss: RPC_SendReceive failed.\n"); + return FALSE; + } + + return TRUE; } diff -ur -x CVS -x 'bigdif*' ../wine.test/include/rpcdce.h ./include/rpcdce.h --- ../wine.test/include/rpcdce.h 2002-10-31 20:13:50.000000000 -0600 +++ ./include/rpcdce.h 2002-11-13 10:34:48.000000000 -0600 @@ -21,6 +21,21 @@ #include "windef.h" +/* avoid delving into windows.h ifndef __WINE__; this + would pull in rpcndr.h, which needs rpcdcep.h, which + needs us, in turn, causing a compile failure */ +#ifndef RPC_NO_WINDOWS_H +#define __NO_HAD_RPC_NO_WINDOWS_H +#define RPC_NO_WINDOWS_H +#endif + +#include "rpc.h" + +#ifdef __NO_HAD_RPC_NO_WINDOWS_H +#undef RPC_NO_WINDOWS_H +#undef __NO_HAD_RPC_NO_WINDOWS_H +#endif + #ifndef GUID_DEFINED #include "guiddef.h" #endif diff -ur -x CVS -x 'bigdif*' ../wine.test/include/rpcdcep.h ./include/rpcdcep.h --- ../wine.test/include/rpcdcep.h 2002-10-31 20:13:50.000000000 -0600 +++ ./include/rpcdcep.h 2002-11-13 10:34:48.000000000 -0600 @@ -19,6 +19,8 @@ #ifndef __WINE_RPCDCEP_H #define __WINE_RPCDCEP_H +#include "rpcdce.h" + typedef struct _RPC_VERSION { unsigned short MajorVersion; unsigned short MinorVersion; diff -ur -x CVS -x 'bigdif*' ../wine.test/include/rpcndr.h ./include/rpcndr.h --- ../wine.test/include/rpcndr.h 2002-10-31 18:58:12.000000000 -0600 +++ ./include/rpcndr.h 2002-11-13 10:34:48.000000000 -0600 @@ -25,7 +25,7 @@ #define __WINE_RPCNDR_H #include "basetsd.h" -#include "rpc.h" +#include "rpcdcep.h" /* stupid #if can't handle casts... this __stupidity is just a workaround for that limitation */ diff -ur -x CVS -x 'bigdif*' ../wine.test/include/winbase.h ./include/winbase.h --- ../wine.test/include/winbase.h 2002-11-04 21:30:27.000000000 -0600 +++ ./include/winbase.h 2002-11-13 10:34:48.000000000 -0600 @@ -1473,6 +1473,7 @@ BOOL WINAPI SetFileTime(HANDLE,const FILETIME*,const FILETIME*,const FILETIME*); BOOL WINAPI SetHandleInformation(HANDLE,DWORD,DWORD); BOOL WINAPI SetKernelObjectSecurity(HANDLE,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR); +BOOL WINAPI SetNamedPipeHandleState(HANDLE,LPDWORD,LPDWORD,LPDWORD); BOOL WINAPI SetPriorityClass(HANDLE,DWORD); BOOL WINAPI SetLocalTime(const SYSTEMTIME*); BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR,BOOL,PACL,BOOL); diff -ur -x CVS -x 'bigdif*' ../wine.test/programs/Makefile.in ./programs/Makefile.in --- ../wine.test/programs/Makefile.in 2002-11-12 15:57:30.000000000 -0600 +++ ./programs/Makefile.in 2002-11-13 10:37:37.000000000 -0600 @@ -17,6 +17,7 @@ regedit \ regsvr32 \ regtest \ + rpcss \ uninstaller \ view \ wcmd \ @@ -38,6 +39,7 @@ progman \ regedit \ regsvr32 \ + rpcss \ uninstaller \ wcmd \ wineconsole \ @@ -55,6 +57,7 @@ progman \ regedit \ regsvr32 \ + rpcss \ uninstaller \ wcmd \ wineconsole \ @@ -66,6 +69,7 @@ # Symlinks to apps that we want to run from inside the source tree SYMLINKS = \ + rpcss.exe \ wineconsole.exe \ winedbg.exe \ winhelp.exe @@ -115,6 +119,9 @@ # Rules for symlinks +rpcss.exe$(DLLEXT): rpcss/rpcss.exe$(DLLEXT) + $(RM) $@ && $(LN_S) rpcss/rpcss.exe$(DLLEXT) $@ + wineconsole.exe$(DLLEXT): wineconsole/wineconsole.exe$(DLLEXT) $(RM) $@ && $(LN_S) wineconsole/wineconsole.exe$(DLLEXT) $@ @@ -124,6 +131,7 @@ winhelp.exe$(DLLEXT): winhelp/winhelp.exe$(DLLEXT) $(RM) $@ && $(LN_S) winhelp/winhelp.exe$(DLLEXT) $@ +rpcss/rpcss.exe$(DLLEXT): rpcss wineconsole/wineconsole.exe$(DLLEXT): wineconsole winedbg/winedbg.exe$(DLLEXT): winedbg winhelp/winhelp.exe$(DLLEXT): winhelp --- /dev/null 1969-12-31 18:00:00.000000000 -0600 +++ ./dlls/rpcrt4/rpc_epmap.c 2002-11-13 21:47:49.000000000 -0600 @@ -0,0 +1,232 @@ +/* + * RPC endpoint mapper + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * + * TODO: + * - actually do things right + */ + +#include <stdio.h> +#include <string.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "rpc.h" + +#include "wine/debug.h" + +#include "rpc_binding.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/* The "real" RPC portmapper endpoints that I know of are: + * + * ncadg_ip_udp: 135 + * ncacn_ip_tcp: 135 + * ncacn_np: \\pipe\epmapper (?) + * ncalrpc: epmapper + * + * If the user's machine ran a DCE RPC daemon, it would + * probably be possible to connect to it, but there are many + * reasons not to, like: + * - the user probably does *not* run one, and probably + * shouldn't be forced to run one just for local COM + * - very few Unix systems use DCE RPC... if they run a RPC + * daemon at all, it's usually Sun RPC + * - DCE RPC registrations are persistent and saved on disk, + * while MS-RPC registrations are documented as non-persistent + * and stored only in RAM, and auto-destroyed when the process + * dies (something DCE RPC can't do) + * + * Of course, if the user *did* want to run a DCE RPC daemon anyway, + * there would be interoperability advantages, like the possibility + * of running a fully functional DCOM server using Wine... + */ + +/*********************************************************************** + * RpcEpRegisterA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, PRPC_BINDING_VECTOR BindingVector, + PUUID_VECTOR UuidVector, LPSTR Annotation ) +{ + RPCSS_NP_MESSAGE msg; + RPCSS_NP_REPLY reply; + char *vardata_payload, *vp; + PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; + unsigned long c; + RPC_STATUS rslt = RPC_S_OK; + + TRACE("(%p,%p,%p,%s)\n", IfSpec, BindingVector, UuidVector, debugstr_a(Annotation)); + TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); + for (c=0; c<BindingVector->Count; c++) { + RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[c]); + TRACE(" protseq[%ld]=%s\n", c, debugstr_a(bind->Protseq)); + TRACE(" endpoint[%ld]=%s\n", c, debugstr_a(bind->Endpoint)); + } + if (UuidVector) { + for (c=0; c<UuidVector->Count; c++) + TRACE(" obj[%ld]=%s\n", c, debugstr_guid(UuidVector->Uuid[c])); + } + + /* FIXME: Do something with annotation. */ + + /* construct the message to rpcss */ + msg.message_type = RPCSS_NP_MESSAGE_TYPEID_REGISTEREPMSG; + msg.message.registerepmsg.iface = If->InterfaceId; + msg.message.registerepmsg.no_replace = 0; + + msg.message.registerepmsg.object_count = (UuidVector) ? UuidVector->Count : 0; + msg.message.registerepmsg.binding_count = BindingVector->Count; + + /* calculate vardata payload size */ + msg.vardata_payload_size = msg.message.registerepmsg.object_count * sizeof(UUID); + for (c=0; c < msg.message.registerepmsg.binding_count; c++) { + RpcBinding *bind = (RpcBinding *)(BindingVector->BindingH[c]); + msg.vardata_payload_size += strlen(bind->Protseq) + 1; + msg.vardata_payload_size += strlen(bind->Endpoint) + 1; + } + + /* allocate the payload buffer */ + vp = vardata_payload = LocalAlloc(LPTR, msg.vardata_payload_size); + if (!vardata_payload) + return RPC_S_OUT_OF_MEMORY; + + /* populate the payload data */ + for (c=0; c < msg.message.registerepmsg.object_count; c++) { + CopyMemory(vp, UuidVector->Uuid[c], sizeof(UUID)); + vp += sizeof(UUID); + } + + for (c=0; c < msg.message.registerepmsg.binding_count; c++) { + RpcBinding *bind = (RpcBinding*)(BindingVector->BindingH[c]); + unsigned long pslen = strlen(bind->Protseq) + 1, eplen = strlen(bind->Endpoint) + 1; + CopyMemory(vp, bind->Protseq, pslen); + vp += pslen; + CopyMemory(vp, bind->Endpoint, eplen); + vp += eplen; + } + + /* send our request */ + if (!RPCRT4_SnazzyRPCSSCall(&msg, vardata_payload, &reply)) + rslt = RPC_S_OUT_OF_MEMORY; + + /* free the payload buffer */ + LocalFree(vardata_payload); + + return rslt; +} + +/*********************************************************************** + * RpcEpUnregister (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, PRPC_BINDING_VECTOR BindingVector, + PUUID_VECTOR UuidVector ) +{ + RPCSS_NP_MESSAGE msg; + RPCSS_NP_REPLY reply; + char *vardata_payload, *vp; + PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; + unsigned long c; + RPC_STATUS rslt = RPC_S_OK; + + TRACE("(%p,%p,%p)\n", IfSpec, BindingVector, UuidVector); + TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); + for (c=0; c<BindingVector->Count; c++) { + RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[c]); + TRACE(" protseq[%ld]=%s\n", c, debugstr_a(bind->Protseq)); + TRACE(" endpoint[%ld]=%s\n", c, debugstr_a(bind->Endpoint)); + } + if (UuidVector) { + for (c=0; c<UuidVector->Count; c++) + TRACE(" obj[%ld]=%s\n", c, debugstr_guid(UuidVector->Uuid[c])); + } + + /* construct the message to rpcss */ + msg.message_type = RPCSS_NP_MESSAGE_TYPEID_UNREGISTEREPMSG; + msg.message.unregisterepmsg.iface = If->InterfaceId; + + msg.message.unregisterepmsg.object_count = (UuidVector) ? UuidVector->Count : 0; + msg.message.unregisterepmsg.binding_count = BindingVector->Count; + + /* calculate vardata payload size */ + msg.vardata_payload_size = msg.message.unregisterepmsg.object_count * sizeof(UUID); + for (c=0; c < msg.message.unregisterepmsg.binding_count; c++) { + RpcBinding *bind = (RpcBinding *)(BindingVector->BindingH[c]); + msg.vardata_payload_size += strlen(bind->Protseq) + 1; + msg.vardata_payload_size += strlen(bind->Endpoint) + 1; + } + + /* allocate the payload buffer */ + vp = vardata_payload = LocalAlloc(LPTR, msg.vardata_payload_size); + if (!vardata_payload) + return RPC_S_OUT_OF_MEMORY; + + /* populate the payload data */ + for (c=0; c < msg.message.unregisterepmsg.object_count; c++) { + CopyMemory(vp, UuidVector->Uuid[c], sizeof(UUID)); + vp += sizeof(UUID); + } + + for (c=0; c < msg.message.unregisterepmsg.binding_count; c++) { + RpcBinding *bind = (RpcBinding*)(BindingVector->BindingH[c]); + unsigned long pslen = strlen(bind->Protseq) + 1, eplen = strlen(bind->Endpoint) + 1; + CopyMemory(vp, bind->Protseq, pslen); + vp += pslen; + CopyMemory(vp, bind->Endpoint, eplen); + vp += eplen; + } + + /* send our request */ + if (!RPCRT4_SnazzyRPCSSCall(&msg, vardata_payload, &reply)) + rslt = RPC_S_OUT_OF_MEMORY; + + /* free the payload buffer */ + LocalFree(vardata_payload); + + return rslt; +} + +/*********************************************************************** + * RpcEpResolveBinding (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcEpResolveBinding( RPC_BINDING_HANDLE Binding, RPC_IF_HANDLE IfSpec ) +{ + RPCSS_NP_MESSAGE msg; + RPCSS_NP_REPLY reply; + PRPC_CLIENT_INTERFACE If = (PRPC_CLIENT_INTERFACE)IfSpec; + RpcBinding* bind = (RpcBinding*)Binding; + + TRACE("(%p,%p)\n", Binding, IfSpec); + TRACE(" protseq=%s\n", debugstr_a(bind->Protseq)); + TRACE(" obj=%s\n", debugstr_guid(&bind->ObjectUuid)); + TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); + + /* FIXME: totally untested */ + + /* just return for fully bound handles */ + if (bind->Endpoint && (bind->Endpoint[0] != '\0')) + return RPC_S_OK; + + /* construct the message to rpcss */ + msg.message_type = RPCSS_NP_MESSAGE_TYPEID_RESOLVEEPMSG; + msg.message.resolveepmsg.iface = If->InterfaceId; + msg.message.resolveepmsg.object = bind->ObjectUuid; + + msg.vardata_payload_size = strlen(bind->Protseq) + 1; + + /* send the message */ + if (!RPCRT4_SnazzyRPCSSCall(&msg, bind->Protseq, &reply)) + return RPC_S_OUT_OF_MEMORY; + + /* empty-string result means not registered */ + if (reply.as_string[0] == '\0') + return EPT_S_NOT_REGISTERED; + + /* otherwise we fully bind the handle & return RPC_S_OK */ + return RPCRT4_ResolveBinding(Binding, reply.as_string); +} + --- /dev/null 1969-12-31 18:00:00.000000000 -0600 +++ ./include/wine/rpcss_shared.h 2002-11-13 11:37:50.000000000 -0600 @@ -0,0 +1,124 @@ +/* + * Copyright 2002 Greg Turner <gmturner007@ameritech.net> + * + * For license terms, see programs/rpcss/README + */ + +#ifndef __WINE_RPCSS_SHARED_H +#define __WINE_RPCSS_SHARED_H + +#include "basetsd.h" +#include "winnt.h" + +#include "rpcdcep.h" + +/* comment this out to turn on annoying periodic traces */ +#define RPC_AVOID_EXCESSIVE_TRACING + +/* only local communications are supported so far on this pipe. + until this changes, we can just use a constant pipe-name */ +#define NAME_RPCSS_NAMED_PIPE "\\\\.\\pipe\\RpcssKludge" + +/* payloads above 5K are fragmented into multiple messages */ +#define VARDATA_PAYLOAD_BYTES 5120 + +/* ick -- maybe we should pass a handle to a mailslot or something? */ +#define MAX_RPCSS_NP_REPLY_STRING_LEN 512 + +/* a data payload; not a normal message */ +#define RPCSS_NP_MESSAGE_TYPEID_VARDATAPAYLOADMSG 1 +typedef struct _RPCSS_NP_MESSAGE_UNION_VARDATAPAYLOADMSG { + char payload[VARDATA_PAYLOAD_BYTES]; +} RPCSS_NP_MESSAGE_UNION_VARDATAPAYLOADMSG; + +/* RANMSG: + * Simply tells the server that another rpcss instance ran. + * The server should respond by resetting its timeout to the + * full lazy timeout. + */ +#define RPCSS_NP_MESSAGE_TYPEID_RANMSG 2 +typedef struct _RPCSS_NP_MESSAGE_UNION_RANMSG { + /* empty */ +} RPCSS_NP_MESSAGE_UNION_RANMSG; + +/* REGISTEREPMSG: + * Registers endpoints with the endpoint server. + * object_count and binding_count contain the number + * of object uuids and endpoints in the vardata payload, + * respectively. + */ +#define RPCSS_NP_MESSAGE_TYPEID_REGISTEREPMSG 3 +typedef struct _RPCSS_NP_MESSAGE_UNION_REGISTEREPMSG { + RPC_SYNTAX_IDENTIFIER iface; + int object_count; + int binding_count; + int no_replace; +} RPCSS_NP_MESSAGE_UNION_REGISTEREPMSG; + +/* UNREGISTEREPMSG: + * Unregisters endpoints with the endpoint server. + * object_count and binding_count contain the number + * of object uuids and endpoints in the vardata payload, + * respectively. + */ +#define RPCSS_NP_MESSAGE_TYPEID_UNREGISTEREPMSG 4 +typedef struct _RPCSS_NP_MESSAGE_UNION_UNREGISTEREPMSG { + RPC_SYNTAX_IDENTIFIER iface; + int object_count; + int binding_count; +} RPCSS_NP_MESSAGE_UNION_UNREGISTEREPMSG; + +/* RESOLVEEPMSG: + * Locates an endpoint registered with the endpoint server. + * Vardata contains a single protseq string. This is a bit + * silly: the protseq string is probably shorter than the + * reply (an endpoint string), which is truncated at + * MAX_RPCSS_NP_REPLY_STRING_LEN, at least for the moment. + * returns the empty string if the requested endpoint isn't + * registered. + */ +#define RPCSS_NP_MESSAGE_TYPEID_RESOLVEEPMSG 5 +typedef struct _RPCSS_NP_MESSAGE_UNION_RESOLVEEPMSG { + RPC_SYNTAX_IDENTIFIER iface; + UUID object; +} RPCSS_NP_MESSAGE_UNION_RESOLVEEPMSG; + +typedef union { + RPCSS_NP_MESSAGE_UNION_RANMSG ranmsg; + RPCSS_NP_MESSAGE_UNION_VARDATAPAYLOADMSG vardatapayloadmsg; + RPCSS_NP_MESSAGE_UNION_REGISTEREPMSG registerepmsg; + RPCSS_NP_MESSAGE_UNION_UNREGISTEREPMSG unregisterepmsg; + RPCSS_NP_MESSAGE_UNION_RESOLVEEPMSG resolveepmsg; +} RPCSS_NP_MESSAGE_UNION; + +/* vardata_payload_size specifies the number of bytes + * to be transferred over the pipe in VARDATAPAYLOAD + * messages (divide by VARDATA_PAYLOAD_BYTES to + * get the # of payloads) + */ +typedef struct _RPCSS_NP_MESSAGE { + UINT32 message_type; + RPCSS_NP_MESSAGE_UNION message; + UINT32 vardata_payload_size; +} RPCSS_NP_MESSAGE, *PRPCSS_NP_MESSAGE; + +typedef union { + /* some of these aren't used, but I guess we don't care */ + UINT as_uint; + INT as_int; + void *as_pvoid; + HANDLE as_handle; + char as_string[MAX_RPCSS_NP_REPLY_STRING_LEN]; /* FIXME: yucky */ +} RPCSS_NP_REPLY, *PRPCSS_NP_REPLY; + +/* atomicity.c */ +BOOL RPC_GetMasterMutex(); +BOOL RPC_ReleaseMasterMutex(); +BOOL RPC_EnterMasterMutex(); +BOOL RPC_LeaveMasterMutex(); + +/* named_pipe_kludge_client.c */ +HANDLE RPC_RpcssNPConnect(); +BOOL RPC_SendReceiveNPMsg(HANDLE, PRPCSS_NP_MESSAGE, char *, PRPCSS_NP_REPLY); + +#endif /* __WINE_RPCSS_SHARED_H */ --- /dev/null 1969-12-31 18:00:00.000000000 -0600 +++ ./programs/rpcss/.cvsignore 2002-11-13 10:34:48.000000000 -0600 @@ -0,0 +1,3 @@ +Makefile +rpcss.exe.dbg.c +rpcss.exe.spec.c --- /dev/null 1969-12-31 18:00:00.000000000 -0600 +++ ./programs/rpcss/Makefile.in 2002-11-13 10:34:48.000000000 -0600 @@ -0,0 +1,19 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = rpcss.exe +APPMODE = cui +IMPORTS = kernel32 + +C_SRCS = \ + atomicity.c \ + epmap_server.c \ + named_pipe_kludge_client.c \ + named_pipe_kludge_server.c \ + rpcss_main.c + +@MAKE_PROG_RULES@ + +### Dependencies: + --- /dev/null 1969-12-31 18:00:00.000000000 -0600 +++ ./programs/rpcss/README 2002-11-13 21:57:54.000000000 -0600 @@ -0,0 +1,61 @@ +rpcss.exe + copyright 2002, Greg Turner + copyright 2001, Ove Kåven, TransGaming Technologies Inc, + +========================== + +Portions of this code are available for use under the X11/MIT +and LGPL licenses; all rpcss code is available under the LGPL +license, as follows: + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +========================== + +Wine needs a server whose role is somewhat like that +of rpcss.exe in windows. This is not really a clone of +windows rpcss at all. It has been given the same name, however +to provide for the possibility that at some point in the future, +it may become interface compatible with the "real" rpcss.exe on +Windows. + +Enjoy. + +KNOWN BUGS / TODO: + + o Service hooks are unimplemented (if you bother to implement + these, also implement net.exe, at least for "net start" and + "net stop" (should be pretty easy I guess, assuming the rest + of the services API infrastructure works (which net.exe should + assume, even if the API is lean or bugged))). + + o Is supposed to use RPC, not random kludges, to map endpoints. + + o Probably name services should be implemented here as well. + + o Wine's named pipes (in general) may not interoperate with those of + Windows yet (?) + + o There is a looming problem regarding listening on priveleged + ports. We will need to be able to coexist with SAMBA, and able + to function without running winelib code as root. This may + take some doing, including significant reconceptualization of the + role of rpcss.exe in wine. + + o Who knows? Whatever rpcss does, we ought to at + least think about doing... but what /does/ it do? + +-gmt + --- /dev/null 1969-12-31 18:00:00.000000000 -0600 +++ ./programs/rpcss/atomicity.c 2002-11-13 16:51:21.000000000 -0600 @@ -0,0 +1,80 @@ +/* + * RPC atomicity controls + * + * Copyright (C) 2002 Greg Turner + * + * For license terms, see programs/rpcss/README + */ + +#include <assert.h> + +#include "winbase.h" + +#include "wine/rpcss_shared.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +static HANDLE master_mutex; + +BOOL RPC_GetMasterMutex() +{ + WINE_TRACE("\n"); + assert (!master_mutex); /* else someone botched the semantics */ + + master_mutex = CreateMutexA( NULL, FALSE, "RPCSSMasterMutex" ); + if (!master_mutex) + return FALSE; + else + return TRUE; +} + +BOOL RPC_ReleaseMasterMutex() +{ + WINE_TRACE("\n"); + assert(master_mutex); /* else someone botched the semantics */ + + if (!CloseHandle(master_mutex)) + return FALSE; + + master_mutex = (HANDLE)NULL; + return TRUE; +} + +BOOL RPC_EnterMasterMutex() +{ + DWORD wait_result; + + WINE_TRACE("\n"); + assert(master_mutex); /* else someone botched the semantics */ + + /* it should never take 120 seconds to get this. timeout is + presumed to indicate a (potentially unrecoverable) bug */ + wait_result = WaitForSingleObject(master_mutex, 120000); + + switch (wait_result) { + case WAIT_ABANDONED: /* ? */ + case WAIT_OBJECT_0: + /* we have ownership */ + return TRUE; + case WAIT_FAILED: + case WAIT_TIMEOUT: + default: + WINE_ERR("This should never happen: couldn't enter mutex.\n"); + return FALSE; + } +} + +BOOL RPC_LeaveMasterMutex() +{ + WINE_TRACE("\n"); + assert(master_mutex); /* else someone bothced the semantics */ + + if (ReleaseMutex(master_mutex)) + return TRUE; + else { + WINE_ERR("Mutex release failed.\n"); + return FALSE; + } +} + --- /dev/null 1969-12-31 18:00:00.000000000 -0600 +++ ./programs/rpcss/epmap_server.c 2002-11-13 12:18:16.000000000 -0600 @@ -0,0 +1,198 @@ +/* + * RPC endpoint mapper server + * + * Copyright (C) 2001 Ove Kåven, TransGaming Technologies Inc, + * 2002 Greg Turner + * + * For license terms, see dlls/rpcss/README + */ + +#include <assert.h> +#include <string.h> + +#include "rpcss.h" +#include "rpc.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +struct epmap_entry +{ + struct epmap_entry *next; + RPC_SYNTAX_IDENTIFIER iface; + UUID object; + char *protseq; + char *endpoint; +}; + +static struct epmap_entry *epmap; + +static const UUID nil_object; + +char *mystrdup(const char *str) { + char *rval; + rval = LocalAlloc(LPTR, strlen(str)+1); + CopyMemory(rval, str, strlen(str)+1); + return rval; +} + +static struct epmap_entry *find_endpoint(const RPC_SYNTAX_IDENTIFIER *iface, + const char *protseq, const UUID *object) +{ + struct epmap_entry *map; + for (map=epmap; map; map=map->next) { + if (memcmp(&map->iface, iface, sizeof(RPC_SYNTAX_IDENTIFIER))) continue; + if (memcmp(&map->object, object, sizeof(UUID))) continue; + if (strcmp(map->protseq, protseq)) continue; + WINE_TRACE("found.\n"); + return map; + } + WINE_TRACE("not found.\n"); + return NULL; +} + +static void register_endpoint(const RPC_SYNTAX_IDENTIFIER *iface, const char *protseq, + const char *endpoint, const UUID *objects, int objcount, + int no_replace) +{ + int c; + + WINE_TRACE("(protseq == %s, endpoint == %s, objcount == %i, no_replace == %i)\n", + wine_dbgstr_a(protseq), wine_dbgstr_a(endpoint), objcount, no_replace); + + if (!objcount) { + objects = &nil_object; + objcount = 1; + } + + for (c=0; c<objcount; c++) { + struct epmap_entry *map = NULL; + if (!no_replace) + map = find_endpoint(iface, protseq, &objects[c]); + if (map) { + LocalFree(map->endpoint); + } + else { + map = LocalAlloc(LPTR, sizeof(struct epmap_entry)); + memcpy(&map->iface, iface, sizeof(RPC_SYNTAX_IDENTIFIER)); + memcpy(&map->object, &objects[c], sizeof(UUID)); + map->protseq = mystrdup(protseq); + map->next = epmap; + epmap = map; + } + WINE_TRACE(" mapping endpoint (protseq == %s, endpoint == %s, uuid == %s)\n", + wine_dbgstr_a(protseq), wine_dbgstr_a(endpoint), wine_dbgstr_guid(&objects[c])); + map->endpoint = mystrdup(endpoint); + } +} + +static void unregister_endpoint(const RPC_SYNTAX_IDENTIFIER *iface, const char *protseq, + const char *endpoint, const UUID *objects, int objcount) +{ + struct epmap_entry *map, *prev, *nprev, *next; + int c; + + WINE_TRACE("(protseq == %s, endpoint == %s, objcount == %i)\n", + wine_dbgstr_a(protseq), wine_dbgstr_a(endpoint), objcount); + + if (!objcount) { + objects = &nil_object; + objcount = 1; + } + prev=NULL; + nprev=NULL; + map=epmap; + while(map) { + next = map->next; + nprev = map; + if (memcmp(&map->iface, iface, sizeof(RPC_SYNTAX_IDENTIFIER))) goto cont; + for (c=0; c<objcount; c++) + if (!memcmp(&map->object, &objects[c], sizeof(UUID))) break; + if (c==objcount) goto cont; + if (strcmp(map->protseq, protseq)) goto cont; + + WINE_TRACE(" unmapping: (protseq == %s, endpoint == %s, uuid == %s)\n", + wine_dbgstr_a(map->protseq), wine_dbgstr_a(map->endpoint), + wine_dbgstr_guid(&map->object)); + + if (prev) prev->next = map->next; + else epmap = map->next; + nprev = prev; + + LocalFree(map->protseq); + LocalFree(map->endpoint); + LocalFree(map); + + cont: + + prev = nprev; + map = next; + } +} + +static void resolve_endpoint(const RPC_SYNTAX_IDENTIFIER *iface, const char *protseq, + const UUID *object, char *rslt_ep) +{ + size_t len; + struct epmap_entry *map; + + if (!(map = find_endpoint(iface, protseq, object))) return; + + len = min( MAX_RPCSS_NP_REPLY_STRING_LEN, strlen(map->endpoint)+1 ); + if (len) memcpy(rslt_ep, map->endpoint, len); +} + +static const char *get_string(const char**ptr, const char*end) +{ + const char *str = *ptr, *nptr = str; + + while (nptr < end && *nptr) nptr++; + if (nptr == end) + return NULL; + *ptr = nptr + 1; + return str; +} + +BOOL RPCSS_EpmapEmpty() +{ + return (!epmap); +} + +void RPCSS_RegisterRpcEndpoints(RPC_SYNTAX_IDENTIFIER iface, int object_count, + int binding_count, int no_replace, char *vardata, long vardata_size) +{ + const char *data = vardata; + const char *end = data + vardata_size; + UUID *objects = (UUID *)data; + int c; + + data += object_count * sizeof(UUID); + for (c=0; c < binding_count; c++) { + const char *protseq = get_string(&data, end); + const char *endpoint = get_string(&data, end); + if (protseq && endpoint) + register_endpoint(&iface, protseq, endpoint, objects, object_count, no_replace); + } +} + +void RPCSS_UnregisterRpcEndpoints(RPC_SYNTAX_IDENTIFIER iface, int object_count, + int binding_count, char *vardata, long vardata_size) +{ + const char *data = vardata; + const char *end = data + vardata_size; + const UUID *objects = (UUID *)data; + int c; + + data += object_count * sizeof(UUID); + for (c=0; c < binding_count; c++) { + const char *protseq = get_string(&data, end); + const char *endpoint = get_string(&data, end); + if (protseq && endpoint) + unregister_endpoint(&iface, protseq, endpoint, objects, object_count); + } +} + +void RPCSS_ResolveRpcEndpoints(RPC_SYNTAX_IDENTIFIER iface, UUID object, char *protseq, char *rslt_ep) +{ + resolve_endpoint(&iface, protseq, &object, rslt_ep); +} --- /dev/null 1969-12-31 18:00:00.000000000 -0600 +++ ./programs/rpcss/named_pipe_kludge_client.c 2002-11-13 10:34:48.000000000 -0600 @@ -0,0 +1,129 @@ +/* + * RPC named pipe kludge (client) implementation + * + * Copyright (C) 2002 Greg Turner + * + * For license terms, see programs/rpcss/README + */ + +#include <assert.h> + +#include "winbase.h" + +#include "wine/rpcss_shared.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +HANDLE RPC_RpcssNPConnect() +{ + HANDLE the_pipe = NULL; + DWORD dwmode; + + WINE_TRACE("\n"); + if (!RPC_EnterMasterMutex()) { + WINE_ERR("Failed to acquire the RPC Master Mutex!\n"); + return NULL; + } + + /* now try to open the client side of the named pipe. */ + while (TRUE) { + the_pipe = CreateFileA( + NAME_RPCSS_NAMED_PIPE, /* pipe name */ + GENERIC_READ | GENERIC_WRITE, /* r/w access */ + 0, /* no sharing */ + NULL, /* no security attributes */ + OPEN_EXISTING, /* open an existing pipe */ + 0, /* default attributes */ + NULL /* no template file */ + ); + if (the_pipe != INVALID_HANDLE_VALUE) + break; + if (GetLastError() != ERROR_PIPE_BUSY) { + WINE_WARN("Unable to open named pipe (assuming unavailable).\n"); + the_pipe = NULL; + break; + } + WINE_WARN("Pipe busy.\n"); + /* leave the mutex temporarily and wait for the named pipe. We are only + willing to wait only 5 seconds. It should be available /very/ soon. */ + if (!RPC_LeaveMasterMutex()) { + WINE_ERR("Error leaving master mutex!?\n"); + the_pipe = NULL; + break; + } + if (! WaitNamedPipeA(NAME_RPCSS_NAMED_PIPE, 5000)) { + WINE_ERR("Named pipe unavailable after waiting. Something is wrong.\n"); + the_pipe = NULL; + return NULL; + } + if (!RPC_EnterMasterMutex()) { + WINE_ERR("Error re-acquiring master mutex!\n"); + the_pipe = NULL; + return NULL; + } + } + + if (the_pipe) { + dwmode = PIPE_READMODE_MESSAGE; + /* SetNamedPipeHandleState not implemented ATM */ + if (! SetNamedPipeHandleState(the_pipe, &dwmode, NULL, NULL)) + WINE_WARN("Failed to set pipe handle state\n"); + } + + if (!RPC_LeaveMasterMutex()) + WINE_ERR("Uh oh, failed to leave the RPC Master Mutex!\n"); + + return the_pipe; +} + +BOOL RPC_SendReceiveNPMsg(HANDLE np, PRPCSS_NP_MESSAGE msg, char *vardata, PRPCSS_NP_REPLY reply) +{ + DWORD count; + UINT32 payload_offset; + RPCSS_NP_MESSAGE vardata_payload_msg; + + WINE_TRACE("(np == %p, msg == %p, vardata == %p, reply == %p)\n", + np, msg, vardata, reply); + + if (! WriteFile(np, msg, sizeof(RPCSS_NP_MESSAGE), &count, NULL)) { + WINE_ERR("write failed.\n"); + return FALSE; + } + + if (count != sizeof(RPCSS_NP_MESSAGE)) { + WINE_ERR("write count mismatch.\n"); + return FALSE; + } + + /* process the vardata payload if neccesary */ + vardata_payload_msg.message_type = RPCSS_NP_MESSAGE_TYPEID_VARDATAPAYLOADMSG; + vardata_payload_msg.vardata_payload_size = 0; /* meaningless */ + for ( payload_offset = 0; payload_offset < msg->vardata_payload_size; + payload_offset += VARDATA_PAYLOAD_BYTES ) { + WINE_TRACE("sending vardata payload. vd=%p, po=%d, ps=%d\n", vardata, + payload_offset, msg->vardata_payload_size); + ZeroMemory(vardata_payload_msg.message.vardatapayloadmsg.payload, VARDATA_PAYLOAD_BYTES); + CopyMemory(vardata_payload_msg.message.vardatapayloadmsg.payload, + vardata, + min( VARDATA_PAYLOAD_BYTES, msg->vardata_payload_size - payload_offset )); + vardata += VARDATA_PAYLOAD_BYTES; + if (! WriteFile(np, &vardata_payload_msg, sizeof(RPCSS_NP_MESSAGE), &count, NULL)) { + WINE_ERR("vardata write failed at %u bytes.\n", payload_offset); + return FALSE; + } + } + + if (! ReadFile(np, reply, sizeof(RPCSS_NP_REPLY), &count, NULL)) { + WINE_ERR("read failed.\n"); + return FALSE; + } + + if (count != sizeof(RPCSS_NP_REPLY)) { + WINE_ERR("read count mismatch. got %ld, expected %u.\n", count, sizeof(RPCSS_NP_REPLY)); + return FALSE; + } + + /* message execution was successful */ + return TRUE; +} --- /dev/null 1969-12-31 18:00:00.000000000 -0600 +++ ./programs/rpcss/named_pipe_kludge_server.c 2002-11-13 12:22:49.000000000 -0600 @@ -0,0 +1,417 @@ +/* + * RPC named pipe kludge + * + * Copyright (C) 2002 Greg Turner + * + * For license terms, see programs/rpcss/README + */ + +#include <assert.h> + +#include "rpcss.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +static HANDLE np_server_end; +static HANDLE np_server_work_event; +static CRITICAL_SECTION np_server_cs; +static LONG srv_thread_count; +static BOOL server_live; + +LONG RPCSS_SrvThreadCount() +{ + return srv_thread_count; +} + +BOOL RPCSS_UnBecomePipeServer() +{ + BOOL rslt = TRUE; + + WINE_TRACE("\n"); + + if (!RPC_EnterMasterMutex()) { + WINE_ERR("Couldn't enter master mutex.\n"); + /* this is totally unacceptable. no graceful out exists */ + assert(FALSE); + } + + /* now that we have the master mutex, we can safely stop + listening on the pipe. Before we proceed, we do a final + check that it's OK to shut down to ensure atomicity */ + + if (!RPCSS_ReadyToDie()) + rslt = FALSE; + else { + WINE_TRACE("shutting down pipe.\n"); + server_live = FALSE; + if (!CloseHandle(np_server_end)) + WINE_WARN("Failed to close named pipe.\n"); + if (!CloseHandle(np_server_work_event)) + WINE_WARN("Failed to close the event handle.\n"); + DeleteCriticalSection(&np_server_cs); + } + + if (!RPC_LeaveMasterMutex()) { + WINE_ERR("Unable to leave master mutex!??\n"); + } + + return rslt; +} + +void RPCSS_ServerProcessRANMessage(PRPCSS_NP_MESSAGE pMsg, PRPCSS_NP_REPLY pReply) +{ + WINE_TRACE("\n"); + /* we do absolutely nothing, but on the server end, + the lazy timeout is reset as a result of our connection. + this is the point of the message so we have nothing to do */ + pReply->as_uint = 0; +} + +void RPCSS_ServerProcessREGISTEREPMessage(PRPCSS_NP_MESSAGE pMsg, PRPCSS_NP_REPLY pReply, + char *vardata) +{ + WINE_TRACE("\n"); + + RPCSS_RegisterRpcEndpoints( + pMsg->message.registerepmsg.iface, + pMsg->message.registerepmsg.object_count, + pMsg->message.registerepmsg.binding_count, + pMsg->message.registerepmsg.no_replace, + vardata, + pMsg->vardata_payload_size + ); + + /* no reply */ + pReply->as_uint = 0; +} + +void RPCSS_ServerProcessUNREGISTEREPMessage(PRPCSS_NP_MESSAGE pMsg, + PRPCSS_NP_REPLY pReply, char *vardata) +{ + WINE_TRACE("\n"); + + RPCSS_UnregisterRpcEndpoints( + pMsg->message.unregisterepmsg.iface, + pMsg->message.unregisterepmsg.object_count, + pMsg->message.unregisterepmsg.binding_count, + vardata, + pMsg->vardata_payload_size + ); + + /* no reply */ + pReply->as_uint = 0; +} + +void RPCSS_ServerProcessRESOLVEEPMessage(PRPCSS_NP_MESSAGE pMsg, + PRPCSS_NP_REPLY pReply, char *vardata) +{ + WINE_TRACE("\n"); + + /* for now, reply is placed into *pReply.as_string, on success, by RPCSS_ResolveRpcEndpoints */ + ZeroMemory(pReply->as_string, MAX_RPCSS_NP_REPLY_STRING_LEN); + RPCSS_ResolveRpcEndpoints( + pMsg->message.resolveepmsg.iface, + pMsg->message.resolveepmsg.object, + vardata, + pReply->as_string + ); +} + +void RPCSS_ServerProcessMessage(PRPCSS_NP_MESSAGE pMsg, PRPCSS_NP_REPLY pReply, char *vardata) +{ + WINE_TRACE("\n"); + switch (pMsg->message_type) { + case RPCSS_NP_MESSAGE_TYPEID_RANMSG: + RPCSS_ServerProcessRANMessage(pMsg, pReply); + break; + case RPCSS_NP_MESSAGE_TYPEID_REGISTEREPMSG: + RPCSS_ServerProcessREGISTEREPMessage(pMsg, pReply, vardata); + break; + case RPCSS_NP_MESSAGE_TYPEID_UNREGISTEREPMSG: + RPCSS_ServerProcessUNREGISTEREPMessage(pMsg, pReply, vardata); + break; + case RPCSS_NP_MESSAGE_TYPEID_RESOLVEEPMSG: + RPCSS_ServerProcessRESOLVEEPMessage(pMsg, pReply, vardata); + break; + default: + WINE_ERR("Message type unknown!! No action taken.\n"); + } +} + +/* each message gets its own thread. this is it. */ +VOID HandlerThread(LPVOID lpvPipeHandle) +{ + RPCSS_NP_MESSAGE msg, vardata_payload_msg; + char *c, *vardata = NULL; + RPCSS_NP_REPLY reply; + DWORD bytesread, written; + BOOL success, had_payload = FALSE; + HANDLE mypipe; + + mypipe = (HANDLE) lpvPipeHandle; + + WINE_TRACE("mypipe: %p\n", mypipe); + + success = ReadFile( + mypipe, /* pipe handle */ + (char *) &msg, /* message buffer */ + sizeof(RPCSS_NP_MESSAGE), /* message buffer size */ + &bytesread, /* receives number of bytes read */ + NULL /* not overlapped */ + ); + + if (msg.vardata_payload_size) { + had_payload = TRUE; + /* this fudge space allows us not to worry about exceeding the buffer space + on the last read */ + vardata = LocalAlloc(LPTR, (msg.vardata_payload_size) + VARDATA_PAYLOAD_BYTES); + if (!vardata) { + WINE_ERR("vardata memory allocation failure.\n"); + success = FALSE; + } else { + for ( c = vardata; (c - vardata) < msg.vardata_payload_size; + c += VARDATA_PAYLOAD_BYTES) { + success = ReadFile( + mypipe, + (char *) &vardata_payload_msg, + sizeof(RPCSS_NP_MESSAGE), + &bytesread, + NULL + ); + if ( (!success) || (bytesread != sizeof(RPCSS_NP_MESSAGE)) || + (vardata_payload_msg.message_type != RPCSS_NP_MESSAGE_TYPEID_VARDATAPAYLOADMSG) ) { + WINE_ERR("vardata payload read failure! (s=%s,br=%ld,exp_br=%d,mt=%u,mt_exp=%u\n", + success ? "TRUE" : "FALSE", bytesread, sizeof(RPCSS_NP_MESSAGE), + vardata_payload_msg.message_type, RPCSS_NP_MESSAGE_TYPEID_VARDATAPAYLOADMSG); + success = FALSE; + break; + } + CopyMemory(c, vardata_payload_msg.message.vardatapayloadmsg.payload, VARDATA_PAYLOAD_BYTES); + WINE_TRACE("payload read.\n"); + } + } + } + + if (success && (bytesread == sizeof(RPCSS_NP_MESSAGE))) { + WINE_TRACE("read success.\n"); + /* process the message and send a reply, serializing requests. */ + EnterCriticalSection(&np_server_cs); + WINE_TRACE("processing message.\n"); + RPCSS_ServerProcessMessage(&msg, &reply, vardata); + LeaveCriticalSection(&np_server_cs); + + if (had_payload) LocalFree(vardata); + + WINE_TRACE("message processed, sending reply....\n"); + + success = WriteFile( + mypipe, /* pipe handle */ + (char *) &reply, /* reply buffer */ + sizeof(RPCSS_NP_REPLY), /* reply buffer size */ + &written, /* receives number of bytes written */ + NULL /* not overlapped */ + ); + + if ( (!success) || (written != sizeof(RPCSS_NP_REPLY)) ) + WINE_WARN("Message reply failed. (successs=%s, br=%ld, exp_br=%d)\n", + success ? "TRUE" : "FALSE", written, sizeof(RPCSS_NP_REPLY)); + else + WINE_TRACE("Reply sent successfully.\n"); + } else + WINE_WARN("Message receipt failed.\n"); + + FlushFileBuffers(mypipe); + DisconnectNamedPipe(mypipe); + CloseHandle(mypipe); + InterlockedDecrement(&srv_thread_count); +} + +VOID NPMainWorkThread(LPVOID ignored) +{ + BOOL connected; + HANDLE hthread; + DWORD threadid; + + WINE_TRACE("\n"); + + while (server_live) { + connected = ConnectNamedPipe(np_server_end, NULL) ? + TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); + + if (connected) { + /* is "work" the act of connecting pipes, or the act of serving + requests successfully? for now I will make it the former. */ + if (!SetEvent(np_server_work_event)) + WINE_WARN("failed to signal np_server_work_event.\n"); + + /* Create a thread for this client. */ + InterlockedIncrement(&srv_thread_count); + hthread = CreateThread( + NULL, /* no security attribute */ + 0, /* default stack size */ + (LPTHREAD_START_ROUTINE) HandlerThread, + (LPVOID) np_server_end, /* thread parameter */ + 0, /* not suspended */ + &threadid /* returns thread ID (not used) */ + ); + + if (hthread) { + WINE_TRACE("Spawned handler thread: %p\n", hthread); + CloseHandle(hthread); + + /* for safety's sake, hold the mutex while we switch the pipe */ + if (!RPC_EnterMasterMutex()) { + WINE_ERR("Couldn't enter master mutex. Expect prolems.\n"); + } else { + /* now create a new named pipe instance to listen on */ + np_server_end = CreateNamedPipe( + NAME_RPCSS_NAMED_PIPE, /* pipe name */ + PIPE_ACCESS_DUPLEX, /* pipe open mode */ + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, /* pipe-specific modes */ + PIPE_UNLIMITED_INSTANCES, /* maximum instances */ + sizeof(RPCSS_NP_REPLY), /* output buffer size */ + sizeof(RPCSS_NP_MESSAGE), /* input buffer size */ + 2000, /* time-out interval */ + NULL /* SD */ + ); + + if (np_server_end == INVALID_HANDLE_VALUE) { + WINE_ERR("Failed to recreate named pipe!\n"); + /* not sure what to do? */ + assert(FALSE); + } + + if (!RPC_LeaveMasterMutex()) { + WINE_ERR("Uh oh. Couldn't leave master mutex. Expect deadlock.\n"); + } + } + } else { + WINE_ERR("Failed to spawn handler thread!\n"); + DisconnectNamedPipe(np_server_end); + InterlockedDecrement(&srv_thread_count); + } + } + } + WINE_TRACE("Server thread shutdown.\n"); +} + +BOOL RPCSS_BecomePipeServer() +{ + RPCSS_NP_MESSAGE msg; + RPCSS_NP_REPLY reply; + BOOL rslt = TRUE; + HANDLE client_handle, hthread; + DWORD threadid; + + WINE_TRACE("\n"); + + if (!RPC_EnterMasterMutex()) { + WINE_ERR("Couldn't enter master mutex.\n"); + return FALSE; + } + + /* now we have the master mutex. during this time we will + * + * o check if an rpcss already listens on the pipe. If so, + * we will tell it we were invoked, which will cause the + * other end to update its timeouts. After, we just return + * false. + * + * o otherwise, we establish the pipe for ourselves and get + * ready to listen on it + */ + + if ((client_handle = RPC_RpcssNPConnect()) != NULL) { + msg.message_type = RPCSS_NP_MESSAGE_TYPEID_RANMSG; + msg.vardata_payload_size = 0; + if (!RPC_SendReceiveNPMsg(client_handle, &msg, NULL, &reply)) + WINE_ERR("Something is amiss: RPC_SendReceive failed.\n"); + rslt = FALSE; + } + if (rslt) { + np_server_work_event = CreateEventA(NULL, FALSE, FALSE, "RpcNpServerWorkEvent"); + if (np_server_work_event == NULL) { + /* dunno what we can do then */ + WINE_ERR("Unable to create the np_server_work_event\n"); + assert(FALSE); + } + InitializeCriticalSection(&np_server_cs); + + np_server_end = CreateNamedPipe( + NAME_RPCSS_NAMED_PIPE, /* pipe name */ + PIPE_ACCESS_DUPLEX, /* pipe open mode */ + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, /* pipe-specific modes */ + PIPE_UNLIMITED_INSTANCES, /* maximum number of instances */ + sizeof(RPCSS_NP_REPLY), /* output buffer size */ + sizeof(RPCSS_NP_MESSAGE), /* input buffer size */ + 2000, /* time-out interval */ + NULL /* SD */ + ); + + if (np_server_end == INVALID_HANDLE_VALUE) { + WINE_ERR("Failed to create named pipe!\n"); + DeleteCriticalSection(&np_server_cs); + if (!CloseHandle(np_server_work_event)) /* we will leak the handle... */ + WINE_WARN("Failed to close np_server_work_event handle!\n"); + np_server_work_event = NULL; + np_server_end = NULL; + rslt = FALSE; + } + } + + server_live = rslt; + + if (rslt) { + /* OK, now spawn the (single) server thread */ + hthread = CreateThread( + NULL, /* no security attribute */ + 0, /* default stack size */ + (LPTHREAD_START_ROUTINE) NPMainWorkThread, + (LPVOID) NULL, /* thread parameter */ + 0, /* not suspended */ + &threadid /* returns thread ID (not used) */ + ); + if (hthread) { + WINE_TRACE("Created server thread.\n"); + CloseHandle(hthread); + } else { + WINE_ERR("Serious error: unable to create server thread!\n"); + if (!CloseHandle(np_server_work_event)) /* we will leak the handle... */ + WINE_WARN("Failed to close np_server_work_event handle!\n"); + if (!CloseHandle(np_server_end)) /* we will leak the handle... */ + WINE_WARN("Unable to close named pipe handle!\n"); + DeleteCriticalSection(&np_server_cs); + np_server_end = NULL; + np_server_work_event = NULL; + rslt = FALSE; + server_live = FALSE; + } + } + if (!RPC_LeaveMasterMutex()) + WINE_ERR("Unable to leave master mutex!??\n"); + + return rslt; +} + +BOOL RPCSS_NPDoWork() +{ + DWORD waitresult = WaitForSingleObject(np_server_work_event, 1000); + + if (waitresult == WAIT_TIMEOUT) { + #ifndef RPC_AVOID_EXCESSIVE_TRACING + WINE_TRACE("no work.\n"); + #endif + return FALSE; + } + if (waitresult == WAIT_OBJECT_0) { + #ifndef RPC_AVOID_EXCESSIVE_TRACING + WINE_TRACE("worked.\n"); + #endif + return TRUE; + } + #ifndef RPC_AVOID_EXCESSIVE_TRACING + WINE_TRACE("abandoned(!?)\n"); + #endif + return FALSE; +} --- /dev/null 1969-12-31 18:00:00.000000000 -0600 +++ ./programs/rpcss/rpcss.h 2002-11-13 12:22:10.000000000 -0600 @@ -0,0 +1,37 @@ +/* + * Copyright 2002 Greg Turner <gmturner007@ameritech.net> + * + * For license terms, see programs/rpcss/README + */ + +#ifndef __WINE_RPCSS_H +#define __WINE_RPCSS_H + +#include "wine/rpcss_shared.h" +#include "windows.h" + +/* in seconds */ +#define RPCSS_LAZY_TIMEOUT 30 + +/* rpcss_main.c */ +BOOL RPCSS_ReadyToDie(); +void RPCSS_SetLazyTimeRemaining(long); + +/* epmap_server.c */ +BOOL RPCSS_EpmapEmpty(); +BOOL RPCSS_NPDoWork(); +void RPCSS_RegisterRpcEndpoints(RPC_SYNTAX_IDENTIFIER iface, int object_count, + int binding_count, int no_replace, char *vardata, long vardata_size); +void RPCSS_UnregisterRpcEndpoints(RPC_SYNTAX_IDENTIFIER iface, int object_count, + int binding_count, char *vardata, long vardata_size); +void RPCSS_ResolveRpcEndpoints(RPC_SYNTAX_IDENTIFIER iface, UUID object, + char *protseq, char *rslt_ep); + +/* named_pipe_kludge.c */ +BOOL RPCSS_BecomePipeServer(); +BOOL RPCSS_UnBecomePipeServer(); +LONG RPCSS_SrvThreadCount(); + +#endif /* __WINE_RPCSS_H */ + +/* end of header */ --- /dev/null 1969-12-31 18:00:00.000000000 -0600 +++ ./programs/rpcss/rpcss_main.c 2002-11-13 10:34:48.000000000 -0600 @@ -0,0 +1,296 @@ +/* + * rpcss (main.c) + * + * Copyright 2002 Greg Turner <gmturner007@ameritech.net> + * For license terms, see programs/rpcss/README + */ + +#include <stdio.h> +#include <assert.h> + +#include "rpcss.h" +#include "winnt.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +#undef RPCSS_CAN_FORK + +#ifdef RPCSS_CAN_FORK +/* are we the "fork child"? */ +static BOOL secret_fork_child; + +/* are we the "fork parent"? */ +static BOOL secret_fork_parent; +#endif + +/* when do we just give up and bail? (UTC) */ +static SYSTEMTIME lazy_timeout_time; + +#if defined(NONAMELESSSTRUCT) + #define FILETIME_TO_ULARGEINT(filetime, ularge) \ + ( ularge.s.LowPart = filetime.dwLowDateTime, \ + ularge.s.HighPart = filetime.dwHighDateTime ) + #define ULARGEINT_TO_FILETIME(ularge, filetime) \ + ( filetime.dwLowDateTime = ularge.s.LowPart, \ + filetime.dwHighDateTime = ularge.s.HighPart ) +#else + #define FILETIME_TO_ULARGEINT(filetime, ularge) \ + ( ularge.LowPart = filetime.dwLowDateTime, \ + ularge.HighPart = filetime.dwHighDateTime ) + #define ULARGEINT_TO_FILETIME(ularge, filetime) \ + ( filetime.dwLowDateTime = ularge.LowPart, \ + filetime.dwHighDateTime = ularge.HighPart ) +#endif /* NONAMELESSSTRUCT */ + +#define TEN_MIL 10000000LL + +/* returns time remaining in seconds */ +long RPCSS_GetLazyTimeRemaining() +{ + SYSTEMTIME st_just_now; + FILETIME ft_jn, ft_ltt; + ULARGE_INTEGER ul_jn, ul_ltt; + + GetSystemTime(&st_just_now); + SystemTimeToFileTime(&st_just_now, &ft_jn); + FILETIME_TO_ULARGEINT(ft_jn, ul_jn); + + SystemTimeToFileTime(&lazy_timeout_time, &ft_ltt); + FILETIME_TO_ULARGEINT(ft_ltt, ul_ltt); + + if (ul_jn.QuadPart > ul_ltt.QuadPart) + return 0; + else + return (ul_ltt.QuadPart - ul_jn.QuadPart) / TEN_MIL; +} + +void RPCSS_SetLazyTimeRemaining(long seconds) +{ + SYSTEMTIME st_just_now; + FILETIME ft_jn, ft_ltt; + ULARGE_INTEGER ul_jn, ul_ltt; + + WINE_TRACE("(seconds == %ld)\n", seconds); + + assert(seconds >= 0); /* negatives are not allowed */ + + GetSystemTime(&st_just_now); + SystemTimeToFileTime(&st_just_now, &ft_jn); + FILETIME_TO_ULARGEINT(ft_jn, ul_jn); + + /* we want to find the time ltt, s.t. ltt = just_now + seconds */ + ul_ltt.QuadPart = ul_jn.QuadPart + seconds * TEN_MIL; + + /* great. just remember it */ + ULARGEINT_TO_FILETIME(ul_ltt, ft_ltt); + if (! FileTimeToSystemTime(&ft_ltt, &lazy_timeout_time)) + assert(FALSE); +} + +#undef FILETIME_TO_ULARGEINT +#undef ULARGEINT_TO_FILETIME +#undef TEN_MIL + +BOOL RPCSS_work() +{ + return RPCSS_NPDoWork(); +} + +BOOL RPCSS_Empty() +{ + BOOL rslt = TRUE; + + rslt = RPCSS_EpmapEmpty(); + + return rslt; +} + +BOOL RPCSS_ReadyToDie() +{ + long ltr = RPCSS_GetLazyTimeRemaining(); + LONG stc = RPCSS_SrvThreadCount(); + BOOL empty = RPCSS_Empty(); + #ifndef RPC_AVOID_EXCESSIVE_TRACING + WINE_TRACE("\n Empty: %s\n LazyTimeRemaining: %ld\n SrvThreadCount: %ld\n", + empty ? "TRUE" : "FALSE", ltr, stc); + #endif + return ( empty && (ltr <= 0) && (stc == 0) ); +} + +BOOL RPCSS_Initialize() +{ + WINE_TRACE("\n"); + + if (!RPC_GetMasterMutex()) { + WINE_ERR("failed to acquire master mutex: exiting.\n"); + return FALSE; + } + + if (!RPCSS_BecomePipeServer()) { + WINE_WARN("server already running: exiting.\n"); + + if (!RPC_ReleaseMasterMutex()) + WINE_WARN("failed to release master mutex\n"); + + return FALSE; + } + + return TRUE; +} + +/* returns false if we discover at the last moment that we + aren't ready to terminate */ +BOOL RPCSS_Shutdown() +{ + if (!RPCSS_UnBecomePipeServer()) + return FALSE; + + if (!RPC_ReleaseMasterMutex()) + WINE_WARN("failed to release master mutex\n"); + + return TRUE; +} + +void RPCSS_MainLoop() +{ + BOOL did_something_new; + + WINE_TRACE("\n"); + + for (;;) { + did_something_new = FALSE; + + while ( (! did_something_new) && (! RPCSS_ReadyToDie()) ) + did_something_new = (RPCSS_work() || did_something_new); + + if ((! did_something_new) && RPCSS_ReadyToDie()) + break; /* that's it for us */ + + if (did_something_new) + RPCSS_SetLazyTimeRemaining(RPCSS_LAZY_TIMEOUT); + } +} + +BOOL RPCSS_ProcessArgs( int argc, char **argv ) +{ + int i; + char *c; + + for (i = 1; i < argc; i++) { + c = argv[i]; + while (*c == ' ') c++; + if ((*c != '-') && (*c != '/')) + return FALSE; + c++; + switch (*c++) { + #ifdef RPCSS_CAN_FORK + case 'd': + case 'D': + secret_fork_parent = TRUE; + break; + case '^': + /* "secret" hidden command-line arg means we are the "fork child" */ + secret_fork_child = TRUE; + break; + #endif + default: + return FALSE; + break; + } + while (*c == ' ') c++; + if (*c != '\0') return FALSE; + } + + return TRUE; +} + +void RPCSS_Usage() +{ + printf("\nWine RPCSS\n"); + printf("\nsyntax: rpcss"); + printf("\n\n"); +} + +#ifdef RPCSS_CAN_FORK +void RPCSS_Spork() +{ + /* Because we are a wine app, we can't fork. This is + a trick to invoke ourselves, so we can provide a + similar effect of creating a "background" process */ + + PROCESS_INFORMATION pi; + STARTUPINFO si; + char *oldcmdline, *newcmdline; + + /* create a string to invoke ourselves */ + oldcmdline = GetCommandLineA(); + newcmdline = LocalAlloc(LPTR, strlen(oldcmdline) + 10); /* more than enough */ + assert(newcmdline); /* must succeed */ + + sprintf(newcmdline, "%s /^", oldcmdline); + + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + + if (!CreateProcess( + NULL, /* executable */ + newcmdline, /* command line */ + NULL, /* process security attributes */ + NULL, /* primary thread security attributes */ + FALSE, /* no inherit handles */ + 0, /* creation flags */ + NULL, /* use parent's environment */ + NULL, /* use parent's current directory */ + &si, /* STARTUPINFO pointer */ + &pi /* PROCESS_INFORMATION */ + )) + assert(FALSE); + + LocalFree(newcmdline); +} +#endif + +int main( int argc, char **argv ) +{ + /* + * We are invoked as a standard executable; we act in a + * "lazy" manner. We open up our pipe, and hang around until we have + * nothing left to do, and then silently terminate. When we're needed + * again, rpcrt4.dll.so will invoke us automatically. + */ + + if (!RPCSS_ProcessArgs(argc, argv)) { + RPCSS_Usage(); + return 1; + } + + #ifdef RPCSS_CAN_FORK + if (secret_fork_parent) { + if (secret_fork_child) + FreeConsole(); + else { + /* pseudo-fork */ + RPCSS_Spork(); + return 0; + } + } else if (secret_fork_child) { + /* this should never happen... perhaps they typed /^ on cmd line */ + RPCSS_Usage(); + return 2; + } + #endif + + /* we want to wait for something to happen, and then + timeout when no activity occurs. */ + RPCSS_SetLazyTimeRemaining(RPCSS_LAZY_TIMEOUT); + + if (RPCSS_Initialize()) { + do + RPCSS_MainLoop(); + while (!RPCSS_Shutdown()); + } + + return 0; +}