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