STABLE14-win-power-mgmt-flush-test-20041003

The windows power management code responds to a request to suspend or
hibernate by performing a "fs flushvol" as the logged in user on each
of the SMB/CIFS mounted shares.  This can be very time consuming if
the cell servers cannot be reached.

This patch adds a test to ensure that there is at least one network
adapter in the machine which is not a loopback adapter.

While developing this patch other areas of concern have been raised.
The power management code waits a fixed period of time based upon
the hard dead timeout before allowing the suspend/hibernate to continue.
This allows the machine to shutdown even if there are active flush
operations being performed.  This defeats the benefit of performing
the flush at all.

A better mechanism could be developed if the functions called via
cm_IoctlFlushVolume returned and checked error codes.  Then it might
be possible to abandon the flush operation if a Server Not Reachable
state was obtained.

The power management flush operations will also not work on Terminal
Server.  This would be important in the case where a terminal server
is shutting down due to a switch over to a UPS.  The reason it does
not work on Terminal Server is that there is that it is not possible
for afsd_service.exe to enumerate the SMB/CIFS shares and impersonate
the individual logged in users.

It would be preferred for there to be a new cm_FlushAll() function
implemented which was not dependent on the use of the ioctl mechanism
for the purpose of identifying a volume ID or a user ID.


(cherry picked from commit 2469663d0d)
This commit is contained in:
Jeffrey Altman 2004-10-03 14:35:15 +00:00 committed by Jeffrey Altman
parent 4dcdbec005
commit 15e0bc5f3f
4 changed files with 515 additions and 476 deletions

View File

