Fix miscellaneous spelling errors and typos.
[wine] / programs / rpcss / rpcss_main.c
1 /*
2  * Copyright 2001, Ove Kåven, TransGaming Technologies Inc.
3  * Copyright 2002 Greg Turner
4  *
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.
9  *
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.
14  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * ---- rpcss_main.c:
20  *   Initialize and start serving requests.  Bail if rpcss already is
21  *   running.
22  *
23  * ---- RPCSS.EXE:
24  *   
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.
31  *
32  * ---- KNOWN BUGS / TODO:
33  *
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.
38  * 
39  *   o Is supposed to use RPC, not random kludges, to map endpoints.
40  *
41  *   o Probably name services should be implemented here as well.
42  *
43  *   o Wine's named pipes (in general) may not interoperate with those of 
44  *     Windows yet (?)
45  *
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.
51  *
52  *   o Who knows?  Whatever rpcss does, we ought to at
53  *     least think about doing... but what /does/ it do?
54  */
55
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <limits.h>
59 #include <assert.h>
60
61 #define NONAMELESSUNION
62 #define NONAMELESSSTRUCT
63 #include "rpcss.h"
64 #include "winnt.h"
65
66 #include "wine/debug.h"
67
68 WINE_DEFAULT_DEBUG_CHANNEL(ole);
69
70 static HANDLE master_mutex;
71 static long max_lazy_timeout = RPCSS_DEFAULT_MAX_LAZY_TIMEOUT;
72
73 HANDLE RPCSS_GetMasterMutex(void)
74 {
75   return master_mutex;
76 }
77
78 void RPCSS_SetMaxLazyTimeout(long mlt)
79 {
80   /* FIXME: this max ensures that no caller will decrease our wait time,
81      but could have other bad results.  fix: Store "next_max_lazy_timeout" 
82      and install it as neccesary next time we "do work"? */
83   max_lazy_timeout = max(RPCSS_GetLazyTimeRemaining(), mlt);
84 }
85
86 long RPCSS_GetMaxLazyTimeout(void)
87 {
88   return max_lazy_timeout;
89 }
90
91 /* when do we just give up and bail? (UTC) */
92 static SYSTEMTIME lazy_timeout_time;
93
94 #if defined(NONAMELESSSTRUCT)
95   #define FILETIME_TO_ULARGEINT(filetime, ularge) \
96     ( ularge.s.LowPart = filetime.dwLowDateTime, \
97       ularge.s.HighPart = filetime.dwHighDateTime )
98   #define ULARGEINT_TO_FILETIME(ularge, filetime) \
99     ( filetime.dwLowDateTime = ularge.s.LowPart, \
100       filetime.dwHighDateTime = ularge.s.HighPart )
101 #else
102   #define FILETIME_TO_ULARGEINT(filetime, ularge) \
103     ( ularge.LowPart = filetime.dwLowDateTime, \
104       ularge.HighPart = filetime.dwHighDateTime )
105   #define ULARGEINT_TO_FILETIME(ularge, filetime) \
106     ( filetime.dwLowDateTime = ularge.LowPart, \
107       filetime.dwHighDateTime = ularge.HighPart )
108 #endif /* NONAMELESSSTRUCT */
109
110 #define TEN_MIL 10000000LL
111
112 /* returns time remaining in seconds */
113 long RPCSS_GetLazyTimeRemaining(void)
114 {
115   SYSTEMTIME st_just_now;
116   FILETIME ft_jn, ft_ltt;
117   ULARGE_INTEGER ul_jn, ul_ltt;
118
119   GetSystemTime(&st_just_now);
120   SystemTimeToFileTime(&st_just_now, &ft_jn);
121   FILETIME_TO_ULARGEINT(ft_jn, ul_jn);
122
123   SystemTimeToFileTime(&lazy_timeout_time, &ft_ltt);
124   FILETIME_TO_ULARGEINT(ft_ltt, ul_ltt);
125   
126   if (ul_jn.QuadPart > ul_ltt.QuadPart)
127     return 0;
128   else
129     return (ul_ltt.QuadPart - ul_jn.QuadPart) / TEN_MIL;
130 }
131
132 void RPCSS_SetLazyTimeRemaining(long seconds)
133 {
134   SYSTEMTIME st_just_now;
135   FILETIME ft_jn, ft_ltt;
136   ULARGE_INTEGER ul_jn, ul_ltt;
137
138   WINE_TRACE("(seconds == %ld)\n", seconds);
139
140   assert(seconds >= 0);     /* negatives are not allowed */
141   
142   GetSystemTime(&st_just_now);
143   SystemTimeToFileTime(&st_just_now, &ft_jn);
144   FILETIME_TO_ULARGEINT(ft_jn, ul_jn);
145
146   /* we want to find the time ltt, s.t. ltt = just_now + seconds */
147   ul_ltt.QuadPart = ul_jn.QuadPart + seconds * TEN_MIL;
148
149   /* great. just remember it */
150   ULARGEINT_TO_FILETIME(ul_ltt, ft_ltt);
151   if (! FileTimeToSystemTime(&ft_ltt, &lazy_timeout_time))
152     assert(FALSE);
153 }
154
155 #undef FILETIME_TO_ULARGEINT
156 #undef ULARGEINT_TO_FILETIME
157 #undef TEN_MIL
158
159 BOOL RPCSS_work(void)
160 {
161   return RPCSS_NPDoWork();
162 }
163
164 BOOL RPCSS_Empty(void)
165 {
166   BOOL rslt = TRUE;
167
168   rslt = RPCSS_EpmapEmpty();
169
170   return rslt;
171 }
172
173 BOOL RPCSS_ReadyToDie(void)
174 {
175   long ltr = RPCSS_GetLazyTimeRemaining();
176   LONG stc = RPCSS_SrvThreadCount();
177   BOOL empty = RPCSS_Empty();
178   return ( empty && (ltr <= 0) && (stc == 0) );
179 }
180
181 BOOL RPCSS_Initialize(void)
182 {
183   WINE_TRACE("\n");
184
185   master_mutex = CreateMutexA( NULL, FALSE, RPCSS_MASTER_MUTEX_NAME);
186   if (!master_mutex) {
187     WINE_ERR("Failed to create master mutex\n");
188     return FALSE;
189   }
190
191   if (!RPCSS_BecomePipeServer()) {
192     WINE_WARN("Server already running: exiting.\n");
193
194     CloseHandle(master_mutex);
195     master_mutex = NULL;
196
197     return FALSE;
198   }
199
200   return TRUE;
201 }
202
203 /* returns false if we discover at the last moment that we
204    aren't ready to terminate */
205 BOOL RPCSS_Shutdown(void)
206 {
207   if (!RPCSS_UnBecomePipeServer())
208     return FALSE;
209    
210   if (!CloseHandle(master_mutex))
211     WINE_WARN("Failed to release master mutex\n");
212
213   master_mutex = NULL;
214
215   return TRUE;
216 }
217
218 void RPCSS_MainLoop(void)
219 {
220   BOOL did_something_new;
221
222   WINE_TRACE("\n");
223
224   for (;;) {
225     did_something_new = FALSE;
226
227     while ( (! did_something_new) && (! RPCSS_ReadyToDie()) )
228       did_something_new = (RPCSS_work() || did_something_new);
229
230     if ((! did_something_new) && RPCSS_ReadyToDie())
231       break; /* that's it for us */
232
233     if (did_something_new)
234       RPCSS_SetLazyTimeRemaining(max_lazy_timeout);
235   }
236 }
237
238 BOOL RPCSS_ProcessArgs( int argc, char **argv )
239 {
240   int i;
241   char *c,*c1;
242
243   for (i = 1; i < argc; i++) {
244     c = argv[i];
245     while (*c == ' ') c++;
246     if ((*c != '-') && (*c != '/'))
247       return FALSE;
248     c++;
249     switch (*(c++)) {
250       case 't':
251       case 'T':
252         while (*c == ' ') c++;
253         if (*c == '\0')  {
254           /* next arg */
255           if (++i >= argc)
256             return FALSE;
257           c = argv[i];
258           while (*c == ' ') c++;
259           if (c == '\0')
260             return FALSE;
261         } else
262           return FALSE;
263         max_lazy_timeout = strtol(c, &c1, 0);
264         if (c == c1)
265           return FALSE;
266         c = c1;
267         if (max_lazy_timeout <= 0)
268           return FALSE;
269         if (max_lazy_timeout == LONG_MAX)
270           return FALSE;
271         WINE_TRACE("read timeout argument: %ld\n", max_lazy_timeout);
272         break;
273       default: 
274         return FALSE;
275         break;
276     }
277     while (*c == ' ') c++;
278     if (*c != '\0') return FALSE;
279   }
280
281   return TRUE;
282 }
283
284 void RPCSS_Usage(void)
285 {
286   printf("\nWine RPCSS\n");
287   printf("\nsyntax: rpcss [-t timeout]\n\n");
288   printf("  -t: rpcss (or the running rpcss process) will\n");
289   printf("      execute with at least the specified timeout.\n");
290   printf("\n");
291 }
292
293 int main( int argc, char **argv )
294 {
295   /* 
296    * We are invoked as a standard executable; we act in a
297    * "lazy" manner.  We open up our pipe, and hang around until we have
298    * nothing left to do, and then silently terminate.  When we're needed
299    * again, rpcrt4.dll.so will invoke us automatically.
300    */
301        
302   if (!RPCSS_ProcessArgs(argc, argv)) {
303     RPCSS_Usage();
304     return 1;
305   }
306       
307   /* we want to wait for something to happen, and then 
308      timeout when no activity occurs. */
309   RPCSS_SetLazyTimeRemaining(max_lazy_timeout);
310
311   if (RPCSS_Initialize()) {
312     do
313       RPCSS_MainLoop();
314     while (!RPCSS_Shutdown());
315   }
316
317   return 0;
318 }