the dreaded rpcss patch (rpc_J_PL0)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




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;
+}

[Index of Archives]     [Gimp for Windows]     [Red Hat]     [Samba]     [Yosemite Camping]     [Graphics Cards]     [Wine Home]

  Powered by Linux