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