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.

636 lines
16 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. RegCloseKey( notifyeeRootKey );
  104. MPR_LOG0(CNOTIFY,"MprConnectInfoInit: Couldn't get key info\n");
  105. return(WN_SUCCESS);
  106. }
  107. MPR_LOG1(CNOTIFY,"MprConnectInfoInit: GlobalNumNotifyees = %d\n",numValues);
  108. //
  109. // Allocate space for that many notifyees.
  110. //
  111. if (numValues == 0) {
  112. RegCloseKey( notifyeeRootKey );
  113. return(WN_SUCCESS);
  114. }
  115. NotifyList = (LPNOTIFYEE) LocalAlloc(LPTR,numValues * sizeof(NOTIFYEE));
  116. if (NotifyList == NULL) {
  117. RegCloseKey( notifyeeRootKey );
  118. return(GetLastError());
  119. }
  120. NotifyEntry = NotifyList;
  121. //
  122. // Load the Notifyees and get their entry points.
  123. //
  124. for (i=0; i<numValues; i++) {
  125. bufSize = MAX_PATH * sizeof (TCHAR);
  126. nameSize = MAX_PATH;
  127. expandedPath = NULL;
  128. status = RegEnumValue(
  129. notifyeeRootKey,
  130. i,
  131. buffer,
  132. &nameSize,
  133. NULL,
  134. &type,
  135. (LPBYTE)dllPath,
  136. &bufSize);
  137. if (status != NO_ERROR) {
  138. MPR_LOG0(CNOTIFY,"MprConnectInfoInit: RegEnumValue failure\n");
  139. }
  140. else {
  141. switch (type) {
  142. case REG_EXPAND_SZ:
  143. numReqd = ExpandEnvironmentStrings(dllPath,buffer,MAX_PATH);
  144. if (numReqd > MAX_PATH) {
  145. expandedPath = (LPTSTR) LocalAlloc(LMEM_FIXED,numReqd*sizeof(TCHAR) );
  146. if (expandedPath == NULL) {
  147. //
  148. // We can't expand the string, so we skip this notifyee
  149. // and go onto the next.
  150. //
  151. status = GetLastError();
  152. break; // Leave the switch and cleanup this notifyee
  153. }
  154. numReqd = ExpandEnvironmentStrings(dllPath,expandedPath,numReqd);
  155. if (numReqd > MAX_PATH) {
  156. MPR_LOG0(CNOTIFY,"MprConnectNotifyInit: Couldn't Expand Path\n");
  157. status = ERROR_BAD_LENGTH;
  158. break; // Leave the switch and cleanup this notifyee
  159. }
  160. }
  161. else {
  162. expandedPath = buffer;
  163. }
  164. // Fall thru to the REG_SZ case....
  165. case REG_SZ:
  166. if (expandedPath == NULL) {
  167. expandedPath = dllPath;
  168. }
  169. //
  170. // Load the DLL
  171. //
  172. hLib = LoadLibraryEx(expandedPath,
  173. NULL,
  174. LOAD_WITH_ALTERED_SEARCH_PATH);
  175. if (hLib == NULL) {
  176. status = GetLastError();
  177. MPR_LOG2(CNOTIFY,"MprConnectInfoInit:LoadLibraryEx for %ws failed %d\n",
  178. expandedPath, status);
  179. break; // Leave the switch and cleanup this notifyee
  180. }
  181. //
  182. // Get the Entry Points from the DLL.
  183. //
  184. NotifyEntry->PF_AddConnectNotify =
  185. (PF_AddConnectNotify)GetProcAddress(hLib,"AddConnectNotify");
  186. NotifyEntry->PF_CancelConnectNotify =
  187. (PF_CancelConnectNotify)GetProcAddress(hLib,"CancelConnectNotify");
  188. //
  189. // If and Only If both functions are supported, then increment
  190. // the NotifyList.
  191. //
  192. if ((NotifyEntry->PF_AddConnectNotify != NULL) &&
  193. (NotifyEntry->PF_CancelConnectNotify != NULL)) {
  194. NotifyEntry->DllHandle = hLib;
  195. NotifyEntry++;
  196. GlobalNumNotifyees++;
  197. MPR_LOG1(CNOTIFY,"MprConnectInfoInit: Item added to "
  198. "notify list %d\n",GlobalNumNotifyees);
  199. }
  200. else {
  201. FreeLibrary (hLib);
  202. hLib = NULL;
  203. }
  204. break;
  205. default:
  206. break;
  207. }
  208. }
  209. //
  210. // Cleanup resources for this notifyee
  211. //
  212. if ((expandedPath != NULL) &&
  213. (expandedPath != dllPath) &&
  214. (expandedPath != buffer)) {
  215. LocalFree(expandedPath);
  216. }
  217. } // End for(Each Notifyee)
  218. if (GlobalNumNotifyees == 0) {
  219. if (NotifyList != NULL) {
  220. LocalFree(NotifyList);
  221. NotifyList = NULL;
  222. }
  223. }
  224. RegCloseKey(notifyeeRootKey);
  225. return(WN_SUCCESS);
  226. }
  227. VOID
  228. MprCleanupNotifyInfo(
  229. VOID
  230. )
  231. /*++
  232. Routine Description:
  233. Arguments:
  234. Return Value:
  235. --*/
  236. {
  237. DWORD i;
  238. ASSERT_INITIALIZED(NOTIFIEE);
  239. for (i=0; i<GlobalNumNotifyees; i++ ) {
  240. FreeLibrary(NotifyList[i].DllHandle);
  241. }
  242. LocalFree(NotifyList);
  243. return;
  244. }
  245. PVOID
  246. MprAllocConnectContext(
  247. VOID
  248. )
  249. /*++
  250. Routine Description:
  251. Arguments:
  252. Return Value:
  253. --*/
  254. {
  255. ASSERT_INITIALIZED(NOTIFIEE);
  256. if (GlobalNumNotifyees == 0) {
  257. return(NULL);
  258. }
  259. MPR_LOG1(CNOTIFY,"In MprAllocConnectContext. Allocating for %d notifyees\n",
  260. GlobalNumNotifyees);
  261. return(PVOID)(LocalAlloc(LPTR,sizeof(PVOID) * GlobalNumNotifyees));
  262. }
  263. VOID
  264. MprFreeConnectContext(
  265. PVOID ConnectContext
  266. )
  267. /*++
  268. Routine Description:
  269. Arguments:
  270. Return Value:
  271. --*/
  272. {
  273. MPR_LOG0(CNOTIFY,"In MprFreeConnectContext\n");
  274. LocalFree(ConnectContext);
  275. }
  276. DWORD
  277. MprAddConnectNotify(
  278. LPNOTIFYINFO lpNotifyInfo,
  279. LPNOTIFYADD lpAddInfo
  280. )
  281. /*++
  282. Routine Description:
  283. This function calls all the Notifyees if an add connection event.
  284. Arguments:
  285. lpNotifyInfo -
  286. lpAddInfo -
  287. Return Value:
  288. If any of the notifyees returns WN_CANCEL, the notification is immediately
  289. aborted and the WN_CANCEL is returned from the caller.
  290. Aside from that error, if WN_RETRY is returned from any notifyee, then
  291. WN_RETRY is returned to the caller. Otherwise, the last error is returned.
  292. If all notifyees return WN_SUCCESS, then the last error will be WN_SUCCESS.
  293. --*/
  294. {
  295. DWORD i;
  296. DWORD status;
  297. DWORD lastError=WN_SUCCESS;
  298. BOOL retryFlag=FALSE;
  299. DWORD numNotifyees = GlobalNumNotifyees;
  300. PVOID *ContextInfo;
  301. LPNOTIFYEE NotifyEntry=NotifyList;
  302. MPR_LOG0(CNOTIFY,"In MprAddConnectNotify\n");
  303. ASSERT_INITIALIZED(NOTIFIEE);
  304. //
  305. // Save away the pointer to the array of context information.
  306. //
  307. ContextInfo = (PVOID *) lpNotifyInfo->lpContext;
  308. for (i=0; i<numNotifyees; i++,NotifyEntry++ )
  309. {
  310. if (lpNotifyInfo->dwNotifyStatus == NOTIFY_POST)
  311. {
  312. if (ContextInfo && ContextInfo[i] != NULL)
  313. {
  314. lpNotifyInfo->lpContext = ContextInfo[i];
  315. }
  316. else
  317. {
  318. //
  319. // Don't notify if it is a POST notification, and there
  320. // is no context saved. Here we go directly to the next
  321. // notifyee (or out of the for loop).
  322. //
  323. continue;
  324. }
  325. }
  326. status = NotifyEntry->PF_AddConnectNotify(lpNotifyInfo,lpAddInfo);
  327. switch (status) {
  328. case WN_SUCCESS:
  329. MPR_LOG0(CNOTIFY,"AddConnectNotify SUCCESS\n");
  330. if (ContextInfo != NULL)
  331. {
  332. ContextInfo[i] = lpNotifyInfo->lpContext;
  333. }
  334. break;
  335. case WN_CANCEL:
  336. MPR_LOG0(CNOTIFY,"AddConnectNotify WN_CANCEL\n");
  337. //
  338. // CANCEL shouldn't be returned from NOTIFY_POST calls.
  339. //
  340. if (lpNotifyInfo->dwNotifyStatus == NOTIFY_PRE) {
  341. //
  342. // If we got the cancel for the first notifyee, then we can
  343. // stop here.
  344. //
  345. if (i == 0) {
  346. lpNotifyInfo->lpContext = ContextInfo;
  347. return(status);
  348. }
  349. //
  350. // If we have already successfully called some notifyees, then we
  351. // must now post notify them of the cancel.
  352. //
  353. numNotifyees = i;
  354. lpNotifyInfo->dwNotifyStatus = NOTIFY_POST;
  355. i = 0xffffffff;
  356. }
  357. break;
  358. case WN_RETRY:
  359. MPR_LOG0(CNOTIFY,"AddConnectNotify WN_RETRY\n");
  360. //
  361. // RETRY is only valid if the operation failed and
  362. // this is a post notification.
  363. //
  364. if ((lpNotifyInfo->dwOperationStatus != WN_SUCCESS) &&
  365. (lpNotifyInfo->dwNotifyStatus == NOTIFY_POST)) {
  366. retryFlag = TRUE;
  367. if (ContextInfo != NULL)
  368. {
  369. ContextInfo[i] = lpNotifyInfo->lpContext;
  370. }
  371. //
  372. // If we need to retry, then we must now pre-notify those
  373. // notifyees that we have already post-notified. We don't
  374. // want to post-notify any more notifyees.
  375. //
  376. if (i > 0) {
  377. numNotifyees = i;
  378. lpNotifyInfo->dwNotifyStatus = NOTIFY_PRE;
  379. i = 0xffffffff;
  380. }
  381. }
  382. break;
  383. default:
  384. MPR_LOG1(CNOTIFY,"AddConnectNotify returned an error %d\n",status);
  385. lastError = status;
  386. break;
  387. }
  388. }
  389. //
  390. // Restore the pointer to the array of context information.
  391. //
  392. lpNotifyInfo->lpContext = ContextInfo;
  393. //
  394. // No matter if other error occured, if one of the notifyees wants
  395. // a retry, we will return retry.
  396. //
  397. if (retryFlag == TRUE) {
  398. return(WN_RETRY);
  399. }
  400. return(lastError);
  401. }
  402. DWORD
  403. MprCancelConnectNotify(
  404. LPNOTIFYINFO lpNotifyInfo,
  405. LPNOTIFYCANCEL lpCancelInfo
  406. )
  407. /*++
  408. Routine Description:
  409. Arguments:
  410. Return Value:
  411. --*/
  412. {
  413. DWORD i;
  414. DWORD status;
  415. DWORD lastError=WN_SUCCESS;
  416. BOOL retryFlag=FALSE;
  417. DWORD numNotifyees = GlobalNumNotifyees;
  418. PVOID *ContextInfo;
  419. LPNOTIFYEE NotifyEntry=NotifyList;
  420. MPR_LOG0(CNOTIFY,"In MprCancelConnectNotify\n");
  421. ASSERT_INITIALIZED(NOTIFIEE);
  422. //
  423. // Save away the pointer to the array of context information.
  424. //
  425. ContextInfo = (PVOID *) lpNotifyInfo->lpContext;
  426. for (i=0; i<numNotifyees; i++,NotifyEntry++)
  427. {
  428. if (lpNotifyInfo->dwNotifyStatus == NOTIFY_POST)
  429. {
  430. if (ContextInfo && ContextInfo[i] != NULL)
  431. {
  432. lpNotifyInfo->lpContext = ContextInfo[i];
  433. }
  434. else
  435. {
  436. //
  437. // Don't notify if it is a POST notification, and there
  438. // is no context saved. Here we go directly to the next
  439. // notifyee (or out of the for loop).
  440. //
  441. continue;
  442. }
  443. }
  444. status = NotifyEntry->PF_CancelConnectNotify(lpNotifyInfo,lpCancelInfo);
  445. switch (status) {
  446. case WN_SUCCESS:
  447. MPR_LOG0(CNOTIFY,"CancelConnectNotify SUCCESS\n");
  448. if (ContextInfo != NULL)
  449. {
  450. ContextInfo[i] = lpNotifyInfo->lpContext;
  451. }
  452. break;
  453. case WN_CANCEL:
  454. MPR_LOG0(CNOTIFY,"CancelConnectNotify WN_CANCEL\n");
  455. //
  456. // It is assumed that CANCEL won't be returned from
  457. // NOTIFY_POST calls.
  458. //
  459. // If we got the cancel for the first notifyee, then we can
  460. // stop here.
  461. //
  462. if (i == 0) {
  463. lpNotifyInfo->lpContext = ContextInfo;
  464. return(status);
  465. }
  466. //
  467. // If we have already successfully called some notifyees, then we
  468. // must now post notify them of the cancel.
  469. //
  470. numNotifyees = i;
  471. lpNotifyInfo->dwNotifyStatus = NOTIFY_POST;
  472. i = 0xffffffff;
  473. break;
  474. case WN_RETRY:
  475. MPR_LOG0(CNOTIFY,"CancelConnectNotify WN_RETRY\n");
  476. retryFlag = TRUE;
  477. if (ContextInfo != NULL)
  478. {
  479. ContextInfo[i] = lpNotifyInfo->lpContext;
  480. }
  481. break;
  482. default:
  483. MPR_LOG1(CNOTIFY,"CancelConnectNotify returned an error %d\n",status);
  484. lastError = status;
  485. break;
  486. }
  487. }
  488. //
  489. // Restore the pointer to the array of context information.
  490. //
  491. lpNotifyInfo->lpContext = ContextInfo;
  492. //
  493. // No matter if other error occured, if one of the notifyees wants
  494. // a retry, we will return retry.
  495. //
  496. if (retryFlag == TRUE) {
  497. return(WN_RETRY);
  498. }
  499. return(lastError);
  500. }