rx: Remove RX_CALL_BUSY
[openafs.git] / src / WINNT / afssvrmgr / dispatch.cpp
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 <winsock2.h>
11 #include <ws2tcpip.h>
12
13 extern "C" {
14 #include <afsconfig.h>
15 #include <afs/param.h>
16 #include <roken.h>
17 }
18
19 #include "svrmgr.h"
20 #include "dispatch.h"
21 #include "action.h"
22 #include "svr_general.h"
23 #include "svc_general.h"
24 #include "agg_general.h"
25 #include "set_general.h"
26 #include "subset.h"
27 #include "display.h"
28
29
30 /*
31  * DEFINITIONS ________________________________________________________________
32  *
33  */
34
35 #define cREALLOC_DISPATCH  32
36
37
38 /*
39  * VARIABLES __________________________________________________________________
40  *
41  */
42
43 static CRITICAL_SECTION csDispatch;
44
45 static LPNOTIFYCALLBACK Handler = NULL;
46
47 static struct
48    {
49    NOTIFYWHEN when;
50    LPIDENT lpiObject;
51    HWND hWnd;
52    LPARAM lpUser;
53    } *aDispatchList = NULL;
54
55 static size_t nDispatchList = 0;
56
57
58 typedef struct NOTIFYQUEUEITEM
59    {
60    struct NOTIFYQUEUEITEM *pNext;
61    NOTIFYEVENT evt;
62    NOTIFYPARAMS Params;
63    } NOTIFYQUEUEITEM, *LPNOTIFYQUEUEITEM;
64
65 static LPNOTIFYQUEUEITEM pDispatchQueuePop = NULL;
66 static LPNOTIFYQUEUEITEM pDispatchQueuePushAfter = NULL;
67
68
69 /*
70  * PROTOTYPES _________________________________________________________________
71  *
72  */
73
74 BOOL CALLBACK DispatchNotification (NOTIFYEVENT evt, PNOTIFYPARAMS pParams);
75
76 void DispatchNotification_AltThread (NOTIFYEVENT evt, PNOTIFYPARAMS pParams);
77
78 void DispatchNotification_MainThread (NOTIFYEVENT evt, PNOTIFYPARAMS pParams);
79
80
81 /*
82  * ROUTINES ___________________________________________________________________
83  *
84  */
85
86 void CreateNotificationDispatch (void)
87 {
88    InitializeCriticalSection (&csDispatch);
89
90    Handler = New2 (NOTIFYCALLBACK,((NOTIFYCALLBACKPROC)DispatchNotification, 0L));
91 }
92
93
94 void PostNotification (NOTIFYEVENT evt, LPIDENT lpi)
95 {
96    NOTIFYCALLBACK::SendNotificationToAll (evt, lpi);
97 }
98
99
100 /*
101  * DispatchNotification
102  *
103  * This routine is called by our NOTIFYCALLBACK object ("Handler") whenever
104  * anything interesting happens within the library.  Note that it's called
105  * on whatever thread the library is using--for that reason, we only handle
106  * some of the requests right away.  The rest get posted to our DispatchQueue,
107  * to be popped off by g.hMain's thread.
108  *
109  */
110
111 BOOL CALLBACK DispatchNotification (NOTIFYEVENT evt, PNOTIFYPARAMS pParams)
112 {
113    // Some things must be done right now--for instance, if we've just created
114    // or deleted a SERVER object, we'll load or free that server's preferences
115    // instantly.  So, give our on-alternate-thread handler a chance to
116    // look over the notification.
117    //
118    DispatchNotification_AltThread (evt, pParams);
119
120    // Then push this notification onto our DispatchQueue, so that the main
121    // pump will pop off each request in turn and take a look at it.
122    //
123    EnterCriticalSection (&csDispatch);
124
125    LPNOTIFYQUEUEITEM lpnqi = New (NOTIFYQUEUEITEM);
126    lpnqi->pNext = NULL;
127    lpnqi->evt = evt;
128    memcpy (&lpnqi->Params, pParams, sizeof(NOTIFYPARAMS));
129
130    if (pDispatchQueuePushAfter != NULL)
131       pDispatchQueuePushAfter->pNext = lpnqi;
132    pDispatchQueuePushAfter = lpnqi;
133
134    if (pDispatchQueuePop == NULL)
135       pDispatchQueuePop = lpnqi;
136
137    LeaveCriticalSection (&csDispatch);
138
139    return TRUE;
140 }
141
142
143 void DispatchNotification_OnPump (void)
144 {
145    BOOL fFound = TRUE;
146
147    do {
148       NOTIFYQUEUEITEM nqi;
149
150       EnterCriticalSection (&csDispatch);
151
152       if (!pDispatchQueuePop)
153          fFound = FALSE;
154       else
155          {
156          LPNOTIFYQUEUEITEM lpnqiNext = pDispatchQueuePop->pNext;
157          memcpy (&nqi, pDispatchQueuePop, sizeof(NOTIFYQUEUEITEM));
158
159          if (pDispatchQueuePushAfter == pDispatchQueuePop)
160             pDispatchQueuePushAfter = NULL;
161          Delete (pDispatchQueuePop);
162          pDispatchQueuePop = lpnqiNext;
163          }
164
165       LeaveCriticalSection (&csDispatch);
166
167       if (fFound)
168          {
169          DispatchNotification_MainThread (nqi.evt, &nqi.Params);
170          }
171       } while (fFound);
172 }
173
174
175 void DispatchNotification_AltThread (NOTIFYEVENT evt, PNOTIFYPARAMS pParams)
176 {
177    LPIDENT lpiEvt = pParams->lpi1;
178
179    switch (evt)
180       {
181       case evtRefreshStatusEnd:
182          if (lpiEvt && (lpiEvt->fIsService() || lpiEvt->fIsAggregate() || lpiEvt->fIsFileset()))
183             {
184             Alert_RemoveSecondary (lpiEvt);
185             Alert_Scout_QueueCheckServer (lpiEvt);
186             }
187          if (lpiEvt && lpiEvt->fIsServer())
188             {
189             LPSERVER_PREF lpsp;
190             if ((lpsp = (LPSERVER_PREF)lpiEvt->GetUserParam()) != NULL)
191                {
192                LPSERVER lpServer;
193                if ((lpServer = lpiEvt->OpenServer()) != NULL)
194                   {
195                   if (lpsp->fIsMonitored != lpServer->fIsMonitored())
196                      {
197                      g.sub = Subsets_SetMonitor (g.sub, lpiEvt, lpServer->fIsMonitored());
198                      UpdateDisplay_ServerWindow (FALSE, lpiEvt);
199                      }
200                   lpsp->fIsMonitored = lpServer->fIsMonitored();
201                   lpServer->Close();
202                   }
203                }
204
205             Alert_Scout_ServerStatus (lpiEvt, pParams->status);
206             }
207          break;
208
209       // When we get a create request, use the object's Get/SetUserParam()
210       // methods to attach an allocated structure to the thing--the structure
211       // contains the preferences for the server/fileset/etc (for instance,
212       // its warning threshholds, any current scout problems, etc).
213       // On delete requests, free that structure.
214       //
215       case evtCreate:
216          if (lpiEvt->fIsServer())
217             {
218             PVOID pPref = Server_LoadPreferences (lpiEvt);
219             lpiEvt->SetUserParam (pPref);
220
221             // Should this server be monitored?
222             //
223             if (!Subsets_fMonitorServer (g.sub, lpiEvt))
224                {
225                LPSERVER lpServer;
226                if ((lpServer = lpiEvt->OpenServer()) != NULL)
227                   {
228                   lpServer->SetMonitor (FALSE);
229                   lpServer->Close();
230                   }
231                }
232
233             Alert_Scout_SetOutOfDate (lpiEvt);
234             }
235          else if (lpiEvt->fIsService())
236             {
237             PVOID pPref = Services_LoadPreferences (lpiEvt);
238             lpiEvt->SetUserParam (pPref);
239             }
240          else if (lpiEvt->fIsAggregate())
241             {
242             PVOID pPref = Aggregates_LoadPreferences (lpiEvt);
243             lpiEvt->SetUserParam (pPref);
244             }
245          else if (lpiEvt->fIsFileset())
246             {
247             PVOID pPref = Filesets_LoadPreferences (lpiEvt);
248             lpiEvt->SetUserParam (pPref);
249             }
250          if (!lpiEvt->fIsCell())
251             {
252             Alert_Scout_QueueCheckServer (lpiEvt);
253             }
254          break;
255
256       // When we get a create request, use the object's Get/SetUserParam()
257       // methods to attach an allocated structure to the thing--the structure
258       // contains the preferences for the server/fileset/etc (for instance,
259       // its warning threshholds, any current scout problems, etc).
260       // On delete requests, free that structure.
261       //
262       case evtDestroy:
263          if (lpiEvt->fIsServer())
264             {
265             PVOID pPref = lpiEvt->GetUserParam();
266             lpiEvt->SetUserParam (0);
267             if (pPref)  Delete (pPref);
268             }
269          else if (lpiEvt->fIsService() || lpiEvt->fIsAggregate() || lpiEvt->fIsFileset())
270             {
271             Alert_RemoveSecondary (lpiEvt);
272             PVOID pPref = lpiEvt->GetUserParam();
273             lpiEvt->SetUserParam (0);
274             if (pPref)  Delete (pPref);
275             }
276          break;
277       }
278 }
279
280
281 void DispatchNotification_MainThread (NOTIFYEVENT evt, PNOTIFYPARAMS pParams)
282 {
283    LPIDENT lpiEvt = pParams->lpi1;
284
285    // There are several notifications which are sent when beginning or ending
286    // lengthy operations.  These "actions" each get a window indicating
287    // progress, and get added to our ongoing list of actions-in-progress.
288    //
289    ActionNotification_MainThread (evt, pParams);
290
291    // The real reason for this routine is as a dispatcher for the AFSClass's
292    // notifications: various windows throughout the app register themselves
293    // with this dispatcher, and thereby get a message whenever a particular
294    // event of interest to that window happens.  Just what notifications
295    // are "of interest" is specified by the window when it registers with
296    // this dispatcher.
297    //
298    for (size_t iDispatch = 0; iDispatch < nDispatchList; ++iDispatch)
299       {
300       if (!aDispatchList[ iDispatch ].hWnd)
301          continue;
302
303       BOOL fDispatch = FALSE;
304
305       // WHEN_CELL_OPENED + NULL      -> notify if any new cell is opened
306       // WHEN_OBJECT_CHANGES + NULL   -> notify if anything at all changes
307       // WHEN_OBJECT_CHANGES + lpi    -> notify if this object changes
308       // WHEN_SVCS(etc)_CHANGE + NULL -> notify if any service at all changes
309       // WHEN_SVCS(etc)_CHANGE + lpi  -> notify if any svc on this svr changes
310
311       switch (aDispatchList[ iDispatch ].when)
312          {
313          case WHEN_CELL_OPENED:
314             if (evt == evtCreate && lpiEvt->fIsCell())
315                fDispatch = TRUE;
316             break;
317
318          case WHEN_OBJECT_CHANGES:
319             if ( (aDispatchList[ iDispatch ].lpiObject == lpiEvt) ||
320                  (aDispatchList[ iDispatch ].lpiObject == NULL) )
321                {
322                if (evt != evtCreate)
323                   fDispatch = TRUE;
324                }
325             break;
326
327          case WHEN_SVRS_CHANGE:
328             switch (evt)
329                {
330                case evtInvalidate:
331                case evtRefreshServersBegin:
332                case evtRefreshServersEnd:
333                   if ( (lpiEvt && lpiEvt->fIsCell()) ||
334                        (aDispatchList[ iDispatch ].lpiObject == lpiEvt) ||
335                        (aDispatchList[ iDispatch ].lpiObject == NULL) )
336                      {
337                      if (lpiEvt && lpiEvt->fIsCell())
338                         fDispatch = TRUE;
339                      }
340                   break;
341
342                case evtCreate:
343                case evtDestroy:
344                case evtRefreshStatusBegin:
345                case evtRefreshStatusEnd:
346                case evtAlertsChanged:
347                   if (lpiEvt && lpiEvt->fIsServer())
348                      {
349                      if (aDispatchList[ iDispatch ].lpiObject == NULL)
350                         fDispatch = TRUE;
351                      else
352                         {
353                         LPIDENT lpiEvtCell = lpiEvt->GetCell();
354
355                         if (aDispatchList[ iDispatch ].lpiObject == lpiEvtCell)
356                            fDispatch = TRUE;
357                         }
358                      }
359                   break;
360                }
361             break;
362
363          case WHEN_SETS_CHANGE:
364             switch (evt)
365                {
366                case evtInvalidate:
367                case evtRefreshFilesetsBegin:
368                case evtRefreshFilesetsEnd:
369                   {
370                   LPIDENT lpiEvtSvr = NULL;
371                   if (lpiEvt && !lpiEvt->fIsCell())
372                      lpiEvtSvr = lpiEvt->GetServer();
373
374                   if ( (lpiEvt && lpiEvt->fIsCell()) ||
375                        (aDispatchList[ iDispatch ].lpiObject == lpiEvt)    ||
376                        (aDispatchList[ iDispatch ].lpiObject == lpiEvtSvr) ||
377                        (aDispatchList[ iDispatch ].lpiObject == NULL) )
378                      {
379                      if (lpiEvt && (lpiEvt->fIsCell() || lpiEvt->fIsServer() || lpiEvt->fIsAggregate()))
380                         fDispatch = TRUE;
381                      }
382                   }
383                   break;
384
385                case evtCreate:
386                case evtDestroy:
387                case evtRefreshStatusBegin:
388                case evtRefreshStatusEnd:
389                case evtAlertsChanged:
390                   if (lpiEvt && lpiEvt->fIsFileset())
391                      {
392                      if (aDispatchList[ iDispatch ].lpiObject == NULL)
393                         fDispatch = TRUE;
394                      else
395                         {
396                         LPIDENT lpiEvtAgg = lpiEvt->GetAggregate();
397                         LPIDENT lpiEvtSvr = lpiEvt->GetServer();
398
399                         if (aDispatchList[ iDispatch ].lpiObject == lpiEvtAgg)
400                            fDispatch = TRUE;
401                         if (aDispatchList[ iDispatch ].lpiObject == lpiEvtSvr)
402                            fDispatch = TRUE;
403                         }
404                      }
405                   break;
406                }
407             break;
408
409          case WHEN_AGGS_CHANGE:
410             switch (evt)
411                {
412                case evtRefreshAggregatesBegin:
413                case evtRefreshAggregatesEnd:
414                   if ( (lpiEvt && lpiEvt->fIsCell()) ||
415                        (aDispatchList[ iDispatch ].lpiObject == lpiEvt) ||
416                        (aDispatchList[ iDispatch ].lpiObject == NULL) )
417                      {
418                      if (lpiEvt && (lpiEvt->fIsCell() || lpiEvt->fIsServer()))
419                         fDispatch = TRUE;
420                      }
421                   break;
422
423                case evtCreate:
424                case evtDestroy:
425                case evtRefreshStatusBegin:
426                case evtRefreshStatusEnd:
427                case evtAlertsChanged:
428                   if (lpiEvt && lpiEvt->fIsAggregate())
429                      {
430                      if (aDispatchList[ iDispatch ].lpiObject == NULL)
431                         fDispatch = TRUE;
432                      else
433                         {
434                         LPIDENT lpiEvtSvr = lpiEvt->GetServer();
435
436                         if (aDispatchList[ iDispatch ].lpiObject == lpiEvtSvr)
437                            fDispatch = TRUE;
438                         }
439                      }
440                   break;
441                }
442             break;
443
444          case WHEN_SVCS_CHANGE:
445             switch (evt)
446                {
447                case evtRefreshServicesBegin:
448                case evtRefreshServicesEnd:
449                   if ( (lpiEvt && lpiEvt->fIsCell()) ||
450                        (aDispatchList[ iDispatch ].lpiObject == lpiEvt) ||
451                        (aDispatchList[ iDispatch ].lpiObject == NULL) )
452                      {
453                      if (lpiEvt && (lpiEvt->fIsCell() || lpiEvt->fIsServer()))
454                         fDispatch = TRUE;
455                      }
456                   break;
457
458                case evtCreate:
459                case evtDestroy:
460                case evtRefreshStatusBegin:
461                case evtRefreshStatusEnd:
462                case evtAlertsChanged:
463                   if (lpiEvt && lpiEvt->fIsService())
464                      {
465                      if (aDispatchList[ iDispatch ].lpiObject == NULL)
466                         fDispatch = TRUE;
467                      else
468                         {
469                         LPIDENT lpiEvtSvr = lpiEvt->GetServer();
470
471                         if (aDispatchList[ iDispatch ].lpiObject == lpiEvtSvr)
472                            fDispatch = TRUE;
473                         }
474                      }
475                   break;
476                }
477             break;
478          }
479
480       if (fDispatch)
481          {
482          LPNOTIFYSTRUCT lpns = New (NOTIFYSTRUCT);
483          lpns->hwndTarget = aDispatchList[ iDispatch ].hWnd;
484          lpns->evt = evt;
485          memcpy (&lpns->Params, pParams, sizeof(NOTIFYPARAMS));
486          lpns->Params.lpUser = aDispatchList[ iDispatch ].lpUser;
487
488          PostMessage (aDispatchList[ iDispatch ].hWnd,
489                       WM_NOTIFY_FROM_DISPATCH,
490                       (WPARAM)0,
491                       (LPARAM)lpns);
492          }
493       }
494 }
495
496
497 void NotifyMe (NOTIFYWHEN when, LPIDENT lpiObject, HWND hWnd, LPARAM lpUser)
498 {
499    EnterCriticalSection (&csDispatch);
500
501    size_t iDispatch;
502    for (iDispatch = 0; iDispatch < nDispatchList; ++iDispatch)
503       {
504       if ( (aDispatchList[ iDispatch ].hWnd == hWnd) &&
505            (aDispatchList[ iDispatch ].when == when) &&
506            (aDispatchList[ iDispatch ].lpiObject == lpiObject) )
507          {
508          LeaveCriticalSection (&csDispatch);
509          return;
510          }
511       }
512
513    for (iDispatch = 0; iDispatch < nDispatchList; ++iDispatch)
514       {
515       if (!aDispatchList[ iDispatch ].hWnd)
516          break;
517       }
518
519    if (iDispatch >= nDispatchList)
520       {
521       if (!REALLOC (aDispatchList, nDispatchList, 1+iDispatch, cREALLOC_DISPATCH))
522          {
523          LeaveCriticalSection (&csDispatch);
524          return;
525          }
526       }
527
528    aDispatchList[ iDispatch ].hWnd = hWnd;
529    aDispatchList[ iDispatch ].when = when;
530    aDispatchList[ iDispatch ].lpiObject = lpiObject;
531    aDispatchList[ iDispatch ].lpUser = lpUser;
532
533    LeaveCriticalSection (&csDispatch);
534 }
535
536
537 void DontNotifyMe (NOTIFYWHEN when, LPIDENT lpiObject, HWND hWnd)
538 {
539    EnterCriticalSection (&csDispatch);
540
541    for (size_t iDispatch = 0; iDispatch < nDispatchList; ++iDispatch)
542       {
543       if ( (aDispatchList[ iDispatch ].hWnd == hWnd) &&
544            (aDispatchList[ iDispatch ].when == when) &&
545            (aDispatchList[ iDispatch ].lpiObject == lpiObject) )
546          {
547          aDispatchList[ iDispatch ].hWnd = NULL;
548          }
549       }
550
551    LeaveCriticalSection (&csDispatch);
552 }
553
554
555 void DontNotifyMeEver (HWND hWnd)
556 {
557    EnterCriticalSection (&csDispatch);
558
559    for (size_t iDispatch = 0; iDispatch < nDispatchList; ++iDispatch)
560       {
561       if (aDispatchList[ iDispatch ].hWnd == hWnd)
562          {
563          aDispatchList[ iDispatch ].hWnd = NULL;
564          }
565       }
566
567    LeaveCriticalSection (&csDispatch);
568 }
569