This one implements "pseudo-fork" behavior, a main workhorse loop,
pseudo-debug log emitter, and command-line interpretation. In
particular I'm looking for comments/criticism/flames/etc for:
o my handling of NO_NAMELESS_STRUCT... works for me, but
how correct will this be, say, under MSVC with Microsoft
headers?
o I differentiate between "server mode" and "lazy mode"...
In lazy mode I assume that I'll have at least one incoming
connection (if not I time out after 20 minutes); after that,
once all endpoints are unmapped (all RPC-specific code
is unimplmented, but this is what RPCSS_empty() is supposed
to detect) I time out after a short delay (20 sec.)
In server mode, I just wait around forever until I'm told to
terminate (unimplemented, will be a command-line arg in the
tradition of "wineserver -k", processed via the pipe)...
reasonable?
o Pseudo-debug log emitter: should I be using stderr? is this
basically an OK approach? What is the hex number that
most real wine debug logs begin with? I'd like to look the
same.
o Make/autoconf BS
o the pseudo-fork crud (RPCSS_spork() and the /^ cmd-line arg.)
should I be worried about accidentally invoking the real
rpcss.exe? is this an unacceptably stupid approach in general?
thanks for your help.
diff -ur -x CVS -x 'bigdif*' ../wine.test/configure.ac ./configure.ac
--- ../wine.test/configure.ac 2002-11-03 11:50:15.000000000 -0600
+++ ./configure.ac 2002-11-01 18:53:32.000000000 -0600
@@ -1501,6 +1501,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/programs/Makefile.in ./programs/Makefile.in
--- ../wine.test/programs/Makefile.in 2002-11-03 11:50:15.000000000 -0600
+++ ./programs/Makefile.in 2002-11-01 18:53:18.000000000 -0600
@@ -17,6 +17,7 @@
regedit \
regsvr32 \
regtest \
+ rpcss \
uninstaller \
view \
wcmd \
@@ -39,6 +40,7 @@
progman \
regedit \
regsvr32 \
+ rpcss \
uninstaller \
wcmd \
wineconsole \
@@ -56,6 +58,7 @@
progman \
regedit \
regsvr32 \
+ rpcss \
uninstaller \
wcmd \
wineconsole \
@@ -67,6 +70,7 @@
# Symlinks to apps that we want to run from inside the source tree
SYMLINKS = \
+ rpcss.exe \
wineconsole.exe \
winedbg.exe
@@ -115,12 +119,16 @@
# 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) $@
winedbg.exe$(DLLEXT): winedbg/winedbg.exe$(DLLEXT)
$(RM) $@ && $(LN_S) winedbg/winedbg.exe$(DLLEXT) $@
+rpcss/rpcss.exe$(DLLEXT): rpcss
wineconsole/wineconsole.exe$(DLLEXT): wineconsole
winedbg/winedbg.exe$(DLLEXT): winedbg
--- /dev/null 1969-12-31 18:00:00.000000000 -0600
+++ ./programs/rpcss/Makefile.in 2002-11-03 18:51:44.000000000 -0600
@@ -0,0 +1,15 @@
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR = @srcdir@
+VPATH = @srcdir@
+MODULE = rpcss.exe
+APPMODE = cui
+IMPORTS = user32 kernel32
+
+C_SRCS = \
+ rpcss_main.c
+
+@MAKE_PROG_RULES@
+
+### Dependencies:
+
--- /dev/null 1969-12-31 18:00:00.000000000 -0600
+++ ./programs/rpcss/README 2002-11-03 18:52:12.000000000 -0600
@@ -0,0 +1,23 @@
+rpcss README
+
+rpcss, copyright 2002, Greg Turner
+rpcss is to be distributed under the LGPL/X11-MIT licenses
+See the Wine License for further information.
+
+Wine needs a server whose role is somewhat like that
+of rpcss.exe in 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 Who knows? Whatever (sane) things rpcss does, we ought to at
+ least think about doing... but what /does/ it do?
--- /dev/null 1969-12-31 18:00:00.000000000 -0600
+++ ./programs/rpcss/rpcss.h 2002-11-03 18:50:26.000000000 -0600
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2002 Greg Turner <gmturner007(a)ameritech.net>
+ *
+ * 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
+ */
+
+#ifndef __WINE_RPCSS_H
+#define __WINE_RPCSS_H
+
+#include <stdio.h>
+
+#include "windows.h"
+
+/* yet another crude debug logger substitute (just what wine needed!) */
+#define RPCSS_DEBUG(args...) \
+ do { \
+ if (in_debug_mode) {\
+ printf("rpcss.exe.so:%s: ", __FUNCTION__); \
+ printf(args); \
+ } \
+ } while (FALSE)
+
+extern BOOL in_debug_mode;
+
+extern BOOL RPCSS_is_server();
+extern void RPCSS_be_server();
+extern void RPCSS_server_terminate();
+
+#endif /* __WINE_RPCSS_H */
+
+/* end of header */
--- /dev/null 1969-12-31 18:00:00.000000000 -0600
+++ ./programs/rpcss/rpcss_main.c 2002-11-04 01:16:29.000000000 -0600
@@ -0,0 +1,308 @@
+/*
+ * rpcss (main.c)
+ *
+ * Copyright 2002 Greg Turner <gmturner007(a)ameritech.net>
+ *
+ * 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
+ */
+
+#include <assert.h>
+
+#include "rpcss.h"
+#include "winnt.h"
+
+/* in seconds */
+#define RPCSS_LONG_LAZY_TIMEOUT 1200
+#define RPCSS_SHORT_LAZY_TIMEOUT 20
+
+/* are we the "fork child"? */
+static BOOL secret_fork_child;
+
+/* do we dump debug info to the console? */
+static BOOL in_debug_mode;
+
+/* are we in server mode, with no timeout? */
+static BOOL in_server_mode;
+
+/* was server mode terminated? */
+static BOOL server_mode_was_terminated;
+
+/* 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, \
+ ularge ) /* r-value */
+ #define ULARGEINT_TO_FILETIME(ularge, filetime) \
+ ( filetime.dwLowDateTime = ularge.s.LowPart, \
+ filetime.dwHighDateTime = ularge.s.HighPart, \
+ filetime ) /* r-value */
+#else
+ #define FILETIME_TO_ULARGEINT(filetime, ularge) \
+ ( ularge.LowPart = filetime.dwLowDateTime, \
+ ularge.HighPart = filetime.dwHighDateTime, \
+ ularge ) /* r-value */
+ #define ULARGEINT_TO_FILETIME(ularge, filetime) \
+ ( filetime.dwLowDateTime = ularge.LowPart, \
+ filetime.dwHighDateTime = ularge.HighPart, \
+ filetime ) /* r-value */
+#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;
+
+ assert(! in_server_mode); /* then why are you calling? */
+
+ 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);
+
+ 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;
+
+ RPCSS_DEBUG("(seconds == %ld)\n", seconds);
+
+ assert(! in_server_mode); /* then why are you calling? */
+ 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_is_server()
+{
+ return in_server_mode;
+}
+
+void RPCSS_be_server()
+{
+ RPCSS_DEBUG("\n");
+ in_server_mode = TRUE;
+}
+
+void RPCSS_server_terminate()
+{
+ assert(in_server_mode);
+ server_mode_was_terminated = TRUE;
+}
+
+BOOL RPCSS_work()
+{
+ RPCSS_DEBUG("\n");
+ Sleep(1000);
+ return FALSE; /* we didn't do anything */
+}
+
+BOOL RPCSS_empty()
+{
+ BOOL rslt = TRUE;
+
+ /* FIXME */
+
+ RPCSS_DEBUG("%s\n", rslt ? "TRUE" : "FALSE" );
+ return rslt;
+}
+
+BOOL RPCSS_is_ready_to_die()
+{
+ return
+ (
+ RPCSS_empty() &&
+ (
+ (in_server_mode && server_mode_was_terminated) ||
+ (
+ (! in_server_mode) &&
+ (RPCSS_GetLazyTimeRemaining() <= 0)
+ )
+ )
+ );
+}
+
+void RPCSS_main_loop() {
+ BOOL did_something_new;
+
+ RPCSS_DEBUG("\n");
+
+ for (;;) {
+ did_something_new = FALSE;
+
+ while ( (! did_something_new) && (! RPCSS_is_ready_to_die()) )
+ did_something_new = (RPCSS_work() || did_something_new);
+
+ if ((! did_something_new) && RPCSS_is_ready_to_die())
+ break; /* that's it for us */
+
+ if (did_something_new) {
+ /* if we were in server mode, but terminated, then,
+ because we did something new, fall back to lazy mode */
+ if (in_server_mode && server_mode_was_terminated)
+ in_server_mode = server_mode_was_terminated = FALSE;
+
+ /* if we aren't in server mode, set the lazy timeout */
+ if (! in_server_mode)
+ RPCSS_SetLazyTimeRemaining(RPCSS_SHORT_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++) {
+ case 's':
+ case 'S':
+ in_server_mode = TRUE;
+ break;
+ case 'd':
+ case 'D':
+ in_debug_mode = TRUE;
+ break;
+ case '^':
+ /* "secret" hidden command-line arg means we are the "fork child" */
+ secret_fork_child = TRUE;
+ break;
+ default:
+ return FALSE;
+ break;
+ }
+ while (*c == ' ') c++;
+ if (*c != '\0') return FALSE;
+ }
+
+ return TRUE;
+}
+
+void RPCSS_Usage()
+{
+ printf("\nWine RPCSS\n");
+ printf("\nsyntax: rpcss [/d] [/s]\n\n");
+ printf(" /d: debug mode (print debug messages to std. output)\n");
+ printf(" /s: server mode (don't time out)\n\n");
+}
+
+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);
+}
+
+int main( int argc, char **argv )
+{
+ /*
+ * We are invoked as a standard executable; typically, 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;
+ }
+
+ if (! in_debug_mode) {
+ if (secret_fork_child)
+ FreeConsole();
+ else {
+ /* pseudo-fork */
+ RPCSS_Spork();
+ return 0;
+ }
+ } else if (secret_fork_child) {
+ /* this should never happen... perhaps they typed /d /^ on cmd line */
+ RPCSS_Usage();
+ return 2;
+ }
+
+ if (! in_server_mode)
+ /* we want to wait for something to happen, and then
+ timeout when no activity occurs... but we will be
+ extra patient on the first wait */
+ RPCSS_SetLazyTimeRemaining(RPCSS_LONG_LAZY_TIMEOUT);
+
+ RPCSS_main_loop();
+
+ return 0;
+}
--
gmt
"The purpose of government is to rein in the rights of the people"
--President Bill Clinton, MTV interview, 1993