diff --git a/src/WINNT/afsd/cm_conn.c b/src/WINNT/afsd/cm_conn.c index 39b8a20297..c333dad87f 100644 --- a/src/WINNT/afsd/cm_conn.c +++ b/src/WINNT/afsd/cm_conn.c @@ -30,6 +30,7 @@ unsigned short IdleDeadtimeout = CM_CONN_IDLEDEADTIME; #define LANMAN_WKS_PARAM_KEY "SYSTEM\\CurrentControlSet\\Services\\lanmanworkstation\\parameters" #define LANMAN_WKS_SESSION_TIMEOUT "SessTimeout" +#define LANMAN_WKS_EXT_SESSION_TIMEOUT "ExtendedSessTimeout" afs_uint32 cryptall = 0; afs_uint32 cm_anonvldb = 0; @@ -63,11 +64,36 @@ void cm_InitConn(void) 0, KEY_QUERY_VALUE, &parmKey); if (code == ERROR_SUCCESS) { - dummyLen = sizeof(DWORD); - code = RegQueryValueEx(parmKey, LANMAN_WKS_SESSION_TIMEOUT, NULL, NULL, - (BYTE *) &dwValue, &dummyLen); - if (code == ERROR_SUCCESS) - RDRtimeout = dwValue; + BOOL extTimeouts = msftSMBRedirectorSupportsExtendedTimeouts(); + + if (extTimeouts) { + /* + * The default value is 1000 seconds. However, this default + * will not apply to "\\AFS" unless "AFS" is listed in + * ServersWithExtendedSessTimeout which we will add when we + * create the ExtendedSessTimeout value in smb_Init() + */ + dummyLen = sizeof(DWORD); + code = RegQueryValueEx(parmKey, + LANMAN_WKS_EXT_SESSION_TIMEOUT, + NULL, NULL, + (BYTE *) &dwValue, &dummyLen); + if (code == ERROR_SUCCESS) { + RDRtimeout = dwValue; + afsi_log("lanmanworkstation : ExtSessTimeout %u", RDRtimeout); + } + } + if (!extTimeouts || code != ERROR_SUCCESS) { + dummyLen = sizeof(DWORD); + code = RegQueryValueEx(parmKey, + LANMAN_WKS_SESSION_TIMEOUT, + NULL, NULL, + (BYTE *) &dwValue, &dummyLen); + if (code == ERROR_SUCCESS) { + RDRtimeout = dwValue; + afsi_log("lanmanworkstation : SessTimeout %u", RDRtimeout); + } + } RegCloseKey(parmKey); } @@ -98,17 +124,27 @@ void cm_InitConn(void) RegCloseKey(parmKey); } - afsi_log("lanmanworkstation : SessTimeout %u", RDRtimeout); + /* + * If these values were not set via cpp macro or obtained + * from the registry, we use a value that is derived from + * the smb redirector session timeout (RDRtimeout). + * + * The UNIX cache manager uses 120 seconds for the hard dead + * timeout and 50 seconds for the connection and idle timeouts. + * + * We base our values on those while making sure we leave + * enough time for overhead. + */ if (ConnDeadtimeout == 0) { - ConnDeadtimeout = (unsigned short) (RDRtimeout / 2); + ConnDeadtimeout = (unsigned short) ((RDRtimeout / 2) < 50 ? (RDRtimeout / 2) : 50); afsi_log("ConnDeadTimeout is %d", ConnDeadtimeout); } if (HardDeadtimeout == 0) { - HardDeadtimeout = (unsigned short) RDRtimeout; + HardDeadtimeout = (unsigned short) (RDRtimeout > 125 ? 120 : (RDRtimeout - 5)); afsi_log("HardDeadTimeout is %d", HardDeadtimeout); } if (IdleDeadtimeout == 0) { - IdleDeadtimeout = (unsigned short) RDRtimeout; + IdleDeadtimeout = (unsigned short) ConnDeadtimeout; afsi_log("IdleDeadTimeout is %d", IdleDeadtimeout); } osi_EndOnce(&once); diff --git a/src/WINNT/afsd/cm_conn.h b/src/WINNT/afsd/cm_conn.h index d5f41e2790..5e0b6732a2 100644 --- a/src/WINNT/afsd/cm_conn.h +++ b/src/WINNT/afsd/cm_conn.h @@ -11,9 +11,15 @@ #define __CM_CONN_H_ENV__ 1 #define CM_CONN_DEFAULTRDRTIMEOUT 45 +#ifndef CM_CONN_CONNDEADTIME #define CM_CONN_CONNDEADTIME 0 +#endif +#ifndef CM_CONN_HARDDEADTIME #define CM_CONN_HARDDEADTIME 0 +#endif +#ifndef CM_CONN_IDLEDEADTIME #define CM_CONN_IDLEDEADTIME 0 +#endif extern unsigned short ConnDeadtimeout; extern unsigned short HardDeadtimeout; diff --git a/src/WINNT/afsd/cm_utils.c b/src/WINNT/afsd/cm_utils.c index 90c12d3a94..30119678bf 100644 --- a/src/WINNT/afsd/cm_utils.c +++ b/src/WINNT/afsd/cm_utils.c @@ -786,3 +786,180 @@ cm_LoadAfsdHookLib(void) return hLib; } + +/* + * Obtain the file info structure for the specified file. + * If a full path is not specified, the search order is the + * same as that used by LoadLibrary(). + */ +BOOL +cm_GetOSFileVersion (char *filename, LARGE_INTEGER *liVer) +{ + DWORD dwHandle; + DWORD dwSize; + char* pInfo = NULL; + BOOL rc; + UINT uLen; + void *pbuf; + VS_FIXEDFILEINFO vsf; + + dwSize = GetFileVersionInfoSizeA(filename,&dwHandle); + if (dwSize == 0) { + rc = FALSE; + goto done; + } + pInfo = (char*)malloc(dwSize); + if (!pInfo) { + rc = FALSE; + goto done; + } + rc = GetFileVersionInfoA(filename, dwHandle, dwSize, pInfo); + if (!rc) + goto done; + rc = VerQueryValueA(pInfo,"\\",&pbuf, &uLen); + if (!rc) + goto done; + memcpy(&vsf, pbuf, sizeof(VS_FIXEDFILEINFO)); + + liVer->LowPart = vsf.dwFileVersionLS; + liVer->HighPart = vsf.dwFileVersionMS; + rc = TRUE; + + done: + if (pInfo) + free(pInfo); + return rc; +} + +typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); +typedef BOOL (WINAPI *LPFN_DISABLEWOW64FSREDIRECTION) (PVOID *); +typedef BOOL (WINAPI *LPFN_REVERTWOW64FSREDIRECTION) (PVOID); + +BOOL msftSMBRedirectorSupportsExtendedTimeouts(void) +{ + static BOOL fChecked = FALSE; + static BOOL fSupportsExtendedTimeouts = FALSE; + + if (!fChecked) + { + BOOL isWow64 = FALSE; + OSVERSIONINFOEX Version; + HANDLE h1 = NULL; + LPFN_ISWOW64PROCESS fnIsWow64Process = NULL; + LPFN_DISABLEWOW64FSREDIRECTION fnDisableWow64FsRedirection = NULL; + LPFN_REVERTWOW64FSREDIRECTION fnRevertWow64FsRedirection = NULL; + PVOID Wow64RedirectionState; + LARGE_INTEGER fvFile, fvHotFixMin; + + h1 = GetModuleHandle("kernel32.dll"); /* no refcount increase */ + /* + * If we don't find the fnIsWow64Process function then we + * are not running in a Wow64 environment + */ + fnIsWow64Process = + (LPFN_ISWOW64PROCESS)GetProcAddress(h1, "IsWow64Process"); + + memset (&Version, 0x00, sizeof(Version)); + Version.dwOSVersionInfoSize = sizeof(Version); + GetVersionEx((OSVERSIONINFO *) &Version); + + /* + * Support is available as hot fixes / service packs on: + * XP SP2 + * XP SP3 + * 2003 and XP64 SP2 + * Vista and 2008 SP2 + * Win7 and 2008 R2 + */ + if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT && + Version.dwMajorVersion >= 5) { + + /* 32-bit XP */ + if (Version.dwMajorVersion == 5 && + Version.dwMinorVersion == 1) { + + fvHotFixMin.HighPart = (5 << 16) | 1; + + switch (Version.wServicePackMajor) { + case 3: + fvHotFixMin.LowPart = (2600 << 16) | 5815; + break; + case 2: + fvHotFixMin.LowPart = (2600 << 16) | 3572; + break; + default: + fSupportsExtendedTimeouts = (Version.wServicePackMajor > 3); + goto checked; + } + } + + /* 64-bit XP and Server 2003 */ + else if (Version.dwMajorVersion == 5 && + Version.dwMinorVersion == 2) { + + fvHotFixMin.HighPart = (5 << 16) | 2; + + switch (Version.wServicePackMajor) { + case 2: + fvHotFixMin.LowPart = (3790 << 16) | 4479; + break; + case 1: + fvHotFixMin.LowPart = (3790 << 16) | 3310; + break; + default: + fSupportsExtendedTimeouts = (Version.wServicePackMajor > 2); + goto checked; + } + } + + /* Vista and Server 2008 */ + else if (Version.dwMajorVersion == 6 && + Version.dwMinorVersion == 0) { + + fvHotFixMin.HighPart = (6 << 16) | 0; + + switch (Version.wServicePackMajor) { + case 2: + fvHotFixMin.LowPart = (6002 << 16) | 18005; + break; + default: + fSupportsExtendedTimeouts = (Version.wServicePackMajor > 2); + goto checked; + } + } + + /* Windows 7 and Server 2008 R2 and beyond */ + else if (Version.dwMajorVersion > 6 || + Version.dwMajorVersion == 6 && + Version.dwMinorVersion >= 1) { + fSupportsExtendedTimeouts = TRUE; + goto checked; + } + + /* If wow64, disable wow64 redirection and preserve the existing state */ + if (fnIsWow64Process && + fnIsWow64Process(GetCurrentProcess(), &isWow64) && + isWow64) { + fnDisableWow64FsRedirection = + (LPFN_DISABLEWOW64FSREDIRECTION)GetProcAddress(h1, "Wow64DisableWow64FsRedirection"); + fnRevertWow64FsRedirection = + (LPFN_REVERTWOW64FSREDIRECTION)GetProcAddress(h1, "Wow64RevertWow64FsRedirection"); + fnDisableWow64FsRedirection(&Wow64RedirectionState); + } + + if (cm_GetOSFileVersion("drivers\\mrxsmb.sys", &fvFile) || + (fvFile.QuadPart >= fvHotFixMin.QuadPart)) + fSupportsExtendedTimeouts = TRUE; + + /* If wow64, restore the previous redirection state */ + if (fnIsWow64Process && isWow64) { + fnRevertWow64FsRedirection(Wow64RedirectionState); + } + } + checked: + fChecked = TRUE; + } + + return fSupportsExtendedTimeouts; +} + diff --git a/src/WINNT/afsd/cm_utils.h b/src/WINNT/afsd/cm_utils.h index f1708cc045..653ff96be0 100644 --- a/src/WINNT/afsd/cm_utils.h +++ b/src/WINNT/afsd/cm_utils.h @@ -85,4 +85,8 @@ extern BOOL cm_TargetPerceivedAsDirectory(const fschar_t *target); extern HANDLE cm_LoadAfsdHookLib(void); +extern BOOL cm_GetOSFileVersion(char *filename, LARGE_INTEGER *liVer); + +extern BOOL msftSMBRedirectorSupportsExtendedTimeouts(void); + #endif /* __CM_UTILS_H_ENV__ */ diff --git a/src/WINNT/afsd/smb.c b/src/WINNT/afsd/smb.c index 4cc33cb223..1611b2af5d 100644 --- a/src/WINNT/afsd/smb.c +++ b/src/WINNT/afsd/smb.c @@ -9692,7 +9692,7 @@ configureExtendedSMBSessionTimeouts(void) { dwType = REG_DWORD; dwSize = sizeof(dwValue); - dwValue = 600; /* 10 minutes */ + dwValue = 300; /* 5 minutes */ RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize); } RegCloseKey(hkLanMan); @@ -9997,7 +9997,10 @@ void smb_StartListeners(int locked) configureBackConnectionHostNames(); /* Configure Extended SMB Session Timeouts */ - configureExtendedSMBSessionTimeouts(); + if (msftSMBRedirectorSupportsExtendedTimeouts()) { + afsi_log("Microsoft SMB Redirector supports Extended Timeouts"); + configureExtendedSMBSessionTimeouts(); + } smb_ListenerState = SMB_LISTENER_STARTED; cm_VolStatus_Network_Started(cm_NetbiosName