@ -27,6 +27,9 @@
#include "afsd_flushvol.h"
#include "afsd_eventlog.h"
#include "lanahelper.h"
extern void afsi_log(char *pattern, ...);
static FLUSHVOLTHREADINFO gThreadInfo = {0};
static HANDLE gThreadHandle = NULL;
@ -45,145 +48,150 @@ static HANDLE gThreadHandle = NULL;
afs_int32
afsd_ServicePerformFlushVolumeCmd(char *data)
{
register afs_int32 code;
struct ViceIoctl blob;
register afs_int32 code;
struct ViceIoctl blob;
memset(&blob, '\0', sizeof(blob));
code = pioctl(data, VIOC_FLUSHVOLUME, &blob, 0);
afsi_log("Flushing Volume \"%s\"",data);
memset(&blob, '\0', sizeof(blob));
code = pioctl(data, VIOC_FLUSHVOLUME, &blob, 0);
return code;
return code;
}
BOOL
afsd_ServicePerformFlushVolumes()
{
CONST CHAR COLON = ':';
CONST CHAR SLASH = '\\';
CONST DWORD NETRESBUFSIZE = 16384;
CHAR bufMessage[1024];
UINT i;
DWORD dwServerSize;
DWORD dwRet;
DWORD dwCount;
DWORD dwNetResBufSize;
DWORD dwTotalVols = 0;
DWORD dwVolBegin, dwVolEnd;
DWORD dwFlushBegin, dwFlushEnd;
HANDLE hEnum;
LPNETRESOURCE lpNetResBuf, lpnr;
PCHAR pszShareName, pc;
afs_int32 afsRet = 0;
{
CONST CHAR COLON = ':';
CONST CHAR SLASH = '\\';
CONST DWORD NETRESBUFSIZE = 16384;
CHAR bufMessage[1024];
UINT i;
DWORD dwServerSize;
DWORD dwRet;
DWORD dwCount;
DWORD dwNetResBufSize;
DWORD dwTotalVols = 0;
DWORD dwVolBegin, dwVolEnd;
DWORD dwFlushBegin, dwFlushEnd;
HANDLE hEnum;
LPNETRESOURCE lpNetResBuf, lpnr;
PCHAR pszShareName, pc;
afs_int32 afsRet = 0;
if ( lana_OnlyLoopback() ) {
// Nothing to do if we only have a loopback interface
return TRUE;
}
// Determine the root share name (\\AFS\ALL or \\<machine>-AFS\ALL),
// and the length of the server name prefix.
pszShareName = smb_GetSharename();
if (pszShareName == NULL)
{
LogEvent(EVENTLOG_ERROR_TYPE, MSG_FLUSH_NO_SHARE_NAME, NULL);
return FALSE;
}
pc = strrchr(pszShareName, SLASH);
if ((pc == NULL) || ((dwServerSize = pc - pszShareName) < 3))
{
LogEvent(EVENTLOG_ERROR_TYPE, MSG_FLUSH_BAD_SHARE_NAME,
pszShareName, NULL);
free(pszShareName);
return FALSE;
}
// Allocate a buffer to hold network resources returned by
// WNetEnumResource().
lpNetResBuf = malloc(NETRESBUFSIZE);
if (lpNetResBuf == NULL)
{
// Out of memory, give up now.
LogEvent(EVENTLOG_ERROR_TYPE, MSG_FLUSH_NO_MEMORY, NULL);
free(pszShareName);
return FALSE;
}
// Initialize the flush timer. Note that GetTickCount() returns
// the number of milliseconds since the system started, in a DWORD,
// so that the value wraps around every 49.7 days. We do not bother
// to handle the case where the flush elapsed time is greater than
// that.
dwFlushBegin = GetTickCount();
dwRet = WNetOpenEnum(RESOURCE_CONNECTED, RESOURCETYPE_ANY, 0, NULL,
&hEnum);
if (dwRet != NO_ERROR)
{
LogEventMessage(EVENTLOG_ERROR_TYPE, MSG_FLUSH_OPEN_ENUM_ERROR,
dwRet);
free(pszShareName);
return FALSE;
}
// Loop to enumerate network resources, and flush those associated
// with AFS volumes.
while (1)
{
dwCount = -1;
memset(lpNetResBuf, 0, NETRESBUFSIZE);
dwNetResBufSize = NETRESBUFSIZE;
dwRet = WNetEnumResource(hEnum, &dwCount,
lpNetResBuf, &dwNetResBufSize);
if (dwRet != NO_ERROR)
break;
// Iterate over the returned network resources.
for (i = 0, lpnr = lpNetResBuf; i < dwCount; i++, lpnr++)
{
// Ensure resource has a remote name, and is connected.
if ((lpnr->lpRemoteName == NULL) ||
(lpnr->dwScope != RESOURCE_CONNECTED))
continue;
if ((_strnicmp(lpnr->lpRemoteName, pszShareName,
dwServerSize) == 0) &&
(lpnr->lpRemoteName[dwServerSize] == SLASH))
{
// got one!
// but we don't want to flush '\\[...]afs\all'
if (_stricmp(lpnr->lpRemoteName, pszShareName) == 0)
continue;
++dwTotalVols;
dwVolBegin = GetTickCount();
afsRet = afsd_ServicePerformFlushVolumeCmd(lpnr->lpRemoteName);
dwVolEnd = GetTickCount();
if (afsRet == 0)
{
LogTimingEvent(MSG_TIME_FLUSH_PER_VOLUME,
lpnr->lpRemoteName,
dwVolEnd - dwVolBegin);
}
else
{
LogEvent(EVENTLOG_WARNING_TYPE,
MSG_FLUSH_FAILED,
lpnr->lpRemoteName, NULL);
}
}
}
}
WNetCloseEnum(hEnum);
free(lpNetResBuf);
free(pszShareName);
if (dwRet != ERROR_NO_MORE_ITEMS)
{
LogEventMessage(EVENTLOG_ERROR_TYPE, MSG_FLUSH_ENUM_ERROR,
dwRet);
return FALSE;
}
dwFlushEnd = GetTickCount();
// Determine the root share name (\\AFS\ALL or \\<machine>-AFS\ALL),
// and the length of the server name prefix.
pszShareName = smb_GetSharename();
if (pszShareName == NULL)
{
LogEvent(EVENTLOG_ERROR_TYPE, MSG_FLUSH_NO_SHARE_NAME, NULL);
return FALSE;
}
pc = strrchr(pszShareName, SLASH);
if ((pc == NULL) || ((dwServerSize = pc - pszShareName) < 3))
{
LogEvent(EVENTLOG_ERROR_TYPE, MSG_FLUSH_BAD_SHARE_NAME,
pszShareName, NULL);
free(pszShareName);
return FALSE;
}
// display total volume count in Event Logger
sprintf(bufMessage, "%d", dwTotalVols);
LogTimingEvent(MSG_TIME_FLUSH_TOTAL, bufMessage,
dwFlushEnd - dwFlushBegin);
// Allocate a buffer to hold network resources returned by
// WNetEnumResource().
lpNetResBuf = malloc(NETRESBUFSIZE);
if (lpNetResBuf == NULL)
{
// Out of memory, give up now.
LogEvent(EVENTLOG_ERROR_TYPE, MSG_FLUSH_NO_MEMORY, NULL);
free(pszShareName);
return FALSE;
}
// Initialize the flush timer. Note that GetTickCount() returns
// the number of milliseconds since the system started, in a DWORD,
// so that the value wraps around every 49.7 days. We do not bother
// to handle the case where the flush elapsed time is greater than
// that.
dwFlushBegin = GetTickCount();
dwRet = WNetOpenEnum(RESOURCE_CONNECTED, RESOURCETYPE_ANY, 0, NULL,
&hEnum);
if (dwRet != NO_ERROR)
{
LogEventMessage(EVENTLOG_ERROR_TYPE, MSG_FLUSH_OPEN_ENUM_ERROR,
dwRet);
free(pszShareName);
return FALSE;
}
// Loop to enumerate network resources, and flush those associated
// with AFS volumes.
while (1)
{
dwCount = -1;
memset(lpNetResBuf, 0, NETRESBUFSIZE);
dwNetResBufSize = NETRESBUFSIZE;
dwRet = WNetEnumResource(hEnum, &dwCount,
lpNetResBuf, &dwNetResBufSize);
if (dwRet != NO_ERROR)
break;
// Iterate over the returned network resources.
for (i = 0, lpnr = lpNetResBuf; i < dwCount; i++, lpnr++)
{
// Ensure resource has a remote name, and is connected.
if ((lpnr->lpRemoteName == NULL) ||
(lpnr->dwScope != RESOURCE_CONNECTED))
continue;
if ((_strnicmp(lpnr->lpRemoteName, pszShareName,
dwServerSize) == 0) &&
(lpnr->lpRemoteName[dwServerSize] == SLASH))
{
// got one!
// but we don't want to flush '\\[...]afs\all'
if (_stricmp(lpnr->lpRemoteName,
pszShareName) == 0)
continue;
++dwTotalVols;
dwVolBegin = GetTickCount();
afsRet = afsd_ServicePerformFlushVolumeCmd(lpnr->lpRemoteName);
dwVolEnd = GetTickCount();
if (afsRet == 0)
{
LogTimingEvent(MSG_TIME_FLUSH_PER_VOLUME,
lpnr->lpRemoteName,
dwVolEnd - dwVolBegin);
}
else
{
LogEvent(EVENTLOG_WARNING_TYPE,
MSG_FLUSH_FAILED,
lpnr->lpRemoteName, NULL);
}
}
}
}
WNetCloseEnum(hEnum);
free(lpNetResBuf);
free(pszShareName);
if (dwRet != ERROR_NO_MORE_ITEMS)
{
LogEventMessage(EVENTLOG_ERROR_TYPE, MSG_FLUSH_ENUM_ERROR,
dwRet);
return FALSE;
}
dwFlushEnd = GetTickCount();
// display total volume count in Event Logger
sprintf(bufMessage, "%d", dwTotalVols);
LogTimingEvent(MSG_TIME_FLUSH_TOTAL, bufMessage,
dwFlushEnd - dwFlushBegin);
return TRUE;
return TRUE;
}
// Report a timing event to the system event log.
@ -193,11 +201,11 @@ afsd_ServicePerformFlushVolumes()
static VOID
LogTimingEvent(DWORD dwEventID, LPTSTR lpString1, DWORD dwTime)
{
CHAR szTime[16];
CHAR szTime[16];
sprintf(szTime, "%lu", dwTime);
LogEvent(EVENTLOG_INFORMATION_TYPE, dwEventID, lpString1, szTime,
NULL);
sprintf(szTime, "%lu", dwTime);
LogEvent(EVENTLOG_INFORMATION_TYPE, dwEventID, lpString1, szTime,
NULL);
}
@ -223,91 +231,91 @@ LogTimingEvent(DWORD dwEventID, LPTSTR lpString1, DWORD dwTime)
//
HANDLE GetUserToken(DWORD access)
{
HANDLE hTok = NULL;
DWORD pid = 0, tid = 0;
HANDLE hTok = NULL;
DWORD pid = 0, tid = 0;
// Try it the easy way first - look for a window owned by the shell on
// our current desktop. If we find one, use that to get the process id.
HWND shell = FindWindowEx(NULL, NULL, "Progman", NULL);
if (shell != NULL)
{
tid = GetWindowThreadProcessId(shell, &pid);
}
// Try it the easy way first - look for a window owned by the shell on
// our current desktop. If we find one, use that to get the process id.
HWND shell = FindWindowEx(NULL, NULL, "Progman", NULL);
if (shell != NULL)
{
tid = GetWindowThreadProcessId(shell, &pid);
}
// We are possibly running on a private window station and desktop: we must
// switch to the default (which we suppose is where we will find the
// running shell).
else
{
HWINSTA saveWinSta = GetProcessWindowStation();
HDESK saveDesk = GetThreadDesktop(GetCurrentThreadId());
HWINSTA winSta = NULL;
HDESK desk = NULL;
BOOL changeFlag = FALSE;
BOOL dummy = saveWinSta != NULL &&
saveDesk != NULL &&
(winSta = OpenWindowStation("WinSta0", FALSE,
MAXIMUM_ALLOWED)) != NULL &&
(changeFlag = SetProcessWindowStation(winSta)) != 0 &&
(desk = OpenDesktop("Default", 0, FALSE,
MAXIMUM_ALLOWED)) != NULL &&
SetThreadDesktop(desk) != 0;
// We are possibly running on a private window station and desktop: we must
// switch to the default (which we suppose is where we will find the
// running shell).
else
{
HWINSTA saveWinSta = GetProcessWindowStation();
HDESK saveDesk = GetThreadDesktop(GetCurrentThreadId());
HWINSTA winSta = NULL;
HDESK desk = NULL;
BOOL changeFlag = FALSE;
BOOL dummy = saveWinSta != NULL &&
saveDesk != NULL &&
(winSta = OpenWindowStation("WinSta0", FALSE,
MAXIMUM_ALLOWED)) != NULL &&
(changeFlag = SetProcessWindowStation(winSta)) != 0 &&
(desk = OpenDesktop("Default", 0, FALSE,
MAXIMUM_ALLOWED)) != NULL &&
SetThreadDesktop(desk) != 0;
// Now find the window and process on this desktop
shell = FindWindowEx(NULL, NULL, "Progman", NULL);
if (shell != NULL)
{
tid = GetWindowThreadProcessId(shell, &pid);
}
// Now find the window and process on this desktop
shell = FindWindowEx(NULL, NULL, "Progman", NULL);
if (shell != NULL)
{
tid = GetWindowThreadProcessId(shell, &pid);
}
// Restore our own window station and desktop
if (changeFlag)
{
SetProcessWindowStation(saveWinSta);
SetThreadDesktop(saveDesk);
}
// Restore our own window station and desktop
if (changeFlag)
{
SetProcessWindowStation(saveWinSta);
SetThreadDesktop(saveDesk);
}
// Close temporary objects
if (winSta != NULL)
CloseWindowStation(winSta);
if (desk != NULL)
CloseDesktop(desk);
}
// Close temporary objects
if (winSta != NULL)
CloseWindowStation(winSta);
if (desk != NULL)
CloseDesktop(desk);
}
//
// If we have a process id, use that to get the process handle and
// from there the process' access token.
//
if (pid != 0)
{
HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
if (hProc != NULL)
{
OpenProcessToken(hProc, access, &hTok) || (hTok = NULL);
CloseHandle(hProc);
}
}
//
// If we have a process id, use that to get the process handle and
// from there the process' access token.
//
if (pid != 0)
{
HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
if (hProc != NULL)
{
OpenProcessToken(hProc, access, &hTok) || (hTok = NULL);
CloseHandle(hProc);
}
}
// Return token if we got one
return hTok;
}
// Return token if we got one
return hTok;
}
// impersonate logged-on user as client
BOOL
ImpersonateClient()
{
DWORD dwDesiredAccess = TOKEN_ALL_ACCESS;
HANDLE hUserToken = GetUserToken(dwDesiredAccess);
DWORD dwDesiredAccess = TOKEN_ALL_ACCESS;
HANDLE hUserToken = GetUserToken(dwDesiredAccess);
if (hUserToken == NULL)
return FALSE;
if (ImpersonateLoggedOnUser(hUserToken) == 0)
{
LogEvent(EVENTLOG_ERROR_TYPE, MSG_FLUSH_IMPERSONATE_ERROR,
NULL);
return FALSE;
}
return TRUE;
if (hUserToken == NULL)
return FALSE;
if (ImpersonateLoggedOnUser(hUserToken) == 0)
{
LogEvent(EVENTLOG_ERROR_TYPE, MSG_FLUSH_IMPERSONATE_ERROR,
NULL);
return FALSE;
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////
@ -317,67 +325,67 @@ ImpersonateClient()
DWORD WINAPI
afsd_ServiceFlushVolumesThreadProc(LPVOID lpParam)
{
FLUSHVOLTHREADINFO ThreadInfo;
PFLUSHVOLTHREADINFO pThreadInfo = (PFLUSHVOLTHREADINFO) lpParam;
HANDLE arHandles[2] = {0};
DWORD dwWaitState = 0;
FLUSHVOLTHREADINFO ThreadInfo;
PFLUSHVOLTHREADINFO pThreadInfo = (PFLUSHVOLTHREADINFO) lpParam;
HANDLE arHandles[2] = {0};
DWORD dwWaitState = 0;
// thread running - get handles
ThreadInfo.hEventPowerEvent = pThreadInfo->hEventPowerEvent;
ThreadInfo.hEventResumeMain = pThreadInfo->hEventResumeMain;
ThreadInfo.hEventTerminate = pThreadInfo->hEventTerminate;
// thread running - get handles
ThreadInfo.hEventPowerEvent = pThreadInfo->hEventPowerEvent;
ThreadInfo.hEventResumeMain = pThreadInfo->hEventResumeMain;
ThreadInfo.hEventTerminate = pThreadInfo->hEventTerminate;
// setup to wait
arHandles[0] = ThreadInfo.hEventTerminate;
arHandles[1] = ThreadInfo.hEventPowerEvent;
// setup to wait
arHandles[0] = ThreadInfo.hEventTerminate;
arHandles[1] = ThreadInfo.hEventPowerEvent;
// do stuff ..
while (1)
{
// wait for an event to happen
dwWaitState = WaitForMultipleObjectsEx(2, arHandles, FALSE, INFINITE, FALSE);
// do stuff ..
while (1)
{
// wait for an event to happen
dwWaitState = WaitForMultipleObjectsEx(2, arHandles, FALSE, INFINITE, FALSE);
switch (dwWaitState)
{
case WAIT_OBJECT_0:
// termination signaled
RevertToSelf();
switch (dwWaitState)
{
case WAIT_OBJECT_0:
// termination signaled
RevertToSelf();
CheckAndCloseHandle(ThreadInfo.hEventPowerEvent);
CheckAndCloseHandle(ThreadInfo.hEventResumeMain);
CheckAndCloseHandle(ThreadInfo.hEventTerminate);
ExitThread(0);
break;
ExitThread(0);
break;
case WAIT_OBJECT_0+1:
// Power event
// - flush 'em!
if (ImpersonateClient())
{
afsd_ServicePerformFlushVolumes();
}
// acknowledge event
ResetEvent(ThreadInfo.hEventPowerEvent);
break;
case WAIT_OBJECT_0+1:
// Power event
// - flush 'em!
if (ImpersonateClient())
{
afsd_ServicePerformFlushVolumes();
}
// acknowledge event
ResetEvent(ThreadInfo.hEventPowerEvent);
break;
case WAIT_ABANDONED_0:
case WAIT_ABANDONED_0+1:
case WAIT_IO_COMPLETION:
case WAIT_TIMEOUT:
// sno*
LogEvent(EVENTLOG_WARNING_TYPE,
MSG_FLUSH_UNEXPECTED_EVENT, NULL);
break;
} // end switch
case WAIT_ABANDONED_0:
case WAIT_ABANDONED_0+1:
case WAIT_IO_COMPLETION:
case WAIT_TIMEOUT:
// sno*
LogEvent(EVENTLOG_WARNING_TYPE,
MSG_FLUSH_UNEXPECTED_EVENT, NULL);
break;
// signal back to waiting mainline
SetEvent(ThreadInfo.hEventResumeMain);
} // end switch
} // end while
// I suppose we never get here
ExitThread(0);
}
// signal back to waiting mainline
SetEvent(ThreadInfo.hEventResumeMain);
} // end while
// I suppose we never get here
ExitThread(0);
}
/////////////////////////////////////////////////////////////////////
//
@ -387,11 +395,11 @@ afsd_ServiceFlushVolumesThreadProc(LPVOID lpParam)
VOID
CheckAndCloseHandle(HANDLE thisHandle)
{
if (thisHandle != NULL)
{
CloseHandle(thisHandle);
thisHandle = NULL;
}
if (thisHandle != NULL)
{
CloseHandle(thisHandle);
thisHandle = NULL;
}
}
//
@ -400,62 +408,62 @@ CheckAndCloseHandle(HANDLE thisHandle)
BOOL
PowerNotificationThreadCreate()
{
BOOL bSuccess = FALSE;
DWORD dwThreadId = 0;
BOOL bSuccess = FALSE;
DWORD dwThreadId = 0;
char eventName[MAX_PATH];
do
{
// create power event notification event
// bManualReset=TRUE, bInitialState=FALSE
gThreadInfo.hEventPowerEvent = CreateEvent(NULL, TRUE, FALSE,
do
{
// create power event notification event
// bManualReset=TRUE, bInitialState=FALSE
gThreadInfo.hEventPowerEvent = CreateEvent(NULL, TRUE, FALSE,
TEXT("afsd_flushvol_EventPowerEvent"));
if ( GetLastError() == ERROR_ALREADY_EXISTS )
afsi_log("Event Object Already Exists: %s", eventName);
if (gThreadInfo.hEventPowerEvent == NULL)
break;
if (gThreadInfo.hEventPowerEvent == NULL)
break;
// create mainline resume event
// bManualReset=FALSE, bInitialState=FALSE
gThreadInfo.hEventResumeMain = CreateEvent(NULL, FALSE, FALSE,
// create mainline resume event
// bManualReset=FALSE, bInitialState=FALSE
gThreadInfo.hEventResumeMain = CreateEvent(NULL, FALSE, FALSE,
TEXT("afsd_flushvol_EventResumeMain"));
if ( GetLastError() == ERROR_ALREADY_EXISTS )
afsi_log("Event Object Already Exists: %s", eventName);
if (gThreadInfo.hEventResumeMain == NULL)
break;
if (gThreadInfo.hEventResumeMain == NULL)
break;
// create thread terminate event
// bManualReset=FALSE, bInitialState=FALSE
gThreadInfo.hEventTerminate = CreateEvent(NULL, FALSE, FALSE,
// create thread terminate event
// bManualReset=FALSE, bInitialState=FALSE
gThreadInfo.hEventTerminate = CreateEvent(NULL, FALSE, FALSE,
TEXT("afsd_flushvol_EventTerminate"));
if ( GetLastError() == ERROR_ALREADY_EXISTS )
afsi_log("Event Object Already Exists: %s", eventName);
if (gThreadInfo.hEventTerminate == NULL)
break;
if (gThreadInfo.hEventTerminate == NULL)
break;
// good so far - create thread
gThreadHandle = CreateThread(NULL, 0,
afsd_ServiceFlushVolumesThreadProc,
(LPVOID) &gThreadInfo,
0, &dwThreadId);
// good so far - create thread
gThreadHandle = CreateThread(NULL, 0,
afsd_ServiceFlushVolumesThreadProc,
(LPVOID) &gThreadInfo,
0, &dwThreadId);
if (!gThreadHandle)
break;
if (!gThreadHandle)
break;
bSuccess = TRUE;
bSuccess = TRUE;
} while (0);
} while (0);
if (!bSuccess)
{
CheckAndCloseHandle(gThreadInfo.hEventPowerEvent);
CheckAndCloseHandle(gThreadInfo.hEventResumeMain);
CheckAndCloseHandle(gThreadInfo.hEventTerminate);
CheckAndCloseHandle(gThreadHandle);
}
if (!bSuccess)
{
CheckAndCloseHandle(gThreadInfo.hEventPowerEvent);
CheckAndCloseHandle(gThreadInfo.hEventResumeMain);
CheckAndCloseHandle(gThreadInfo.hEventTerminate);
CheckAndCloseHandle(gThreadHandle);
}
return bSuccess;
return bSuccess;
}
//
@ -464,21 +472,21 @@ PowerNotificationThreadCreate()
BOOL
PowerNotificationThreadNotify()
{
DWORD dwRet = 0;
BOOL bRet = FALSE;
DWORD dwRet = 0;
BOOL bRet = FALSE;
// Notify thread of power event, and wait for the HardDead timeout period
dwRet = SignalObjectAndWait(
gThreadInfo.hEventPowerEvent, // object to signal
gThreadInfo.hEventResumeMain, // object to watch
HardDeadtimeout*1000, // timeout (ms)
FALSE // alertable
);
// Notify thread of power event, and wait for the HardDead timeout period
dwRet = SignalObjectAndWait(
gThreadInfo.hEventPowerEvent, // object to signal
gThreadInfo.hEventResumeMain, // object to watch
HardDeadtimeout*1000, // timeout (ms)
FALSE // alertable
);
if (dwRet == WAIT_OBJECT_0)
bRet = TRUE;
if (dwRet == WAIT_OBJECT_0)
bRet = TRUE;
return bRet;
return bRet;
}
//
@ -487,12 +495,12 @@ PowerNotificationThreadNotify()
VOID
PowerNotificationThreadExit()
{
// ExitThread
if (gThreadHandle)
{
SetEvent(gThreadInfo.hEventTerminate);
// ExitThread
if (gThreadHandle)
{
SetEvent(gThreadInfo.hEventTerminate);
WaitForSingleObject(gThreadHandle, INFINITE);
CloseHandle(gThreadHandle);
}
CloseHandle(gThreadHandle);
}
}

View File

@ -32,7 +32,8 @@
// The following is defined if you want to receive Power notifications,
// including Hibernation, and also subsequent flushing of AFS volumes
//
#define REGISTER_POWER_NOTIFICATIONS
#define REGISTER_POWER_NOTIFICATIONS 1
#define FLUSH_VOLUME 1
//
// Check
*/
@ -59,26 +60,26 @@ extern HANDLE afsi_file;
*/
static void afsd_notifier(char *msgp, char *filep, long line)
{
char tbuffer[512];
char *ptbuf[1];
HANDLE h;
char tbuffer[512];
char *ptbuf[1];
HANDLE h;
if (filep)
sprintf(tbuffer, "Error at file %s, line %d: %s",
filep, line, msgp);
else
sprintf(tbuffer, "Error at unknown location: %s", msgp);
if (filep)
sprintf(tbuffer, "Error at file %s, line %d: %s",
filep, line, msgp);
else
sprintf(tbuffer, "Error at unknown location: %s", msgp);
h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
ptbuf[0] = tbuffer;
ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, line, NULL, 1, 0, ptbuf, NULL);
DeregisterEventSource(h);
h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
ptbuf[0] = tbuffer;
ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, line, NULL, 1, 0, ptbuf, NULL);
DeregisterEventSource(h);
GlobalStatus = line;
GlobalStatus = line;
osi_LogEnable(afsd_logp);
osi_LogEnable(afsd_logp);
afsd_ForceTrace(TRUE);
afsd_ForceTrace(TRUE);
afsi_log("--- begin dump ---");
cm_DumpSCache(afsi_file, "a");
@ -91,14 +92,14 @@ static void afsd_notifier(char *msgp, char *filep, long line)
DebugBreak();
SetEvent(WaitToTerminate);
SetEvent(WaitToTerminate);
#ifdef JUMP
if (GetCurrentThreadId() == MainThreadId)
longjmp(notifier_jmp, 1);
else
if (GetCurrentThreadId() == MainThreadId)
longjmp(notifier_jmp, 1);
else
#endif /* JUMP */
ExitThread(1);
ExitThread(1);
}
/*
@ -106,7 +107,7 @@ static void afsd_notifier(char *msgp, char *filep, long line)
*/
static int _stdcall DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
{
return 0;
return 0;
}
static SERVICE_STATUS ServiceStatus;
@ -130,7 +131,6 @@ afsd_ServiceFlushVolume(DWORD dwlpEventData)
{
dwRet = NO_ERROR;
}
else
{
/* flush was unsuccessful, or timeout - deny shutdown */
@ -151,53 +151,53 @@ afsd_ServiceFlushVolume(DWORD dwlpEventData)
VOID WINAPI
afsd_ServiceControlHandler(DWORD ctrlCode)
{
HKEY parmKey;
DWORD dummyLen, doTrace;
long code;
HKEY parmKey;
DWORD dummyLen, doTrace;
long code;
switch (ctrlCode) {
case SERVICE_CONTROL_STOP:
/* Shutdown RPC */
RpcMgmtStopServerListening(NULL);
switch (ctrlCode) {
case SERVICE_CONTROL_STOP:
/* Shutdown RPC */
RpcMgmtStopServerListening(NULL);
/* Force trace if requested */
code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
AFSConfigKeyName,
0, KEY_QUERY_VALUE, &parmKey);
if (code != ERROR_SUCCESS)
goto doneTrace;
/* Force trace if requested */
code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
AFSConfigKeyName,
0, KEY_QUERY_VALUE, &parmKey);
if (code != ERROR_SUCCESS)
goto doneTrace;
dummyLen = sizeof(doTrace);
code = RegQueryValueEx(parmKey, "TraceOnShutdown",
NULL, NULL,
(BYTE *) &doTrace, &dummyLen);
RegCloseKey (parmKey);
if (code != ERROR_SUCCESS)
doTrace = 0;
if (doTrace)
afsd_ForceTrace(FALSE);
dummyLen = sizeof(doTrace);
code = RegQueryValueEx(parmKey, "TraceOnShutdown",
NULL, NULL,
(BYTE *) &doTrace, &dummyLen);
RegCloseKey (parmKey);
if (code != ERROR_SUCCESS)
doTrace = 0;
if (doTrace)
afsd_ForceTrace(FALSE);
doneTrace:
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
ServiceStatus.dwWin32ExitCode = NO_ERROR;
ServiceStatus.dwCheckPoint = 1;
ServiceStatus.dwWaitHint = 10000;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
SetServiceStatus(StatusHandle, &ServiceStatus);
SetEvent(WaitToTerminate);
break;
case SERVICE_CONTROL_INTERROGATE:
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwWin32ExitCode = NO_ERROR;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
SetServiceStatus(StatusHandle, &ServiceStatus);
break;
/* XXX handle system shutdown */
/* XXX handle pause & continue */
}
}
doneTrace:
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
ServiceStatus.dwWin32ExitCode = NO_ERROR;
ServiceStatus.dwCheckPoint = 1;
ServiceStatus.dwWaitHint = 10000;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
SetServiceStatus(StatusHandle, &ServiceStatus);
SetEvent(WaitToTerminate);
break;
case SERVICE_CONTROL_INTERROGATE:
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwWin32ExitCode = NO_ERROR;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
SetServiceStatus(StatusHandle, &ServiceStatus);
break;
/* XXX handle system shutdown */
/* XXX handle pause & continue */
}
}
/*
@ -212,12 +212,12 @@ afsd_ServiceControlHandlerEx(
LPVOID lpContext
)
{
HKEY parmKey;
DWORD dummyLen, doTrace;
long code;
HKEY parmKey;
DWORD dummyLen, doTrace;
long code;
DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
switch (ctrlCode)
switch (ctrlCode)
{
case SERVICE_CONTROL_STOP:
/* Shutdown RPC */
@ -261,45 +261,45 @@ afsd_ServiceControlHandlerEx(
dwRet = NO_ERROR;
break;
/* XXX handle system shutdown */
/* XXX handle pause & continue */
case SERVICE_CONTROL_POWEREVENT:
{
/*
/* XXX handle system shutdown */
/* XXX handle pause & continue */
case SERVICE_CONTROL_POWEREVENT:
{
/*
** dwEventType of this notification == WPARAM of WM_POWERBROADCAST
** Return NO_ERROR == return TRUE for that message, i.e. accept request
** Return any error code to deny request,
** i.e. as if returning BROADCAST_QUERY_DENY
*/
switch((int) dwEventType)
** Return NO_ERROR == return TRUE for that message, i.e. accept request
** Return any error code to deny request,
** i.e. as if returning BROADCAST_QUERY_DENY
*/
switch((int) dwEventType)
{
case PBT_APMQUERYSUSPEND:
case PBT_APMQUERYSTANDBY:
#ifdef REGISTER_POWER_NOTIFICATIONS
/* handle event */
dwRet = afsd_ServiceFlushVolume((DWORD) lpEventData);
case PBT_APMQUERYSUSPEND:
case PBT_APMQUERYSTANDBY:
#ifdef FLUSH_VOLUME
/* handle event */
dwRet = afsd_ServiceFlushVolume((DWORD) lpEventData);
#else
dwRet = NO_ERROR;
dwRet = NO_ERROR;
#endif
break;
break;
/* allow remaining case PBT_WhatEver */
case PBT_APMSUSPEND:
case PBT_APMSTANDBY:
case PBT_APMRESUMECRITICAL:
case PBT_APMRESUMESUSPEND:
case PBT_APMRESUMESTANDBY:
case PBT_APMBATTERYLOW:
case PBT_APMPOWERSTATUSCHANGE:
case PBT_APMOEMEVENT:
case PBT_APMRESUMEAUTOMATIC:
default:
dwRet = NO_ERROR;
}
/* allow remaining case PBT_WhatEver */
case PBT_APMSUSPEND:
case PBT_APMSTANDBY:
case PBT_APMRESUMECRITICAL:
case PBT_APMRESUMESUSPEND:
case PBT_APMRESUMESTANDBY:
case PBT_APMBATTERYLOW:
case PBT_APMPOWERSTATUSCHANGE:
case PBT_APMOEMEVENT:
case PBT_APMRESUMEAUTOMATIC:
default:
dwRet = NO_ERROR;
}
}
} /* end switch(ctrlCode) */
return dwRet;
return dwRet;
}
/* There is similar code in client_config\drivemap.cpp GlobalMountDrive()
@ -323,8 +323,8 @@ static void MountGlobalDrives()
sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
if (dwResult != ERROR_SUCCESS)
dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
if (dwResult != ERROR_SUCCESS)
return;
while (dwRetry < MAX_RETRIES) {
@ -385,8 +385,8 @@ static void DismountGlobalDrives()
sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
if (dwResult != ERROR_SUCCESS)
dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
if (dwResult != ERROR_SUCCESS)
return;
while (1) {
@ -428,10 +428,10 @@ RegisterServiceCtrlHandlerFunc pRegisterServiceCtrlHandler = NULL;
void afsd_Main(DWORD argc, LPTSTR *argv)
{
long code;
char *reason;
long code;
char *reason;
#ifdef JUMP
int jmpret;
int jmpret;
#endif /* JUMP */
HANDLE hInitHookDll;
HANDLE hAdvApi32;
@ -443,13 +443,13 @@ void afsd_Main(DWORD argc, LPTSTR *argv)
#endif
osi_InitPanic(afsd_notifier);
osi_InitTraceOption();
osi_InitTraceOption();
GlobalStatus = 0;
GlobalStatus = 0;
afsi_start();
afsi_start();
WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate"));
WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate"));
if ( GetLastError() == ERROR_ALREADY_EXISTS )
afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
@ -472,15 +472,15 @@ void afsd_Main(DWORD argc, LPTSTR *argv)
StatusHandle = RegisterServiceCtrlHandler(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandler);
}
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwWin32ExitCode = NO_ERROR;
ServiceStatus.dwCheckPoint = 1;
ServiceStatus.dwWaitHint = 30000;
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwWin32ExitCode = NO_ERROR;
ServiceStatus.dwCheckPoint = 1;
ServiceStatus.dwWaitHint = 30000;
/* accept Power Events */
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
SetServiceStatus(StatusHandle, &ServiceStatus);
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
SetServiceStatus(StatusHandle, &ServiceStatus);
#endif
{
@ -538,15 +538,15 @@ void afsd_Main(DWORD argc, LPTSTR *argv)
#ifdef JUMP
MainThreadId = GetCurrentThreadId();
jmpret = setjmp(notifier_jmp);
jmpret = setjmp(notifier_jmp);
if (jmpret == 0)
if (jmpret == 0)
#endif /* JUMP */
{
code = afsd_InitCM(&reason);
if (code != 0) {
code = afsd_InitCM(&reason);
if (code != 0) {
afsi_log("afsd_InitCM failed: %s (code = %d)", reason, code);
osi_panic(reason, __FILE__, __LINE__);
osi_panic(reason, __FILE__, __LINE__);
}
#ifndef NOTSERVICE
@ -554,8 +554,8 @@ void afsd_Main(DWORD argc, LPTSTR *argv)
ServiceStatus.dwWaitHint -= 5000;
SetServiceStatus(StatusHandle, &ServiceStatus);
#endif
code = afsd_InitDaemons(&reason);
if (code != 0) {
code = afsd_InitDaemons(&reason);
if (code != 0) {
afsi_log("afsd_InitDaemons failed: %s (code = %d)", reason, code);
osi_panic(reason, __FILE__, __LINE__);
}
@ -565,42 +565,42 @@ void afsd_Main(DWORD argc, LPTSTR *argv)
ServiceStatus.dwWaitHint -= 5000;
SetServiceStatus(StatusHandle, &ServiceStatus);
#endif
code = afsd_InitSMB(&reason, MessageBox);
if (code != 0) {
code = afsd_InitSMB(&reason, MessageBox);
if (code != 0) {
afsi_log("afsd_InitSMB failed: %s (code = %d)", reason, code);
osi_panic(reason, __FILE__, __LINE__);
osi_panic(reason, __FILE__, __LINE__);
}
MountGlobalDrives();
#ifndef NOTSERVICE
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwWin32ExitCode = NO_ERROR;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwWin32ExitCode = NO_ERROR;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
/* accept Power events */
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
SetServiceStatus(StatusHandle, &ServiceStatus);
#endif
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
SetServiceStatus(StatusHandle, &ServiceStatus);
#endif
{
HANDLE h; char *ptbuf[1];
h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
ptbuf[0] = "AFS running";
ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
DeregisterEventSource(h);
h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
ptbuf[0] = "AFS running";
ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
DeregisterEventSource(h);
}
}
}
WaitForSingleObject(WaitToTerminate, INFINITE);
WaitForSingleObject(WaitToTerminate, INFINITE);
{
HANDLE h; char *ptbuf[1];
HANDLE h; char *ptbuf[1];
h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
ptbuf[0] = "AFS quitting";
ReportEvent(h, GlobalStatus ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
0, 0, NULL, 1, 0, ptbuf, NULL);
DeregisterEventSource(h);
DeregisterEventSource(h);
}
DismountGlobalDrives();
@ -608,20 +608,20 @@ void afsd_Main(DWORD argc, LPTSTR *argv)
rx_Finalize();
#ifdef REGISTER_POWER_NOTIFICATIONS
/* terminate thread used to flush cache */
PowerNotificationThreadExit();
/* terminate thread used to flush cache */
PowerNotificationThreadExit();
#endif
/* Remove the ExceptionFilter */
SetUnhandledExceptionFilter(NULL);
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
ServiceStatus.dwControlsAccepted = 0;
SetServiceStatus(StatusHandle, &ServiceStatus);
}
ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
ServiceStatus.dwControlsAccepted = 0;
SetServiceStatus(StatusHandle, &ServiceStatus);
}
DWORD __stdcall afsdMain_thread(void* notUsed)
{
@ -633,15 +633,15 @@ DWORD __stdcall afsdMain_thread(void* notUsed)
int
main(void)
{
static SERVICE_TABLE_ENTRY dispatchTable[] = {
{AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
{NULL, NULL}
};
static SERVICE_TABLE_ENTRY dispatchTable[] = {
{AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
{NULL, NULL}
};
if (!StartServiceCtrlDispatcher(dispatchTable))
if (!StartServiceCtrlDispatcher(dispatchTable))
{
LONG status = GetLastError();
if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
{
DWORD tid;
hAFSDMainThread = CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);

View File

@ -394,6 +394,35 @@ extern "C" lana_number_t lana_FindLoopback(void)
return LANA_INVALID;
}
/* Returns TRUE if all adapters are loopback adapters */
extern "C" BOOL lana_OnlyLoopback(void)
{
NCB ncb;
LANA_ENUM lana_list;
int status;
int i;
memset(&ncb, 0, sizeof(ncb));
ncb.ncb_command = NCBENUM;
ncb.ncb_buffer = (UCHAR *) &lana_list;
ncb.ncb_length = sizeof(lana_list);
status = Netbios(&ncb);
if (status != 0) {
#ifndef NOLOGGING
afsi_log("Netbios NCBENUM failed: status %ld", status);
#endif
return FALSE;
}
for (i = 0; i < lana_list.length; i++) {
if (!lana_IsLoopback(lana_list.lana[i])) {
// Found one non-Loopback adapter
return FALSE;
}
}
// All adapters are loopback
return TRUE;
}
// Is the given lana a Windows Loopback Adapter?
// TODO: implement a better check for loopback
// TODO: also check for proper bindings (IPv4)

View File

@ -59,6 +59,8 @@ extern "C" {
lana_number_t lana_FindLoopback(void);
BOOL lana_OnlyLoopback(void);
BOOL lana_IsLoopback(lana_number_t lana);
long lana_GetUncServerNameEx(char *buffer, lana_number_t * pLana, int * pIsGateway, int flags);