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.

633 lines
15 KiB

  1. /*++
  2. Copyright (c) 1991-1993 Microsoft Corporation
  3. Module Name:
  4. connify.cxx
  5. Abstract:
  6. Contains code used to notify all DLLs interested in notifiable MPR
  7. Events. Currently only connection information results in
  8. notification.
  9. Author:
  10. Dan Lafferty (danl) 14-Dec-1993
  11. Environment:
  12. User Mode -Win32
  13. Revision History:
  14. 14-Dec-1993 danl
  15. created
  16. 05-May-1999 jschwart
  17. Make provider addition/removal dynamic
  18. --*/
  19. //
  20. // INCLUDES
  21. //
  22. #include "precomp.hxx"
  23. #include "connify.h" // MprAddConnectNotify
  24. //===================
  25. // TYPEDEFs
  26. //===================
  27. typedef struct _NOTIFYEE {
  28. PF_AddConnectNotify PF_AddConnectNotify;
  29. PF_CancelConnectNotify PF_CancelConnectNotify;
  30. HINSTANCE DllHandle;
  31. }NOTIFYEE, *LPNOTIFYEE;
  32. //===================
  33. // DEFINES
  34. //===================
  35. #define NOTIFYEE_ROOT TEXT("system\\CurrentControlSet\\Control\\NetworkProvider\\Notifyees")
  36. //===================
  37. // GLOBALs
  38. //===================
  39. //
  40. // A pointer to an array of NOTIFYEE structures.
  41. // These are only modified by MprConnectNotifyInif.
  42. // The MprInitCritSec is obtained prior to calling
  43. // MprConnectNotifyInit.
  44. //
  45. LPNOTIFYEE NotifyList = NULL;
  46. DWORD GlobalNumNotifyees = 0;
  47. DWORD
  48. MprConnectNotifyInit(
  49. VOID
  50. )
  51. /*++
  52. Routine Description:
  53. This function does the following:
  54. 1) Look in the registry to determine which DLLs want to be notified of
  55. Connection Events.
  56. 2) Load the Notifiee DLLs.
  57. 3) Obtain the entry points for the notify functions.
  58. 4) Create a list of all the Notifiee Information.
  59. Arguments:
  60. NONE
  61. Return Value:
  62. WN_SUCCESS
  63. --*/
  64. {
  65. HKEY notifyeeRootKey;
  66. DWORD status;
  67. DWORD numSubKeys;
  68. DWORD cchMaxSubKey;
  69. DWORD numValues;
  70. DWORD cchMaxValueName;
  71. DWORD type;
  72. DWORD bufSize;
  73. TCHAR dllPath[MAX_PATH];
  74. TCHAR buffer[MAX_PATH];
  75. LPTSTR expandedPath=NULL;
  76. DWORD nameSize;
  77. HINSTANCE hLib=NULL;
  78. DWORD i;
  79. DWORD numReqd;
  80. LPNOTIFYEE NotifyEntry;
  81. //
  82. // Read the Registry Information for Notifiees.
  83. // If the key doesn't exist, then there is no one to notify.
  84. //
  85. if (!MprOpenKey (
  86. HKEY_LOCAL_MACHINE, // hKey
  87. NOTIFYEE_ROOT, // lpSubKey
  88. &notifyeeRootKey, // Newly Opened Key Handle
  89. DA_READ)) { // Desired Access
  90. MPR_LOG0(CNOTIFY,"MprConnectInfoInit: NOTIFYEE_ROOT doesen't exist\n");
  91. return(WN_SUCCESS);
  92. }
  93. //
  94. // GetKeyInfo (find out how many values)
  95. //
  96. if (!MprGetKeyInfo (
  97. notifyeeRootKey,
  98. NULL,
  99. &numSubKeys,
  100. &cchMaxSubKey,
  101. &numValues,
  102. &cchMaxValueName)) {
  103. MPR_LOG0(CNOTIFY,"MprConnectInfoInit: Couldn't get key info\n");
  104. return(WN_SUCCESS);
  105. }
  106. MPR_LOG1(CNOTIFY,"MprConnectInfoInit: GlobalNumNotifyees = %d\n",numValues);
  107. //
  108. // Allocate space for that many notifyees.
  109. //
  110. if (numValues == 0) {
  111. return(WN_SUCCESS);
  112. }
  113. NotifyList = (LPNOTIFYEE) LocalAlloc(LPTR,numValues * sizeof(NOTIFYEE));
  114. if (NotifyList == NULL) {
  115. return(GetLastError());
  116. }
  117. NotifyEntry = NotifyList;
  118. //
  119. // Load the Notifyees and get their entry points.
  120. //
  121. for (i=0; i<numValues; i++) {
  122. bufSize = MAX_PATH * sizeof (TCHAR);
  123. nameSize = MAX_PATH;
  124. expandedPath = NULL;
  125. status = RegEnumValue(
  126. notifyeeRootKey,
  127. i,
  128. buffer,
  129. &nameSize,
  130. NULL,
  131. &type,
  132. (LPBYTE)dllPath,
  133. &bufSize);
  134. if (status != NO_ERROR) {
  135. MPR_LOG0(CNOTIFY,"MprConnectInfoInit: RegEnumValue failure\n");
  136. }
  137. else {
  138. switch (type) {
  139. case REG_EXPAND_SZ:
  140. numReqd = ExpandEnvironmentStrings(dllPath,buffer,MAX_PATH);
  141. if (numReqd > MAX_PATH) {
  142. expandedPath = (LPTSTR) LocalAlloc(LMEM_FIXED,numReqd*sizeof(TCHAR) );
  143. if (expandedPath == NULL) {
  144. //
  145. // We can't expand the string, so we skip this notifyee
  146. // and go onto the next.
  147. //
  148. status = GetLastError();
  149. break; // Leave the switch and cleanup this notifyee
  150. }
  151. numReqd = ExpandEnvironmentStrings(dllPath,expandedPath,numReqd);
  152. if (numReqd > MAX_PATH) {
  153. MPR_LOG0(CNOTIFY,"MprConnectNotifyInit: Couldn't Expand Path\n");
  154. status = ERROR_BAD_LENGTH;
  155. break; // Leave the switch and cleanup this notifyee
  156. }
  157. }
  158. else {
  159. expandedPath = buffer;
  160. }
  161. // Fall thru to the REG_SZ case....
  162. case REG_SZ:
  163. if (expandedPath == NULL) {
  164. expandedPath = dllPath;
  165. }
  166. //
  167. // Load the DLL
  168. //
  169. hLib = LoadLibraryEx(expandedPath,
  170. NULL,
  171. LOAD_WITH_ALTERED_SEARCH_PATH);
  172. if (hLib == NULL) {
  173. status = GetLastError();
  174. MPR_LOG2(CNOTIFY,"MprConnectInfoInit:LoadLibraryEx for %ws failed %d\n",
  175. expandedPath, status);
  176. break; // Leave the switch and cleanup this notifyee
  177. }
  178. //
  179. // Get the Entry Points from the DLL.
  180. //
  181. NotifyEntry->PF_AddConnectNotify =
  182. (PF_AddConnectNotify)GetProcAddress(hLib,"AddConnectNotify");
  183. NotifyEntry->PF_CancelConnectNotify =
  184. (PF_CancelConnectNotify)GetProcAddress(hLib,"CancelConnectNotify");
  185. //
  186. // If and Only If both functions are supported, then increment
  187. // the NotifyList.
  188. //
  189. if ((NotifyEntry->PF_AddConnectNotify != NULL) &&
  190. (NotifyEntry->PF_CancelConnectNotify != NULL)) {
  191. NotifyEntry->DllHandle = hLib;
  192. NotifyEntry++;
  193. GlobalNumNotifyees++;
  194. MPR_LOG1(CNOTIFY,"MprConnectInfoInit: Item added to "
  195. "notify list %d\n",GlobalNumNotifyees);
  196. }
  197. else {
  198. FreeLibrary (hLib);
  199. hLib = NULL;
  200. }
  201. break;
  202. default:
  203. break;
  204. }
  205. }
  206. //
  207. // Cleanup resources for this notifyee
  208. //
  209. if ((expandedPath != NULL) &&
  210. (expandedPath != dllPath) &&
  211. (expandedPath != buffer)) {
  212. LocalFree(expandedPath);
  213. }
  214. } // End for(Each Notifyee)
  215. if (GlobalNumNotifyees == 0) {
  216. if (NotifyList != NULL) {
  217. LocalFree(NotifyList);
  218. NotifyList = NULL;
  219. }
  220. }
  221. RegCloseKey(notifyeeRootKey);
  222. return(WN_SUCCESS);
  223. }
  224. VOID
  225. MprCleanupNotifyInfo(
  226. VOID
  227. )
  228. /*++
  229. Routine Description:
  230. Arguments:
  231. Return Value:
  232. --*/
  233. {
  234. DWORD i;
  235. ASSERT_INITIALIZED(NOTIFIEE);
  236. for (i=0; i<GlobalNumNotifyees; i++ ) {
  237. FreeLibrary(NotifyList[i].DllHandle);
  238. }
  239. LocalFree(NotifyList);
  240. return;
  241. }
  242. PVOID
  243. MprAllocConnectContext(
  244. VOID
  245. )
  246. /*++
  247. Routine Description:
  248. Arguments:
  249. Return Value:
  250. --*/
  251. {
  252. ASSERT_INITIALIZED(NOTIFIEE);
  253. if (GlobalNumNotifyees == 0) {
  254. return(NULL);
  255. }
  256. MPR_LOG1(CNOTIFY,"In MprAllocConnectContext. Allocating for %d notifyees\n",
  257. GlobalNumNotifyees);
  258. return(PVOID)(LocalAlloc(LPTR,sizeof(PVOID) * GlobalNumNotifyees));
  259. }
  260. VOID
  261. MprFreeConnectContext(
  262. PVOID ConnectContext
  263. )
  264. /*++
  265. Routine Description:
  266. Arguments:
  267. Return Value:
  268. --*/
  269. {
  270. MPR_LOG0(CNOTIFY,"In MprFreeConnectContext\n");
  271. LocalFree(ConnectContext);
  272. }
  273. DWORD
  274. MprAddConnectNotify(
  275. LPNOTIFYINFO lpNotifyInfo,
  276. LPNOTIFYADD lpAddInfo
  277. )
  278. /*++
  279. Routine Description:
  280. This function calls all the Notifyees if an add connection event.
  281. Arguments:
  282. lpNotifyInfo -
  283. lpAddInfo -
  284. Return Value:
  285. If any of the notifyees returns WN_CANCEL, the notification is immediately
  286. aborted and the WN_CANCEL is returned from the caller.
  287. Aside from that error, if WN_RETRY is returned from any notifyee, then
  288. WN_RETRY is returned to the caller. Otherwise, the last error is returned.
  289. If all notifyees return WN_SUCCESS, then the last error will be WN_SUCCESS.
  290. --*/
  291. {
  292. DWORD i;
  293. DWORD status;
  294. DWORD lastError=WN_SUCCESS;
  295. BOOL retryFlag=FALSE;
  296. DWORD numNotifyees = GlobalNumNotifyees;
  297. PVOID *ContextInfo;
  298. LPNOTIFYEE NotifyEntry=NotifyList;
  299. MPR_LOG0(CNOTIFY,"In MprAddConnectNotify\n");
  300. ASSERT_INITIALIZED(NOTIFIEE);
  301. //
  302. // Save away the pointer to the array of context information.
  303. //
  304. ContextInfo = (PVOID *) lpNotifyInfo->lpContext;
  305. for (i=0; i<numNotifyees; i++,NotifyEntry++ )
  306. {
  307. if (lpNotifyInfo->dwNotifyStatus == NOTIFY_POST)
  308. {
  309. if (ContextInfo && ContextInfo[i] != NULL)
  310. {
  311. lpNotifyInfo->lpContext = ContextInfo[i];
  312. }
  313. else
  314. {
  315. //
  316. // Don't notify if it is a POST notification, and there
  317. // is no context saved. Here we go directly to the next
  318. // notifyee (or out of the for loop).
  319. //
  320. continue;
  321. }
  322. }
  323. status = NotifyEntry->PF_AddConnectNotify(lpNotifyInfo,lpAddInfo);
  324. switch (status) {
  325. case WN_SUCCESS:
  326. MPR_LOG0(CNOTIFY,"AddConnectNotify SUCCESS\n");
  327. if (ContextInfo != NULL)
  328. {
  329. ContextInfo[i] = lpNotifyInfo->lpContext;
  330. }
  331. break;
  332. case WN_CANCEL:
  333. MPR_LOG0(CNOTIFY,"AddConnectNotify WN_CANCEL\n");
  334. //
  335. // CANCEL shouldn't be returned from NOTIFY_POST calls.
  336. //
  337. if (lpNotifyInfo->dwNotifyStatus == NOTIFY_PRE) {
  338. //
  339. // If we got the cancel for the first notifyee, then we can
  340. // stop here.
  341. //
  342. if (i == 0) {
  343. lpNotifyInfo->lpContext = ContextInfo;
  344. return(status);
  345. }
  346. //
  347. // If we have already successfully called some notifyees, then we
  348. // must now post notify them of the cancel.
  349. //
  350. numNotifyees = i;
  351. lpNotifyInfo->dwNotifyStatus = NOTIFY_POST;
  352. i = 0xffffffff;
  353. }
  354. break;
  355. case WN_RETRY:
  356. MPR_LOG0(CNOTIFY,"AddConnectNotify WN_RETRY\n");
  357. //
  358. // RETRY is only valid if the operation failed and
  359. // this is a post notification.
  360. //
  361. if ((lpNotifyInfo->dwOperationStatus != WN_SUCCESS) &&
  362. (lpNotifyInfo->dwNotifyStatus == NOTIFY_POST)) {
  363. retryFlag = TRUE;
  364. if (ContextInfo != NULL)
  365. {
  366. ContextInfo[i] = lpNotifyInfo->lpContext;
  367. }
  368. //
  369. // If we need to retry, then we must now pre-notify those
  370. // notifyees that we have already post-notified. We don't
  371. // want to post-notify any more notifyees.
  372. //
  373. if (i > 0) {
  374. numNotifyees = i;
  375. lpNotifyInfo->dwNotifyStatus = NOTIFY_PRE;
  376. i = 0xffffffff;
  377. }
  378. }
  379. break;
  380. default:
  381. MPR_LOG1(CNOTIFY,"AddConnectNotify returned an error %d\n",status);
  382. lastError = status;
  383. break;
  384. }
  385. }
  386. //
  387. // Restore the pointer to the array of context information.
  388. //
  389. lpNotifyInfo->lpContext = ContextInfo;
  390. //
  391. // No matter if other error occured, if one of the notifyees wants
  392. // a retry, we will return retry.
  393. //
  394. if (retryFlag == TRUE) {
  395. return(WN_RETRY);
  396. }
  397. return(lastError);
  398. }
  399. DWORD
  400. MprCancelConnectNotify(
  401. LPNOTIFYINFO lpNotifyInfo,
  402. LPNOTIFYCANCEL lpCancelInfo
  403. )
  404. /*++
  405. Routine Description:
  406. Arguments:
  407. Return Value:
  408. --*/
  409. {
  410. DWORD i;
  411. DWORD status;
  412. DWORD lastError=WN_SUCCESS;
  413. BOOL retryFlag=FALSE;
  414. DWORD numNotifyees = GlobalNumNotifyees;
  415. PVOID *ContextInfo;
  416. LPNOTIFYEE NotifyEntry=NotifyList;
  417. MPR_LOG0(CNOTIFY,"In MprCancelConnectNotify\n");
  418. ASSERT_INITIALIZED(NOTIFIEE);
  419. //
  420. // Save away the pointer to the array of context information.
  421. //
  422. ContextInfo = (PVOID *) lpNotifyInfo->lpContext;
  423. for (i=0; i<numNotifyees; i++,NotifyEntry++)
  424. {
  425. if (lpNotifyInfo->dwNotifyStatus == NOTIFY_POST)
  426. {
  427. if (ContextInfo && ContextInfo[i] != NULL)
  428. {
  429. lpNotifyInfo->lpContext = ContextInfo[i];
  430. }
  431. else
  432. {
  433. //
  434. // Don't notify if it is a POST notification, and there
  435. // is no context saved. Here we go directly to the next
  436. // notifyee (or out of the for loop).
  437. //
  438. continue;
  439. }
  440. }
  441. status = NotifyEntry->PF_CancelConnectNotify(lpNotifyInfo,lpCancelInfo);
  442. switch (status) {
  443. case WN_SUCCESS:
  444. MPR_LOG0(CNOTIFY,"CancelConnectNotify SUCCESS\n");
  445. if (ContextInfo != NULL)
  446. {
  447. ContextInfo[i] = lpNotifyInfo->lpContext;
  448. }
  449. break;
  450. case WN_CANCEL:
  451. MPR_LOG0(CNOTIFY,"CancelConnectNotify WN_CANCEL\n");
  452. //
  453. // It is assumed that CANCEL won't be returned from
  454. // NOTIFY_POST calls.
  455. //
  456. // If we got the cancel for the first notifyee, then we can
  457. // stop here.
  458. //
  459. if (i == 0) {
  460. lpNotifyInfo->lpContext = ContextInfo;
  461. return(status);
  462. }
  463. //
  464. // If we have already successfully called some notifyees, then we
  465. // must now post notify them of the cancel.
  466. //
  467. numNotifyees = i;
  468. lpNotifyInfo->dwNotifyStatus = NOTIFY_POST;
  469. i = 0xffffffff;
  470. break;
  471. case WN_RETRY:
  472. MPR_LOG0(CNOTIFY,"CancelConnectNotify WN_RETRY\n");
  473. retryFlag = TRUE;
  474. if (ContextInfo != NULL)
  475. {
  476. ContextInfo[i] = lpNotifyInfo->lpContext;
  477. }
  478. break;
  479. default:
  480. MPR_LOG1(CNOTIFY,"CancelConnectNotify returned an error %d\n",status);
  481. lastError = status;
  482. break;
  483. }
  484. }
  485. //
  486. // Restore the pointer to the array of context information.
  487. //
  488. lpNotifyInfo->lpContext = ContextInfo;
  489. //
  490. // No matter if other error occured, if one of the notifyees wants
  491. // a retry, we will return retry.
  492. //
  493. if (retryFlag == TRUE) {
  494. return(WN_RETRY);
  495. }
  496. return(lastError);
  497. }