RFC: rpcss skeleton prototype #2

Greg Turner gmturner007 at ameritech.net
Mon Nov 4 02:13:34 CST 2002


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
+
+ at 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 at 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 at 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




More information about the wine-devel mailing list