LINUX: afs_create infinite fetchStatus loop
[pkg-k5-afs_openafs.git] / src / WINNT / afsclass / c_svr.cpp
blobe18f9e411939cf8ded61fbd76a9144594532c52b
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
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 */
10 #include <winsock2.h>
11 #include <ws2tcpip.h>
13 extern "C" {
14 #include <afsconfig.h>
15 #include <afs/param.h>
16 #include <roken.h>
19 #include <WINNT/afsclass.h>
20 #include "internal.h"
24 * DEFINITIONS ________________________________________________________________
28 // Each SERVER object maintains a list of aggregates and a list
29 // of services; those lists have hashtables placed across their
30 // names (and, for aggregates, their IDs) for faster lookup.
31 // The default table size in a HASHLIST is 1000 elements--that's
32 // too large for a list of aggregates or services on a server,
33 // as it's enough to handle up to 30,000 objects before the table
34 // would need to resize iteself (see the documentation in
35 // hashlist.cpp for info). Instead, we choose a more reasonable
36 // default table size.
38 #define cKEYAGGREGATENAME_TABLESIZE 100
39 #define cKEYAGGREGATEID_TABLESIZE 100
41 #define cKEYSERVICENAME_TABLESIZE 50
45 * VARIABLES __________________________________________________________________
51 * PROTOTYPES _________________________________________________________________
57 * ROUTINES ___________________________________________________________________
62 SERVER::SERVER (LPCELL lpCellParent, LPTSTR pszName)
64 m_lpiCell = lpCellParent->GetIdentifier();
66 lstrcpy (m_szName, pszName);
68 m_lpCellBOS = NULL;
69 m_hCellBOS = NULL;
70 m_hBOS = NULL;
71 m_cReqBOS = 0;
73 m_hCellVOS = NULL;
74 m_hVOS = NULL;
75 m_cReqVOS = 0;
77 m_fCanGetAggregates = TRUE;
78 m_fAggregatesOutOfDate = TRUE;
79 m_lAggregates = New (HASHLIST);
80 m_lAggregates->SetCriticalSection (AfsClass_GetCriticalSection());
81 m_lkAggregateName = m_lAggregates->CreateKey ("Aggregate Name", SERVER::KeyAggregateName_Compare, SERVER::KeyAggregateName_HashObject, SERVER::KeyAggregateName_HashData, cKEYAGGREGATENAME_TABLESIZE);
82 m_lkAggregateID = m_lAggregates->CreateKey ("Aggregate ID", SERVER::KeyAggregateID_Compare, SERVER::KeyAggregateID_HashObject, SERVER::KeyAggregateID_HashData, cKEYAGGREGATEID_TABLESIZE);
84 m_fCanGetServices = TRUE;
85 m_fServicesOutOfDate = TRUE;
86 m_lServices = New (HASHLIST);
87 m_lServices->SetCriticalSection (AfsClass_GetCriticalSection());
88 m_lkServiceName = m_lServices->CreateKey ("Service Name", SERVER::KeyServiceName_Compare, SERVER::KeyServiceName_HashObject, SERVER::KeyServiceName_HashData, cKEYSERVICENAME_TABLESIZE);
90 m_wGhost = 0;
91 m_lpiThis = NULL;
92 m_fMonitor = TRUE;
93 m_fDelete = FALSE;
94 m_lastStatus = 0;
96 m_fVLDBOutOfDate = FALSE; /* FIXME: added because it was missing */
97 m_fStatusOutOfDate = TRUE;
98 memset (&m_ss, 0x00, sizeof(SERVERSTATUS));
102 SERVER::~SERVER (void)
104 if (!m_fMonitor)
106 LPCELL lpCell;
107 if ((lpCell = m_lpiCell->OpenCell()) != NULL)
109 (lpCell->m_nServersUnmonitored)--;
110 lpCell->Close();
114 if (m_lpiThis)
115 m_lpiThis->m_cRef --;
117 FreeAll();
118 Delete (m_lAggregates);
119 Delete (m_lServices);
123 void SERVER::FreeAll (void)
125 if (m_cReqBOS)
127 m_cReqBOS = 1;
128 CloseBosObject();
130 if (m_cReqVOS)
132 m_cReqVOS = 1;
133 CloseVosObject();
136 FreeAggregates();
137 FreeServices();
141 void SERVER::FreeAggregates (void)
143 for (LPENUM pEnum = m_lAggregates->FindLast(); pEnum; pEnum = pEnum->FindPrevious())
145 LPAGGREGATE lpAggregate = (LPAGGREGATE)(pEnum->GetObject());
146 m_lAggregates->Remove (lpAggregate);
147 Delete (lpAggregate);
152 void SERVER::FreeServices (void)
154 for (LPENUM pEnum = m_lServices->FindLast(); pEnum; pEnum = pEnum->FindPrevious())
156 LPSERVICE lpService = (LPSERVICE)(pEnum->GetObject());
157 m_lServices->Remove (lpService);
158 Delete (lpService);
163 void SERVER::SendDeleteNotifications (void)
165 LPENUM pEnum;
166 for (pEnum = m_lAggregates->FindFirst(); pEnum; pEnum = pEnum->FindNext())
168 LPAGGREGATE lpAggregate = (LPAGGREGATE)(pEnum->GetObject());
169 lpAggregate->SendDeleteNotifications ();
172 for (pEnum = m_lServices->FindFirst(); pEnum; pEnum = pEnum->FindNext())
174 LPSERVICE lpService = (LPSERVICE)(pEnum->GetObject());
175 lpService->SendDeleteNotifications();
178 NOTIFYCALLBACK::SendNotificationToAll (evtDestroy, GetIdentifier());
182 void SERVER::Close (void)
184 AfsClass_Leave();
188 LPIDENT SERVER::GetIdentifier (void)
190 if (m_lpiThis == NULL)
192 if ((m_lpiThis = IDENT::FindIdent (this)) == NULL)
193 m_lpiThis = New2 (IDENT,(this));
194 m_lpiThis->m_cRef ++;
197 return m_lpiThis;
201 PVOID SERVER::OpenBosObject (PVOID *phCell, ULONG *pStatus)
203 if (!m_hBOS)
205 if ((m_lpCellBOS = m_lpiCell->OpenCell (pStatus)) != NULL)
207 if ((m_hCellBOS = m_lpCellBOS->GetCellObject (pStatus)) != NULL)
209 TCHAR szCell[ cchNAME ];
210 m_lpiCell->GetCellName (szCell);
212 WORKERPACKET wp;
213 wp.wpBosServerOpen.hCell = m_hCellBOS;
214 wp.wpBosServerOpen.pszServer = m_szName;
215 if (Worker_DoTask (wtaskBosServerOpen, &wp, pStatus))
216 m_hBOS = wp.wpBosServerOpen.hServer;
219 if (!m_hBOS)
221 m_lpCellBOS->Close();
222 m_lpCellBOS = NULL;
223 m_hCellBOS = NULL;
228 if (m_hBOS)
230 if (phCell)
231 *phCell = m_hCellBOS;
232 ++m_cReqBOS;
234 return m_hBOS;
238 BOOL SERVER::CloseBosObject (ULONG *pStatus)
240 BOOL rc = TRUE;
242 if ((m_cReqBOS > 0) && ((--m_cReqBOS) == 0))
244 if (m_hBOS != NULL)
246 WORKERPACKET wp;
247 wp.wpBosServerClose.hServer = m_hBOS;
248 if (!Worker_DoTask (wtaskBosServerClose, &wp, pStatus))
249 rc = FALSE;
250 m_hBOS = NULL;
252 if (m_lpCellBOS != NULL)
254 m_lpCellBOS->Close();
255 m_lpCellBOS = NULL;
259 return rc;
263 PVOID SERVER::OpenVosObject (PVOID *phCell, ULONG *pStatus)
265 if (!m_hCellVOS)
267 LPCELL lpCell;
268 if ((lpCell = m_lpiCell->OpenCell (pStatus)) != NULL)
270 m_hCellVOS = lpCell->GetCellObject (pStatus);
271 lpCell->Close();
275 if (m_hCellVOS && !m_hVOS)
277 TCHAR szCell[ cchNAME ];
278 m_lpiCell->GetCellName (szCell);
280 WORKERPACKET wp;
281 wp.wpVosServerOpen.hCell = m_hCellVOS;
282 wp.wpVosServerOpen.pszServer = m_szName;
283 if (Worker_DoTask (wtaskVosServerOpen, &wp, pStatus))
284 m_hVOS = wp.wpVosServerOpen.hServer;
287 if (m_hVOS)
289 if (phCell)
290 *phCell = m_hCellVOS;
291 ++m_cReqVOS;
293 return m_hVOS;
297 BOOL SERVER::CloseVosObject (ULONG *pStatus)
299 BOOL rc = TRUE;
301 if ((m_cReqVOS > 0) && ((--m_cReqVOS) == 0))
303 if (m_hVOS != NULL)
305 WORKERPACKET wp;
306 wp.wpVosServerClose.hServer = m_hVOS;
307 if (!Worker_DoTask (wtaskVosServerClose, &wp, pStatus))
308 rc = FALSE;
311 m_hVOS = NULL;
312 m_hCellVOS = NULL;
315 return rc;
319 void SERVER::Invalidate (void)
321 if (!m_fAggregatesOutOfDate || !m_fServicesOutOfDate || !m_fStatusOutOfDate)
323 if (m_wGhost & GHOST_HAS_SERVER_ENTRY)
325 m_fAggregatesOutOfDate = TRUE;
326 m_fServicesOutOfDate = TRUE;
327 m_fStatusOutOfDate = TRUE;
330 NOTIFYCALLBACK::SendNotificationToAll (evtInvalidate, GetIdentifier());
335 void SERVER::InvalidateStatus (void)
337 if (!m_fStatusOutOfDate)
339 if (m_wGhost & GHOST_HAS_SERVER_ENTRY)
341 m_fStatusOutOfDate = TRUE;
344 NOTIFYCALLBACK::SendNotificationToAll (evtInvalidate, GetIdentifier());
349 void SERVER::InvalidateServices (void)
351 if (!m_fServicesOutOfDate)
353 if (m_wGhost & GHOST_HAS_SERVER_ENTRY)
355 m_fServicesOutOfDate = TRUE;
358 NOTIFYCALLBACK::SendNotificationToAll (evtInvalidate, GetIdentifier());
363 BOOL SERVER::RefreshAggregates (BOOL fNotify, ULONG *pStatus)
365 BOOL rc = TRUE;
366 DWORD status = 0;
368 if (m_fAggregatesOutOfDate)
370 m_fAggregatesOutOfDate = FALSE;
372 if (fIsMonitored())
374 if (fNotify)
375 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAggregatesBegin, GetIdentifier());
377 // First thing is to forget about what aggregates we think we have
378 // now.
380 LPENUM pEnum;
381 for (pEnum = m_lAggregates->FindLast(); pEnum; pEnum = pEnum->FindPrevious())
383 LPAGGREGATE lpAggregate = (LPAGGREGATE)(pEnum->GetObject());
384 lpAggregate->SendDeleteNotifications();
385 m_lAggregates->Remove (lpAggregate);
386 Delete (lpAggregate);
389 // Next, the harder part: look through the server to find a list
390 // of aggregates.
392 PVOID hCell;
393 PVOID hVOS;
394 if ((hVOS = OpenVosObject (&hCell, &status)) == NULL)
395 rc = FALSE;
396 else
398 WORKERPACKET wpBegin;
399 wpBegin.wpVosPartitionGetBegin.hCell = hCell;
400 wpBegin.wpVosPartitionGetBegin.hServer = hVOS;
402 if (!Worker_DoTask (wtaskVosPartitionGetBegin, &wpBegin, &status))
403 rc = FALSE;
404 else
406 for (;;)
408 WORKERPACKET wpNext;
409 wpNext.wpVosPartitionGetNext.hEnum = wpBegin.wpVosPartitionGetBegin.hEnum;
410 if (!Worker_DoTask (wtaskVosPartitionGetNext, &wpNext, &status))
412 if (status == ADMITERATORDONE)
413 status = 0;
414 else
415 rc = FALSE;
416 break;
419 vos_partitionEntry_p pData = &wpNext.wpVosPartitionGetNext.Data;
421 LPTSTR pszName = AnsiToString (pData->name);
422 LPTSTR pszDevice = AnsiToString (pData->deviceName);
424 LPAGGREGATE lpAggregate = New2 (AGGREGATE,(this, pszName, pszDevice));
426 lpAggregate->m_as.dwID = lpAggregate->GetID();
428 FreeString (pszDevice, pData->deviceName);
429 FreeString (pszName, pData->name);
431 lpAggregate->m_wGhost |= GHOST_HAS_SERVER_ENTRY;
432 lpAggregate->m_as.ckStorageTotal = pData->totalSpace;
433 lpAggregate->m_as.ckStorageFree = pData->totalFreeSpace;
434 m_lAggregates->Add (lpAggregate);
436 NOTIFYCALLBACK::SendNotificationToAll (evtCreate, lpAggregate->GetIdentifier());
439 WORKERPACKET wpDone;
440 wpDone.wpVosPartitionGetDone.hEnum = wpBegin.wpVosPartitionGetBegin.hEnum;
441 Worker_DoTask (wtaskVosPartitionGetDone, &wpDone);
444 CloseVosObject();
447 if (fNotify)
448 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAggregatesEnd, GetIdentifier(), ((rc) ? 0 : status));
452 if (pStatus && !rc)
453 *pStatus = status;
454 return TRUE;
458 BOOL SERVER::RefreshServices (BOOL fNotify, ULONG *pStatus)
460 BOOL rc = TRUE;
461 DWORD status = 0;
463 if (m_fServicesOutOfDate)
465 m_fServicesOutOfDate = FALSE;
467 if (fIsMonitored())
469 if (fNotify)
470 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshServicesBegin, GetIdentifier());
472 // First thing is to forget about what services we think we have now.
474 LPENUM pEnum;
475 for (pEnum = m_lServices->FindLast(); pEnum; pEnum = pEnum->FindPrevious())
477 LPSERVICE lpService = (LPSERVICE)(pEnum->GetObject());
478 lpService->SendDeleteNotifications();
479 m_lServices->Remove (lpService);
480 Delete (lpService);
483 // Next, the harder part: look through the server to find a list
484 // of services.
486 PVOID hCell;
487 PVOID hBOS;
488 if ((hBOS = OpenBosObject (&hCell, &status)) == NULL)
489 rc = FALSE;
490 else
492 WORKERPACKET wpBegin;
493 wpBegin.wpBosProcessNameGetBegin.hServer = hBOS;
494 if (!Worker_DoTask (wtaskBosProcessNameGetBegin, &wpBegin, &status))
495 rc = FALSE;
496 else
498 LPSERVICE lpService = New2 (SERVICE,(this, TEXT("BOS")));
499 m_lServices->Add (lpService);
500 NOTIFYCALLBACK::SendNotificationToAll (evtCreate, lpService->GetIdentifier());
502 for (;;)
504 TCHAR szServiceName[ cchNAME ];
506 WORKERPACKET wpNext;
507 wpNext.wpBosProcessNameGetNext.hEnum = wpBegin.wpBosProcessNameGetBegin.hEnum;
508 wpNext.wpBosProcessNameGetNext.pszService = szServiceName;
510 if (!Worker_DoTask (wtaskBosProcessNameGetNext, &wpNext, &status))
512 if (status == ADMITERATORDONE)
513 status = 0;
514 else
515 rc = FALSE;
516 break;
519 lpService = New2 (SERVICE,(this, wpNext.wpBosProcessNameGetNext.pszService));
520 m_lServices->Add (lpService);
521 NOTIFYCALLBACK::SendNotificationToAll (evtCreate, lpService->GetIdentifier());
524 WORKERPACKET wpDone;
525 wpDone.wpBosProcessNameGetDone.hEnum = wpBegin.wpBosProcessNameGetBegin.hEnum;
526 Worker_DoTask (wtaskBosProcessNameGetDone, &wpDone);
529 CloseBosObject();
532 if (fNotify)
533 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshServicesEnd, GetIdentifier(), ((rc) ? 0 : status));
537 if (pStatus && !rc)
538 *pStatus = status;
539 return TRUE;
543 BOOL SERVER::RefreshStatus (BOOL fNotify, ULONG *pStatus)
545 BOOL rc = TRUE;
546 DWORD status = 0;
548 if (m_fStatusOutOfDate)
550 m_fStatusOutOfDate = FALSE;
552 if (fNotify)
553 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusBegin, GetIdentifier());
555 LPCELL lpCell;
556 if ((lpCell = OpenCell (&status)) == NULL)
557 rc = FALSE;
558 else
560 PVOID hCell;
561 if ((hCell = lpCell->GetCellObject (&status)) == NULL)
562 rc = FALSE;
563 else
565 WORKERPACKET wp;
566 wp.wpClientAFSServerGet.hCell = hCell;
567 wp.wpClientAFSServerGet.pszServer = m_szName;
569 if (!Worker_DoTask (wtaskClientAFSServerGet, &wp, &status))
570 rc = FALSE;
571 else
573 m_ss.nAddresses = 0;
575 for (size_t iAddr = 0; iAddr < AFS_MAX_SERVER_ADDRESS; ++iAddr)
577 if (wp.wpClientAFSServerGet.Entry.serverAddress[ iAddr ] == 0)
578 continue;
579 AfsClass_IntToAddress (&m_ss.aAddresses[ m_ss.nAddresses++ ], wp.wpClientAFSServerGet.Entry.serverAddress[ iAddr ]);
582 lpCell->m_lServers->Update (this); // That update affected a hashlistkey
585 lpCell->Close();
588 if (fNotify)
589 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusEnd, GetIdentifier(), ((rc) ? 0 : status));
592 if (pStatus && !rc)
593 *pStatus = status;
594 return TRUE;
598 void SERVER::GetName (LPTSTR pszName)
600 SERVER::ShortenName (pszName, m_szName);
604 void SERVER::GetLongName (LPTSTR pszName)
606 lstrcpy (pszName, m_szName);
610 LPCELL SERVER::OpenCell (ULONG *pStatus)
612 return m_lpiCell->OpenCell (pStatus);
615 BOOL SERVER::GetStatus (LPSERVERSTATUS lpss, BOOL fNotify, ULONG *pStatus)
617 BOOL rc = TRUE;
619 if (m_fMonitor)
620 rc = RefreshStatus (fNotify, pStatus);
622 memcpy (lpss, &m_ss, sizeof(SERVERSTATUS));
623 return rc;
627 short SERVER::GetGhostStatus (void)
629 return m_wGhost;
633 PVOID SERVER::GetUserParam (void)
635 return GetIdentifier()->GetUserParam();
639 void SERVER::SetUserParam (PVOID pUserNew)
641 GetIdentifier()->SetUserParam (pUserNew);
645 void SERVER::ShortenName (LPTSTR pszTarget, LPTSTR pszSource, BOOL fForce)
647 lstrcpy (pszTarget, pszSource);
649 if (fForce || !fLongServerNames)
651 // If the name is really an IP address, don't shorten it.
653 BOOL fIsIPAddress = TRUE;
654 for (LPTSTR pch = pszTarget; *pch && fIsIPAddress; ++pch)
656 if (!isdigit(*pch) && !(*pch == TEXT('.')))
657 fIsIPAddress = FALSE;
660 if (!fIsIPAddress)
662 if ((pszTarget = (LPTSTR)lstrchr (pszTarget, TEXT('.'))) != NULL)
663 *pszTarget = TEXT('\0');
669 BOOL SERVER::fIsMonitored (void)
671 return m_fMonitor;
675 BOOL SERVER::SetMonitor (BOOL fShouldMonitor, ULONG *pStatus)
677 BOOL rc = TRUE;
678 ULONG status = 0;
680 if (m_fMonitor != fShouldMonitor)
682 LPCELL lpCell;
683 if ((lpCell = m_lpiCell->OpenCell (&status)) == NULL)
684 rc = FALSE;
685 else
687 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusBegin, GetIdentifier());
689 if ((m_fMonitor = fShouldMonitor) == FALSE)
691 FreeAll();
692 (lpCell->m_nServersUnmonitored)++;
694 else // (fMonitor == TRUE)
696 (lpCell->m_nServersUnmonitored)--;
697 Invalidate();
698 rc = RefreshAll (&status);
701 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusEnd, GetIdentifier(), m_lastStatus);
702 lpCell->Close();
706 if (!rc && pStatus)
707 *pStatus = status;
708 return rc;
713 * REFRESHALL __________________________________________________________________
715 * If a server is down, or doesn't have an VOS process running, it could
716 * take some time before we time out trying to talk to the server. During
717 * the course of a refresh, the first timeout-and-fail that we will hit is
718 * our call to wtaskVosPartitionGetBegin; since this call is very quick if
719 * it's going to be successful, we can safely perform this call once up-front
720 * to test to see if the server is listening at all. That test is performed
721 * on a separate thread, so that in the event the request times out, we can
722 * simply discard the thread and let it terminate on its own.
726 typedef struct
728 BOOL fInUse;
729 BOOL fCanceled;
730 LPSERVER lpServer;
731 PVOID hCell;
732 } REFRESHSECTION, *LPREFRESHSECTION;
734 static REFRESHSECTION *aRefSec = NULL;
735 static size_t cRefSec = 0;
736 static LPCRITICAL_SECTION pcsRefSec = NULL;
738 void AfsClass_InitRefreshSections (void)
740 if (pcsRefSec == NULL)
742 pcsRefSec = New (CRITICAL_SECTION);
743 InitializeCriticalSection (pcsRefSec);
748 void AfsClass_SkipRefresh (int idSection)
750 AfsClass_InitRefreshSections();
751 EnterCriticalSection (pcsRefSec);
753 if (aRefSec && (idSection < (int)cRefSec))
755 if (aRefSec[ idSection ].fInUse)
757 aRefSec[ idSection ].fCanceled = TRUE;
761 LeaveCriticalSection (pcsRefSec);
765 DWORD WINAPI SERVER::CanTalkToServer_ThreadProc (PVOID lp)
767 int idSection = PtrToInt(lp);
769 // Until we post a notification saying that we've entered
770 // a section, we don't need to worry about the aRefSec[] entry
771 // being invalid. Once that post is made, the user can skip
772 // the section at any time--so we'll have to check frequently,
773 // always under the pcsRefSec critical section.
775 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAllSectionStart, NULL, NULL, NULL, NULL, idSection, 0);
777 BOOL fAggregatesOK = FALSE;
778 BOOL fServicesOK = FALSE;
779 BOOL fContinue = TRUE;
781 // Try to get the BOS object for this server. Remember, there's
782 // a catch here: we can only assume that the aRefSec[idSection].lpServer
783 // pointer is valid so long as we're within the pcsRefSec critical
784 // section! (if we're in that critsec, we can verify that no one
785 // has canceled the operation--and if no one has, there is a thread
786 // hanging around which holds the library's critsec, which ensures
787 // the lpServer pointer won't have been freed.)
789 PVOID hCell;
790 PVOID hBOS = NULL;
791 PVOID hVOS = NULL;
793 TCHAR szServer[ cchNAME ];
795 EnterCriticalSection (pcsRefSec);
796 if ( ((!aRefSec[ idSection ].fInUse) || (aRefSec[ idSection ].fCanceled)) )
797 fContinue = FALSE;
798 else
800 hCell = aRefSec[ idSection ].hCell;
801 aRefSec[ idSection ].lpServer->GetLongName (szServer);
803 LeaveCriticalSection (pcsRefSec);
805 if (fContinue)
807 WORKERPACKET wp;
808 wp.wpBosServerOpen.hCell = hCell;
809 wp.wpBosServerOpen.pszServer = szServer;
811 ULONG status;
812 fContinue = Worker_DoTask (wtaskBosServerOpen, &wp, &status);
814 EnterCriticalSection (pcsRefSec);
815 if ( ((!aRefSec[ idSection ].fInUse) || (aRefSec[ idSection ].fCanceled)) )
816 fContinue = FALSE;
817 else if (!fContinue)
818 aRefSec[ idSection ].lpServer->m_lastStatus = status;
819 else
820 hBOS = wp.wpBosServerOpen.hServer;
821 LeaveCriticalSection (pcsRefSec);
824 if (fContinue)
826 WORKERPACKET wpBegin;
827 wpBegin.wpBosProcessNameGetBegin.hServer = hBOS;
829 ULONG status;
830 fContinue = Worker_DoTask (wtaskBosProcessNameGetBegin, &wpBegin, &status);
832 EnterCriticalSection (pcsRefSec);
833 if ( ((!aRefSec[ idSection ].fInUse) || (aRefSec[ idSection ].fCanceled)) )
834 fContinue = FALSE;
835 else if (fContinue)
836 aRefSec[ idSection ].lpServer->m_lastStatus = status;
837 LeaveCriticalSection (pcsRefSec);
839 if (fContinue)
841 WORKERPACKET wpDone;
842 wpDone.wpBosProcessNameGetDone.hEnum = wpBegin.wpBosProcessNameGetBegin.hEnum;
843 Worker_DoTask (wtaskBosProcessNameGetDone, &wpDone);
845 // We can talk to BOS!
846 fServicesOK = TRUE;
850 // If we couldn't talk to BOS, it's a sure bet the server is down--
851 // and regardless, if BOS isn't around, VOS isn't either. So
852 // we may not even have to test that.
854 if (fContinue)
856 WORKERPACKET wp;
857 wp.wpVosServerOpen.hCell = hCell;
858 wp.wpVosServerOpen.pszServer = szServer;
860 ULONG status;
861 fContinue = Worker_DoTask (wtaskVosServerOpen, &wp, &status);
863 EnterCriticalSection (pcsRefSec);
864 if ( ((!aRefSec[ idSection ].fInUse) || (aRefSec[ idSection ].fCanceled)) )
865 fContinue = FALSE;
866 else if (!fContinue)
867 aRefSec[ idSection ].lpServer->m_lastStatus = status;
868 else
869 hVOS = wp.wpVosServerOpen.hServer;
870 LeaveCriticalSection (pcsRefSec);
873 if (fContinue)
875 WORKERPACKET wpBegin;
876 wpBegin.wpVosPartitionGetBegin.hCell = hCell;
877 wpBegin.wpVosPartitionGetBegin.hServer = hVOS;
879 ULONG status;
880 fContinue = Worker_DoTask (wtaskVosPartitionGetBegin, &wpBegin, &status);
882 EnterCriticalSection (pcsRefSec);
883 if ( ((!aRefSec[ idSection ].fInUse) || (aRefSec[ idSection ].fCanceled)) )
884 fContinue = FALSE;
885 else if (fContinue)
886 aRefSec[ idSection ].lpServer->m_lastStatus = status;
887 LeaveCriticalSection (pcsRefSec);
889 if (fContinue)
891 WORKERPACKET wpDone;
892 wpDone.wpVosPartitionGetDone.hEnum = wpBegin.wpVosPartitionGetBegin.hEnum;
893 Worker_DoTask (wtaskVosPartitionGetDone, &wpDone);
895 // We can talk to VOS!
896 fAggregatesOK = TRUE;
900 // Close the VOS and BOS objects we obtained.
902 if (hBOS)
904 WORKERPACKET wp;
905 wp.wpBosServerClose.hServer = hBOS;
906 Worker_DoTask (wtaskBosServerClose, &wp);
908 if (hVOS)
910 WORKERPACKET wp;
911 wp.wpVosServerClose.hServer = hVOS;
912 Worker_DoTask (wtaskVosServerClose, &wp);
915 // Return our entry in the RefSec array back to the pool.
916 // If the request was never canceled, there is another
917 // thread waiting to hear our results--update the server
918 // entry specified by RefSec before leaving.
920 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAllSectionEnd, NULL, NULL, NULL, NULL, idSection, 0);
922 EnterCriticalSection (pcsRefSec);
923 if ( (aRefSec[ idSection ].fInUse) && (!aRefSec[ idSection ].fCanceled) )
925 aRefSec[ idSection ].lpServer->m_fCanGetAggregates = fAggregatesOK;
926 aRefSec[ idSection ].lpServer->m_fCanGetServices = fServicesOK;
928 aRefSec[ idSection ].fInUse = FALSE;
929 LeaveCriticalSection (pcsRefSec);
930 return 1;
934 BOOL SERVER::CanTalkToServer (ULONG *pStatus)
936 // Ensure the server exists in the cell at all--
937 // this call just updates the server's IP addresses
938 // etc (information it gets from the database servers)
939 // and doesn't require talking to the server itself.
941 if (!RefreshStatus (FALSE, pStatus))
942 return FALSE;
944 // Find a new refsec array element to use...
946 AfsClass_InitRefreshSections();
947 EnterCriticalSection (pcsRefSec);
949 int idSection;
950 for (idSection = 0; idSection < (int)cRefSec; ++idSection)
952 if (!aRefSec[ idSection ].fInUse)
953 break;
955 if (idSection == (int)cRefSec)
957 if (!REALLOC (aRefSec, cRefSec, 1+idSection, 4))
959 if (pStatus)
960 *pStatus = GetLastError();
961 LeaveCriticalSection (pcsRefSec);
962 return FALSE;
965 aRefSec[ idSection ].fInUse = TRUE;
966 aRefSec[ idSection ].fCanceled = FALSE;
967 aRefSec[ idSection ].lpServer = this;
968 aRefSec[ idSection ].hCell = NULL;
970 LPCELL lpCell;
971 if ((lpCell = OpenCell()) != NULL)
973 aRefSec[ idSection ].hCell = lpCell->GetCellObject();
974 lpCell->Close();
977 LeaveCriticalSection (pcsRefSec);
979 // Until we find out differently, assume that we won't be
980 // able to query VOS or BOS on this server.
982 m_fCanGetAggregates = FALSE;
983 m_fCanGetServices = FALSE;
984 m_lastStatus = 0;
986 // Fork a separate thread, on which to quickly try to talk
987 // to the server.
989 DWORD dwThreadID;
990 HANDLE hThread;
991 if ((hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)CanTalkToServer_ThreadProc, IntToPtr(idSection), 0, &dwThreadID)) == NULL)
993 EnterCriticalSection (pcsRefSec);
994 aRefSec[ idSection ].fInUse = FALSE;
995 LeaveCriticalSection (pcsRefSec);
996 if (pStatus)
997 *pStatus = GetLastError();
998 return FALSE;
1000 SetThreadPriority (hThread, THREAD_PRIORITY_BELOW_NORMAL);
1002 // Wait for that thread to terminate, or for our
1003 // newly-allocated RefSec entry to be marked Canceled.
1005 DWORD dw;
1006 for (dw = STILL_ACTIVE; dw == STILL_ACTIVE; )
1008 EnterCriticalSection (pcsRefSec);
1010 GetExitCodeThread (hThread, &dw);
1011 if (dw == STILL_ACTIVE)
1013 if ( (aRefSec[ idSection ].fInUse) &&
1014 (aRefSec[ idSection ].lpServer == this) &&
1015 (aRefSec[ idSection ].fCanceled) )
1017 if (m_lastStatus == 0)
1018 m_lastStatus = ERROR_CANCELLED;
1019 dw = 0;
1023 LeaveCriticalSection (pcsRefSec);
1025 if (dw == STILL_ACTIVE)
1026 Sleep(100); // wait another brief instant
1029 // dw == 0 : user canceled operation (thread is still running!)
1030 // dw == 1 : thread completed successfully, and set fCanTalkTo* flags.
1032 // Note that the thread will clear aRefSec[idSection].fInUse when it
1033 // terminates (so, if dw!=-1, it has already done so).
1035 if (pStatus)
1036 *pStatus = m_lastStatus;
1037 return (dw == 0) ? FALSE : TRUE;
1041 BOOL SERVER::RefreshAll (ULONG *pStatus, double dInit, double dFactor)
1043 BOOL rc = TRUE;
1044 ULONG status = 0;
1046 if (m_fAggregatesOutOfDate || m_fServicesOutOfDate)
1048 if ((++cRefreshAllReq) == 1)
1050 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAllBegin, GetIdentifier(), 0);
1053 double perAGGREGATES = 65.0; // % of time spent finding aggs & sets
1054 double perSERVICES = 25.0; // % of time spent finding services
1055 double perVLDB = 10.0; // % of time spent finding VLDB info
1057 if (cRefreshAllReq >= 2) // being called as part of a cell-wide op?
1059 perAGGREGATES = 80.0; // % of time spent finding aggs & sets
1060 perSERVICES = 20.0; // % of time spent finding services
1061 perVLDB = 0.0; // we won't query VLDB stuff ourself.
1064 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusBegin, GetIdentifier());
1066 if (!CanTalkToServer (&status)) // Determines fCanGetAggregates, fCanGetServices
1068 if (m_fMonitor)
1069 SetMonitor (FALSE);
1070 rc = FALSE;
1072 else
1074 if (!m_fCanGetAggregates)
1076 FreeAggregates();
1077 m_fAggregatesOutOfDate = FALSE;
1079 else
1081 size_t nAggregates = 0;
1082 size_t iAggregate = 0;
1083 HENUM hEnum;
1084 LPAGGREGATE lpAggregate;
1085 for (lpAggregate = AggregateFindFirst (&hEnum); lpAggregate; lpAggregate = AggregateFindNext (&hEnum))
1087 ++nAggregates;
1088 lpAggregate->Close();
1091 if (nAggregates)
1093 for (lpAggregate = AggregateFindFirst (&hEnum); lpAggregate; lpAggregate = AggregateFindNext (&hEnum))
1095 ULONG perComplete = (ULONG)( ((double)perAGGREGATES / 100.0) * ((double)iAggregate * 100.0 / nAggregates) );
1096 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAllUpdate, lpAggregate->GetIdentifier(), NULL, NULL, NULL, (ULONG)( 100.0 * dInit + dFactor * (double)perComplete ), 0);
1098 lpAggregate->RefreshFilesets (TRUE);
1099 lpAggregate->Close();
1101 ++iAggregate;
1106 if (!m_fCanGetServices)
1108 FreeServices();
1109 m_fServicesOutOfDate = FALSE;
1111 else
1113 size_t nServices = 0;
1114 size_t iService = 0;
1115 HENUM hEnum;
1116 LPSERVICE lpService;
1117 for (lpService = ServiceFindFirst (&hEnum); lpService; lpService = ServiceFindNext (&hEnum))
1119 ++nServices;
1120 lpService->Close();
1123 if (nServices)
1125 for (lpService = ServiceFindFirst (&hEnum); lpService; lpService = ServiceFindNext (&hEnum))
1127 ULONG perComplete = (ULONG)( (double)perAGGREGATES + ((double)perSERVICES / 100.0) * ((double)iService * 100.0 / nServices) );
1128 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAllUpdate, lpService->GetIdentifier(), NULL, NULL, NULL, (ULONG)( 100.0 * dInit + dFactor * (double)perComplete ), 0);
1130 lpService->RefreshStatus (TRUE);
1131 lpService->Close();
1133 ++iService;
1138 if (cRefreshAllReq == 1) // not being called as part of a cell-wide op?
1140 LPCELL lpCell;
1141 if ((lpCell = OpenCell()) != NULL)
1143 lpCell->RefreshVLDB (GetIdentifier(), TRUE, NULL);
1144 lpCell->Close();
1149 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusEnd, GetIdentifier(), m_lastStatus);
1151 if ((--cRefreshAllReq) == 0)
1153 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAllEnd, GetIdentifier(), NULL, NULL, NULL, 100, m_lastStatus);
1157 if (rc && m_lastStatus)
1158 rc = FALSE;
1159 if (!rc && pStatus)
1160 *pStatus = status;
1161 return rc;
1166 * AGGREGATES _________________________________________________________________
1170 LPAGGREGATE SERVER::OpenAggregate (LPTSTR pszName, ULONG *pStatus)
1172 if (!RefreshAggregates (TRUE, pStatus))
1173 return NULL;
1175 LPAGGREGATE lpAggregate;
1176 if ((lpAggregate = (LPAGGREGATE)(m_lkAggregateName->GetFirstObject (pszName))) != NULL)
1177 AfsClass_Enter();
1179 return lpAggregate;
1183 LPAGGREGATE SERVER::OpenAggregate (ULONG dwID, ULONG *pStatus)
1185 if (!RefreshAggregates (TRUE, pStatus))
1186 return NULL;
1188 LPAGGREGATE lpAggregate;
1189 if ((lpAggregate = (LPAGGREGATE)(m_lkAggregateID->GetFirstObject (&dwID))) != NULL)
1190 AfsClass_Enter();
1192 return lpAggregate;
1196 LPAGGREGATE SERVER::AggregateFindFirst (HENUM *phEnum, BOOL fNotify, ULONG *pStatus)
1198 return AggregateFindFirst (phEnum, NULL, fNotify, pStatus);
1202 LPAGGREGATE SERVER::AggregateFindFirst (HENUM *phEnum, LPIDENT lpiFind, BOOL fNotify, ULONG *pStatus)
1204 LPAGGREGATE lpAggregate = NULL;
1206 if (!RefreshAggregates (fNotify, pStatus))
1207 return NULL;
1209 if (lpiFind != NULL)
1211 lpAggregate = lpiFind->OpenAggregate();
1212 *phEnum = NULL;
1214 else if ((*phEnum = m_lAggregates->FindFirst()) != NULL)
1216 lpAggregate = (LPAGGREGATE)( (*phEnum)->GetObject() );
1217 AfsClass_Enter();
1220 if (!lpAggregate && pStatus)
1221 *pStatus = ERROR_FILE_NOT_FOUND;
1222 return lpAggregate;
1226 LPAGGREGATE SERVER::AggregateFindNext (HENUM *phEnum)
1228 LPAGGREGATE lpAggregate = NULL;
1230 if (*phEnum)
1232 if ((*phEnum = (*phEnum)->FindNext()) != NULL)
1234 lpAggregate = (LPAGGREGATE)( (*phEnum)->GetObject() );
1235 AfsClass_Enter();
1239 return lpAggregate;
1243 void SERVER::AggregateFindClose (HENUM *phEnum)
1245 if (*phEnum)
1247 Delete (*phEnum);
1248 *phEnum = NULL;
1254 * SERVICES ___________________________________________________________________
1258 LPSERVICE SERVER::OpenService (LPTSTR pszName, ULONG *pStatus)
1260 if (!RefreshServices (TRUE, pStatus))
1261 return NULL;
1263 LPSERVICE lpService;
1264 if ((lpService = (LPSERVICE)(m_lkServiceName->GetFirstObject (pszName))) != NULL)
1265 AfsClass_Enter();
1267 return lpService;
1271 LPSERVICE SERVER::ServiceFindFirst (HENUM *phEnum, BOOL fNotify, ULONG *pStatus)
1273 return ServiceFindFirst (phEnum, NULL, fNotify, pStatus);
1277 LPSERVICE SERVER::ServiceFindFirst (HENUM *phEnum, LPIDENT lpiFind, BOOL fNotify, ULONG *pStatus)
1279 LPSERVICE lpService = NULL;
1281 if (!RefreshServices (fNotify, pStatus))
1282 return NULL;
1284 if (lpiFind != NULL)
1286 lpService = lpiFind->OpenService();
1287 *phEnum = NULL;
1289 else if ((*phEnum = m_lServices->FindFirst()) != NULL)
1291 lpService = (LPSERVICE)( (*phEnum)->GetObject() );
1292 AfsClass_Enter();
1295 if (!lpService && pStatus)
1296 *pStatus = ERROR_FILE_NOT_FOUND;
1297 return lpService;
1301 LPSERVICE SERVER::ServiceFindNext (HENUM *phEnum)
1303 LPSERVICE lpService = NULL;
1305 if (*phEnum)
1307 if ((*phEnum = (*phEnum)->FindNext()) != NULL)
1309 lpService = (LPSERVICE)( (*phEnum)->GetObject() );
1310 AfsClass_Enter();
1314 return lpService;
1318 void SERVER::ServiceFindClose (HENUM *phEnum)
1320 if (*phEnum)
1322 Delete (*phEnum);
1323 *phEnum = NULL;
1329 * HASH KEYS __________________________________________________________________
1333 BOOL CALLBACK SERVER::KeyAggregateName_Compare (LPHASHLISTKEY pKey, PVOID pObject, PVOID pData)
1335 return !lstrcmp (((LPAGGREGATE)pObject)->m_szName, (LPTSTR)pData);
1338 HASHVALUE CALLBACK SERVER::KeyAggregateName_HashObject (LPHASHLISTKEY pKey, PVOID pObject)
1340 return SERVER::KeyAggregateName_HashData (pKey, ((LPAGGREGATE)pObject)->m_szName);
1343 HASHVALUE CALLBACK SERVER::KeyAggregateName_HashData (LPHASHLISTKEY pKey, PVOID pData)
1345 return HashString ((LPTSTR)pData);
1349 BOOL CALLBACK SERVER::KeyAggregateID_Compare (LPHASHLISTKEY pKey, PVOID pObject, PVOID pData)
1351 return (((LPAGGREGATE)pObject)->m_as.dwID == *(ULONG*)pData);
1354 HASHVALUE CALLBACK SERVER::KeyAggregateID_HashObject (LPHASHLISTKEY pKey, PVOID pObject)
1356 return SERVER::KeyAggregateID_HashData (pKey, &((LPAGGREGATE)pObject)->m_as.dwID);
1359 HASHVALUE CALLBACK SERVER::KeyAggregateID_HashData (LPHASHLISTKEY pKey, PVOID pData)
1361 return (HASHVALUE)*(ULONG*)pData;
1365 BOOL CALLBACK SERVER::KeyServiceName_Compare (LPHASHLISTKEY pKey, PVOID pObject, PVOID pData)
1367 return !lstrcmp (((LPSERVICE)pObject)->m_szName, (LPTSTR)pData);
1370 HASHVALUE CALLBACK SERVER::KeyServiceName_HashObject (LPHASHLISTKEY pKey, PVOID pObject)
1372 return SERVER::KeyServiceName_HashData (pKey, ((LPSERVICE)pObject)->m_szName);
1375 HASHVALUE CALLBACK SERVER::KeyServiceName_HashData (LPHASHLISTKEY pKey, PVOID pData)
1377 return HashString ((LPTSTR)pData);