msi/tests: Fixed a typo.
[wine.git] / programs / rpcss / rpcss_main.c
blobb8739a4a7bb7ea99c3c2ccbfa747776dfc16dba2
1 /*
2 * Copyright 2001, Ove Kåven, TransGaming Technologies Inc.
3 * Copyright 2002 Greg Turner
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 * ---- rpcss_main.c:
20 * Initialize and start serving requests. Bail if rpcss already is
21 * running.
23 * ---- RPCSS.EXE:
25 * Wine needs a server whose role is somewhat like that
26 * of rpcss.exe in windows. This is not a clone of
27 * windows rpcss at all. It has been given the same name, however,
28 * to provide for the possibility that at some point in the future,
29 * it may become interface compatible with the "real" rpcss.exe on
30 * Windows.
32 * ---- KNOWN BUGS / TODO:
34 * o Service hooks are unimplemented (if you bother to implement
35 * these, also implement net.exe, at least for "net start" and
36 * "net stop" (should be pretty easy I guess, assuming the rest
37 * of the services API infrastructure works.
39 * o Is supposed to use RPC, not random kludges, to map endpoints.
41 * o Probably name services should be implemented here as well.
43 * o Wine's named pipes (in general) may not interoperate with those of
44 * Windows yet (?)
46 * o There is a looming problem regarding listening on privileged
47 * ports. We will need to be able to coexist with SAMBA, and be able
48 * to function without running winelib code as root. This may
49 * take some doing, including significant reconceptualization of the
50 * role of rpcss.exe in wine.
52 * o Who knows? Whatever rpcss does, we ought to at
53 * least think about doing... but what /does/ it do?
56 #include <stdio.h>
57 #include <limits.h>
58 #include <assert.h>
60 #define NONAMELESSUNION
61 #define NONAMELESSSTRUCT
62 #include "rpcss.h"
63 #include "winnt.h"
65 #include "wine/debug.h"
67 WINE_DEFAULT_DEBUG_CHANNEL(ole);
69 static HANDLE master_mutex;
70 static long max_lazy_timeout = RPCSS_DEFAULT_MAX_LAZY_TIMEOUT;
72 HANDLE RPCSS_GetMasterMutex(void)
74 return master_mutex;
77 void RPCSS_SetMaxLazyTimeout(long mlt)
79 /* FIXME: this max ensures that no caller will decrease our wait time,
80 but could have other bad results. fix: Store "next_max_lazy_timeout"
81 and install it as necessary next time we "do work"? */
82 max_lazy_timeout = max(RPCSS_GetLazyTimeRemaining(), mlt);
85 long RPCSS_GetMaxLazyTimeout(void)
87 return max_lazy_timeout;
90 /* when do we just give up and bail? (UTC) */
91 static SYSTEMTIME lazy_timeout_time;
93 #if defined(NONAMELESSSTRUCT)
94 # define FILETIME_TO_ULARGEINT(filetime, ularge) \
95 ( ularge.u.LowPart = filetime.dwLowDateTime, \
96 ularge.u.HighPart = filetime.dwHighDateTime )
97 # define ULARGEINT_TO_FILETIME(ularge, filetime) \
98 ( filetime.dwLowDateTime = ularge.u.LowPart, \
99 filetime.dwHighDateTime = ularge.u.HighPart )
100 #else
101 # define FILETIME_TO_ULARGEINT(filetime, ularge) \
102 ( ularge.LowPart = filetime.dwLowDateTime, \
103 ularge.HighPart = filetime.dwHighDateTime )
104 # define ULARGEINT_TO_FILETIME(ularge, filetime) \
105 ( filetime.dwLowDateTime = ularge.LowPart, \
106 filetime.dwHighDateTime = ularge.HighPart )
107 #endif /* NONAMELESSSTRUCT */
109 #define TEN_MIL ((ULONGLONG)10000000)
111 /* returns time remaining in seconds */
112 long RPCSS_GetLazyTimeRemaining(void)
114 SYSTEMTIME st_just_now;
115 FILETIME ft_jn, ft_ltt;
116 ULARGE_INTEGER ul_jn, ul_ltt;
118 GetSystemTime(&st_just_now);
119 SystemTimeToFileTime(&st_just_now, &ft_jn);
120 FILETIME_TO_ULARGEINT(ft_jn, ul_jn);
122 SystemTimeToFileTime(&lazy_timeout_time, &ft_ltt);
123 FILETIME_TO_ULARGEINT(ft_ltt, ul_ltt);
125 if (ul_jn.QuadPart > ul_ltt.QuadPart)
126 return 0;
127 else
128 return (ul_ltt.QuadPart - ul_jn.QuadPart) / TEN_MIL;
131 void RPCSS_SetLazyTimeRemaining(long seconds)
133 SYSTEMTIME st_just_now;
134 FILETIME ft_jn, ft_ltt;
135 ULARGE_INTEGER ul_jn, ul_ltt;
137 WINE_TRACE("(seconds == %ld)\n", seconds);
139 assert(seconds >= 0); /* negatives are not allowed */
141 GetSystemTime(&st_just_now);
142 SystemTimeToFileTime(&st_just_now, &ft_jn);
143 FILETIME_TO_ULARGEINT(ft_jn, ul_jn);
145 /* we want to find the time ltt, s.t. ltt = just_now + seconds */
146 ul_ltt.QuadPart = ul_jn.QuadPart + seconds * TEN_MIL;
148 /* great. just remember it */
149 ULARGEINT_TO_FILETIME(ul_ltt, ft_ltt);
150 if (! FileTimeToSystemTime(&ft_ltt, &lazy_timeout_time))
151 assert(FALSE);
154 #undef FILETIME_TO_ULARGEINT
155 #undef ULARGEINT_TO_FILETIME
156 #undef TEN_MIL
158 static BOOL RPCSS_work(void)
160 return RPCSS_NPDoWork();
163 static BOOL RPCSS_Empty(void)
165 BOOL rslt = TRUE;
167 rslt = RPCSS_EpmapEmpty();
169 return rslt;
172 BOOL RPCSS_ReadyToDie(void)
174 long ltr = RPCSS_GetLazyTimeRemaining();
175 LONG stc = RPCSS_SrvThreadCount();
176 BOOL empty = RPCSS_Empty();
177 return ( empty && (ltr <= 0) && (stc == 0) );
180 static BOOL RPCSS_Initialize(void)
182 WINE_TRACE("\n");
184 master_mutex = CreateMutexA( NULL, FALSE, RPCSS_MASTER_MUTEX_NAME);
185 if (!master_mutex) {
186 WINE_ERR("Failed to create master mutex\n");
187 return FALSE;
190 if (!RPCSS_BecomePipeServer()) {
191 WINE_WARN("Server already running: exiting.\n");
193 CloseHandle(master_mutex);
194 master_mutex = NULL;
196 return FALSE;
199 return TRUE;
202 /* returns false if we discover at the last moment that we
203 aren't ready to terminate */
204 static BOOL RPCSS_Shutdown(void)
206 if (!RPCSS_UnBecomePipeServer())
207 return FALSE;
209 if (!CloseHandle(master_mutex))
210 WINE_WARN("Failed to release master mutex\n");
212 master_mutex = NULL;
214 return TRUE;
217 static void RPCSS_MainLoop(void)
219 BOOL did_something_new;
221 WINE_TRACE("\n");
223 for (;;) {
224 did_something_new = FALSE;
226 while ( (! did_something_new) && (! RPCSS_ReadyToDie()) )
227 did_something_new = (RPCSS_work() || did_something_new);
229 if ((! did_something_new) && RPCSS_ReadyToDie())
230 break; /* that's it for us */
232 if (did_something_new)
233 RPCSS_SetLazyTimeRemaining(max_lazy_timeout);
237 static BOOL RPCSS_ProcessArgs( int argc, char **argv )
239 int i;
240 char *c,*c1;
242 for (i = 1; i < argc; i++) {
243 c = argv[i];
244 while (*c == ' ') c++;
245 if ((*c != '-') && (*c != '/'))
246 return FALSE;
247 c++;
248 switch (*(c++)) {
249 case 't':
250 case 'T':
251 while (*c == ' ') c++;
252 if (*c == '\0') {
253 /* next arg */
254 if (++i >= argc)
255 return FALSE;
256 c = argv[i];
257 while (*c == ' ') c++;
258 if (c == '\0')
259 return FALSE;
260 } else
261 return FALSE;
262 max_lazy_timeout = strtol(c, &c1, 0);
263 if (c == c1)
264 return FALSE;
265 c = c1;
266 if (max_lazy_timeout <= 0)
267 return FALSE;
268 if (max_lazy_timeout == LONG_MAX)
269 return FALSE;
270 WINE_TRACE("read timeout argument: %ld\n", max_lazy_timeout);
271 break;
272 default:
273 return FALSE;
274 break;
276 while (*c == ' ') c++;
277 if (*c != '\0') return FALSE;
280 return TRUE;
283 static void RPCSS_Usage(void)
285 printf("\nWine RPCSS\n");
286 printf("\nsyntax: rpcss [-t timeout]\n\n");
287 printf(" -t: rpcss (or the running rpcss process) will\n");
288 printf(" execute with at least the specified timeout.\n");
289 printf("\n");
292 int main( int argc, char **argv )
295 * We are invoked as a standard executable; we act in a
296 * "lazy" manner. We open up our pipe, and hang around until we have
297 * nothing left to do, and then silently terminate. When we're needed
298 * again, rpcrt4.dll.so will invoke us automatically.
301 if (!RPCSS_ProcessArgs(argc, argv)) {
302 RPCSS_Usage();
303 return 1;
306 /* we want to wait for something to happen, and then
307 timeout when no activity occurs. */
308 RPCSS_SetLazyTimeRemaining(max_lazy_timeout);
310 if (RPCSS_Initialize()) {
312 RPCSS_MainLoop();
313 while (!RPCSS_Shutdown());
316 return 0;