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
11 #include <afs/param.h>
15 #include "TaAfsAdmSvrInternal.h"
18 #include <afs/afs_AdminErrors.h>
23 * VARIABLES __________________________________________________________________
27 #define cminREQ_CLIENT_PING (csecAFSADMSVR_CLIENT_PING * 2L / 60L)
29 #define cREALLOC_CLIENTS 1
30 #define cREALLOC_OPERATIONS 16
32 #define cminAUTO_SHUTDOWN 2 // stop if idle for more than 2min
33 #define cminAUTO_SHUTDOWN_SLEEP 1 // test for stop every minute
37 TCHAR szName[ cchSTRING ];
38 SOCKADDR_IN ipAddress;
40 } CLIENTINFO, *LPCLIENTINFO;
48 } OPERATION, *LPOPERATION;
53 LPCRITICAL_SECTION pcsAfsAdmSvr;
55 LPCLIENTINFO *aClients;
57 size_t cClientsAllocated;
59 LPNOTIFYCALLBACK pNotify;
62 HANDLE hThreadShutdown;
63 DWORD timeLastIdleStart;
65 OPERATION *aOperations;
67 size_t cOperationsAllocated;
75 * PROTOTYPES _________________________________________________________________
79 void AfsAdmSvr_TestShutdown (void);
80 DWORD WINAPI AfsAdmSvr_AutoShutdownThread (LPVOID lp);
84 * SYNCHRONIZATION ____________________________________________________________
88 void AfsAdmSvr_Enter (void)
92 l.pcsAfsAdmSvr = New (CRITICAL_SECTION);
93 InitializeCriticalSection (l.pcsAfsAdmSvr);
95 EnterCriticalSection (l.pcsAfsAdmSvr);
98 void AfsAdmSvr_Leave (void)
100 LeaveCriticalSection (l.pcsAfsAdmSvr);
105 * CLIENT INFORMATION _________________________________________________________
109 BOOL AfsAdmSvr_fIsValidClient (UINT_PTR idClient)
114 for (size_t iClient = 0; !rc && iClient < l.cClientsAllocated; ++iClient)
116 if (idClient == (UINT_PTR)l.aClients[ iClient ])
118 if (l.aClients[ iClient ]->timeLastPing + cminREQ_CLIENT_PING > AfsAdmSvr_GetCurrentTime())
128 BOOL AfsAdmSvr_AttachClient (LPCTSTR pszName, PVOID *pidClient, ULONG *pStatus)
132 for (iClient = 0; iClient < l.cClientsAllocated; ++iClient)
134 if (!l.aClients[ iClient ])
137 if (!REALLOC (l.aClients, l.cClientsAllocated, 1+iClient, cREALLOC_CLIENTS))
142 if ((l.aClients[ iClient ] = New (CLIENTINFO)) == NULL)
147 memset (l.aClients[ iClient ], 0x00, sizeof(CLIENTINFO));
148 lstrcpy (l.aClients[ iClient ]->szName, pszName);
149 l.aClients[ iClient ]->timeLastPing = AfsAdmSvr_GetCurrentTime();
152 if (!AfsAdmSvr_ResolveName (&l.aClients[ iClient ]->ipAddress, l.aClients[ iClient ]->szName))
153 memset (&l.aClients[ iClient ]->ipAddress, 0x00, sizeof(SOCKADDR_IN));
155 *pidClient = (PVOID)(l.aClients[ iClient ]);
161 void AfsAdmSvr_DetachClient (UINT_PTR idClient)
165 for (iClient = 0; iClient < l.cClientsAllocated; ++iClient)
167 if (idClient == (UINT_PTR)(l.aClients[ iClient ]))
170 if (iClient < l.cClientsAllocated)
172 Delete (l.aClients[ iClient ]);
173 l.aClients[ iClient ] = NULL;
176 AfsAdmSvr_TestShutdown();
181 LPCTSTR AfsAdmSvr_GetClientName (UINT_PTR idClient)
183 static TCHAR szName[ cchSTRING ];
184 LPCTSTR pszName = NULL;
187 for (size_t iClient = 0; !pszName && iClient < l.cClientsAllocated; ++iClient)
189 if (idClient == (UINT_PTR)(l.aClients[ iClient ]))
191 lstrcpy (szName, l.aClients[ iClient ]->szName);
201 LPSOCKADDR_IN AfsAdmSvr_GetClientAddress (UINT_PTR idClient)
203 static SOCKADDR_IN ipAddress;
204 LPSOCKADDR_IN pAddress = NULL;
207 for (size_t iClient = 0; !pAddress && iClient < l.cClientsAllocated; ++iClient)
209 if (idClient == (UINT_PTR)(l.aClients[ iClient ]))
211 memcpy (&ipAddress, &l.aClients[ iClient ]->ipAddress, sizeof(SOCKADDR_IN));
212 pAddress = &ipAddress;
221 void AfsAdmSvr_PingClient (UINT_PTR idClient)
225 for (size_t iClient = 0; iClient < l.cClientsAllocated; ++iClient)
227 if (idClient == (UINT_PTR)(l.aClients[ iClient ]))
229 l.aClients[ iClient ]->timeLastPing = AfsAdmSvr_GetCurrentTime();
237 DWORD AfsAdmSvr_GetCurrentTime (void) // returns counter in ~minute increments
239 static WORD wMonthish = 0; // One "Monthish" is 49.7 days
240 static WORD wTickLast = 0;
241 DWORD dwTick = GetTickCount();
242 WORD wTickNow = HIWORD(dwTick);
243 if (wTickNow < wTickLast) // wrapped over a Monthish?
245 wTickLast = wTickNow;
246 return MAKELONG(wTickNow,wMonthish);
251 * STARTUP/SHUTDOWN ___________________________________________________________
255 void AfsAdmSvr_Startup (void)
257 l.pNotify = New2 (NOTIFYCALLBACK,(AfsAdmSvr_NotifyCallback, 0));
258 l.fOperational = FALSE;
261 if (AfsClass_Initialize (&status))
262 l.fOperational = TRUE;
265 Print (dlERROR, TEXT("Could not initialize AfsClass (fatal error 0x%08lX)"), status);
266 Print (dlERROR, TEXT("Remaining active to tell potential clients about the problem"));
269 if (!l.hThreadShutdown)
272 l.hThreadShutdown = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)AfsAdmSvr_AutoShutdownThread, (LPVOID)0, 0, &dwThreadID);
277 void AfsAdmSvr_Shutdown (void)
281 l.fOperational = FALSE;
286 * GENERAL ____________________________________________________________________
290 BOOL FALSE_ (ULONG status, ULONG *pStatus, size_t iOp)
294 if (iOp != (size_t)-2)
295 AfsAdmSvr_EndOperation (iOp);
299 BOOL Leave_FALSE_ (ULONG status, ULONG *pStatus, size_t iOp)
304 if (iOp != (size_t)-2)
305 AfsAdmSvr_EndOperation (iOp);
309 PVOID NULL_ (ULONG status, ULONG *pStatus, size_t iOp)
313 if (iOp != (size_t)-2)
314 AfsAdmSvr_EndOperation (iOp);
318 PVOID Leave_NULL_ (ULONG status, ULONG *pStatus, size_t iOp)
323 if (iOp != (size_t)-2)
324 AfsAdmSvr_EndOperation (iOp);
328 BOOL TRUE_ (ULONG *pStatus, size_t iOp)
332 if (iOp != (size_t)-2)
333 AfsAdmSvr_EndOperation (iOp);
337 BOOL Leave_TRUE_ (ULONG *pStatus, size_t iOp)
342 if (iOp != (size_t)-2)
343 AfsAdmSvr_EndOperation (iOp);
347 IDENTTYPE GetAsidType (ASID idObject)
351 iType = ((LPIDENT)idObject)->GetType();
359 BOOL AfsAdmSvr_ResolveName (LPSOCKADDR_IN pAddress, LPTSTR pszName)
361 if ((pszName[0] >= TEXT('0')) && (pszName[0] <= TEXT('9')))
364 if ((ipAddress = inet_addr (pszName)) == INADDR_NONE)
367 memset (pAddress, 0x00, sizeof(SOCKADDR_IN));
368 pAddress->sin_family = AF_INET;
369 pAddress->sin_addr.s_addr = ipAddress;
372 if ((pEntry = gethostbyaddr ((char*)&ipAddress, sizeof(ipAddress), AF_INET)) != NULL)
373 lstrcpy (pszName, pEntry->h_name);
375 else // (!isdigit(szServer[0]))
378 if ((pEntry = gethostbyname (pszName)) == NULL)
381 memset (pAddress, 0x00, sizeof(SOCKADDR_IN));
382 pAddress->sin_family = AF_INET;
383 pAddress->sin_addr.s_addr = *(int *)pEntry->h_addr;
385 lstrcpy (pszName, pEntry->h_name);
393 * AUTO-SHUTDOWN ______________________________________________________________
397 DWORD WINAPI AfsAdmSvr_AutoShutdownThread (LPVOID lp)
403 BOOL fShutdown = l.fAutoShutdown;
405 // If there are any clients connected, forcably disconnect any
406 // that haven't pinged us for too long
408 for (size_t iClient = 0; iClient < l.cClientsAllocated; ++iClient)
410 if (!l.aClients[ iClient ])
412 if (l.aClients[ iClient ]->timeLastPing + cminREQ_CLIENT_PING <= AfsAdmSvr_GetCurrentTime())
414 Print (dlCONNECTION, "Client 0x%08lX idle for too long; detaching", l.aClients[ iClient ]);
415 AfsAdmSvr_DetachClient ((UINT_PTR)l.aClients[ iClient ]);
419 // If any operations are in progress, we can't shutdown.
424 // If any clients are still connected, we can't shutdown.
429 // If we haven't been idle long enough, we can't shutdown
431 if (!l.timeLastIdleStart)
433 else if (l.timeLastIdleStart + cminAUTO_SHUTDOWN > AfsAdmSvr_GetCurrentTime())
436 // That's it; can we stop now?
440 Print ("Idle for too long; shutting down.");
441 RpcMgmtStopServerListening (NULL);
442 AfsAdmSvr_StopCallbackManagers();
450 Sleep (cminAUTO_SHUTDOWN_SLEEP * 60L * 1000L);
458 void AfsAdmSvr_EnableAutoShutdown (BOOL fEnable)
462 l.fAutoShutdown = fEnable;
465 Print (dlDETAIL, TEXT("Auto-shutdown enabled, trigger = %lu minutes idle time"), cminAUTO_SHUTDOWN);
467 Print (dlDETAIL, TEXT("Auto-shutdown on idle disabled"));
473 void AfsAdmSvr_TestShutdown (void)
475 if (!l.cOperations && !l.cClients)
477 l.timeLastIdleStart = AfsAdmSvr_GetCurrentTime();
482 size_t AfsAdmSvr_BeginOperation (UINT_PTR idClient, LPASACTION pAction)
489 for (iOp = 0; iOp < l.cOperationsAllocated; ++iOp)
491 if (!l.aOperations[ iOp ].fInUse)
494 if (!REALLOC (l.aOperations, l.cOperationsAllocated, 1+iOp, cREALLOC_OPERATIONS))
500 l.aOperations[ iOp ].idClient = idClient;
501 l.aOperations[ iOp ].pAction = NULL;
502 l.aOperations[ iOp ].fInUse = TRUE;
506 l.aOperations[ iOp ].pAction = New (ASACTION);
507 memcpy (l.aOperations[ iOp ].pAction, pAction, sizeof(ASACTION));
508 l.aOperations[ iOp ].pAction->idAction = ++l.idActionLast;
509 l.aOperations[ iOp ].pAction->idClient = idClient;
510 l.aOperations[ iOp ].pAction->csecActive = 0;
513 switch (l.aOperations[ iOp ].pAction->Action)
516 wsprintf (szDesc, TEXT("Refresh (scope=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Refresh.idScope);
519 wsprintf (szDesc, TEXT("Scout (scope=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Refresh.idScope);
521 case ACTION_USER_CHANGE:
522 wsprintf (szDesc, TEXT("ChangeUser (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Change.idUser);
524 case ACTION_USER_PW_CHANGE:
525 wsprintf (szDesc, TEXT("SetUserPassword (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Pw_Change.idUser);
527 case ACTION_USER_UNLOCK:
528 wsprintf (szDesc, TEXT("UnlockUser (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Unlock.idUser);
530 case ACTION_USER_CREATE:
531 wsprintf (szDesc, TEXT("CreateUser (user=%s)"), l.aOperations[ iOp ].pAction->u.User_Create.szUser);
533 case ACTION_USER_DELETE:
534 wsprintf (szDesc, TEXT("CreateUser (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Delete.idUser);
536 case ACTION_GROUP_CHANGE:
537 wsprintf (szDesc, TEXT("ChangeGroup (group=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Group_Change.idGroup);
539 case ACTION_GROUP_MEMBER_ADD:
540 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);
542 case ACTION_GROUP_MEMBER_REMOVE:
543 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);
545 case ACTION_GROUP_RENAME:
546 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);
548 case ACTION_GROUP_DELETE:
549 wsprintf (szDesc, TEXT("CreateGroup (group=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Group_Delete.idGroup);
551 case ACTION_CELL_CHANGE:
552 wsprintf (szDesc, TEXT("ChangeCell (cell=0x%08lX)"), l.aOperations[ iOp ].pAction->idCell);
555 wsprintf (szDesc, TEXT("Unknown Action (#%lu)"), l.aOperations[ iOp ].pAction->Action);
558 Print (dlOPERATION, TEXT("Starting action 0x%08lX: %s"), l.aOperations[ iOp ].pAction->idAction, szDesc);
560 AfsAdmSvr_PostCallback (cbtACTION, FALSE, l.aOperations[ iOp ].pAction);
563 l.aOperations[ iOp ].dwTickStart = GetTickCount();
569 void AfsAdmSvr_EndOperation (size_t iOp)
573 if ((iOp != (size_t)-1) && (iOp < l.cOperationsAllocated) && (l.aOperations[ iOp ].fInUse))
575 if (l.aOperations[ iOp ].pAction)
577 Print (dlOPERATION, TEXT("Ending action 0x%08lX"), l.aOperations[ iOp ].pAction->idAction);
578 AfsAdmSvr_PostCallback (cbtACTION, TRUE, l.aOperations[ iOp ].pAction);
579 Delete (l.aOperations[ iOp ].pAction);
581 memset (&l.aOperations[ iOp ], 0x00, sizeof(l.aOperations[ iOp ]));
585 AfsAdmSvr_TestShutdown();
590 BOOL AfsAdmSvr_GetOperation (DWORD idAction, LPASACTION pAction)
594 for (size_t iOp = 0; iOp < l.cOperationsAllocated; ++iOp)
596 if (!l.aOperations[ iOp ].fInUse)
598 if (!l.aOperations[ iOp ].pAction)
600 if (l.aOperations[ iOp ].pAction->idAction != idAction)
603 memcpy (pAction, l.aOperations[ iOp ].pAction, sizeof(ASACTION));
604 pAction->csecActive = (GetTickCount() - l.aOperations[ iOp ].dwTickStart) / 1000;
614 LPASACTIONLIST AfsAdmSvr_GetOperations (UINT_PTR idClientSearch, ASID idCellSearch)
616 LPASACTIONLIST pList = AfsAdmSvr_CreateActionList();
619 for (WORD iOp = 0; iOp < l.cOperationsAllocated; ++iOp)
621 if (!l.aOperations[ iOp ].fInUse)
623 if (!l.aOperations[ iOp ].pAction)
625 if (idClientSearch && ((UINT_PTR)idClientSearch != l.aOperations[ iOp ].pAction->idClient))
627 if (idCellSearch && (idCellSearch != l.aOperations[ iOp ].pAction->idCell))
631 memcpy (&Action, l.aOperations[ iOp ].pAction, sizeof(ASACTION));
632 Action.csecActive = (GetTickCount() - l.aOperations[ iOp ].dwTickStart) / 1000;
633 if (!AfsAdmSvr_AddToActionList (&pList, &Action))
635 AfsAdmSvr_FreeActionList (&pList);
645 void AfsAdmSvr_Action_StartRefresh (ASID idScope)
647 switch (GetAsidType (idScope))
650 AfsAdmSvr_MarkRefreshThread (idScope);
655 memset (&Action, 0x00, sizeof(Action));
656 Action.Action = ACTION_REFRESH;
657 Action.idCell = (ASID)( ((LPIDENT)idScope)->GetCell() );
658 Action.u.Refresh.idScope = idScope;
659 (void)AfsAdmSvr_BeginOperation (0, &Action);
663 // Don't bother listing status-refreshes as ongoing operations
664 // for any granularity smaller than the server; they'll occur
665 // really frequently, and finish really quickly.
671 void AfsAdmSvr_Action_StopRefresh (ASID idScope)
675 for (size_t iOp = 0; iOp < l.cOperationsAllocated; ++iOp)
677 if (!l.aOperations[ iOp ].fInUse)
679 if (!l.aOperations[ iOp ].pAction)
681 if (l.aOperations[ iOp ].pAction->Action != ACTION_REFRESH)
683 if (l.aOperations[ iOp ].pAction->u.Refresh.idScope != idScope)
686 AfsAdmSvr_EndOperation (iOp);
690 if (GetAsidType (idScope) == itCELL)
692 AfsAdmSvr_MarkRefreshThread (idScope);
699 DWORD WINAPI AfsAdmSvr_AutoOpen_ThreadProc (PVOID lp)
701 DWORD dwScope = PtrToUlong(lp);
707 // First we'll have to find out which cell to open
709 TCHAR szCell[ cchNAME ];
710 if (!CELL::GetDefaultCell (szCell, &status))
712 Print (dlERROR, TEXT("CELL::GetDefaultCell failed; error 0x%08lX"), status);
716 // Then try to actually open the cell
718 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"));
721 if ((lpiCell = CELL::OpenCell ((LPTSTR)szCell, &status)) == NULL)
723 Print (dlERROR, TEXT("Auto-open of cell %s failed; error 0x%08lX"), szCell, status);
728 if ((lpCell = lpiCell->OpenCell (&status)) == NULL)
730 Print (dlERROR, TEXT("Auto-open: OpenCell failed; error 0x%08lX"), status);
734 AfsAdmSvr_AddToMinScope (dwScope);
735 if (!lpCell->RefreshAll (&status))
736 Print (dlERROR, TEXT("Auto-open: RefreshCell failed; error 0x%08lX"), status);
738 Print (dlSTANDARD, TEXT("Auto-open of cell %s successful"), szCell);
741 // We intentionally do not call CELL::CloseCell() here--as would
742 // ordinarily be necessary to balance our CELL::OpenCell() call
743 // above--because we never want to close our cache for this cell.
744 // The point of calling AutoOpen() up front is to keep an admin
745 // server alive and ready for use on a particular cell--calling
746 // CELL::CloseCell() here negates that purpose.
756 void AfsAdmSvr_AddToMinScope (DWORD dwScope)
758 l.dwScopeMin |= dwScope;
759 AfsClass_SpecifyRefreshDomain (l.dwScopeMin);
763 void AfsAdmSvr_SetMinScope (DWORD dwScope)
765 l.dwScopeMin = dwScope;
769 DWORD AfsAdmSvr_GetMinScope (void)