From 2b9525fe9e09ad90b08c9a60fa4b098df542c047 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Thu, 5 Jul 2007 20:21:19 +0000 Subject: [PATCH] windows-volume-status-plugin-20070705 This delta adds an interface to an optional volume status handler. The handler (if provided) receives status updates when volumes change state between online, offline, busy, and alldown. --- src/WINNT/afsd/NTMakefile | 2 + src/WINNT/afsd/afsd.h | 1 + src/WINNT/afsd/afsd_service.c | 12 ++ src/WINNT/afsd/cm.h | 1 + src/WINNT/afsd/cm_daemon.c | 1 + src/WINNT/afsd/cm_volstat.c | 286 ++++++++++++++++++++++++++++++++++ src/WINNT/afsd/cm_volstat.h | 55 +++++++ src/WINNT/afsd/cm_volume.c | 2 + src/WINNT/afsd/smb.c | 27 +++- src/WINNT/afsd/smb.h | 1 + 10 files changed, 387 insertions(+), 1 deletion(-) create mode 100644 src/WINNT/afsd/cm_volstat.c create mode 100644 src/WINNT/afsd/cm_volstat.h diff --git a/src/WINNT/afsd/NTMakefile b/src/WINNT/afsd/NTMakefile index 6029def95..b9ac3e484 100644 --- a/src/WINNT/afsd/NTMakefile +++ b/src/WINNT/afsd/NTMakefile @@ -51,6 +51,7 @@ INCFILES =\ $(INCFILEDIR)\cm_callback.h \ $(INCFILEDIR)\cm_aclent.h \ $(INCFILEDIR)\cm_volume.h \ + $(INCFILEDIR)\cm_volstat.h \ $(INCFILEDIR)\cm_dcache.h \ $(INCFILEDIR)\cm_access.h \ $(INCFILEDIR)\cm_vnodeops.h \ @@ -100,6 +101,7 @@ AFSDOBJS=\ $(OUT)\cm_cell.obj \ $(OUT)\cm_server.obj \ $(OUT)\cm_volume.obj \ + $(OUT)\cm_volstat.obj \ $(OUT)\cm_config.obj \ $(OUT)\cm_conn.obj \ $(OUT)\cm_user.obj \ diff --git a/src/WINNT/afsd/afsd.h b/src/WINNT/afsd/afsd.h index 82cab846b..a06adf696 100644 --- a/src/WINNT/afsd/afsd.h +++ b/src/WINNT/afsd/afsd.h @@ -35,6 +35,7 @@ BOOL APIENTRY About(HWND, unsigned int, unsigned int, long); #include "cm_cell.h" #include "cm_scache.h" #include "cm_volume.h" +#include "cm_volstat.h" #include "cm_dcache.h" #include "cm_access.h" #include "cm_utils.h" diff --git a/src/WINNT/afsd/afsd_service.c b/src/WINNT/afsd/afsd_service.c index 20fc69de4..6180a891c 100644 --- a/src/WINNT/afsd/afsd_service.c +++ b/src/WINNT/afsd/afsd_service.c @@ -1241,6 +1241,9 @@ afsd_Main(DWORD argc, LPTSTR *argv) } } + /* Perform Volume Status Notification Initialization */ + cm_VolStatus_Initialization(); + #ifdef JUMP MainThreadId = GetCurrentThreadId(); jmpret = setjmp(notifier_jmp); @@ -1360,6 +1363,9 @@ afsd_Main(DWORD argc, LPTSTR *argv) LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_RUNNING); } + /* Notify any volume status handlers that we have started */ + cm_VolStatus_Service_Started(); + /* allow an exit to be called when started */ hHookDll = LoadLibrary(AFSD_HOOK_DLL); if (hHookDll) @@ -1402,6 +1408,9 @@ afsd_Main(DWORD argc, LPTSTR *argv) else LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_STOPPING); + /* Notify any Volume Status Handlers that we are stopping */ + cm_VolStatus_Service_Stopped(); + /* allow an exit to be called prior to stopping the service */ hHookDll = LoadLibrary(AFSD_HOOK_DLL); if (hHookDll) @@ -1469,6 +1478,9 @@ afsd_Main(DWORD argc, LPTSTR *argv) PowerNotificationThreadExit(); #endif + /* Cleanup any Volume Status Notification Handler */ + cm_VolStatus_Finalize(); + /* allow an exit to be called after stopping the service */ hHookDll = LoadLibrary(AFSD_HOOK_DLL); if (hHookDll) diff --git a/src/WINNT/afsd/cm.h b/src/WINNT/afsd/cm.h index c193d5f46..379d2a303 100644 --- a/src/WINNT/afsd/cm.h +++ b/src/WINNT/afsd/cm.h @@ -296,6 +296,7 @@ int RXAFS_Lookup (struct rx_connection *, #define CM_ERROR_TOOFEWBUFS (CM_ERROR_BASE+50) #define CM_ERROR_TOOMANYBUFS (CM_ERROR_BASE+51) #define CM_ERROR_BAD_LEVEL (CM_ERROR_BASE+52) +#define CM_ERROR_NOT_A_DFSLINK (CM_ERROR_BASE+53) /* Used by cm_FollowMountPoint and cm_GetVolumeByName */ #define RWVOL 0 diff --git a/src/WINNT/afsd/cm_daemon.c b/src/WINNT/afsd/cm_daemon.c index e5f1bab6e..a64750e89 100644 --- a/src/WINNT/afsd/cm_daemon.c +++ b/src/WINNT/afsd/cm_daemon.c @@ -60,6 +60,7 @@ void cm_IpAddrDaemon(long parm) cm_ForceNewConnectionsAllServers(); cm_CheckServers(CM_FLAG_CHECKFILESERVERS | CM_FLAG_CHECKUPSERVERS | CM_FLAG_CHECKDOWNSERVERS, NULL); smb_CheckVCs(); + cm_VolStatus_Network_Addr_Change(); } } } diff --git a/src/WINNT/afsd/cm_volstat.c b/src/WINNT/afsd/cm_volstat.c new file mode 100644 index 000000000..9cb6cbf79 --- /dev/null +++ b/src/WINNT/afsd/cm_volstat.c @@ -0,0 +1,286 @@ +/* Copyright 2007 Secure Endpoints Inc. + * + * BSD 2-part License + */ + +/* This source file provides the declarations + * which specify the AFS Cache Manager Volume Status Event + * Notification API + */ + +#include +#include + +#include +#include +#include +#include +#include +#include "afsd.h" +#include + +HMODULE hVolStatus = NULL; +dll_VolStatus_Funcs_t dll_funcs; +cm_VolStatus_Funcs_t cm_funcs; + +/* This function is used to load any Volume Status Handlers + * and their associated function pointers. + */ +long +cm_VolStatus_Initialization(void) +{ + long (__fastcall * dll_VolStatus_Initialization)(dll_VolStatus_Funcs_t * dll_funcs, cm_VolStatus_Funcs_t *cm_funcs) = NULL; + long code = 0; + HKEY parmKey; + DWORD dummyLen; + char wd[MAX_PATH+1] = ""; + + code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, + 0, KEY_QUERY_VALUE, &parmKey); + if (code == ERROR_SUCCESS) { + dummyLen = sizeof(wd); + code = RegQueryValueEx(parmKey, "VolStatusHandler", NULL, NULL, + (BYTE *) &wd, &dummyLen); + RegCloseKey (parmKey); + } + + if (code == ERROR_SUCCESS && wd[0]) + hVolStatus = LoadLibrary(wd); + if (hVolStatus) { + (FARPROC) dll_VolStatus_Initialization = GetProcAddress(hVolStatus, "@VolStatus_Initialization@8"); + if (dll_VolStatus_Initialization) { + cm_funcs.version = CM_VOLSTATUS_FUNCS_VERSION; + cm_funcs.cm_VolStatus_Path_To_ID = cm_VolStatus_Path_To_ID; + cm_funcs.cm_VolStatus_Path_To_DFSlink = cm_VolStatus_Path_To_DFSlink; + + code = dll_VolStatus_Initialization(&dll_funcs, &cm_funcs); + } + + if (dll_VolStatus_Initialization == NULL || code != 0 || + dll_funcs.version != DLL_VOLSTATUS_FUNCS_VERSION) { + FreeLibrary(hVolStatus); + hVolStatus = NULL; + code = -1; + } + } + + return code; +} + +/* This function is used to unload any Volume Status Handlers + * that were loaded during initialization. + */ +long +cm_VolStatus_Finalize(void) +{ + if (hVolStatus == NULL) + return 0; + + FreeLibrary(hVolStatus); + hVolStatus = NULL; + return 0; +} + +/* This function notifies the Volume Status Handlers that the + * AFS client service has started. If the network is started + * at this point we call cm_VolStatus_Network_Started(). + */ +long +cm_VolStatus_Service_Started(void) +{ + long code = 0; + + if (hVolStatus == NULL) + return 0; + + code = dll_funcs.dll_VolStatus_Service_Started(); + if (code == 0 && smb_IsNetworkStarted()) + code = dll_funcs.dll_VolStatus_Network_Started(cm_NetbiosName, cm_NetbiosName); + + return code; +} + +/* This function notifies the Volume Status Handlers that the + * AFS client service is stopping. + */ +long +cm_VolStatus_Service_Stopped(void) +{ + long code = 0; + + if (hVolStatus == NULL) + return 0; + + code = dll_funcs.dll_VolStatus_Service_Stopped(); + + return code; +} + + +/* This function notifies the Volume Status Handlers that the + * AFS client service is accepting network requests using the + * specified netbios names. + */ +long +#ifdef _WIN64 +cm_VolStatus_Network_Started(const char * netbios32, const char * netbios64) +#else /* _WIN64 */ +cm_VolStatus_Network_Started(const char * netbios) +#endif /* _WIN64 */ +{ + long code = 0; + + if (hVolStatus == NULL) + return 0; + +#ifdef _WIN64 + code = dll_funcs.dll_VolStatus_Network_Started(netbios32, netbios64); +#else + code = dll_funcs.dll_VolStatus_Network_Started(netbios, netbios); +#endif + + return code; +} + +/* This function notifies the Volume Status Handlers that the + * AFS client service is no longer accepting network requests + * using the specified netbios names + */ +long +#ifdef _WIN64 +cm_VolStatus_Network_Stopped(const char * netbios32, const char * netbios64) +#else /* _WIN64 */ +cm_VolStatus_Network_Stopped(const char * netbios) +#endif /* _WIN64 */ +{ + long code = 0; + + if (hVolStatus == NULL) + return 0; + +#ifdef _WIN64 + code = dll_funcs.dll_VolStatus_Network_Stopped(netbios32, netbios64); +#else + code = dll_funcs.dll_VolStatus_Network_Stopped(netbios, netbios); +#endif + + return code; +} + +/* This function is called when the IP address list changes. + * Volume Status Handlers can use this notification as a hint + * that it might be possible to determine volume IDs for paths + * that previously were not accessible. + */ +long +cm_VolStatus_Network_Addr_Change(void) +{ + long code = 0; + + if (hVolStatus == NULL) + return 0; + + code = dll_funcs.dll_VolStatus_Network_Addr_Change(); + + return code; +} + +/* This function notifies the Volume Status Handlers that the + * state of the specified cell.volume has changed. + */ +long +cm_VolStatus_Change_Notification(afs_uint32 cellID, afs_uint32 volID, enum volstatus status) +{ + long code = 0; + + if (hVolStatus == NULL) + return 0; + + code = dll_funcs.dll_VolStatus_Change_Notification(cellID, volID, status); + + return code; +} + + +long __fastcall +cm_VolStatus_Path_To_ID(const char * share, const char * path, afs_uint32 * cellID, afs_uint32 * volID) +{ + afs_uint32 code; + cm_req_t req; + cm_scache_t *scp; + + if (cellID == NULL || volID == NULL) + return CM_ERROR_INVAL; + + cm_InitReq(&req); + + + code = cm_NameI(cm_data.rootSCachep, (char *)path, CM_FLAG_FOLLOW, cm_rootUserp, (char *)share, &req, &scp); + if (code) + return code; + + lock_ObtainMutex(&scp->mx); + code = cm_SyncOp(scp, NULL,cm_rootUserp, &req, 0, + CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS); + if (code) { + lock_ReleaseMutex(&scp->mx); + cm_ReleaseSCache(scp); + return code; + } + + cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS); + + *cellID = scp->fid.cell; + *volID = scp->fid.volume; + + lock_ReleaseMutex(&scp->mx); + cm_ReleaseSCache(scp); + + return 0; +} + +long __fastcall +cm_VolStatus_Path_To_DFSlink(const char * share, const char * path, afs_uint32 *pBufSize, char *pBuffer) +{ + afs_uint32 code; + cm_req_t req; + cm_scache_t *scp; + size_t len; + + if (pBufSize == NULL || (pBuffer == NULL && *pBufSize != 0)) + return CM_ERROR_INVAL; + + cm_InitReq(&req); + + code = cm_NameI(cm_data.rootSCachep, (char *)path, CM_FLAG_FOLLOW, cm_rootUserp, (char *)share, &req, &scp); + if (code) + return code; + + lock_ObtainMutex(&scp->mx); + code = cm_SyncOp(scp, NULL, cm_rootUserp, &req, 0, + CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS); + if (code) { + lock_ReleaseMutex(&scp->mx); + cm_ReleaseSCache(scp); + return code; + } + + cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS); + + if (scp->fileType != CM_SCACHETYPE_DFSLINK) + return CM_ERROR_NOT_A_DFSLINK; + + len = strlen(scp->mountPointStringp) + 1; + if (pBuffer == NULL) + *pBufSize = len; + else if (*pBufSize >= len) { + strcpy(pBuffer, scp->mountPointStringp); + *pBufSize = len; + } else + code = CM_ERROR_TOOBIG; + + lock_ReleaseMutex(&scp->mx); + cm_ReleaseSCache(scp); + + return 0; +} diff --git a/src/WINNT/afsd/cm_volstat.h b/src/WINNT/afsd/cm_volstat.h new file mode 100644 index 000000000..834c0898c --- /dev/null +++ b/src/WINNT/afsd/cm_volstat.h @@ -0,0 +1,55 @@ +/* Copyright 2007 Secure Endpoints Inc. + * + * BSD 2-part License + */ + +/* This header file provides the definitions and prototypes + * which specify the AFS Cache Manager Volume Status Event + * Notification API + */ + + +extern long cm_VolStatus_Initialization(void); + +extern long cm_VolStatus_Finalize(void); + +extern long cm_VolStatus_Service_Started(void); + +extern long cm_VolStatus_Service_Stopping(void); + +#ifdef _WIN64 +extern long cm_VolStatus_Network_Started(const char * netbios32, const char * netbios64); + +extern long cm_VolStatus_Network_Stopped(const char * netbios32, const char * netbios64); +#else /* _WIN64 */ +extern long cm_VolStatus_Network_Started(const char * netbios); + +extern long cm_VolStatus_Network_Stopped(const char * netbios); +#endif /* _WIN64 */ + +extern long cm_VolStatus_Network_Addr_Change(void); + +extern long cm_VolStatus_Change_Notification(afs_uint32 cellID, afs_uint32 volID, enum volstatus status); + +extern long __fastcall cm_VolStatus_Path_To_ID(const char * share, const char * path, afs_uint32 * cellID, afs_uint32 * volID); + +extern long __fastcall cm_VolStatus_Path_To_DFSlink(const char * share, const char * path, afs_uint32 *pBufSize, char *pBuffer); + +#define DLL_VOLSTATUS_FUNCS_VERSION 1 +typedef struct dll_VolStatus_Funcs { + afs_uint32 version; + long (__fastcall * dll_VolStatus_Service_Started)(void); + long (__fastcall * dll_VolStatus_Service_Stopped)(void); + long (__fastcall * dll_VolStatus_Network_Started)(const char *netbios32, const char *netbios64); + long (__fastcall * dll_VolStatus_Network_Stopped)(const char *netbios32, const char *netbios64); + long (__fastcall * dll_VolStatus_Network_Addr_Change)(void); + long (__fastcall * dll_VolStatus_Change_Notification)(afs_uint32 cellID, afs_uint32 volID, enum volstatus status); +} dll_VolStatus_Funcs_t; + +#define CM_VOLSTATUS_FUNCS_VERSION 1 +typedef struct cm_VolStatus_Funcs { + afs_uint32 version; + long (__fastcall * cm_VolStatus_Path_To_ID)(const char * share, const char * path, afs_uint32 * cellID, afs_uint32 * volID); + long (__fastcall * cm_VolStatus_Path_To_DFSlink)(const char * share, const char * path, afs_uint32 *pBufSize, char *pBuffer); +} cm_VolStatus_Funcs_t; + diff --git a/src/WINNT/afsd/cm_volume.c b/src/WINNT/afsd/cm_volume.c index 5016a1683..a558445e3 100644 --- a/src/WINNT/afsd/cm_volume.c +++ b/src/WINNT/afsd/cm_volume.c @@ -1468,4 +1468,6 @@ void cm_VolumeStatusNotification(cm_volume_t * volp, afs_uint32 volID, enum vols osi_Log4(afsd_logp, "VolumeStatusNotification: %-48s [%10u] (%s -> %s)", volstr, volID, volstatus_str(old), volstatus_str(new)); + + cm_VolStatus_Change_Notification(volp->cellp->cellID, volID, new); } diff --git a/src/WINNT/afsd/smb.c b/src/WINNT/afsd/smb.c index 7e707cdf4..fddacf1bb 100644 --- a/src/WINNT/afsd/smb.c +++ b/src/WINNT/afsd/smb.c @@ -6442,7 +6442,7 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(written)); - count -= written; + count -= (unsigned short)written; total_written += written; written = 0; } @@ -7969,6 +7969,11 @@ void smb_Listener(void *parmp) } if (lanaRemaining == 0) { + cm_VolStatus_Network_Stopped(cm_NetbiosName +#ifdef _WIN64 + ,cm_NetbiosName +#endif + ); smb_ListenerState = SMB_LISTENER_STOPPED; smb_LANadapter = -1; lana_list.length = 0; @@ -8333,6 +8338,11 @@ int smb_NetbiosInit(void) lana_list.length = 0; smb_LANadapter = -1; smb_ListenerState = SMB_LISTENER_STOPPED; + cm_VolStatus_Network_Stopped(cm_NetbiosName +#ifdef _WIN64 + ,cm_NetbiosName +#endif + ); } /* we're done with the NCB now */ @@ -8351,6 +8361,11 @@ void smb_StartListeners() return; smb_ListenerState = SMB_LISTENER_STARTED; + cm_VolStatus_Network_Started(cm_NetbiosName +#ifdef _WIN64 + , cm_NetbiosName +#endif + ); for (i = 0; i < lana_list.length; i++) { if (lana_list.lana[i] == 255) @@ -8407,6 +8422,11 @@ void smb_StopListeners(void) return; smb_ListenerState = SMB_LISTENER_STOPPED; + cm_VolStatus_Network_Stopped(cm_NetbiosName +#ifdef _WIN64 + , cm_NetbiosName +#endif + ); ncbp = GetNCB(); @@ -9064,3 +9084,8 @@ int smb_DumpVCP(FILE *outputFile, char *cookie, int lock) lock_ReleaseRead(&smb_rctLock); return 0; } + +long smb_IsNetworkStarted(void) +{ + return (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0); +} diff --git a/src/WINNT/afsd/smb.h b/src/WINNT/afsd/smb.h index b355d9521..721bca9b4 100644 --- a/src/WINNT/afsd/smb.h +++ b/src/WINNT/afsd/smb.h @@ -730,6 +730,7 @@ extern void smb_ResetServerPriority(void); extern void smb_RestartListeners(void); extern void smb_StopListeners(void); extern void smb_StopListener(NCB *ncbp, int lana); +extern long smb_IsNetworkStarted(void); #define SMB_LISTENER_UNINITIALIZED -1 #define SMB_LISTENER_STOPPED 0 -- 2.39.5