2 * Copyright 2000, International Business Machines Corporation and others.
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
14 #include <afsconfig.h>
15 #include <afs/param.h>
20 #include "TaAfsAdmSvrInternal.h"
23 #include <afs/afs_AdminErrors.h>
28 * VARIABLES __________________________________________________________________
32 #define cminREQ_CLIENT_PING (csecAFSADMSVR_CLIENT_PING * 2L / 60L)
34 #define cREALLOC_CLIENTS 1
35 #define cREALLOC_OPERATIONS 16
37 #define cminAUTO_SHUTDOWN 2 // stop if idle for more than 2min
38 #define cminAUTO_SHUTDOWN_SLEEP 1 // test for stop every minute
42 TCHAR szName[ cchSTRING ];
43 SOCKADDR_IN ipAddress;
45 } CLIENTINFO, *LPCLIENTINFO;
53 } OPERATION, *LPOPERATION;
58 LPCRITICAL_SECTION pcsAfsAdmSvr;
60 LPCLIENTINFO *aClients;
62 size_t cClientsAllocated;
64 LPNOTIFYCALLBACK pNotify;
67 HANDLE hThreadShutdown;
68 DWORD timeLastIdleStart;
70 OPERATION *aOperations;
72 size_t cOperationsAllocated;
80 * PROTOTYPES _________________________________________________________________
84 void AfsAdmSvr_TestShutdown (void);
85 DWORD WINAPI AfsAdmSvr_AutoShutdownThread (LPVOID lp);
89 * SYNCHRONIZATION ____________________________________________________________
93 void AfsAdmSvr_Enter (void)
97 l.pcsAfsAdmSvr = New (CRITICAL_SECTION);
98 InitializeCriticalSection (l.pcsAfsAdmSvr);
100 EnterCriticalSection (l.pcsAfsAdmSvr);
103 void AfsAdmSvr_Leave (void)
105 LeaveCriticalSection (l.pcsAfsAdmSvr);
110 * CLIENT INFORMATION _________________________________________________________
114 BOOL AfsAdmSvr_fIsValidClient (UINT_PTR idClient)
119 for (size_t iClient = 0; !rc && iClient < l.cClientsAllocated; ++iClient)
121 if (idClient == (UINT_PTR)l.aClients[ iClient ])
123 if (l.aClients[ iClient ]->timeLastPing + cminREQ_CLIENT_PING > AfsAdmSvr_GetCurrentTime())
133 BOOL AfsAdmSvr_AttachClient (LPCTSTR pszName, PVOID *pidClient, ULONG *pStatus)
137 for (iClient = 0; iClient < l.cClientsAllocated; ++iClient)
139 if (!l.aClients[ iClient ])
142 if (!REALLOC (l.aClients, l.cClientsAllocated, 1+iClient, cREALLOC_CLIENTS))
147 if ((l.aClients[ iClient ] = New (CLIENTINFO)) == NULL)
152 memset (l.aClients[ iClient ], 0x00, sizeof(CLIENTINFO));
153 lstrcpy (l.aClients[ iClient ]->szName, pszName);
154 l.aClients[ iClient ]->timeLastPing = AfsAdmSvr_GetCurrentTime();
157 if (!AfsAdmSvr_ResolveName (&l.aClients[ iClient ]->ipAddress, l.aClients[ iClient ]->szName))
158 memset (&l.aClients[ iClient ]->ipAddress, 0x00, sizeof(SOCKADDR_IN));
160 *pidClient = (PVOID)(l.aClients[ iClient ]);
166 void AfsAdmSvr_DetachClient (UINT_PTR idClient)
170 for (iClient = 0; iClient < l.cClientsAllocated; ++iClient)
172 if (idClient == (UINT_PTR)(l.aClients[ iClient ]))
175 if (iClient < l.cClientsAllocated)
177 Delete (l.aClients[ iClient ]);
178 l.aClients[ iClient ] = NULL;
181 AfsAdmSvr_TestShutdown();
186 LPCTSTR AfsAdmSvr_GetClientName (UINT_PTR idClient)
188 static TCHAR szName[ cchSTRING ];
189 LPCTSTR pszName = NULL;
192 for (size_t iClient = 0; !pszName && iClient < l.cClientsAllocated; ++iClient)
194 if (idClient == (UINT_PTR)(l.aClients[ iClient ]))
196 lstrcpy (szName, l.aClients[ iClient ]->szName);
206 LPSOCKADDR_IN AfsAdmSvr_GetClientAddress (UINT_PTR idClient)
208 static SOCKADDR_IN ipAddress;
209 LPSOCKADDR_IN pAddress = NULL;
212 for (size_t iClient = 0; !pAddress && iClient < l.cClientsAllocated; ++iClient)
214 if (idClient == (UINT_PTR)(l.aClients[ iClient ]))
216 memcpy (&ipAddress, &l.aClients[ iClient ]->ipAddress, sizeof(SOCKADDR_IN));
217 pAddress = &ipAddress;
226 void AfsAdmSvr_PingClient (UINT_PTR idClient)
230 for (size_t iClient = 0; iClient < l.cClientsAllocated; ++iClient)
232 if (idClient == (UINT_PTR)(l.aClients[ iClient ]))
234 l.aClients[ iClient ]->timeLastPing = AfsAdmSvr_GetCurrentTime();
242 DWORD AfsAdmSvr_GetCurrentTime (void) // returns counter in ~minute increments
244 static WORD wMonthish = 0; // One "Monthish" is 49.7 days
245 static WORD wTickLast = 0;
246 DWORD dwTick = GetTickCount();
247 WORD wTickNow = HIWORD(dwTick);
248 if (wTickNow < wTickLast) // wrapped over a Monthish?
250 wTickLast = wTickNow;
251 return MAKELONG(wTickNow,wMonthish);
256 * STARTUP/SHUTDOWN ___________________________________________________________
260 void AfsAdmSvr_Startup (void)
262 l.pNotify = New2 (NOTIFYCALLBACK,(AfsAdmSvr_NotifyCallback, 0));
263 l.fOperational = FALSE;
266 if (AfsClass_Initialize (&status))
267 l.fOperational = TRUE;
270 Print (dlERROR, TEXT("Could not initialize AfsClass (fatal error 0x%08lX)"), status);
271 Print (dlERROR, TEXT("Remaining active to tell potential clients about the problem"));
274 if (!l.hThreadShutdown)
277 l.hThreadShutdown = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)AfsAdmSvr_AutoShutdownThread, (LPVOID)0, 0, &dwThreadID);
282 void AfsAdmSvr_Shutdown (void)
286 l.fOperational = FALSE;
291 * GENERAL ____________________________________________________________________
295 BOOL FALSE_ (ULONG status, ULONG *pStatus, size_t iOp)
299 if (iOp != (size_t)-2)
300 AfsAdmSvr_EndOperation (iOp);
304 BOOL Leave_FALSE_ (ULONG status, ULONG *pStatus, size_t iOp)
309 if (iOp != (size_t)-2)
310 AfsAdmSvr_EndOperation (iOp);
314 PVOID NULL_ (ULONG status, ULONG *pStatus, size_t iOp)
318 if (iOp != (size_t)-2)
319 AfsAdmSvr_EndOperation (iOp);
323 PVOID Leave_NULL_ (ULONG status, ULONG *pStatus, size_t iOp)
328 if (iOp != (size_t)-2)
329 AfsAdmSvr_EndOperation (iOp);
333 BOOL TRUE_ (ULONG *pStatus, size_t iOp)
337 if (iOp != (size_t)-2)
338 AfsAdmSvr_EndOperation (iOp);
342 BOOL Leave_TRUE_ (ULONG *pStatus, size_t iOp)
347 if (iOp != (size_t)-2)
348 AfsAdmSvr_EndOperation (iOp);
352 IDENTTYPE GetAsidType (ASID idObject)
356 iType = ((LPIDENT)idObject)->GetType();
364 BOOL AfsAdmSvr_ResolveName (LPSOCKADDR_IN pAddress, LPTSTR pszName)
366 if ((pszName[0] >= TEXT('0')) && (pszName[0] <= TEXT('9')))
369 if ((ipAddress = inet_addr (pszName)) == INADDR_NONE)
372 memset (pAddress, 0x00, sizeof(SOCKADDR_IN));
373 pAddress->sin_family = AF_INET;
374 pAddress->sin_addr.s_addr = ipAddress;
377 if ((pEntry = gethostbyaddr ((char*)&ipAddress, sizeof(ipAddress), AF_INET)) != NULL)
378 lstrcpy (pszName, pEntry->h_name);
380 else // (!isdigit(szServer[0]))
383 if ((pEntry = gethostbyname (pszName)) == NULL)
386 memset (pAddress, 0x00, sizeof(SOCKADDR_IN));
387 pAddress->sin_family = AF_INET;
388 pAddress->sin_addr.s_addr = *(int *)pEntry->h_addr;
390 lstrcpy (pszName, pEntry->h_name);
398 * AUTO-SHUTDOWN ______________________________________________________________
402 DWORD WINAPI AfsAdmSvr_AutoShutdownThread (LPVOID lp)
408 BOOL fShutdown = l.fAutoShutdown;
410 // If there are any clients connected, forcably disconnect any
411 // that haven't pinged us for too long
413 for (size_t iClient = 0; iClient < l.cClientsAllocated; ++iClient)
415 if (!l.aClients[ iClient ])
417 if (l.aClients[ iClient ]->timeLastPing + cminREQ_CLIENT_PING <= AfsAdmSvr_GetCurrentTime())
419 Print (dlCONNECTION, "Client 0x%08lX idle for too long; detaching", l.aClients[ iClient ]);
420 AfsAdmSvr_DetachClient ((UINT_PTR)l.aClients[ iClient ]);
424 // If any operations are in progress, we can't shutdown.
429 // If any clients are still connected, we can't shutdown.
434 // If we haven't been idle long enough, we can't shutdown
436 if (!l.timeLastIdleStart)
438 else if (l.timeLastIdleStart + cminAUTO_SHUTDOWN > AfsAdmSvr_GetCurrentTime())
441 // That's it; can we stop now?
445 Print ("Idle for too long; shutting down.");
446 RpcMgmtStopServerListening (NULL);
447 AfsAdmSvr_StopCallbackManagers();
455 Sleep (cminAUTO_SHUTDOWN_SLEEP * 60L * 1000L);
463 void AfsAdmSvr_EnableAutoShutdown (BOOL fEnable)
467 l.fAutoShutdown = fEnable;
470 Print (dlDETAIL, TEXT("Auto-shutdown enabled, trigger = %lu minutes idle time"), cminAUTO_SHUTDOWN);
472 Print (dlDETAIL, TEXT("Auto-shutdown on idle disabled"));
478 void AfsAdmSvr_TestShutdown (void)
480 if (!l.cOperations && !l.cClients)
482 l.timeLastIdleStart = AfsAdmSvr_GetCurrentTime();
487 size_t AfsAdmSvr_BeginOperation (UINT_PTR idClient, LPASACTION pAction)
494 for (iOp = 0; iOp < l.cOperationsAllocated; ++iOp)
496 if (!l.aOperations[ iOp ].fInUse)
499 if (!REALLOC (l.aOperations, l.cOperationsAllocated, 1+iOp, cREALLOC_OPERATIONS))
505 l.aOperations[ iOp ].idClient = idClient;
506 l.aOperations[ iOp ].pAction = NULL;
507 l.aOperations[ iOp ].fInUse = TRUE;
511 l.aOperations[ iOp ].pAction = New (ASACTION);
512 memcpy (l.aOperations[ iOp ].pAction, pAction, sizeof(ASACTION));
513 l.aOperations[ iOp ].pAction->idAction = ++l.idActionLast;
514 l.aOperations[ iOp ].pAction->idClient = idClient;
515 l.aOperations[ iOp ].pAction->csecActive = 0;
518 switch (l.aOperations[ iOp ].pAction->Action)
521 wsprintf (szDesc, TEXT("Refresh (scope=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Refresh.idScope);
524 wsprintf (szDesc, TEXT("Scout (scope=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Refresh.idScope);
526 case ACTION_USER_CHANGE:
527 wsprintf (szDesc, TEXT("ChangeUser (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Change.idUser);
529 case ACTION_USER_PW_CHANGE:
530 wsprintf (szDesc, TEXT("SetUserPassword (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Pw_Change.idUser);
532 case ACTION_USER_UNLOCK:
533 wsprintf (szDesc, TEXT("UnlockUser (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Unlock.idUser);
535 case ACTION_USER_CREATE:
536 wsprintf (szDesc, TEXT("CreateUser (user=%s)"), l.aOperations[ iOp ].pAction->u.User_Create.szUser);
538 case ACTION_USER_DELETE:
539 wsprintf (szDesc, TEXT("CreateUser (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Delete.idUser);
541 case ACTION_GROUP_CHANGE:
542 wsprintf (szDesc, TEXT("ChangeGroup (group=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Group_Change.idGroup);
544 case ACTION_GROUP_MEMBER_ADD:
545 wsprintf (szDesc, TEXT("AddGroupMember (group=0x%08lX, user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Group_Member_Add.idGroup, l.aOperations[ iOp ].pAction->u.Group_Member_Add.idUser);
547 case ACTION_GROUP_MEMBER_REMOVE:
548 wsprintf (szDesc, TEXT("RemoveGroupMember (group=0x%08lX, user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Group_Member_Remove.idGroup, l.aOperations[ iOp ].pAction->u.Group_Member_Remove.idUser);
550 case ACTION_GROUP_RENAME:
551 wsprintf (szDesc, TEXT("RenameGroup (group=0x%08lX, new name=%s)"), l.aOperations[ iOp ].pAction->u.Group_Rename.idGroup, l.aOperations[ iOp ].pAction->u.Group_Rename.szNewName);
553 case ACTION_GROUP_DELETE:
554 wsprintf (szDesc, TEXT("CreateGroup (group=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Group_Delete.idGroup);
556 case ACTION_CELL_CHANGE:
557 wsprintf (szDesc, TEXT("ChangeCell (cell=0x%08lX)"), l.aOperations[ iOp ].pAction->idCell);
560 wsprintf (szDesc, TEXT("Unknown Action (#%lu)"), l.aOperations[ iOp ].pAction->Action);
563 Print (dlOPERATION, TEXT("Starting action 0x%08lX: %s"), l.aOperations[ iOp ].pAction->idAction, szDesc);
565 AfsAdmSvr_PostCallback (cbtACTION, FALSE, l.aOperations[ iOp ].pAction);
568 l.aOperations[ iOp ].dwTickStart = GetTickCount();
574 void AfsAdmSvr_EndOperation (size_t iOp)
578 if ((iOp != (size_t)-1) && (iOp < l.cOperationsAllocated) && (l.aOperations[ iOp ].fInUse))
580 if (l.aOperations[ iOp ].pAction)
582 Print (dlOPERATION, TEXT("Ending action 0x%08lX"), l.aOperations[ iOp ].pAction->idAction);
583 AfsAdmSvr_PostCallback (cbtACTION, TRUE, l.aOperations[ iOp ].pAction);
584 Delete (l.aOperations[ iOp ].pAction);
586 memset (&l.aOperations[ iOp ], 0x00, sizeof(l.aOperations[ iOp ]));
590 AfsAdmSvr_TestShutdown();
595 BOOL AfsAdmSvr_GetOperation (DWORD idAction, LPASACTION pAction)
599 for (size_t iOp = 0; iOp < l.cOperationsAllocated; ++iOp)
601 if (!l.aOperations[ iOp ].fInUse)
603 if (!l.aOperations[ iOp ].pAction)
605 if (l.aOperations[ iOp ].pAction->idAction != idAction)
608 memcpy (pAction, l.aOperations[ iOp ].pAction, sizeof(ASACTION));
609 pAction->csecActive = (GetTickCount() - l.aOperations[ iOp ].dwTickStart) / 1000;
619 LPASACTIONLIST AfsAdmSvr_GetOperations (UINT_PTR idClientSearch, ASID idCellSearch)
621 LPASACTIONLIST pList = AfsAdmSvr_CreateActionList();
624 for (WORD iOp = 0; iOp < l.cOperationsAllocated; ++iOp)
626 if (!l.aOperations[ iOp ].fInUse)
628 if (!l.aOperations[ iOp ].pAction)
630 if (idClientSearch && ((UINT_PTR)idClientSearch != l.aOperations[ iOp ].pAction->idClient))
632 if (idCellSearch && (idCellSearch != l.aOperations[ iOp ].pAction->idCell))
636 memcpy (&Action, l.aOperations[ iOp ].pAction, sizeof(ASACTION));
637 Action.csecActive = (GetTickCount() - l.aOperations[ iOp ].dwTickStart) / 1000;
638 if (!AfsAdmSvr_AddToActionList (&pList, &Action))
640 AfsAdmSvr_FreeActionList (&pList);
650 void AfsAdmSvr_Action_StartRefresh (ASID idScope)
652 switch (GetAsidType (idScope))
655 AfsAdmSvr_MarkRefreshThread (idScope);
660 memset (&Action, 0x00, sizeof(Action));
661 Action.Action = ACTION_REFRESH;
662 Action.idCell = (ASID)( ((LPIDENT)idScope)->GetCell() );
663 Action.u.Refresh.idScope = idScope;
664 (void)AfsAdmSvr_BeginOperation (0, &Action);
668 // Don't bother listing status-refreshes as ongoing operations
669 // for any granularity smaller than the server; they'll occur
670 // really frequently, and finish really quickly.
676 void AfsAdmSvr_Action_StopRefresh (ASID idScope)
680 for (size_t iOp = 0; iOp < l.cOperationsAllocated; ++iOp)
682 if (!l.aOperations[ iOp ].fInUse)
684 if (!l.aOperations[ iOp ].pAction)
686 if (l.aOperations[ iOp ].pAction->Action != ACTION_REFRESH)
688 if (l.aOperations[ iOp ].pAction->u.Refresh.idScope != idScope)
691 AfsAdmSvr_EndOperation (iOp);
695 if (GetAsidType (idScope) == itCELL)
697 AfsAdmSvr_MarkRefreshThread (idScope);
704 DWORD WINAPI AfsAdmSvr_AutoOpen_ThreadProc (PVOID lp)
706 DWORD dwScope = PtrToUlong(lp);
712 // First we'll have to find out which cell to open
714 TCHAR szCell[ cchNAME ];
715 if (!CELL::GetDefaultCell (szCell, &status))
717 Print (dlERROR, TEXT("CELL::GetDefaultCell failed; error 0x%08lX"), status);
721 // Then try to actually open the cell
723 Print (dlSTANDARD, TEXT("Auto-opening cell %s; scope=%s"), szCell, (dwScope == (AFSADMSVR_SCOPE_VOLUMES | AFSADMSVR_SCOPE_USERS)) ? TEXT("full") : (dwScope == AFSADMSVR_SCOPE_VOLUMES) ? TEXT("volumes") : TEXT("users"));
726 if ((lpiCell = CELL::OpenCell ((LPTSTR)szCell, &status)) == NULL)
728 Print (dlERROR, TEXT("Auto-open of cell %s failed; error 0x%08lX"), szCell, status);
733 if ((lpCell = lpiCell->OpenCell (&status)) == NULL)
735 Print (dlERROR, TEXT("Auto-open: OpenCell failed; error 0x%08lX"), status);
739 AfsAdmSvr_AddToMinScope (dwScope);
740 if (!lpCell->RefreshAll (&status))
741 Print (dlERROR, TEXT("Auto-open: RefreshCell failed; error 0x%08lX"), status);
743 Print (dlSTANDARD, TEXT("Auto-open of cell %s successful"), szCell);
746 // We intentionally do not call CELL::CloseCell() here--as would
747 // ordinarily be necessary to balance our CELL::OpenCell() call
748 // above--because we never want to close our cache for this cell.
749 // The point of calling AutoOpen() up front is to keep an admin
750 // server alive and ready for use on a particular cell--calling
751 // CELL::CloseCell() here negates that purpose.
761 void AfsAdmSvr_AddToMinScope (DWORD dwScope)
763 l.dwScopeMin |= dwScope;
764 AfsClass_SpecifyRefreshDomain (l.dwScopeMin);
768 void AfsAdmSvr_SetMinScope (DWORD dwScope)
770 l.dwScopeMin = dwScope;
774 DWORD AfsAdmSvr_GetMinScope (void)