Source code of Windows XP (NT5)
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.

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