windows-registry-20051214
[openafs.git] / src / WINNT / afsd / cm_daemon.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #ifndef DJGPP
14 #include <windows.h>
15 #include <winsock2.h>
16 #include <iphlpapi.h>
17 #else
18 #include <netdb.h>
19 #endif /* !DJGPP */
20 #include <stdlib.h>
21 #include <malloc.h>
22 #include <string.h>
23
24 #include <rx/rx.h>
25 #include <rx/rx_prototypes.h>
26 #include <WINNT/afsreg.h>
27
28 #include "afsd.h"
29 #include "afsicf.h"
30
31 /* in seconds */
32 long cm_daemonCheckDownInterval  = 180;
33 long cm_daemonCheckUpInterval    = 600;
34 long cm_daemonCheckVolInterval   = 3600;
35 long cm_daemonCheckCBInterval    = 60;
36 long cm_daemonCheckLockInterval  = 60;
37 long cm_daemonTokenCheckInterval = 180;
38
39 osi_rwlock_t cm_daemonLock;
40
41 long cm_bkgQueueCount;          /* # of queued requests */
42
43 int cm_bkgWaitingForCount;      /* true if someone's waiting for cm_bkgQueueCount to drop */
44
45 cm_bkgRequest_t *cm_bkgListp;           /* first elt in the list of requests */
46 cm_bkgRequest_t *cm_bkgListEndp;        /* last elt in the list of requests */
47
48 static int daemon_ShutdownFlag = 0;
49
50 #ifndef DJGPP
51 void cm_IpAddrDaemon(long parm)
52 {
53     rx_StartClientThread();
54
55     while (daemon_ShutdownFlag == 0) {
56         DWORD Result = NotifyAddrChange(NULL,NULL);
57         if (Result == NO_ERROR && daemon_ShutdownFlag == 0) {
58             osi_Log0(afsd_logp, "cm_IpAddrDaemon CheckDownServers");
59             Sleep(2500);
60             cm_CheckServers(CM_FLAG_CHECKDOWNSERVERS, NULL);
61         }
62     }
63 }
64 #endif
65
66 void cm_BkgDaemon(long parm)
67 {
68     cm_bkgRequest_t *rp;
69
70     rx_StartClientThread();
71
72     lock_ObtainWrite(&cm_daemonLock);
73     while (daemon_ShutdownFlag == 0) {
74         if (!cm_bkgListEndp) {
75             osi_SleepW((LONG_PTR)&cm_bkgListp, &cm_daemonLock);
76             lock_ObtainWrite(&cm_daemonLock);
77             continue;
78         }
79                 
80         /* we found a request */
81         rp = cm_bkgListEndp;
82         cm_bkgListEndp = (cm_bkgRequest_t *) osi_QPrev(&rp->q);
83         osi_QRemove((osi_queue_t **) &cm_bkgListp, &rp->q);
84         osi_assert(cm_bkgQueueCount-- > 0);
85         lock_ReleaseWrite(&cm_daemonLock);
86
87         (*rp->procp)(rp->scp, rp->p1, rp->p2, rp->p3, rp->p4, rp->userp);
88                 
89         cm_ReleaseUser(rp->userp);
90         cm_ReleaseSCache(rp->scp);
91         free(rp);
92
93         lock_ObtainWrite(&cm_daemonLock);
94     }
95     lock_ReleaseWrite(&cm_daemonLock);
96 }
97
98 void cm_QueueBKGRequest(cm_scache_t *scp, cm_bkgProc_t *procp, long p1, long p2, long p3, long p4,
99         cm_user_t *userp)
100 {
101     cm_bkgRequest_t *rp;
102         
103     rp = malloc(sizeof(*rp));
104     memset(rp, 0, sizeof(*rp));
105         
106     cm_HoldSCache(scp);
107     rp->scp = scp;
108     cm_HoldUser(userp);
109     rp->userp = userp;
110     rp->procp = procp;
111     rp->p1 = p1;
112     rp->p2 = p2;
113     rp->p3 = p3;
114     rp->p4 = p4;
115
116     lock_ObtainWrite(&cm_daemonLock);
117     cm_bkgQueueCount++;
118     osi_QAdd((osi_queue_t **) &cm_bkgListp, &rp->q);
119     if (!cm_bkgListEndp) 
120         cm_bkgListEndp = rp;
121     lock_ReleaseWrite(&cm_daemonLock);
122
123     osi_Wakeup((LONG_PTR) &cm_bkgListp);
124 }
125
126 static int
127 IsWindowsFirewallPresent(void)
128 {
129     SC_HANDLE scm;
130     SC_HANDLE svc;
131     BOOLEAN flag;
132     BOOLEAN result = FALSE;
133     LPQUERY_SERVICE_CONFIG pConfig = NULL;
134     DWORD BufSize;
135     LONG status;
136
137     /* Open services manager */
138     scm = OpenSCManager(NULL, NULL, GENERIC_READ);
139     if (!scm) return FALSE;
140
141     /* Open Windows Firewall service */
142     svc = OpenService(scm, "SharedAccess", SERVICE_QUERY_CONFIG);
143     if (!svc)
144         goto close_scm;
145
146     /* Query Windows Firewall service config, first just to get buffer size */
147     /* Expected to fail, so don't test return value */
148     (void) QueryServiceConfig(svc, NULL, 0, &BufSize);
149     status = GetLastError();
150     if (status != ERROR_INSUFFICIENT_BUFFER)
151         goto close_svc;
152
153     /* Allocate buffer */
154     pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED,BufSize);
155     if (!pConfig)
156         goto close_svc;
157
158     /* Query Windows Firewall service config, this time for real */
159     flag = QueryServiceConfig(svc, pConfig, BufSize, &BufSize);
160     if (!flag)
161         goto free_pConfig;
162
163     /* Is it autostart? */
164     if (pConfig->dwStartType < SERVICE_DEMAND_START)
165         result = TRUE;
166
167   free_pConfig:
168     GlobalFree(pConfig);
169   close_svc:
170     CloseServiceHandle(svc);
171   close_scm:
172     CloseServiceHandle(scm);
173
174     return result;
175 }
176
177 void
178 cm_DaemonCheckInit(void)
179 {
180     HKEY parmKey;
181     DWORD dummyLen;
182     DWORD dummy;
183     DWORD code;
184
185     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
186                          0, KEY_QUERY_VALUE, &parmKey);
187     if (code)
188         return;
189
190     dummyLen = sizeof(DWORD);
191     code = RegQueryValueEx(parmKey, "DownServerCheckInterval", NULL, NULL,
192                             (BYTE *) &dummy, &dummyLen);
193     if (code == ERROR_SUCCESS)
194         cm_daemonCheckDownInterval = dummy;
195     
196     dummyLen = sizeof(DWORD);
197     code = RegQueryValueEx(parmKey, "UpServerCheckInterval", NULL, NULL,
198                             (BYTE *) &dummy, &dummyLen);
199     if (code == ERROR_SUCCESS)
200         cm_daemonCheckUpInterval = dummy;
201     
202     dummyLen = sizeof(DWORD);
203     code = RegQueryValueEx(parmKey, "VolumeCheckInterval", NULL, NULL,
204                             (BYTE *) &dummy, &dummyLen);
205     if (code == ERROR_SUCCESS)
206         cm_daemonCheckVolInterval = dummy;
207     
208     dummyLen = sizeof(DWORD);
209     code = RegQueryValueEx(parmKey, "CallbackCheckInterval", NULL, NULL,
210                             (BYTE *) &dummy, &dummyLen);
211     if (code == ERROR_SUCCESS)
212         cm_daemonCheckCBInterval = dummy;
213     
214     dummyLen = sizeof(DWORD);
215     code = RegQueryValueEx(parmKey, "LockCheckInterval", NULL, NULL,
216                             (BYTE *) &dummy, &dummyLen);
217     if (code == ERROR_SUCCESS)
218         cm_daemonCheckLockInterval = dummy;
219     
220     dummyLen = sizeof(DWORD);
221     code = RegQueryValueEx(parmKey, "TokenCheckInterval", NULL, NULL,
222                             (BYTE *) &dummy, &dummyLen);
223     if (code == ERROR_SUCCESS)
224         cm_daemonTokenCheckInterval = dummy;
225     
226     RegCloseKey(parmKey);
227 }
228
229 /* periodic check daemon */
230 void cm_Daemon(long parm)
231 {
232     time_t now;
233     time_t lastLockCheck;
234     time_t lastVolCheck;
235     time_t lastCBExpirationCheck;
236     time_t lastDownServerCheck;
237     time_t lastUpServerCheck;
238     time_t lastTokenCacheCheck;
239     char thostName[200];
240     unsigned long code;
241     struct hostent *thp;
242     HMODULE hHookDll;
243     int configureFirewall = IsWindowsFirewallPresent();
244
245     /* ping all file servers, up or down, with unauthenticated connection,
246      * to find out whether we have all our callbacks from the server still.
247      * Also, ping down VLDBs.
248      */
249     /*
250      * Seed the random number generator with our own address, so that
251      * clients starting at the same time don't all do vol checks at the
252      * same time.
253      */
254     gethostname(thostName, sizeof(thostName));
255     thp = gethostbyname(thostName);
256     if (thp == NULL)    /* In djgpp, gethostname returns the netbios
257                            name of the machine.  gethostbyname will fail
258                            looking this up if it differs from DNS name. */
259         code = 0;
260     else
261         memcpy(&code, thp->h_addr_list[0], 4);
262     
263     srand(ntohl(code));
264
265     cm_DaemonCheckInit();
266
267     now = osi_Time();
268     lastVolCheck = now - cm_daemonCheckVolInterval/2 + (rand() % cm_daemonCheckVolInterval);
269     lastCBExpirationCheck = now - cm_daemonCheckCBInterval/2 + (rand() % cm_daemonCheckCBInterval);
270     lastLockCheck = now - cm_daemonCheckLockInterval/2 + (rand() % cm_daemonCheckLockInterval);
271     lastDownServerCheck = now - cm_daemonCheckDownInterval/2 + (rand() % cm_daemonCheckDownInterval);
272     lastUpServerCheck = now - cm_daemonCheckUpInterval/2 + (rand() % cm_daemonCheckUpInterval);
273     lastTokenCacheCheck = now - cm_daemonTokenCheckInterval/2 + (rand() % cm_daemonTokenCheckInterval);
274
275     while (daemon_ShutdownFlag == 0) {
276         thrd_Sleep(30 * 1000);          /* sleep 30 seconds */
277         if (daemon_ShutdownFlag == 1)
278             return;
279
280         if (configureFirewall) {
281             /* Open Microsoft Firewall to allow in port 7001 */
282             switch (icf_CheckAndAddAFSPorts(AFS_PORTSET_CLIENT)) {
283             case 0:
284                 afsi_log("Windows Firewall Configuration succeeded");
285                 configureFirewall = 0;
286                 break;
287             case 1:
288                 afsi_log("Invalid Windows Firewall Port Set");
289                 break;
290             case 2:
291                 afsi_log("Unable to open Windows Firewall Profile");
292                 break;
293             case 3:
294                 afsi_log("Unable to create/modify Windows Firewall Port entries");
295                 break;
296             default:
297                 afsi_log("Unknown Windows Firewall Configuration error");
298             }
299         }
300
301         /* find out what time it is */
302         now = osi_Time();
303
304         /* check down servers */
305         if (now > lastDownServerCheck + cm_daemonCheckDownInterval) {
306             lastDownServerCheck = now;
307             osi_Log0(afsd_logp, "cm_Daemon CheckDownServers");
308             cm_CheckServers(CM_FLAG_CHECKDOWNSERVERS, NULL);
309             now = osi_Time();
310         }
311
312         /* check up servers */
313         if (now > lastUpServerCheck + cm_daemonCheckUpInterval) {
314             lastUpServerCheck = now;
315             osi_Log0(afsd_logp, "cm_Daemon CheckUpServers");
316             cm_CheckServers(CM_FLAG_CHECKUPSERVERS, NULL);
317             now = osi_Time();
318         }
319
320         if (now > lastVolCheck + cm_daemonCheckVolInterval) {
321             lastVolCheck = now;
322             cm_CheckVolumes();
323             now = osi_Time();
324         }
325
326         if (now > lastCBExpirationCheck + cm_daemonCheckCBInterval) {
327             lastCBExpirationCheck = now;
328             cm_CheckCBExpiration();
329             now = osi_Time();
330         }
331
332         if (now > lastLockCheck + cm_daemonCheckLockInterval) {
333             lastLockCheck = now;
334             cm_CheckLocks();
335             now = osi_Time();
336         }
337
338         if (now > lastTokenCacheCheck + cm_daemonTokenCheckInterval) {
339             lastTokenCacheCheck = now;
340             cm_CheckTokenCache(now);
341             now = osi_Time();
342         }
343
344         /* allow an exit to be called prior to stopping the service */
345         hHookDll = LoadLibrary(AFSD_HOOK_DLL);
346         if (hHookDll)
347         {
348             BOOL hookRc = TRUE;
349             AfsdDaemonHook daemonHook = ( AfsdDaemonHook ) GetProcAddress(hHookDll, AFSD_DAEMON_HOOK);
350             if (daemonHook)
351             {
352                 hookRc = daemonHook();
353             }
354             FreeLibrary(hHookDll);
355             hHookDll = NULL;
356
357             if (hookRc == FALSE)
358             {
359                 SetEvent(WaitToTerminate);
360             }
361         }
362     }
363 }       
364
365 void cm_DaemonShutdown(void)
366 {
367     daemon_ShutdownFlag = 1;
368 }
369
370 void cm_InitDaemon(int nDaemons)
371 {
372     static osi_once_t once;
373     long pid;
374     thread_t phandle;
375     int i;
376         
377     if (osi_Once(&once)) {
378         lock_InitializeRWLock(&cm_daemonLock, "cm_daemonLock");
379         osi_EndOnce(&once);
380
381 #ifndef DJGPP
382         /* creating IP Address Change monitor daemon */
383         phandle = thrd_Create((SecurityAttrib) 0, 0,
384                                (ThreadFunc) cm_IpAddrDaemon, 0, 0, &pid, "cm_IpAddrDaemon");
385         osi_assert(phandle != NULL);
386         thrd_CloseHandle(phandle);
387 #endif /* DJGPP */
388
389         /* creating pinging daemon */
390         phandle = thrd_Create((SecurityAttrib) 0, 0,
391                                (ThreadFunc) cm_Daemon, 0, 0, &pid, "cm_Daemon");
392         osi_assert(phandle != NULL);
393         thrd_CloseHandle(phandle);
394
395         for(i=0; i < nDaemons; i++) {
396             phandle = thrd_Create((SecurityAttrib) 0, 0,
397                                    (ThreadFunc) cm_BkgDaemon, 0, 0, &pid,
398                                    "cm_BkgDaemon");
399             osi_assert(phandle != NULL);
400             thrd_CloseHandle(phandle);
401         }
402     }
403 }