Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1330 lines
36 KiB

  1. /***************************************************************************
  2. *
  3. * Copyright (C) 2001-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dpnhupnpdllmain.cpp
  6. *
  7. * Content: DPNHUPNP DLL entry points.
  8. *
  9. * History:
  10. * Date By Reason
  11. * ======== ======== =========
  12. * 04/16/01 VanceO Split DPNATHLP into DPNHUPNP and DPNHPAST.
  13. *
  14. ***************************************************************************/
  15. #include "dpnhupnpi.h"
  16. //=============================================================================
  17. // External globals
  18. //=============================================================================
  19. volatile LONG g_lOutstandingInterfaceCount = 0; // number of outstanding interfaces
  20. DNCRITICAL_SECTION g_csGlobalsLock; // lock protecting all of the following globals
  21. CBilink g_blNATHelpUPnPObjs; // bilink of all the NATHelpUPnP interface objects
  22. DWORD g_dwHoldRand; // current random number sequence
  23. DWORD g_dwUPnPMode; // whether using UPnP is enabled or not
  24. #ifndef DPNBUILD_NOHNETFWAPI
  25. DWORD g_dwHNetFWAPIMode; // whether using HomeNet firewall API is enabled or not
  26. #endif // ! DPNBUILD_NOHNETFWAPI
  27. DWORD g_dwSubnetMaskV4 = 0x00FFFFFF; // = 0xFFFFFF00 in Intel order = 255.255.255.0, a class C network
  28. DWORD g_dwNoActiveNotifyPollInterval = 25000; // start by polling every 25 seconds
  29. DWORD g_dwMinUpdateServerStatusInterval = 1000; // don't hit the network more often than every 1 second
  30. BOOL g_fNoAsymmetricMappings = FALSE; // whether asymmetric mappings can be tried or not
  31. BOOL g_fUseLeaseDurations = FALSE; // whether non-INFINITE lease durations for NAT mappings can be tried or not
  32. INT g_iUnicastTTL = 1; // unicast TTL value, or 0 to use default set by OS; normally we use 1
  33. INT g_iMulticastTTL = 1; // multicast TTL value, or 0 to use default set by OS; normally we use 1
  34. DWORD g_dwUPnPAnnounceResponseWaitTime = 2500; // how long to allow for UPnP device announcement responses to arrive in ms
  35. DWORD g_dwUPnPConnectTimeout = 15; // how long to wait to reconnect to the UPnP device in seconds (default is 15, much shorter than standard TCP/IP timeout)
  36. DWORD g_dwUPnPResponseTimeout = 5000; // how long to wait for a response message from the UPnP device to arrive in ms once the TCP/IP connection is established
  37. #ifndef DPNBUILD_NOHNETFWAPI
  38. BOOL g_fMapUPnPDiscoverySocket = FALSE; // whether the UPnP discovery socket should be mapped or not
  39. #endif // ! DPNBUILD_NOHNETFWAPI
  40. BOOL g_fUseMulticastUPnPDiscovery = FALSE; // whether to multicast UPnP discovery messages instead of the default directed sends to the gateway
  41. DWORD g_dwDefaultGatewayV4 = INADDR_BROADCAST; // fallback to broadcasting UPnP discovery messages when detecting the gateway fails
  42. DWORD g_dwPollIntervalBackoff = 30000; // backoff an additional 0 to 30 seconds if no network changes occur
  43. DWORD g_dwMaxPollInterval = 300000; // don't go more than 5 minutes without polling
  44. BOOL g_fKeepPollingForRemoteGateway = FALSE; // whether to continue to search for new Internet gateway devices if none were found during startup
  45. DWORD g_dwReusePortTime = 60000; // how long to keep using the same port for polling remote Internet gateway devices (default is 1 minute)
  46. DWORD g_dwCacheLifeFound = 30000; // how long to cache QueryAddress results where the address was found
  47. DWORD g_dwCacheLifeNotFound = 30000; // how long to cache QueryAddress results where the address was not found
  48. #ifdef DBG
  49. WCHAR g_wszUPnPTransactionLog[256] = L""; // log file location, or empty string if none
  50. #endif // DBG
  51. //=============================================================================
  52. // Defines
  53. //=============================================================================
  54. #define REGKEY_VALUE_GUID L"Guid"
  55. #define REGKEY_VALUE_DIRECTPLAY8PRIORITY L"DirectPlay8Priority"
  56. #define REGKEY_VALUE_DIRECTPLAY8INITFLAGS L"DirectPlay8InitFlags"
  57. #define REGKEY_VALUE_UPNPMODE L"UPnPMode"
  58. #ifndef DPNBUILD_NOHNETFWAPI
  59. #define REGKEY_VALUE_HNETFWAPIMODE L"HNetFWAPIMode"
  60. #endif // ! DPNBUILD_NOHNETFWAPI
  61. #define REGKEY_VALUE_SUBNETMASKV4 L"SubnetMaskV4"
  62. #define REGKEY_VALUE_NOACTIVENOTIFYPOLLINTERVAL L"NoActiveNotifyPollInterval"
  63. #define REGKEY_VALUE_MINUPDATESERVERSTATUSINTERVAL L"MinUpdateServerStatusInterval"
  64. #define REGKEY_VALUE_NOASYMMETRICMAPPINGS L"NoAsymmetricMappings"
  65. #define REGKEY_VALUE_USELEASEDURATIONS L"UseLeaseDurations"
  66. #define REGKEY_VALUE_UNICASTTTL L"UnicastTTL"
  67. #define REGKEY_VALUE_MULTICASTTTL L"MulticastTTL"
  68. #define REGKEY_VALUE_UPNPANNOUNCERESPONSEWAITTIME L"UPnPAnnounceResponseWaitTime"
  69. #define REGKEY_VALUE_UPNPCONNECTTIMEOUT L"UPnPConnectTimeout"
  70. #define REGKEY_VALUE_UPNPRESPONSETIMEOUT L"UPnPResponseTimeout"
  71. #ifndef DPNBUILD_NOHNETFWAPI
  72. #define REGKEY_VALUE_MAPUPNPDISCOVERYSOCKET L"MapUPnPDiscoverySocket"
  73. #endif // ! DPNBUILD_NOHNETFWAPI
  74. #define REGKEY_VALUE_USEMULTICASTUPNPDISCOVERY L"UseMulticastUPnPDiscovery"
  75. #define REGKEY_VALUE_DEFAULTGATEWAYV4 L"GatewayV4"
  76. #define REGKEY_VALUE_POLLINTERVALBACKOFF L"PollIntervalBackoff"
  77. #define REGKEY_VALUE_MAXPOLLINTERVAL L"MaxPollInterval"
  78. #define REGKEY_VALUE_KEEPPOLLINGFORREMOTEGATEWAY L"KeepPollingForRemoteGateway"
  79. #define REGKEY_VALUE_REUSEPORTTIME L"ReusePortTime"
  80. #define REGKEY_VALUE_CACHELIFEFOUND L"CacheLifeFound"
  81. #define REGKEY_VALUE_CACHELIFENOTFOUND L"CacheLifeNotFound"
  82. #ifdef DBG
  83. #define REGKEY_VALUE_UPNPTRANSACTIONLOG L"UPnPTransactionLog"
  84. #endif // DBG
  85. #define DEFAULT_DIRECTPLAY8PRIORITY 1
  86. #define DEFAULT_DIRECTPLAY8INITFLAGS 0
  87. //=============================================================================
  88. // Local prototypes
  89. //=============================================================================
  90. BOOL InitializeProcessGlobals(void);
  91. void CleanupProcessGlobals(void);
  92. void InitializeGlobalRand(const DWORD dwSeed);
  93. #undef DPF_MODNAME
  94. #define DPF_MODNAME "DllMain"
  95. //=============================================================================
  96. // DllMain
  97. //-----------------------------------------------------------------------------
  98. //
  99. // Description: DLL entry point.
  100. //
  101. // Arguments:
  102. // HANDLE hDllInst - Handle to this DLL module instance.
  103. // DWORD dwReason - Reason for calling this function.
  104. // LPVOID lpvReserved - Reserved.
  105. //
  106. // Returns: TRUE if all goes well, FALSE otherwise.
  107. //=============================================================================
  108. BOOL WINAPI DllMain(HANDLE hDllInst,
  109. DWORD dwReason,
  110. LPVOID lpvReserved)
  111. {
  112. BOOL fResult = TRUE;
  113. switch (dwReason)
  114. {
  115. case DLL_PROCESS_ATTACH:
  116. {
  117. DPFX(DPFPREP, 2, "====> ENTER: DLLMAIN(%p): Process Attach: %08lx, tid=%08lx",
  118. DllMain, GetCurrentProcessId(), GetCurrentThreadId());
  119. //
  120. // Ignore thread attach/detach messages.
  121. //
  122. DisableThreadLibraryCalls((HMODULE) hDllInst);
  123. //
  124. // Attempt to initialize the OS abstraction layer.
  125. //
  126. if (DNOSIndirectionInit(0))
  127. {
  128. //
  129. // Attempt to initialize process-global items.
  130. //
  131. if (! InitializeProcessGlobals())
  132. {
  133. DPFX(DPFPREP, 0, "Failed to initialize globals!");
  134. DNOSIndirectionDeinit();
  135. fResult = FALSE;
  136. }
  137. }
  138. else
  139. {
  140. DPFX(DPFPREP, 0, "Failed to initialize OS indirection layer!");
  141. fResult = FALSE;
  142. }
  143. break;
  144. }
  145. case DLL_THREAD_ATTACH:
  146. {
  147. //
  148. // Ignore.
  149. //
  150. break;
  151. }
  152. case DLL_THREAD_DETACH:
  153. {
  154. //
  155. // Ignore.
  156. //
  157. break;
  158. }
  159. case DLL_PROCESS_DETACH:
  160. {
  161. DPFX(DPFPREP, 2, "====> EXIT: DLLMAIN(%p): Process Detach %08lx, tid=%08lx",
  162. DllMain, GetCurrentProcessId(), GetCurrentThreadId());
  163. CleanupProcessGlobals();
  164. DNOSIndirectionDeinit();
  165. break;
  166. }
  167. default:
  168. {
  169. DNASSERT(FALSE);
  170. break;
  171. }
  172. }
  173. return fResult;
  174. } // DllMain
  175. #ifndef DPNBUILD_NOCOMREGISTER
  176. #undef DPF_MODNAME
  177. #define DPF_MODNAME "DllRegisterServer"
  178. //=============================================================================
  179. // DllRegisterServer
  180. //-----------------------------------------------------------------------------
  181. //
  182. // Description: Registers the DirectPlay NAT Helper UPnP COM object.
  183. //
  184. // Arguments: None.
  185. //
  186. // Returns: HRESULT
  187. // S_OK - Successfully unregistered DirectPlay NAT Helper UPnP.
  188. // E_FAIL - Failed unregistering DirectPlay NAT Helper UPnP.
  189. //=============================================================================
  190. HRESULT WINAPI DllRegisterServer(void)
  191. {
  192. CRegistry RegObject;
  193. #if ((defined(DBG)) && (defined(DIRECTX_REDIST)))
  194. // For redist debug builds we append a 'd' to the name to allow both debug and retail to be installed on the system
  195. #define MAIN_DLL_NAME L"dpnhupnpd.dll"
  196. #else // ! DBG or ! DIRECTX_REDIST
  197. #define MAIN_DLL_NAME L"dpnhupnp.dll"
  198. #endif // ! DBG or ! DIRECTX_REDIST
  199. //
  200. // Register this COM object CLSID.
  201. //
  202. if (! CRegistry::Register(L"DirectPlayNATHelperUPnP.1",
  203. L"DirectPlay NAT Helper UPnP Object",
  204. MAIN_DLL_NAME,
  205. &CLSID_DirectPlayNATHelpUPnP,
  206. L"DirectPlayNATHelperUPnP"))
  207. {
  208. DPFX(DPFPREP, 0, "Could not register DirectPlay NAT Helper UPnP object!");
  209. return E_FAIL;
  210. }
  211. //
  212. // Write this object's GUID and DirectPlay8 availability to the registry.
  213. //
  214. if (! RegObject.Open(HKEY_LOCAL_MACHINE, DIRECTPLAYNATHELP_REGKEY L"\\" REGKEY_COMPONENTSUBKEY, FALSE, TRUE))
  215. {
  216. DPFX(DPFPREP, 0, "Couldn't create DirectPlay NAT Helper UPnP key!");
  217. return E_FAIL;
  218. }
  219. if (! RegObject.WriteGUID(REGKEY_VALUE_GUID, CLSID_DirectPlayNATHelpUPnP))
  220. {
  221. DPFX(DPFPREP, 0, "Couldn't write GUID to registry!");
  222. return E_FAIL;
  223. }
  224. if (! RegObject.WriteDWORD(REGKEY_VALUE_DIRECTPLAY8PRIORITY, DEFAULT_DIRECTPLAY8PRIORITY))
  225. {
  226. DPFX(DPFPREP, 0, "Couldn't write DirectPlay8 priority to registry!");
  227. return E_FAIL;
  228. }
  229. if (! RegObject.WriteDWORD(REGKEY_VALUE_DIRECTPLAY8INITFLAGS, DEFAULT_DIRECTPLAY8INITFLAGS))
  230. {
  231. DPFX(DPFPREP, 0, "Couldn't write DirectPlay8 init flags to registry!");
  232. return E_FAIL;
  233. }
  234. RegObject.Close();
  235. #ifndef DPNBUILD_NOHNETFWAPI
  236. //
  237. // Create the active firewall mappings storage subkey.
  238. //
  239. if (! RegObject.Open(HKEY_LOCAL_MACHINE, DIRECTPLAYNATHELP_REGKEY L"\\" REGKEY_COMPONENTSUBKEY L"\\" REGKEY_ACTIVEFIREWALLMAPPINGS, FALSE, TRUE))
  240. {
  241. DPFX(DPFPREP, 0, "Couldn't create DirectPlay NAT Helper active firewall mappings key! Continuing.");
  242. }
  243. else
  244. {
  245. //
  246. // We don't need to grant access to everyone for the active firewall mappings
  247. // because currently you need to be an administrator to add or remove mappings
  248. // via the HomeNet API anyway.
  249. //
  250. #if 0
  251. #ifdef WINNT
  252. //
  253. // If we're on NT, set the key security to allow everyone full access
  254. // (except WRITE_DAC and WRITE_OWNER).
  255. //
  256. if (DNGetOSType() == VER_PLATFORM_WIN32_NT)
  257. {
  258. if (! RegObject.GrantAllAccessSecurityPermissions())
  259. {
  260. DPFX(DPFPREP, 0, "Failed granting all-access permissions to active firewall mappings key! Continuing.");
  261. }
  262. }
  263. #endif // WINNT
  264. #endif
  265. RegObject.Close();
  266. }
  267. #endif // ! DPNBUILD_NOHNETFWAPI
  268. //
  269. // Create the active NAT mappings storage subkey.
  270. //
  271. if (! RegObject.Open(HKEY_LOCAL_MACHINE, DIRECTPLAYNATHELP_REGKEY L"\\" REGKEY_COMPONENTSUBKEY L"\\" REGKEY_ACTIVENATMAPPINGS, FALSE, TRUE))
  272. {
  273. DPFX(DPFPREP, 0, "Couldn't create DirectPlay NAT Helper active NAT mappings key! Continuing.");
  274. }
  275. else
  276. {
  277. #ifdef WINNT
  278. //
  279. // If we're on NT, set the key security to allow everyone full access
  280. // (except WRITE_DAC and WRITE_OWNER).
  281. // Since anyone can create or delete a NAT mapping already, there's no
  282. // point in securing the registry entries that exist solely for crash
  283. // cleanup.
  284. //
  285. if (DNGetOSType() == VER_PLATFORM_WIN32_NT)
  286. {
  287. if (! RegObject.GrantAllAccessSecurityPermissions())
  288. {
  289. DPFX(DPFPREP, 0, "Failed granting all-access permissions to active NAT mappings key! Continuing.");
  290. }
  291. }
  292. #endif
  293. RegObject.Close();
  294. }
  295. return S_OK;
  296. } // DllRegisterServer
  297. #undef DPF_MODNAME
  298. #define DPF_MODNAME "DllUnregisterServer"
  299. //=============================================================================
  300. // DllUnregisterServer
  301. //-----------------------------------------------------------------------------
  302. //
  303. // Description: Unregisters the DirectPlay NAT Helper UPnP COM object.
  304. //
  305. // Arguments: None.
  306. //
  307. // Returns: HRESULT
  308. // S_OK - Successfully unregistered DirectPlay NAT Helper UPnP.
  309. // E_FAIL - Failed unregistering DirectPlay NAT Helper UPnP.
  310. //=============================================================================
  311. STDAPI DllUnregisterServer(void)
  312. {
  313. CRegistry RegObject;
  314. //
  315. // Unregister the class.
  316. //
  317. if (! CRegistry::UnRegister(&CLSID_DirectPlayNATHelpUPnP))
  318. {
  319. DPFX(DPFPREP, 0, "Failed to unregister DirectPlay NAT Helper UPnP object!");
  320. return E_FAIL;
  321. }
  322. //
  323. // Try removing all the subitems we registered.
  324. //
  325. if (! RegObject.Open(HKEY_LOCAL_MACHINE, DIRECTPLAYNATHELP_REGKEY L"\\" REGKEY_COMPONENTSUBKEY, FALSE, FALSE))
  326. {
  327. DPFX(DPFPREP, 0, "Couldn't open DirectPlay NAT Helper key! Ignoring.");
  328. }
  329. else
  330. {
  331. #ifndef DPNBUILD_NOHNETFWAPI
  332. if (! RegObject.DeleteSubKey(REGKEY_ACTIVEFIREWALLMAPPINGS))
  333. {
  334. DPFX(DPFPREP, 0, "Couldn't delete DirectPlay NAT Helper active firewall mappings key, there may still be subitems! Ignoring.");
  335. }
  336. #endif // ! DPNBUILD_NOHNETFWAPI
  337. if (! RegObject.DeleteSubKey(REGKEY_ACTIVENATMAPPINGS))
  338. {
  339. DPFX(DPFPREP, 0, "Couldn't delete DirectPlay NAT Helper active NAT mappings key, there may still be subitems! Ignoring.");
  340. }
  341. if (! RegObject.DeleteValue(REGKEY_VALUE_GUID))
  342. {
  343. DPFX(DPFPREP, 0, "Couldn't delete GUID registry value! Ignoring.");
  344. }
  345. if (! RegObject.DeleteValue(REGKEY_VALUE_DIRECTPLAY8PRIORITY))
  346. {
  347. DPFX(DPFPREP, 0, "Couldn't delete DirectPlay8 priority registry value! Ignoring.");
  348. }
  349. if (! RegObject.DeleteValue(REGKEY_VALUE_DIRECTPLAY8INITFLAGS))
  350. {
  351. DPFX(DPFPREP, 0, "Couldn't delete DirectPlay8 init flags registry value! Ignoring.");
  352. }
  353. RegObject.Close();
  354. }
  355. return S_OK;
  356. } // DllUnregisterServer
  357. #endif // !DPNBUILD_NOCOMREGISTER
  358. #ifndef WINCE
  359. #undef DPF_MODNAME
  360. #define DPF_MODNAME "DirectPlayNATHelpCreate"
  361. //=============================================================================
  362. // DirectPlayNATHelpCreate
  363. //-----------------------------------------------------------------------------
  364. //
  365. // Description: Creates an IDirectPlayNATHelp interface object.
  366. //
  367. // Arguments:
  368. // GUID * pIID - Pointer to IDirectPlayNATHelp interface GUID.
  369. // void ** ppvInterface - Place to store pointer to interface object
  370. // created.
  371. //
  372. // Returns: HRESULT
  373. // DPNH_OK - Creating the object was successful.
  374. // DPNHERR_INVALIDPOINTER - The destination pointer is invalid.
  375. // DPNHERR_OUTOFMEMORY - Not enough memory to create the object.
  376. // E_NOINTERFACE - The requested interface was invalid.
  377. //=============================================================================
  378. HRESULT WINAPI DirectPlayNATHelpCreate(const GUID * pIID, void ** ppvInterface)
  379. {
  380. HRESULT hr;
  381. DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pIID, ppvInterface);
  382. hr = DoCreateInstance(NULL, // no class factory object necessary
  383. NULL, // ?
  384. CLSID_DirectPlayNATHelpUPnP, // DirectPlayNATHelp class
  385. (*pIID), // requested interface
  386. ppvInterface); // place to store interface
  387. DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr);
  388. return hr;
  389. } // DirectPlayNATHelpCreate
  390. #endif // !WINCE
  391. #undef DPF_MODNAME
  392. #define DPF_MODNAME "InitializeProcessGlobals"
  393. //=============================================================================
  394. // InitializeProcessGlobals
  395. //-----------------------------------------------------------------------------
  396. //
  397. // Description: Initialize global items needed for the DLL to operate.
  398. //
  399. // Arguments: None.
  400. //
  401. // Returns: TRUE if successful, FALSE if an error occurred.
  402. //=============================================================================
  403. BOOL InitializeProcessGlobals(void)
  404. {
  405. BOOL fReturn = TRUE;
  406. if (! DNInitializeCriticalSection(&g_csGlobalsLock))
  407. {
  408. fReturn = FALSE;
  409. }
  410. //
  411. // Don't allow critical section reentry.
  412. //
  413. DebugSetCriticalSectionRecursionCount(&g_csGlobalsLock, 0);
  414. g_blNATHelpUPnPObjs.Initialize();
  415. //
  416. // Seed the random number generator with the current time.
  417. //
  418. InitializeGlobalRand(GETTIMESTAMP());
  419. return fReturn;
  420. } // InitializeProcessGlobals
  421. #undef DPF_MODNAME
  422. #define DPF_MODNAME "CleanupProcessGlobals"
  423. //=============================================================================
  424. // CleanupProcessGlobals
  425. //-----------------------------------------------------------------------------
  426. //
  427. // Description: Releases global items used by DLL.
  428. //
  429. // Arguments: None.
  430. //
  431. // Returns: None.
  432. //=============================================================================
  433. void CleanupProcessGlobals(void)
  434. {
  435. CBilink * pBilink;
  436. CNATHelpUPnP * pNATHelpUPnP;
  437. if (! g_blNATHelpUPnPObjs.IsEmpty())
  438. {
  439. //
  440. // This assert is far more descriptive than hitting one of those in the
  441. // cleanup code that complain about flags incorrectly being set.
  442. //
  443. DNASSERT(! "DPNHUPNP.DLL unloading without all objects having been released! The caller's DirectPlayNATHelpUPnP cleanup code needs to be fixed!");
  444. //
  445. // Force close all the objects still outstanding.
  446. //
  447. pBilink = g_blNATHelpUPnPObjs.GetNext();
  448. while (pBilink != &g_blNATHelpUPnPObjs)
  449. {
  450. DNASSERT(! pBilink->IsEmpty());
  451. pNATHelpUPnP = NATHELPUPNP_FROM_BILINK(pBilink);
  452. pBilink = pBilink->GetNext();
  453. DPFX(DPFPREP, 0, "Forcefully releasing object 0x%p!", pNATHelpUPnP);
  454. pNATHelpUPnP->Close(0); // ignore error
  455. //
  456. // Forcefully remove it from the list and delete it instead of
  457. // using pNATHelpUPnP->Release().
  458. //
  459. pNATHelpUPnP->m_blList.RemoveFromList();
  460. pNATHelpUPnP->UninitializeObject();
  461. delete pNATHelpUPnP;
  462. }
  463. }
  464. DNDeleteCriticalSection(&g_csGlobalsLock);
  465. } // CleanupProcessGlobals
  466. #undef DPF_MODNAME
  467. #define DPF_MODNAME "ReadRegistrySettings"
  468. //=============================================================================
  469. // ReadRegistrySettings
  470. //-----------------------------------------------------------------------------
  471. //
  472. // Description: Reads registry settings to override behavior of this DLL and to
  473. // turn on some debugging features.
  474. //
  475. // Arguments: None.
  476. //
  477. // Returns: None.
  478. //=============================================================================
  479. void ReadRegistrySettings(void)
  480. {
  481. CRegistry RegObject;
  482. DWORD dwNewValue;
  483. BOOL fNewValue;
  484. #ifdef DBG
  485. DWORD dwLength;
  486. #endif // DBG
  487. //
  488. // Try opening the registry key.
  489. //
  490. if (RegObject.Open(HKEY_LOCAL_MACHINE, DIRECTPLAYNATHELP_REGKEY L"\\" REGKEY_COMPONENTSUBKEY) != FALSE)
  491. {
  492. //
  493. // Lock out other interfaces from modifying the globals simultaneously.
  494. //
  495. DNEnterCriticalSection(&g_csGlobalsLock);
  496. //
  497. // If we successfully read a new mode, save it.
  498. //
  499. if (RegObject.ReadDWORD(REGKEY_VALUE_UPNPMODE, &dwNewValue))
  500. {
  501. g_dwUPnPMode = dwNewValue;
  502. DPFX(DPFPREP, 1, "Using UPnP mode %u.", g_dwUPnPMode);
  503. }
  504. #ifndef DPNBUILD_NOHNETFWAPI
  505. //
  506. // If we successfully read a new mode, save it.
  507. //
  508. if (RegObject.ReadDWORD(REGKEY_VALUE_HNETFWAPIMODE, &dwNewValue))
  509. {
  510. g_dwUPnPMode = dwNewValue;
  511. DPFX(DPFPREP, 1, "Using HNet FW API mode %u.", g_dwHNetFWAPIMode);
  512. }
  513. #endif // ! DPNBUILD_NOHNETFWAPI
  514. //
  515. // If we successfully read a new mask, save it.
  516. //
  517. if (RegObject.ReadDWORD(REGKEY_VALUE_SUBNETMASKV4, &dwNewValue))
  518. {
  519. g_dwSubnetMaskV4 = dwNewValue;
  520. DPFX(DPFPREP, 1, "Using subnet mask 0x%08lx.", g_dwSubnetMaskV4);
  521. }
  522. //
  523. // If we successfully read a new interval, save it.
  524. //
  525. if (RegObject.ReadDWORD(REGKEY_VALUE_NOACTIVENOTIFYPOLLINTERVAL, &dwNewValue))
  526. {
  527. g_dwNoActiveNotifyPollInterval = dwNewValue;
  528. DPFX(DPFPREP, 1, "Using no-active-notify recommended poll interval %u ms.", g_dwNoActiveNotifyPollInterval);
  529. }
  530. //
  531. // If we successfully read a new interval, save it.
  532. //
  533. if (RegObject.ReadDWORD(REGKEY_VALUE_MINUPDATESERVERSTATUSINTERVAL, &dwNewValue))
  534. {
  535. g_dwMinUpdateServerStatusInterval = dwNewValue;
  536. DPFX(DPFPREP, 1, "Using minimum update-server-status interval %u ms.", g_dwMinUpdateServerStatusInterval);
  537. }
  538. //
  539. // If we successfully read a new boolean, save it.
  540. //
  541. if (RegObject.ReadBOOL(REGKEY_VALUE_NOASYMMETRICMAPPINGS, &fNewValue))
  542. {
  543. g_fNoAsymmetricMappings = fNewValue;
  544. if (g_fNoAsymmetricMappings)
  545. {
  546. DPFX(DPFPREP, 1, "Never using asymmetric port mappings.");
  547. }
  548. else
  549. {
  550. //
  551. // This is actually default behavior, but print out a statement
  552. // anyway.
  553. //
  554. DPFX(DPFPREP, 1, "Asymmetric port mappings allowed by registry key.");
  555. }
  556. }
  557. //
  558. // If we successfully read a new boolean, save it.
  559. //
  560. if (RegObject.ReadBOOL(REGKEY_VALUE_USELEASEDURATIONS, &fNewValue))
  561. {
  562. g_fUseLeaseDurations = fNewValue;
  563. if (g_fUseLeaseDurations)
  564. {
  565. DPFX(DPFPREP, 1, "Attempting to use non-INFINITE lease durations.");
  566. }
  567. else
  568. {
  569. //
  570. // This is actually default behavior, but print out a statement
  571. // anyway.
  572. //
  573. DPFX(DPFPREP, 1, "Non-INFINITE lease durations specifically prevented by registry key.");
  574. }
  575. }
  576. //
  577. // If we successfully read a new value, save it.
  578. //
  579. if (RegObject.ReadDWORD(REGKEY_VALUE_UNICASTTTL, &dwNewValue))
  580. {
  581. g_iUnicastTTL = dwNewValue;
  582. if (g_iUnicastTTL != 0)
  583. {
  584. DPFX(DPFPREP, 1, "Using unicast TTL of %i.", g_iUnicastTTL);
  585. }
  586. else
  587. {
  588. DPFX(DPFPREP, 1, "Using OS default unicast TTL.");
  589. }
  590. }
  591. //
  592. // If we successfully read a new value, save it.
  593. //
  594. if (RegObject.ReadDWORD(REGKEY_VALUE_MULTICASTTTL, &dwNewValue))
  595. {
  596. g_iMulticastTTL = dwNewValue;
  597. if (g_iMulticastTTL != 0)
  598. {
  599. DPFX(DPFPREP, 1, "Using multicast TTL of %i.", g_iMulticastTTL);
  600. }
  601. else
  602. {
  603. DPFX(DPFPREP, 1, "Using OS default multicast TTL.");
  604. }
  605. }
  606. //
  607. // If we successfully read a new timeout, save it.
  608. //
  609. if (RegObject.ReadDWORD(REGKEY_VALUE_UPNPANNOUNCERESPONSEWAITTIME, &dwNewValue))
  610. {
  611. g_dwUPnPAnnounceResponseWaitTime = dwNewValue;
  612. DPFX(DPFPREP, 1, "Using UPnP announce response wait time of %u ms.", g_dwUPnPAnnounceResponseWaitTime);
  613. }
  614. //
  615. // If we successfully read a new timeout, save it.
  616. //
  617. if (RegObject.ReadDWORD(REGKEY_VALUE_UPNPCONNECTTIMEOUT, &dwNewValue))
  618. {
  619. g_dwUPnPConnectTimeout = dwNewValue;
  620. DPFX(DPFPREP, 1, "Using UPnP connect timeout of %u seconds.", g_dwUPnPConnectTimeout);
  621. }
  622. //
  623. // If we successfully read a new timeout, save it.
  624. //
  625. if (RegObject.ReadDWORD(REGKEY_VALUE_UPNPRESPONSETIMEOUT, &dwNewValue))
  626. {
  627. g_dwUPnPResponseTimeout = dwNewValue;
  628. DPFX(DPFPREP, 1, "Using UPnP response timeout of %u ms.", g_dwUPnPResponseTimeout);
  629. }
  630. #ifndef DPNBUILD_NOHNETFWAPI
  631. //
  632. // If we successfully read a new boolean, save it.
  633. //
  634. if (RegObject.ReadBOOL(REGKEY_VALUE_MAPUPNPDISCOVERYSOCKET, &fNewValue))
  635. {
  636. g_fMapUPnPDiscoverySocket = fNewValue;
  637. if (g_fMapUPnPDiscoverySocket)
  638. {
  639. DPFX(DPFPREP, 1, "Mapping UPnP discovery socket on local firewall.");
  640. }
  641. else
  642. {
  643. //
  644. // This is actually default behavior, but print out a statement
  645. // anyway.
  646. //
  647. DPFX(DPFPREP, 1, "UPnP discovery socket mapping is disallowed by registry key.");
  648. }
  649. }
  650. #endif // ! DPNBUILD_NOHNETFWAPI
  651. //
  652. // If we successfully read a new boolean, save it.
  653. //
  654. if (RegObject.ReadBOOL(REGKEY_VALUE_USEMULTICASTUPNPDISCOVERY, &fNewValue))
  655. {
  656. g_fUseMulticastUPnPDiscovery = fNewValue;
  657. if (g_fUseMulticastUPnPDiscovery)
  658. {
  659. DPFX(DPFPREP, 1, "Using multicast UPnP discovery messages.");
  660. }
  661. else
  662. {
  663. //
  664. // This is actually default behavior, but print out a statement
  665. // anyway.
  666. //
  667. DPFX(DPFPREP, 1, "Multicasted UPnP discovery is disallowed by registry key.");
  668. }
  669. }
  670. //
  671. // If we successfully read a new default gateway, save it.
  672. //
  673. if (RegObject.ReadDWORD(REGKEY_VALUE_DEFAULTGATEWAYV4, &dwNewValue))
  674. {
  675. g_dwDefaultGatewayV4 = dwNewValue;
  676. DPFX(DPFPREP, 1, "Using default gateway 0x%08lx.", g_dwDefaultGatewayV4);
  677. }
  678. //
  679. // If we successfully read a new value, save it.
  680. //
  681. if (RegObject.ReadDWORD(REGKEY_VALUE_POLLINTERVALBACKOFF, &dwNewValue))
  682. {
  683. if (dwNewValue != 0)
  684. {
  685. g_dwPollIntervalBackoff = dwNewValue;
  686. DPFX(DPFPREP, 1, "Using poll interval backoff between 0 and %u ms.",
  687. g_dwPollIntervalBackoff);
  688. }
  689. else
  690. {
  691. DPFX(DPFPREP, 0, "Ignoring invalid poll interval backoff setting, using default between 0 and %u ms!",
  692. g_dwPollIntervalBackoff);
  693. }
  694. }
  695. //
  696. // If we successfully read a new interval, save it.
  697. //
  698. if (RegObject.ReadDWORD(REGKEY_VALUE_MAXPOLLINTERVAL, &dwNewValue))
  699. {
  700. //
  701. // Make sure the value is greater than the starting value.
  702. //
  703. if (dwNewValue >= g_dwNoActiveNotifyPollInterval)
  704. {
  705. g_dwMaxPollInterval = dwNewValue;
  706. DPFX(DPFPREP, 1, "Using max poll interval of %u ms.",
  707. g_dwMaxPollInterval);
  708. }
  709. else
  710. {
  711. g_dwMaxPollInterval = g_dwNoActiveNotifyPollInterval;
  712. DPFX(DPFPREP, 0, "Ignoring max poll interval of %u ms, the starting value is %u ms.",
  713. g_dwMaxPollInterval);
  714. }
  715. }
  716. else
  717. {
  718. //
  719. // Make sure the max poll interval default value is greater than
  720. // the starting value because we may have read in a new
  721. // g_dwNoActiveNotifyPollInterval that makes the default
  722. // g_dwMaxPollInterval invalid.
  723. //
  724. if (g_dwMaxPollInterval < g_dwNoActiveNotifyPollInterval)
  725. {
  726. g_dwMaxPollInterval = g_dwNoActiveNotifyPollInterval;
  727. DPFX(DPFPREP, 0, "Resetting max poll interval to %u ms so as to meet starting value.",
  728. g_dwMaxPollInterval);
  729. }
  730. }
  731. //
  732. // If we successfully read a new boolean, save it.
  733. //
  734. if (RegObject.ReadBOOL(REGKEY_VALUE_KEEPPOLLINGFORREMOTEGATEWAY, &fNewValue))
  735. {
  736. g_fKeepPollingForRemoteGateway = fNewValue;
  737. if (g_fKeepPollingForRemoteGateway)
  738. {
  739. DPFX(DPFPREP, 1, "Will continue to poll for remote gateways.");
  740. }
  741. else
  742. {
  743. //
  744. // This is actually default behavior, but print out a statement
  745. // anyway.
  746. //
  747. DPFX(DPFPREP, 1, "Continually polling for remote gateways is disallowed by registry key.");
  748. }
  749. }
  750. //
  751. // If we successfully read a new value, save it.
  752. //
  753. if (RegObject.ReadDWORD(REGKEY_VALUE_REUSEPORTTIME, &dwNewValue))
  754. {
  755. g_dwReusePortTime = dwNewValue;
  756. DPFX(DPFPREP, 1, "Reusing remote gateway discovery ports for %u ms.",
  757. g_dwReusePortTime);
  758. }
  759. //
  760. // If we successfully read a new value, save it.
  761. //
  762. if (RegObject.ReadDWORD(REGKEY_VALUE_CACHELIFEFOUND, &dwNewValue))
  763. {
  764. g_dwCacheLifeFound = dwNewValue;
  765. DPFX(DPFPREP, 1, "Caching found addresses for %u ms.",
  766. g_dwCacheLifeFound);
  767. }
  768. //
  769. // If we successfully read a new value, save it.
  770. //
  771. if (RegObject.ReadDWORD(REGKEY_VALUE_CACHELIFENOTFOUND, &dwNewValue))
  772. {
  773. g_dwCacheLifeNotFound = dwNewValue;
  774. DPFX(DPFPREP, 1, "Caching not-found addresses for %u ms.",
  775. g_dwCacheLifeNotFound);
  776. }
  777. #ifdef DBG
  778. //
  779. // If we successfully read a log string, print that out.
  780. //
  781. dwLength = sizeof(g_wszUPnPTransactionLog) / sizeof(WCHAR);
  782. if (RegObject.ReadString(REGKEY_VALUE_UPNPTRANSACTIONLOG,
  783. g_wszUPnPTransactionLog,
  784. &dwLength))
  785. {
  786. DPFX(DPFPREP, 1, "Using UPnP transaction log \"%ls\".", g_wszUPnPTransactionLog);
  787. }
  788. #endif // DBG
  789. //
  790. // Okay, we're done. Drop the lock.
  791. //
  792. DNLeaveCriticalSection(&g_csGlobalsLock);
  793. //
  794. // Done reading registry.
  795. //
  796. RegObject.Close();
  797. }
  798. } // ReadRegistrySettings
  799. #ifndef WINCE
  800. #undef DPF_MODNAME
  801. #define DPF_MODNAME "SetDefaultProxyBlanket"
  802. //=============================================================================
  803. // SetDefaultProxyBlanket
  804. //-----------------------------------------------------------------------------
  805. //
  806. // Description: Taken from the HomeNet config utils.
  807. //
  808. // This sets the standard COM security settings on the proxy
  809. // for an object. Even if the CoSetProxyBlanket calls fail, pUnk
  810. // remains in a usable state. Failure is expected in certain
  811. // contexts, such as when, for example, we're being called within
  812. // the desired process where we have direct pointers to the
  813. // objects instead of going through a proxy.
  814. //
  815. // COM is assumed to have been initialized.
  816. //
  817. // Arguments:
  818. // IUnknown * pUnk - The object on which to set the proxy blanket.
  819. // char * szObjectName - (debug only) The name of the object.
  820. //
  821. // Returns: None.
  822. //=============================================================================
  823. #ifdef DBG
  824. void SetDefaultProxyBlanket(IUnknown * pUnk, const char * const szObjectName)
  825. #else // ! DBG
  826. void SetDefaultProxyBlanket(IUnknown * pUnk)
  827. #endif // ! DBG
  828. {
  829. HRESULT hr;
  830. //IUnknown * pUnkSet = NULL;
  831. hr = CoSetProxyBlanket(pUnk,
  832. RPC_C_AUTHN_WINNT, // use NT default security
  833. RPC_C_AUTHN_NONE, // use NT default authentication
  834. NULL, // must be NULL if default
  835. RPC_C_AUTHN_LEVEL_CALL, // call level authentication
  836. RPC_C_IMP_LEVEL_IMPERSONATE,
  837. NULL, // use process token
  838. EOAC_NONE);
  839. if (SUCCEEDED(hr))
  840. {
  841. /*
  842. hr = pUnk->QueryInterface(&pUnkSet);
  843. if (SUCCEEDED(hr))
  844. {
  845. hr = CoSetProxyBlanket(pUnk,
  846. RPC_C_AUTHN_WINNT, // use NT default security
  847. RPC_C_AUTHN_NONE, // use NT default authentication
  848. NULL, // must be NULL if default
  849. RPC_C_AUTHN_LEVEL_CALL, // call level authentication
  850. RPC_C_IMP_LEVEL_IMPERSONATE,
  851. NULL, // use process token
  852. EOAC_NONE);
  853. if (SUCCEEDED(hr))
  854. {
  855. //
  856. // This is what we want.
  857. //
  858. }
  859. else
  860. {
  861. DPFX(DPFPREP, 1, "Couldn't set security blanket (2) on %hs object 0x%p (err = 0x%lx)! Continuing.",
  862. szObjectName, pUnk, hr);
  863. }
  864. pUnkSet->Release();
  865. pUnkSet = NULL;
  866. }
  867. else
  868. {
  869. DPFX(DPFPREP, 1, "Couldn't query for IUnknown interface on %hs object 0x%p (err = 0x%lx)! Continuing.",
  870. szObjectName, pUnk, hr);
  871. }
  872. */
  873. }
  874. else
  875. {
  876. DPFX(DPFPREP, 1, "Couldn't set security blanket (1) on %hs object 0x%p (err = 0x%lx)! Continuing.",
  877. szObjectName, pUnk, hr);
  878. }
  879. } // SetDefaultProxyBlanket
  880. #endif // ! WINCE
  881. #undef DPF_MODNAME
  882. #define DPF_MODNAME "InitializeGlobalRand"
  883. //=============================================================================
  884. // InitializeGlobalRand
  885. //-----------------------------------------------------------------------------
  886. //
  887. // Description: Initializes the fallback global psuedo-random number
  888. // generator, using the given seed value.
  889. //
  890. // Arguments:
  891. // DWORD dwSeed - Seed to use.
  892. //
  893. // Returns: None.
  894. //=============================================================================
  895. void InitializeGlobalRand(const DWORD dwSeed)
  896. {
  897. //
  898. // We don't need to hold a lock, since this should only be done once,
  899. // during initialization time.
  900. //
  901. g_dwHoldRand = dwSeed;
  902. } // InitializeGlobalRand
  903. #undef DPF_MODNAME
  904. #define DPF_MODNAME "GetGlobalRand"
  905. //=============================================================================
  906. // GetGlobalRand
  907. //-----------------------------------------------------------------------------
  908. //
  909. // Description: Generates a pseudo-random DWORD.
  910. //
  911. // Arguments: None.
  912. //
  913. // Returns: Pseudo-random number.
  914. //=============================================================================
  915. DWORD GetGlobalRand(void)
  916. {
  917. HCRYPTPROV hCryptProv;
  918. DWORD dwResult;
  919. WORD wResult1;
  920. WORD wResult2;
  921. #ifdef DBG
  922. DWORD dwError;
  923. #endif // DBG
  924. if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
  925. {
  926. if (CryptGenRandom(hCryptProv, sizeof(dwResult), (BYTE*) (&dwResult)))
  927. {
  928. CryptReleaseContext(hCryptProv, 0);
  929. return dwResult;
  930. }
  931. #ifdef DBG
  932. else
  933. {
  934. dwError = GetLastError();
  935. DPFX(DPFPREP, 0, "Crypto couldn't generate random number (err = %u)!",
  936. dwError);
  937. }
  938. #endif // DBG
  939. CryptReleaseContext(hCryptProv, 0);
  940. }
  941. #ifdef DBG
  942. else
  943. {
  944. dwError = GetLastError();
  945. DPFX(DPFPREP, 0, "Couldn't acquire crypto provider context (err = %u)!",
  946. dwError);
  947. }
  948. #endif // DBG
  949. //
  950. // We couldn't use the crypto API to generate a random number, so make
  951. // our own based off the C run time source.
  952. //
  953. DNEnterCriticalSection(&g_csGlobalsLock);
  954. g_dwHoldRand = ((g_dwHoldRand * 214013L + 2531011L) >> 16) & 0x7fff;
  955. wResult1 = (WORD) g_dwHoldRand;
  956. g_dwHoldRand = ((g_dwHoldRand * 214013L + 2531011L) >> 16) & 0x7fff;
  957. wResult2 = (WORD) g_dwHoldRand;
  958. DNLeaveCriticalSection(&g_csGlobalsLock);
  959. return MAKELONG(wResult1, wResult2);
  960. } // GetGlobalRand
  961. #undef DPF_MODNAME
  962. #define DPF_MODNAME "DoCreateInstance"
  963. //=============================================================================
  964. // DoCreateInstance
  965. //-----------------------------------------------------------------------------
  966. //
  967. // Description: Creates an instance of an interface. Required by the general
  968. // purpose class factory functions.
  969. //
  970. // Arguments:
  971. // LPCLASSFACTORY This - Pointer to class factory.
  972. // LPUNKNOWN pUnkOuter - Pointer to unknown interface.
  973. // REFCLSID rclsid - Reference of GUID of desired interface.
  974. // REFIID riid - Reference to another GUID?
  975. // LPVOID * ppvObj - Pointer to pointer to interface.
  976. //
  977. // Returns: HRESULT
  978. //=============================================================================
  979. HRESULT DoCreateInstance(LPCLASSFACTORY This,
  980. LPUNKNOWN pUnkOuter,
  981. REFCLSID rclsid,
  982. REFIID riid,
  983. LPVOID * ppvObj)
  984. {
  985. HRESULT hr;
  986. BOOL fNotCreatedWithCOM;
  987. CNATHelpUPnP * pNATHelpUPnP = NULL;
  988. DNASSERT(ppvObj != NULL);
  989. if (! IsEqualCLSID(rclsid, CLSID_DirectPlayNATHelpUPnP))
  990. {
  991. //
  992. // This shouldn't happen if they called IClassFactory::CreateObject
  993. // correctly.
  994. //
  995. DNASSERT(FALSE);
  996. //
  997. // Return an error.
  998. //
  999. hr = E_UNEXPECTED;
  1000. goto Failure;
  1001. }
  1002. //
  1003. // If the class factory pointer is NULL, then we were called by the
  1004. // DirectPlayNATHelpCreate function.
  1005. //
  1006. if (This == NULL)
  1007. {
  1008. fNotCreatedWithCOM = TRUE;
  1009. }
  1010. else
  1011. {
  1012. fNotCreatedWithCOM = FALSE;
  1013. }
  1014. //
  1015. // Create the object instance.
  1016. //
  1017. pNATHelpUPnP = new CNATHelpUPnP(fNotCreatedWithCOM);
  1018. if (pNATHelpUPnP == NULL)
  1019. {
  1020. hr = E_OUTOFMEMORY;
  1021. goto Failure;
  1022. }
  1023. //
  1024. // Initialize the base object (which might fail).
  1025. //
  1026. hr = pNATHelpUPnP->InitializeObject();
  1027. if (hr != S_OK)
  1028. {
  1029. DPFX(DPFPREP, 0, "Couldn't initialize object!");
  1030. delete pNATHelpUPnP;
  1031. pNATHelpUPnP = NULL;
  1032. goto Failure;
  1033. }
  1034. //
  1035. // Add it to the global list.
  1036. //
  1037. DNEnterCriticalSection(&g_csGlobalsLock);
  1038. pNATHelpUPnP->m_blList.InsertBefore(&g_blNATHelpUPnPObjs);
  1039. g_lOutstandingInterfaceCount++; // update count so DllCanUnloadNow works correctly
  1040. DNLeaveCriticalSection(&g_csGlobalsLock);
  1041. //
  1042. // Get the right interface for the caller and bump the refcount.
  1043. //
  1044. hr = pNATHelpUPnP->QueryInterface(riid, ppvObj);
  1045. if (hr != S_OK)
  1046. {
  1047. goto Failure;
  1048. }
  1049. Exit:
  1050. //
  1051. // Release the local reference to the object. If this function was
  1052. // successful, there's still a reference in ppvObj.
  1053. //
  1054. if (pNATHelpUPnP != NULL)
  1055. {
  1056. pNATHelpUPnP->Release();
  1057. pNATHelpUPnP = NULL;
  1058. }
  1059. return hr;
  1060. Failure:
  1061. //
  1062. // Make sure we don't hand back a pointer.
  1063. //
  1064. (*ppvObj) = NULL;
  1065. goto Exit;
  1066. } // DoCreateInstance
  1067. #undef DPF_MODNAME
  1068. #define DPF_MODNAME "IsClassImplemented"
  1069. //=============================================================================
  1070. // IsClassImplemented
  1071. //-----------------------------------------------------------------------------
  1072. //
  1073. // Description: Determine if a class is implemented in this DLL. Required by
  1074. // the general purpose class factory functions.
  1075. //
  1076. // Arguments:
  1077. // REFCLSID rclsid - Reference to class GUID.
  1078. //
  1079. // Returns: BOOL
  1080. // TRUE - This DLL implements the class.
  1081. // FALSE - This DLL doesn't implement the class.
  1082. //=============================================================================
  1083. BOOL IsClassImplemented(REFCLSID rclsid)
  1084. {
  1085. return (IsEqualCLSID(rclsid, CLSID_DirectPlayNATHelpUPnP));
  1086. } // IsClassImplemented