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 (DWORD idClient)
114 for (size_t iClient = 0; !rc && iClient < l.cClientsAllocated; ++iClient)
116 if (idClient == (DWORD)(l.aClients[ iClient ]))
118 if (l.aClients[ iClient ]->timeLastPing + cminREQ_CLIENT_PING > AfsAdmSvr_GetCurrentTime())
128 BOOL AfsAdmSvr_AttachClient (LPCTSTR pszName, DWORD *pidClient, ULONG *pStatus)
131 for (size_t iClient = 0; iClient < l.cClientsAllocated; ++iClient)
133 if (!l.aClients[ iClient ])
136 if (!REALLOC (l.aClients, l.cClientsAllocated, 1+iClient, cREALLOC_CLIENTS))
141 if ((l.aClients[ iClient ] = New (CLIENTINFO)) == NULL)
146 memset (l.aClients[ iClient ], 0x00, sizeof(CLIENTINFO));
147 lstrcpy (l.aClients[ iClient ]->szName, pszName);
148 l.aClients[ iClient ]->timeLastPing = AfsAdmSvr_GetCurrentTime();
151 if (!AfsAdmSvr_ResolveName (&l.aClients[ iClient ]->ipAddress, l.aClients[ iClient ]->szName))
152 memset (&l.aClients[ iClient ]->ipAddress, 0x00, sizeof(SOCKADDR_IN));
154 *pidClient = (DWORD)(l.aClients[ iClient ]);
160 void AfsAdmSvr_DetachClient (DWORD idClient)
163 for (size_t iClient = 0; iClient < l.cClientsAllocated; ++iClient)
165 if (idClient == (DWORD)(l.aClients[ iClient ]))
168 if (iClient < l.cClientsAllocated)
170 Delete (l.aClients[ iClient ]);
171 l.aClients[ iClient ] = NULL;
174 AfsAdmSvr_TestShutdown();
179 LPCTSTR AfsAdmSvr_GetClientName (DWORD idClient)
181 static TCHAR szName[ cchSTRING ];
182 LPCTSTR pszName = NULL;
185 for (size_t iClient = 0; !pszName && iClient < l.cClientsAllocated; ++iClient)
187 if (idClient == (DWORD)(l.aClients[ iClient ]))
189 lstrcpy (szName, l.aClients[ iClient ]->szName);
199 LPSOCKADDR_IN AfsAdmSvr_GetClientAddress (DWORD idClient)
201 static SOCKADDR_IN ipAddress;
202 LPSOCKADDR_IN pAddress = NULL;
205 for (size_t iClient = 0; !pAddress && iClient < l.cClientsAllocated; ++iClient)
207 if (idClient == (DWORD)(l.aClients[ iClient ]))
209 memcpy (&ipAddress, &l.aClients[ iClient ]->ipAddress, sizeof(SOCKADDR_IN));
210 pAddress = &ipAddress;
219 void AfsAdmSvr_PingClient (DWORD idClient)
223 for (size_t iClient = 0; iClient < l.cClientsAllocated; ++iClient)
225 if (idClient == (DWORD)(l.aClients[ iClient ]))
227 l.aClients[ iClient ]->timeLastPing = AfsAdmSvr_GetCurrentTime();
235 DWORD AfsAdmSvr_GetCurrentTime (void) // returns counter in ~minute increments
237 static WORD wMonthish = 0; // One "Monthish" is 49.7 days
238 static WORD wTickLast = 0;
239 DWORD dwTick = GetTickCount();
240 WORD wTickNow = HIWORD(dwTick);
241 if (wTickNow < wTickLast) // wrapped over a Monthish?
243 wTickLast = wTickNow;
244 return MAKELONG(wTickNow,wMonthish);
249 * STARTUP/SHUTDOWN ___________________________________________________________
253 void AfsAdmSvr_Startup (void)
255 l.pNotify = New2 (NOTIFYCALLBACK,(AfsAdmSvr_NotifyCallback, 0));
256 l.fOperational = FALSE;
259 if (AfsClass_Initialize (&status))
260 l.fOperational = TRUE;
263 Print (dlERROR, TEXT("Could not initialize AfsClass (fatal error 0x%08lX)"), status);
264 Print (dlERROR, TEXT("Remaining active to tell potential clients about the problem"));
267 if (!l.hThreadShutdown)
270 l.hThreadShutdown = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)AfsAdmSvr_AutoShutdownThread, (LPVOID)0, 0, &dwThreadID);
275 void AfsAdmSvr_Shutdown (void)
279 l.fOperational = FALSE;
284 * GENERAL ____________________________________________________________________
288 BOOL FALSE_ (ULONG status, ULONG *pStatus, size_t iOp)
292 if (iOp != (size_t)-2)
293 AfsAdmSvr_EndOperation (iOp);
297 BOOL Leave_FALSE_ (ULONG status, ULONG *pStatus, size_t iOp)
302 if (iOp != (size_t)-2)
303 AfsAdmSvr_EndOperation (iOp);
307 BOOL TRUE_ (ULONG *pStatus, size_t iOp)
311 if (iOp != (size_t)-2)
312 AfsAdmSvr_EndOperation (iOp);
316 BOOL Leave_TRUE_ (ULONG *pStatus, size_t iOp)
321 if (iOp != (size_t)-2)
322 AfsAdmSvr_EndOperation (iOp);
326 IDENTTYPE GetAsidType (ASID idObject)
330 iType = ((LPIDENT)idObject)->GetType();
338 BOOL AfsAdmSvr_ResolveName (LPSOCKADDR_IN pAddress, LPTSTR pszName)
340 if ((pszName[0] >= TEXT('0')) && (pszName[0] <= TEXT('9')))
343 if ((ipAddress = inet_addr (pszName)) == INADDR_NONE)
346 memset (pAddress, 0x00, sizeof(SOCKADDR_IN));
347 pAddress->sin_family = AF_INET;
348 pAddress->sin_addr.s_addr = ipAddress;
351 if ((pEntry = gethostbyaddr ((char*)&ipAddress, sizeof(ipAddress), AF_INET)) != NULL)
352 lstrcpy (pszName, pEntry->h_name);
354 else // (!isdigit(szServer[0]))
357 if ((pEntry = gethostbyname (pszName)) == NULL)
360 memset (pAddress, 0x00, sizeof(SOCKADDR_IN));
361 pAddress->sin_family = AF_INET;
362 pAddress->sin_addr.s_addr = *(int *)pEntry->h_addr;
364 lstrcpy (pszName, pEntry->h_name);
372 * AUTO-SHUTDOWN ______________________________________________________________
376 DWORD WINAPI AfsAdmSvr_AutoShutdownThread (LPVOID lp)
382 BOOL fShutdown = l.fAutoShutdown;
384 // If there are any clients connected, forcably disconnect any
385 // that haven't pinged us for too long
387 for (size_t iClient = 0; iClient < l.cClientsAllocated; ++iClient)
389 if (!l.aClients[ iClient ])
391 if (l.aClients[ iClient ]->timeLastPing + cminREQ_CLIENT_PING <= AfsAdmSvr_GetCurrentTime())
393 Print (dlCONNECTION, "Client 0x%08lX idle for too long; detaching", l.aClients[ iClient ]);
394 AfsAdmSvr_DetachClient ((DWORD)l.aClients[ iClient ]);
398 // If any operations are in progress, we can't shutdown.
403 // If any clients are still connected, we can't shutdown.
408 // If we haven't been idle long enough, we can't shutdown
410 if (!l.timeLastIdleStart)
412 else if (l.timeLastIdleStart + cminAUTO_SHUTDOWN > AfsAdmSvr_GetCurrentTime())
415 // That's it; can we stop now?
419 Print ("Idle for too long; shutting down.");
420 RpcMgmtStopServerListening (NULL);
421 AfsAdmSvr_StopCallbackManagers();
429 Sleep (cminAUTO_SHUTDOWN_SLEEP * 60L * 1000L);
437 void AfsAdmSvr_EnableAutoShutdown (BOOL fEnable)
441 l.fAutoShutdown = fEnable;
444 Print (dlDETAIL, TEXT("Auto-shutdown enabled, trigger = %lu minutes idle time"), cminAUTO_SHUTDOWN);
446 Print (dlDETAIL, TEXT("Auto-shutdown on idle disabled"));
452 void AfsAdmSvr_TestShutdown (void)
454 if (!l.cOperations && !l.cClients)
456 l.timeLastIdleStart = AfsAdmSvr_GetCurrentTime();
461 size_t AfsAdmSvr_BeginOperation (DWORD idClient, LPASACTION pAction)
467 for (size_t iOp = 0; iOp < l.cOperationsAllocated; ++iOp)
469 if (!l.aOperations[ iOp ].fInUse)
472 if (!REALLOC (l.aOperations, l.cOperationsAllocated, 1+iOp, cREALLOC_OPERATIONS))
478 l.aOperations[ iOp ].idClient = idClient;
479 l.aOperations[ iOp ].pAction = NULL;
480 l.aOperations[ iOp ].fInUse = TRUE;
484 l.aOperations[ iOp ].pAction = New (ASACTION);
485 memcpy (l.aOperations[ iOp ].pAction, pAction, sizeof(ASACTION));
486 l.aOperations[ iOp ].pAction->idAction = ++l.idActionLast;
487 l.aOperations[ iOp ].pAction->idClient = idClient;
488 l.aOperations[ iOp ].pAction->csecActive = 0;
491 switch (l.aOperations[ iOp ].pAction->Action)
494 wsprintf (szDesc, TEXT("Refresh (scope=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Refresh.idScope);
497 wsprintf (szDesc, TEXT("Scout (scope=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Refresh.idScope);
499 case ACTION_USER_CHANGE:
500 wsprintf (szDesc, TEXT("ChangeUser (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Change.idUser);
502 case ACTION_USER_PW_CHANGE:
503 wsprintf (szDesc, TEXT("SetUserPassword (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Pw_Change.idUser);
505 case ACTION_USER_UNLOCK:
506 wsprintf (szDesc, TEXT("UnlockUser (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Unlock.idUser);
508 case ACTION_USER_CREATE:
509 wsprintf (szDesc, TEXT("CreateUser (user=%s)"), l.aOperations[ iOp ].pAction->u.User_Create.szUser);
511 case ACTION_USER_DELETE:
512 wsprintf (szDesc, TEXT("CreateUser (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Delete.idUser);
514 case ACTION_GROUP_CHANGE:
515 wsprintf (szDesc, TEXT("ChangeGroup (group=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Group_Change.idGroup);
517 case ACTION_GROUP_MEMBER_ADD:
518 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);
520 case ACTION_GROUP_MEMBER_REMOVE:
521 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);
523 case ACTION_GROUP_RENAME:
524 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);
526 case ACTION_GROUP_DELETE:
527 wsprintf (szDesc, TEXT("CreateGroup (group=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Group_Delete.idGroup);
529 case ACTION_CELL_CHANGE:
530 wsprintf (szDesc, TEXT("ChangeCell (cell=0x%08lX)"), l.aOperations[ iOp ].pAction->idCell);
533 wsprintf (szDesc, TEXT("Unknown Action (#%lu)"), l.aOperations[ iOp ].pAction->Action);
536 Print (dlOPERATION, TEXT("Starting action 0x%08lX: %s"), l.aOperations[ iOp ].pAction->idAction, szDesc);
538 AfsAdmSvr_PostCallback (cbtACTION, FALSE, l.aOperations[ iOp ].pAction);
541 l.aOperations[ iOp ].dwTickStart = GetTickCount();
547 void AfsAdmSvr_EndOperation (size_t iOp)
551 if ((iOp != (size_t)-1) && (iOp < l.cOperationsAllocated) && (l.aOperations[ iOp ].fInUse))
553 if (l.aOperations[ iOp ].pAction)
555 Print (dlOPERATION, TEXT("Ending action 0x%08lX"), l.aOperations[ iOp ].pAction->idAction);
556 AfsAdmSvr_PostCallback (cbtACTION, TRUE, l.aOperations[ iOp ].pAction);
557 Delete (l.aOperations[ iOp ].pAction);
559 memset (&l.aOperations[ iOp ], 0x00, sizeof(l.aOperations[ iOp ]));
563 AfsAdmSvr_TestShutdown();
568 BOOL AfsAdmSvr_GetOperation (DWORD idAction, LPASACTION pAction)
572 for (size_t iOp = 0; iOp < l.cOperationsAllocated; ++iOp)
574 if (!l.aOperations[ iOp ].fInUse)
576 if (!l.aOperations[ iOp ].pAction)
578 if (l.aOperations[ iOp ].pAction->idAction != idAction)
581 memcpy (pAction, l.aOperations[ iOp ].pAction, sizeof(ASACTION));
582 pAction->csecActive = (GetTickCount() - l.aOperations[ iOp ].dwTickStart) / 1000;
592 LPASACTIONLIST AfsAdmSvr_GetOperations (DWORD idClientSearch, ASID idCellSearch)
594 LPASACTIONLIST pList = AfsAdmSvr_CreateActionList();
597 for (size_t iOp = 0; iOp < l.cOperationsAllocated; ++iOp)
599 if (!l.aOperations[ iOp ].fInUse)
601 if (!l.aOperations[ iOp ].pAction)
603 if (idClientSearch && (idClientSearch != l.aOperations[ iOp ].pAction->idClient))
605 if (idCellSearch && (idCellSearch != l.aOperations[ iOp ].pAction->idCell))
609 memcpy (&Action, l.aOperations[ iOp ].pAction, sizeof(ASACTION));
610 Action.csecActive = (GetTickCount() - l.aOperations[ iOp ].dwTickStart) / 1000;
611 if (!AfsAdmSvr_AddToActionList (&pList, &Action))
613 AfsAdmSvr_FreeActionList (&pList);
623 void AfsAdmSvr_Action_StartRefresh (ASID idScope)
625 switch (GetAsidType (idScope))
628 AfsAdmSvr_MarkRefreshThread (idScope);
633 memset (&Action, 0x00, sizeof(Action));
634 Action.Action = ACTION_REFRESH;
635 Action.idCell = (ASID)( ((LPIDENT)idScope)->GetCell() );
636 Action.u.Refresh.idScope = idScope;
637 (void)AfsAdmSvr_BeginOperation (0, &Action);
641 // Don't bother listing status-refreshes as ongoing operations
642 // for any granularity smaller than the server; they'll occur
643 // really frequently, and finish really quickly.
649 void AfsAdmSvr_Action_StopRefresh (ASID idScope)
653 for (size_t iOp = 0; iOp < l.cOperationsAllocated; ++iOp)
655 if (!l.aOperations[ iOp ].fInUse)
657 if (!l.aOperations[ iOp ].pAction)
659 if (l.aOperations[ iOp ].pAction->Action != ACTION_REFRESH)
661 if (l.aOperations[ iOp ].pAction->u.Refresh.idScope != idScope)
664 AfsAdmSvr_EndOperation (iOp);
668 if (GetAsidType (idScope) == itCELL)
670 AfsAdmSvr_MarkRefreshThread (idScope);
677 DWORD WINAPI AfsAdmSvr_AutoOpen_ThreadProc (PVOID lp)
679 DWORD dwScope = (DWORD)lp;
685 // First we'll have to find out which cell to open
687 TCHAR szCell[ cchNAME ];
688 if (!CELL::GetDefaultCell (szCell, &status))
690 Print (dlERROR, TEXT("CELL::GetDefaultCell failed; error 0x%08lX"), status);
694 // Then try to actually open the cell
696 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"));
699 if ((lpiCell = CELL::OpenCell ((LPTSTR)szCell, &status)) == NULL)
701 Print (dlERROR, TEXT("Auto-open of cell %s failed; error 0x%08lX"), szCell, status);
706 if ((lpCell = lpiCell->OpenCell (&status)) == NULL)
708 Print (dlERROR, TEXT("Auto-open: OpenCell failed; error 0x%08lX"), status);
712 AfsAdmSvr_AddToMinScope (dwScope);
713 if (!lpCell->RefreshAll (&status))
714 Print (dlERROR, TEXT("Auto-open: RefreshCell failed; error 0x%08lX"), status);
716 Print (dlSTANDARD, TEXT("Auto-open of cell %s successful"), szCell);
719 // We intentionally do not call CELL::CloseCell() here--as would
720 // ordinarily be necessary to balance our CELL::OpenCell() call
721 // above--because we never want to close our cache for this cell.
722 // The point of calling AutoOpen() up front is to keep an admin
723 // server alive and ready for use on a particular cell--calling
724 // CELL::CloseCell() here negates that purpose.
734 void AfsAdmSvr_AddToMinScope (DWORD dwScope)
736 l.dwScopeMin |= dwScope;
737 AfsClass_SpecifyRefreshDomain (l.dwScopeMin);
741 void AfsAdmSvr_SetMinScope (DWORD dwScope)
743 l.dwScopeMin = dwScope;
747 DWORD AfsAdmSvr_GetMinScope (void)