Windows: convert daemons threads to pthreads
[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 <afsconfig.h>
11 #include <afs/param.h>
12 #include <roken.h>
13
14 #include <afs/stds.h>
15
16 #include <windows.h>
17 #include <winsock2.h>
18 #include <iphlpapi.h>
19 #include <stdlib.h>
20 #include <malloc.h>
21 #include <string.h>
22
23 #include "afsd.h"
24 #include "smb.h"
25
26 #include <rx/rx.h>
27 #include <rx/rx_prototypes.h>
28 #include <WINNT/afsreg.h>
29
30 #include "afsicf.h"
31
32 /* in seconds */
33 long cm_daemonCheckDownInterval  = 180;
34 long cm_daemonCheckUpInterval    = 240;
35 long cm_daemonCheckVolInterval   = 3600;
36 long cm_daemonCheckCBInterval    = 60;
37 long cm_daemonCheckVolCBInterval = 0;
38 long cm_daemonCheckLockInterval  = 60;
39 long cm_daemonTokenCheckInterval = 180;
40 long cm_daemonCheckOfflineVolInterval = 600;
41 long cm_daemonPerformanceTuningInterval = 0;
42 long cm_daemonRankServerInterval = 600;
43 long cm_daemonRDRShakeExtentsInterval = 0;
44
45 osi_rwlock_t cm_daemonLock;
46
47 long cm_bkgQueueCount;          /* # of queued requests */
48
49 int cm_bkgWaitingForCount;      /* true if someone's waiting for cm_bkgQueueCount to drop */
50
51 cm_bkgRequest_t *cm_bkgListp;           /* first elt in the list of requests */
52 cm_bkgRequest_t *cm_bkgListEndp;        /* last elt in the list of requests */
53
54 extern int powerStateSuspended;
55 int daemon_ShutdownFlag = 0;
56 static int cm_nDaemons = 0;
57 static time_t lastIPAddrChange = 0;
58
59 static EVENT_HANDLE cm_Daemon_ShutdownEvent = NULL;
60 static EVENT_HANDLE cm_LockDaemon_ShutdownEvent = NULL;
61 static EVENT_HANDLE cm_IPAddrDaemon_ShutdownEvent = NULL;
62 static EVENT_HANDLE cm_BkgDaemon_ShutdownEvent[CM_MAX_DAEMONS] =
63        {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
64
65 void * cm_IpAddrDaemon(void * vparm)
66 {
67     extern void smb_CheckVCs(void);
68     char * name = "cm_IPAddrDaemon_ShutdownEvent";
69
70     cm_IPAddrDaemon_ShutdownEvent = thrd_CreateEvent(NULL, FALSE, FALSE, name);
71     if ( GetLastError() == ERROR_ALREADY_EXISTS )
72         afsi_log("Event Object Already Exists: %s", name);
73
74     rx_StartClientThread();
75
76     while (daemon_ShutdownFlag == 0) {
77         DWORD Result;
78
79         thrd_SetEvent(cm_IPAddrDaemon_ShutdownEvent);
80         Result = NotifyAddrChange(NULL,NULL);
81         if (Result == NO_ERROR && daemon_ShutdownFlag == 0) {
82             lastIPAddrChange = osi_Time();
83             if (smb_Enabled)
84                 smb_SetLanAdapterChangeDetected();
85             cm_SetLanAdapterChangeDetected();
86             thrd_ResetEvent(cm_IPAddrDaemon_ShutdownEvent);
87         }
88     }
89
90     thrd_SetEvent(cm_IPAddrDaemon_ShutdownEvent);
91     pthread_exit(NULL);
92     return NULL;
93 }
94
95 afs_int32 cm_RequestWillBlock(cm_bkgRequest_t *rp)
96 {
97     afs_int32 willBlock = 0;
98
99     if (rp->procp == cm_BkgStore) {
100         /*
101          * If the datastoring flag is set, it means that another
102          * thread is already performing an exclusive store operation
103          * on this file.  The exclusive state will be cleared once
104          * the file server locks the vnode.  Therefore, at most two
105          * threads can be actively involved in storing data at a time
106          * on a file.
107          */
108         lock_ObtainRead(&rp->scp->rw);
109         willBlock = (rp->scp->flags & CM_SCACHEFLAG_DATASTORING);
110         lock_ReleaseRead(&rp->scp->rw);
111     }
112     else if (rp->procp == RDR_BkgFetch || rp->procp == cm_BkgPrefetch) {
113         /*
114          * Attempt to determine if there is a conflict on the requested
115          * range of the file.  If the first in the range does not exist
116          * in the cache assume there is no conflict.  If the buffer does
117          * exist, check to see if an I/O operation is in progress
118          * by using the writing and reading flags as an indicator.
119          */
120         osi_hyper_t base;
121         cm_buf_t *bufp = NULL;
122
123         base.LowPart = rp->p1;
124         base.HighPart = rp->p2;
125
126         bufp = buf_Find(&rp->scp->fid, &base);
127         if (bufp) {
128             willBlock = (bufp->flags & (CM_BUF_WRITING|CM_BUF_READING));
129             buf_Release(bufp);
130         }
131     }
132
133     return willBlock;
134 }
135
136 void * cm_BkgDaemon(void * vparm)
137 {
138     cm_bkgRequest_t *rp;
139     afs_int32 code;
140     char name[32] = "";
141     long daemonID = (long)(LONG_PTR)vparm;
142
143     snprintf(name, sizeof(name), "cm_BkgDaemon_ShutdownEvent%u", daemonID);
144
145     cm_BkgDaemon_ShutdownEvent[daemonID] = thrd_CreateEvent(NULL, FALSE, FALSE, name);
146     if ( GetLastError() == ERROR_ALREADY_EXISTS )
147         afsi_log("Event Object Already Exists: %s", name);
148
149     rx_StartClientThread();
150
151     lock_ObtainWrite(&cm_daemonLock);
152     while (daemon_ShutdownFlag == 0) {
153         int willBlock = 0;
154
155         if (powerStateSuspended) {
156             Sleep(1000);
157             continue;
158         }
159         if (!cm_bkgListEndp) {
160             osi_SleepW((LONG_PTR)&cm_bkgListp, &cm_daemonLock);
161             lock_ObtainWrite(&cm_daemonLock);
162             continue;
163         }
164
165         /* we found a request */
166         for (rp = cm_bkgListEndp; rp; rp = (cm_bkgRequest_t *) osi_QPrev(&rp->q))
167         {
168             if (rp->scp->flags & CM_SCACHEFLAG_DELETED)
169                 break;
170
171             /*
172              * If the request has active I/O such that this worker would
173              * be forced to block, leave the request in the queue and move
174              * on to one that might be available for servicing.
175              */
176             if (cm_RequestWillBlock(rp)) {
177                 willBlock++;
178                 continue;
179             }
180
181             if (cm_ServerAvailable(&rp->scp->fid, rp->userp))
182                 break;
183         }
184
185         if (rp == NULL) {
186             /*
187              * Couldn't find a request that we could process at the
188              * current time.  If there were requests that would cause
189              * the worker to block, sleep for 25ms so it can promptly
190              * respond when it is available.  Otherwise, sleep for 1s.
191              *
192              * This polling cycle needs to be replaced with a proper
193              * producer/consumer dynamic worker pool.
194              */
195             lock_ReleaseWrite(&cm_daemonLock);
196             Sleep(willBlock ? 25 : 1000);
197             lock_ObtainWrite(&cm_daemonLock);
198             continue;
199         }
200
201         osi_QRemoveHT((osi_queue_t **) &cm_bkgListp, (osi_queue_t **) &cm_bkgListEndp, &rp->q);
202         osi_assertx(cm_bkgQueueCount-- > 0, "cm_bkgQueueCount 0");
203         lock_ReleaseWrite(&cm_daemonLock);
204
205         osi_Log1(afsd_logp,"cm_BkgDaemon processing request 0x%p", rp);
206
207         if (rp->scp->flags & CM_SCACHEFLAG_DELETED) {
208             osi_Log1(afsd_logp,"cm_BkgDaemon DELETED scp 0x%x",rp->scp);
209             code = CM_ERROR_BADFD;
210         } else {
211 #ifdef DEBUG_REFCOUNT
212             osi_Log2(afsd_logp,"cm_BkgDaemon (before) scp 0x%x ref %d",rp->scp, rp->scp->refCount);
213 #endif
214             code = (*rp->procp)(rp->scp, rp->p1, rp->p2, rp->p3, rp->p4, rp->userp, &rp->req);
215 #ifdef DEBUG_REFCOUNT
216             osi_Log2(afsd_logp,"cm_BkgDaemon (after) scp 0x%x ref %d",rp->scp, rp->scp->refCount);
217 #endif
218         }
219
220         /*
221          * Keep the following list synchronized with the
222          * error code list in cm_BkgStore.
223          * cm_SyncOpDone(CM_SCACHESYNC_ASYNCSTORE) will be called there unless
224          * one of these errors has occurred.
225          */
226         switch ( code ) {
227         case CM_ERROR_TIMEDOUT: /* or server restarting */
228         case CM_ERROR_RETRY:
229         case CM_ERROR_WOULDBLOCK:
230         case CM_ERROR_ALLBUSY:
231         case CM_ERROR_ALLDOWN:
232         case CM_ERROR_ALLOFFLINE:
233         case CM_ERROR_PARTIALWRITE:
234             if (rp->procp == cm_BkgStore ||
235                 rp->procp == RDR_BkgFetch) {
236                 osi_Log2(afsd_logp,
237                          "cm_BkgDaemon re-queueing failed request 0x%p code 0x%x",
238                          rp, code);
239                 lock_ObtainWrite(&cm_daemonLock);
240                 cm_bkgQueueCount++;
241                 osi_QAddT((osi_queue_t **) &cm_bkgListp, (osi_queue_t **)&cm_bkgListEndp, &rp->q);
242                 break;
243             } /* otherwise fall through */
244         case 0:  /* success */
245         default: /* other error */
246             if (code == 0) {
247                 osi_Log1(afsd_logp,"cm_BkgDaemon SUCCESS: request 0x%p", rp);
248             } else {
249                 osi_Log2(afsd_logp,"cm_BkgDaemon FAILED: request dropped 0x%p code 0x%x",
250                          rp, code);
251             }
252             cm_ReleaseUser(rp->userp);
253             cm_ReleaseSCache(rp->scp);
254             free(rp);
255             lock_ObtainWrite(&cm_daemonLock);
256         }
257     }
258     lock_ReleaseWrite(&cm_daemonLock);
259     thrd_SetEvent(cm_BkgDaemon_ShutdownEvent[daemonID]);
260     pthread_exit(NULL);
261     return NULL;
262 }
263
264 void cm_QueueBKGRequest(cm_scache_t *scp, cm_bkgProc_t *procp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4,
265         cm_user_t *userp, cm_req_t *reqp)
266 {
267     cm_bkgRequest_t *rp;
268
269     rp = malloc(sizeof(*rp));
270     memset(rp, 0, sizeof(*rp));
271
272     cm_HoldSCache(scp);
273     rp->scp = scp;
274     cm_HoldUser(userp);
275     rp->userp = userp;
276     rp->procp = procp;
277     rp->p1 = p1;
278     rp->p2 = p2;
279     rp->p3 = p3;
280     rp->p4 = p4;
281     rp->req = *reqp;
282
283     lock_ObtainWrite(&cm_daemonLock);
284     cm_bkgQueueCount++;
285     osi_QAdd((osi_queue_t **) &cm_bkgListp, &rp->q);
286     if (!cm_bkgListEndp)
287         cm_bkgListEndp = rp;
288     lock_ReleaseWrite(&cm_daemonLock);
289
290     osi_Wakeup((LONG_PTR) &cm_bkgListp);
291 }
292
293 static int
294 IsWindowsFirewallPresent(void)
295 {
296     SC_HANDLE scm;
297     SC_HANDLE svc;
298     BOOLEAN flag;
299     BOOLEAN result = FALSE;
300     LPQUERY_SERVICE_CONFIG pConfig = NULL;
301     DWORD BufSize;
302     LONG status;
303
304     /* Open services manager */
305     scm = OpenSCManager(NULL, NULL, GENERIC_READ);
306     if (!scm) return FALSE;
307
308     /* Open Windows Firewall service */
309     svc = OpenService(scm, "MpsSvc", SERVICE_QUERY_CONFIG);
310     if (!svc) {
311         afsi_log("MpsSvc Service could not be opened for query: 0x%x", GetLastError());
312         svc = OpenService(scm, "SharedAccess", SERVICE_QUERY_CONFIG);
313         if (!svc)
314             afsi_log("SharedAccess Service could not be opened for query: 0x%x", GetLastError());
315     }
316     if (!svc)
317         goto close_scm;
318
319     /* Query Windows Firewall service config, first just to get buffer size */
320     /* Expected to fail, so don't test return value */
321     (void) QueryServiceConfig(svc, NULL, 0, &BufSize);
322     status = GetLastError();
323     if (status != ERROR_INSUFFICIENT_BUFFER)
324         goto close_svc;
325
326     /* Allocate buffer */
327     pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED,BufSize);
328     if (!pConfig)
329         goto close_svc;
330
331     /* Query Windows Firewall service config, this time for real */
332     flag = QueryServiceConfig(svc, pConfig, BufSize, &BufSize);
333     if (!flag) {
334         afsi_log("QueryServiceConfig failed: 0x%x", GetLastError());
335         goto free_pConfig;
336     }
337
338     /* Is it autostart? */
339     afsi_log("AutoStart 0x%x", pConfig->dwStartType);
340     if (pConfig->dwStartType < SERVICE_DEMAND_START)
341         result = TRUE;
342
343   free_pConfig:
344     GlobalFree(pConfig);
345   close_svc:
346     CloseServiceHandle(svc);
347   close_scm:
348     CloseServiceHandle(scm);
349
350     return result;
351 }
352
353 void
354 cm_DaemonCheckInit(void)
355 {
356     HKEY parmKey;
357     DWORD dummyLen;
358     DWORD dummy;
359     DWORD code;
360
361     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
362                          0, KEY_QUERY_VALUE, &parmKey);
363     if (code)
364         return;
365
366     dummyLen = sizeof(DWORD);
367     code = RegQueryValueEx(parmKey, "daemonCheckDownInterval", NULL, NULL,
368                             (BYTE *) &dummy, &dummyLen);
369     if (code == ERROR_SUCCESS && dummy)
370         cm_daemonCheckDownInterval = dummy;
371     afsi_log("daemonCheckDownInterval is %d", cm_daemonCheckDownInterval);
372
373     dummyLen = sizeof(DWORD);
374     code = RegQueryValueEx(parmKey, "daemonCheckUpInterval", NULL, NULL,
375                             (BYTE *) &dummy, &dummyLen);
376     if (code == ERROR_SUCCESS && dummy)
377         cm_daemonCheckUpInterval = dummy;
378     afsi_log("daemonCheckUpInterval is %d", cm_daemonCheckUpInterval);
379
380     dummyLen = sizeof(DWORD);
381     code = RegQueryValueEx(parmKey, "daemonCheckVolInterval", NULL, NULL,
382                             (BYTE *) &dummy, &dummyLen);
383     if (code == ERROR_SUCCESS && dummy)
384         cm_daemonCheckVolInterval = dummy;
385     afsi_log("daemonCheckVolInterval is %d", cm_daemonCheckVolInterval);
386
387     dummyLen = sizeof(DWORD);
388     code = RegQueryValueEx(parmKey, "daemonCheckCBInterval", NULL, NULL,
389                             (BYTE *) &dummy, &dummyLen);
390     if (code == ERROR_SUCCESS && dummy)
391         cm_daemonCheckCBInterval = dummy;
392     afsi_log("daemonCheckCBInterval is %d", cm_daemonCheckCBInterval);
393
394     dummyLen = sizeof(DWORD);
395     code = RegQueryValueEx(parmKey, "daemonCheckVolCBInterval", NULL, NULL,
396                             (BYTE *) &dummy, &dummyLen);
397     if (code == ERROR_SUCCESS && dummy)
398         cm_daemonCheckVolCBInterval = dummy;
399     afsi_log("daemonCheckVolCBInterval is %d", cm_daemonCheckVolCBInterval);
400
401     dummyLen = sizeof(DWORD);
402     code = RegQueryValueEx(parmKey, "daemonCheckLockInterval", NULL, NULL,
403                             (BYTE *) &dummy, &dummyLen);
404     if (code == ERROR_SUCCESS && dummy)
405         cm_daemonCheckLockInterval = dummy;
406     afsi_log("daemonCheckLockInterval is %d", cm_daemonCheckLockInterval);
407
408     dummyLen = sizeof(DWORD);
409     code = RegQueryValueEx(parmKey, "daemonCheckTokenInterval", NULL, NULL,
410                             (BYTE *) &dummy, &dummyLen);
411     if (code == ERROR_SUCCESS && dummy)
412         cm_daemonTokenCheckInterval = dummy;
413     afsi_log("daemonCheckTokenInterval is %d", cm_daemonTokenCheckInterval);
414
415     dummyLen = sizeof(DWORD);
416     code = RegQueryValueEx(parmKey, "daemonCheckOfflineVolInterval", NULL, NULL,
417                             (BYTE *) &dummy, &dummyLen);
418     if (code == ERROR_SUCCESS && dummy)
419         cm_daemonCheckOfflineVolInterval = dummy;
420     afsi_log("daemonCheckOfflineVolInterval is %d", cm_daemonCheckOfflineVolInterval);
421
422     dummyLen = sizeof(DWORD);
423     code = RegQueryValueEx(parmKey, "daemonRDRShakeExtentsInterval", NULL, NULL,
424                             (BYTE *) &dummy, &dummyLen);
425     if (code == ERROR_SUCCESS && dummy)
426         cm_daemonRDRShakeExtentsInterval = dummy;
427     afsi_log("daemonRDRShakeExtentsInterval is %d", cm_daemonRDRShakeExtentsInterval);
428
429     dummyLen = sizeof(DWORD);
430     code = RegQueryValueEx(parmKey, "daemonPerformanceTuningInterval", NULL, NULL,
431                             (BYTE *) &dummy, &dummyLen);
432     if (code == ERROR_SUCCESS)
433         cm_daemonPerformanceTuningInterval = dummy;
434     afsi_log("daemonPerformanceTuningInterval is %d", cm_daemonPerformanceTuningInterval);
435
436     dummyLen = sizeof(DWORD);
437     code = RegQueryValueEx(parmKey, "daemonRankServerInterval", NULL, NULL,
438                             (BYTE *) &dummy, &dummyLen);
439     if (code == ERROR_SUCCESS && dummy)
440         cm_daemonRankServerInterval = dummy;
441     afsi_log("daemonRankServerInterval is %d", cm_daemonRankServerInterval);
442
443     RegCloseKey(parmKey);
444
445     if (cm_daemonPerformanceTuningInterval)
446         cm_PerformanceTuningInit();
447 }
448
449 /* periodic lock check daemon */
450 void * cm_LockDaemon(void * vparm)
451 {
452     time_t now;
453     time_t lastLockCheck;
454     char * name = "cm_LockDaemon_ShutdownEvent";
455
456     cm_LockDaemon_ShutdownEvent = thrd_CreateEvent(NULL, FALSE, FALSE, name);
457     if ( GetLastError() == ERROR_ALREADY_EXISTS )
458         afsi_log("Event Object Already Exists: %s", name);
459
460     now = osi_Time();
461     lastLockCheck = now - cm_daemonCheckLockInterval/2 + (rand() % cm_daemonCheckLockInterval);
462
463     while (daemon_ShutdownFlag == 0) {
464         if (powerStateSuspended) {
465             Sleep(1000);
466             continue;
467         }
468
469         now = osi_Time();
470
471         if (now > lastLockCheck + cm_daemonCheckLockInterval &&
472             daemon_ShutdownFlag == 0 &&
473             powerStateSuspended == 0) {
474             lastLockCheck = now;
475             cm_CheckLocks();
476             if (daemon_ShutdownFlag == 1)
477                 break;
478         }
479
480         thrd_Sleep(1000);               /* sleep 1 second */
481     }
482     thrd_SetEvent(cm_LockDaemon_ShutdownEvent);
483     pthread_exit(NULL);
484     return NULL;
485 }
486
487 /* periodic check daemon */
488 void * cm_Daemon(void *vparm)
489 {
490     time_t now;
491     time_t lastVolCheck;
492     time_t lastCBExpirationCheck;
493     time_t lastVolCBRenewalCheck;
494     time_t lastDownServerCheck;
495     time_t lastUpServerCheck;
496     time_t lastTokenCacheCheck;
497     time_t lastBusyVolCheck;
498     time_t lastPerformanceCheck;
499     time_t lastServerRankCheck;
500     time_t lastRDRShakeExtents;
501     char thostName[200];
502     unsigned long code;
503     struct hostent *thp;
504     HMODULE hHookDll;
505     char * name = "cm_Daemon_ShutdownEvent";
506     int configureFirewall = IsWindowsFirewallPresent();
507     int bAddrChangeCheck = 0;
508
509     cm_Daemon_ShutdownEvent = thrd_CreateEvent(NULL, FALSE, FALSE, name);
510     if ( GetLastError() == ERROR_ALREADY_EXISTS )
511         afsi_log("Event Object Already Exists: %s", name);
512
513     if (!configureFirewall) {
514         afsi_log("No Windows Firewall detected");
515     }
516
517     if (cm_freelanceEnabled && cm_freelanceImportCellServDB)
518         cm_FreelanceImportCellServDB();
519
520     /* ping all file servers, up or down, with unauthenticated connection,
521      * to find out whether we have all our callbacks from the server still.
522      * Also, ping down VLDBs.
523      */
524     /*
525      * Seed the random number generator with our own address, so that
526      * clients starting at the same time don't all do vol checks at the
527      * same time.
528      */
529     gethostname(thostName, sizeof(thostName));
530     thp = gethostbyname(thostName);
531     if (thp == NULL)    /* In djgpp, gethostname returns the netbios
532                            name of the machine.  gethostbyname will fail
533                            looking this up if it differs from DNS name. */
534         code = 0;
535     else
536         memcpy(&code, thp->h_addr_list[0], 4);
537
538     srand(ntohl(code));
539
540     cm_DaemonCheckInit();
541
542     now = osi_Time();
543     lastVolCheck = now - cm_daemonCheckVolInterval/2 + (rand() % cm_daemonCheckVolInterval);
544     lastCBExpirationCheck = now - cm_daemonCheckCBInterval/2 + (rand() % cm_daemonCheckCBInterval);
545     if (cm_daemonCheckVolCBInterval)
546         lastVolCBRenewalCheck = now - cm_daemonCheckVolCBInterval/2 + (rand() % cm_daemonCheckVolCBInterval);
547     lastDownServerCheck = now - cm_daemonCheckDownInterval/2 + (rand() % cm_daemonCheckDownInterval);
548     lastUpServerCheck = now - cm_daemonCheckUpInterval/2 + (rand() % cm_daemonCheckUpInterval);
549     lastTokenCacheCheck = now - cm_daemonTokenCheckInterval/2 + (rand() % cm_daemonTokenCheckInterval);
550     if (cm_daemonCheckOfflineVolInterval)
551         lastBusyVolCheck = now - cm_daemonCheckOfflineVolInterval/2 * (rand() % cm_daemonCheckOfflineVolInterval);
552     if (cm_daemonPerformanceTuningInterval)
553         lastPerformanceCheck = now - cm_daemonPerformanceTuningInterval/2 * (rand() % cm_daemonPerformanceTuningInterval);
554     lastServerRankCheck = now - cm_daemonRankServerInterval/2 * (rand() % cm_daemonRankServerInterval);
555     if (cm_daemonRDRShakeExtentsInterval)
556         lastRDRShakeExtents = now - cm_daemonRDRShakeExtentsInterval/2 * (rand() % cm_daemonRDRShakeExtentsInterval);
557
558     while (daemon_ShutdownFlag == 0) {
559         if (powerStateSuspended) {
560             Sleep(1000);
561             continue;
562         }
563         /* check to see if the listener threads halted due to network
564          * disconnect or other issues.  If so, attempt to restart them.
565          */
566         smb_RestartListeners(0);
567
568         if (daemon_ShutdownFlag == 1)
569             break;
570
571         if (configureFirewall) {
572             /* Open Microsoft Firewall to allow in port 7001 */
573             switch (icf_CheckAndAddAFSPorts(AFS_PORTSET_CLIENT)) {
574             case 0:
575                 afsi_log("Windows Firewall Configuration succeeded");
576                 configureFirewall = 0;
577                 break;
578             case 1:
579                 afsi_log("Invalid Windows Firewall Port Set");
580                 break;
581             case 2:
582                 afsi_log("Unable to open Windows Firewall Profile");
583                 break;
584             case 3:
585                 afsi_log("Unable to create/modify Windows Firewall Port entries");
586                 break;
587             default:
588                 afsi_log("Unknown Windows Firewall Configuration error");
589             }
590         }
591
592         /* find out what time it is */
593         now = osi_Time();
594
595         /* Determine whether an address change took place that we need to respond to */
596         if (bAddrChangeCheck)
597             bAddrChangeCheck = 0;
598
599         if (lastIPAddrChange != 0 && lastIPAddrChange + 2500 < now) {
600             bAddrChangeCheck = 1;
601             lastIPAddrChange = 0;
602         }
603
604         /* check down servers */
605         if ((bAddrChangeCheck || now > lastDownServerCheck + cm_daemonCheckDownInterval) &&
606             daemon_ShutdownFlag == 0 &&
607             powerStateSuspended == 0) {
608             lastDownServerCheck = now;
609             osi_Log0(afsd_logp, "cm_Daemon CheckDownServers");
610             cm_CheckServers(CM_FLAG_CHECKDOWNSERVERS, NULL);
611             if (daemon_ShutdownFlag == 1)
612                 break;
613             now = osi_Time();
614         }
615
616         if (bAddrChangeCheck &&
617             daemon_ShutdownFlag == 0 &&
618             powerStateSuspended == 0) {
619             cm_ForceNewConnectionsAllServers();
620         }
621
622         /* check up servers */
623         if ((bAddrChangeCheck || now > lastUpServerCheck + cm_daemonCheckUpInterval) &&
624             daemon_ShutdownFlag == 0 &&
625             powerStateSuspended == 0) {
626             lastUpServerCheck = now;
627             osi_Log0(afsd_logp, "cm_Daemon CheckUpServers");
628             cm_CheckServers(CM_FLAG_CHECKUPSERVERS, NULL);
629             if (daemon_ShutdownFlag == 1)
630                 break;
631             now = osi_Time();
632         }
633
634         if (bAddrChangeCheck &&
635             daemon_ShutdownFlag == 0 &&
636             powerStateSuspended == 0) {
637             smb_CheckVCs();
638             cm_VolStatus_Network_Addr_Change();
639         }
640
641         /*
642          * Once every five minutes inspect the volume list and enforce
643          * the volume location expiration time.
644          */
645         if (now > lastVolCheck + 300 &&
646             daemon_ShutdownFlag == 0 &&
647             powerStateSuspended == 0) {
648             lastVolCheck = now;
649             cm_RefreshVolumes(cm_daemonCheckVolInterval);
650             if (daemon_ShutdownFlag == 1)
651                 break;
652             now = osi_Time();
653         }
654
655         /* Rank all up servers */
656         if ((now > lastServerRankCheck + cm_daemonRankServerInterval) &&
657             daemon_ShutdownFlag == 0 &&
658             powerStateSuspended == 0) {
659             lastServerRankCheck = now;
660             osi_Log0(afsd_logp, "cm_Daemon RankServer");
661             cm_RankUpServers();
662             if(daemon_ShutdownFlag == 1)
663                 break;
664             now = osi_Time();
665         }
666
667         if (cm_daemonCheckVolCBInterval &&
668             now > lastVolCBRenewalCheck + cm_daemonCheckVolCBInterval &&
669             daemon_ShutdownFlag == 0 &&
670             powerStateSuspended == 0) {
671             lastVolCBRenewalCheck = now;
672             cm_VolumeRenewROCallbacks();
673             if (daemon_ShutdownFlag == 1)
674                 break;
675             now = osi_Time();
676         }
677
678         if ((bAddrChangeCheck || (cm_daemonCheckOfflineVolInterval &&
679                                   now > lastBusyVolCheck + cm_daemonCheckOfflineVolInterval)) &&
680             daemon_ShutdownFlag == 0 &&
681             powerStateSuspended == 0) {
682             lastBusyVolCheck = now;
683             cm_CheckOfflineVolumes();
684             if (daemon_ShutdownFlag == 1)
685                 break;
686             now = osi_Time();
687         }
688
689         if (now > lastCBExpirationCheck + cm_daemonCheckCBInterval &&
690             daemon_ShutdownFlag == 0 &&
691             powerStateSuspended == 0) {
692             lastCBExpirationCheck = now;
693             cm_CheckCBExpiration();
694             if (daemon_ShutdownFlag == 1)
695                 break;
696             now = osi_Time();
697         }
698
699         if (now > lastTokenCacheCheck + cm_daemonTokenCheckInterval &&
700             daemon_ShutdownFlag == 0 &&
701             powerStateSuspended == 0) {
702             lastTokenCacheCheck = now;
703             cm_CheckTokenCache(now);
704             if (daemon_ShutdownFlag == 1)
705                 break;
706             now = osi_Time();
707         }
708
709         if (cm_daemonRDRShakeExtentsInterval &&
710             now > lastRDRShakeExtents + cm_daemonRDRShakeExtentsInterval &&
711             daemon_ShutdownFlag == 0 &&
712             powerStateSuspended == 0) {
713             cm_req_t req;
714             cm_InitReq(&req);
715             lastRDRShakeExtents = now;
716             if (cm_data.buf_redirCount > cm_data.buf_freeCount)
717                 buf_RDRShakeSomeExtentsFree(&req, FALSE, 10 /* seconds */);
718             if (daemon_ShutdownFlag == 1)
719                 break;
720             now = osi_Time();
721         }
722
723         /* allow an exit to be called prior to stopping the service */
724         hHookDll = cm_LoadAfsdHookLib();
725         if (hHookDll)
726         {
727             BOOL hookRc = TRUE;
728             AfsdDaemonHook daemonHook = ( AfsdDaemonHook ) GetProcAddress(hHookDll, AFSD_DAEMON_HOOK);
729             if (daemonHook)
730             {
731                 hookRc = daemonHook();
732             }
733             FreeLibrary(hHookDll);
734             hHookDll = NULL;
735
736             if (hookRc == FALSE)
737             {
738                 SetEvent(WaitToTerminate);
739             }
740
741             if (daemon_ShutdownFlag == 1) {
742                 break;
743             }
744             now = osi_Time();
745         }
746
747         if (cm_daemonPerformanceTuningInterval &&
748             now > lastPerformanceCheck + cm_daemonPerformanceTuningInterval &&
749             daemon_ShutdownFlag == 0 &&
750             powerStateSuspended == 0) {
751             lastPerformanceCheck = now;
752             cm_PerformanceTuningCheck();
753             if (daemon_ShutdownFlag == 1)
754                 break;
755             now = osi_Time();
756         }
757
758         /*
759          * sleep .5 seconds.  if the thread blocks for a long time
760          * we risk not being able to close the cache before Windows
761          * kills our process during system shutdown.
762          */
763         thrd_Sleep(500);
764     }
765
766     thrd_SetEvent(cm_Daemon_ShutdownEvent);
767     pthread_exit(NULL);
768     return NULL;
769 }
770
771 void cm_DaemonShutdown(void)
772 {
773     int i;
774     DWORD code;
775
776     daemon_ShutdownFlag = 1;
777     osi_Wakeup((LONG_PTR) &cm_bkgListp);
778
779     /* wait for shutdown */
780     for ( i=0; i<cm_nDaemons; i++) {
781         if (cm_BkgDaemon_ShutdownEvent[i])
782             code = thrd_WaitForSingleObject_Event(cm_BkgDaemon_ShutdownEvent[i], INFINITE);
783     }
784
785     if (cm_Daemon_ShutdownEvent)
786         code = thrd_WaitForSingleObject_Event(cm_Daemon_ShutdownEvent, INFINITE);
787
788     if (cm_LockDaemon_ShutdownEvent)
789         code = thrd_WaitForSingleObject_Event(cm_LockDaemon_ShutdownEvent, INFINITE);
790
791 #if 0
792     /*
793      * Do not waste precious time waiting for the ipaddr daemon to shutdown.
794      * When it does it means we have lost our network connection and we need
795      * it during cache shutdown in order to notify the file servers that this
796      * client is giving up all callbacks.
797      */
798     if (cm_IPAddrDaemon_ShutdownEvent)
799         code = thrd_WaitForSingleObject_Event(cm_IPAddrDaemon_ShutdownEvent, INFINITE);
800 #endif
801 }
802
803 void cm_InitDaemon(int nDaemons)
804 {
805     static osi_once_t once;
806     pthread_t phandle;
807     pthread_attr_t tattr;
808     int pstatus;
809     int i;
810
811     pthread_attr_init(&tattr);
812     pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
813
814     cm_nDaemons = (nDaemons > CM_MAX_DAEMONS) ? CM_MAX_DAEMONS : nDaemons;
815
816     if (osi_Once(&once)) {
817         lock_InitializeRWLock(&cm_daemonLock, "cm_daemonLock",
818                                LOCK_HIERARCHY_DAEMON_GLOBAL);
819         osi_EndOnce(&once);
820
821         /* creating IP Address Change monitor daemon */
822         pstatus = pthread_create(&phandle, &tattr, cm_IpAddrDaemon, 0);
823         osi_assertx(pstatus == 0, "cm_IpAddrDaemon thread creation failure");
824
825         /* creating pinging daemon */
826         pstatus = pthread_create(&phandle, &tattr, cm_Daemon, 0);
827         osi_assertx(pstatus == 0, "cm_Daemon thread creation failure");
828
829         pstatus = pthread_create(&phandle, &tattr, cm_LockDaemon, 0);
830         osi_assertx(pstatus == 0, "cm_LockDaemon thread creation failure");
831
832         for(i=0; i < cm_nDaemons; i++) {
833             pstatus = pthread_create(&phandle, &tattr, cm_BkgDaemon, (LPVOID)(LONG_PTR)i);
834             osi_assertx(pstatus == 0, "cm_BkgDaemon thread creation failure");
835         }
836     }
837
838     pthread_attr_destroy(&tattr);
839 }