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