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.

783 lines
15 KiB

  1. /*****************************************************************/
  2. /** Copyright(c) 1989 Microsoft Corporation. **/
  3. /*****************************************************************/
  4. //***
  5. //
  6. // Filename: init.c
  7. //
  8. // Description: This module contains initialization code for the print
  9. // monitor.
  10. //
  11. // In addition there are the ReadThread and the CaptureThread
  12. // functions.
  13. //
  14. // The following are the functions contained in this module.
  15. // All these functions are exported.
  16. //
  17. // LibMain
  18. // InitializeMonitor
  19. // ReadThread
  20. // CaptureThread
  21. //
  22. //
  23. // History:
  24. //
  25. // Aug 26,1992 frankb Initial version
  26. // June 11,1993. NarenG Bug fixes/clean up
  27. //
  28. #include <windows.h>
  29. #include <winspool.h>
  30. #include <winsplp.h>
  31. #include <winsock.h>
  32. #include <atalkwsh.h>
  33. #include <stdlib.h>
  34. #include <stdio.h>
  35. #include <string.h>
  36. #include <lmcons.h>
  37. #include <prtdefs.h>
  38. #ifdef FE_SB
  39. #include <locale.h>
  40. #endif /* FE_SB */
  41. #define ALLOCATE
  42. #include "atalkmon.h"
  43. #include "atmonmsg.h"
  44. #include <bltrc.h>
  45. #include "dialogs.h"
  46. //**
  47. //
  48. // Call: LibMain
  49. //
  50. // Returns: TRUE - Success
  51. // FALSE - Failure
  52. //
  53. // Description:
  54. // This routine is called when a process attaches
  55. // or detaches from the AppleTalk Monitor. On process attach,
  56. // we save the module handle in the global hInst (we assume that
  57. // only one process will attach to the monitor)
  58. //
  59. // On process detach, we free any system resources we've allocated.
  60. //
  61. BOOL LibMain(
  62. IN HANDLE hModule,
  63. IN DWORD dwReason,
  64. IN LPVOID lpRes
  65. )
  66. {
  67. UNREFERENCED_PARAMETER(lpRes);
  68. switch(dwReason)
  69. {
  70. case DLL_PROCESS_ATTACH:
  71. #ifdef FE_SB
  72. setlocale( LC_ALL, "" );
  73. #endif
  74. //
  75. // Save the instance handle
  76. //
  77. hInst = hModule;
  78. break;
  79. case DLL_PROCESS_DETACH:
  80. //
  81. // Stop the Capture and I/O threads
  82. //
  83. boolExitThread = TRUE;
  84. //
  85. // Release global resources
  86. //
  87. if (hkeyPorts != NULL)
  88. RegCloseKey(hkeyPorts);
  89. if (hevConfigChange != NULL)
  90. {
  91. SetEvent(hevConfigChange);
  92. CloseHandle(hevConfigChange);
  93. }
  94. if (hevPrimeRead != NULL)
  95. {
  96. SetEvent(hevPrimeRead);
  97. CloseHandle(hevPrimeRead);
  98. }
  99. if (hCapturePrinterThread != NULL)
  100. {
  101. WaitForSingleObject(hCapturePrinterThread, ATALKMON_DEFAULT_TIMEOUT);
  102. CloseHandle(hCapturePrinterThread);
  103. }
  104. if (hReadThread != NULL)
  105. {
  106. WaitForSingleObject(hReadThread, ATALKMON_DEFAULT_TIMEOUT);
  107. CloseHandle(hReadThread);
  108. }
  109. if (hmutexPortList != NULL)
  110. CloseHandle(hmutexPortList);
  111. if (hmutexDeleteList != NULL)
  112. CloseHandle(hmutexDeleteList);
  113. //
  114. // Release Windows Sockets
  115. //
  116. WSACleanup();
  117. break;
  118. default:
  119. break;
  120. }
  121. return(TRUE);
  122. }
  123. //**
  124. //
  125. // Call: InitializeMonitor
  126. //
  127. // Returns: TRUE - Success
  128. // FALSE - Failure
  129. //
  130. // Description:
  131. // This routine is called when the spooler starts up.
  132. // We allocate per port resources by reading the current port
  133. // list from the registry.
  134. //
  135. BOOL
  136. InitializeMonitor(
  137. IN LPWSTR pszRegistryRoot
  138. )
  139. {
  140. LPWSTR lpwsPortsKeyPath;
  141. DWORD dwRetCode = NO_ERROR;
  142. DWORD tid;
  143. DWORD RegFilter;
  144. DWORD dwValueType;
  145. DWORD dwDisposition;
  146. WSADATA WsaData;
  147. DWORD dwNameLen;
  148. DBGPRINT (("sfmmon: InitializeMonitor: Entered Initialize Monitor\n"));
  149. //
  150. // Resource clean-up 'loop'
  151. //
  152. do
  153. {
  154. //
  155. // Setup the event log
  156. //
  157. hEventLog = RegisterEventSource(NULL, ATALKMON_EVENT_SOURCE);
  158. lpwsPortsKeyPath = (LPWSTR)LocalAlloc(LPTR,
  159. sizeof(WCHAR)*((wcslen(pszRegistryRoot)+1) +
  160. (wcslen(ATALKMON_PORTS_SUBKEY)+1)));
  161. if (lpwsPortsKeyPath == NULL)
  162. {
  163. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  164. break ;
  165. }
  166. wcscpy(lpwsPortsKeyPath, pszRegistryRoot);
  167. wcscat(lpwsPortsKeyPath, ATALKMON_PORTS_SUBKEY);
  168. //
  169. // Open the ports key
  170. //
  171. if ((dwRetCode = RegCreateKeyEx(
  172. HKEY_LOCAL_MACHINE,
  173. lpwsPortsKeyPath,
  174. 0,
  175. TEXT(""),
  176. REG_OPTION_NON_VOLATILE,
  177. KEY_READ | KEY_WRITE,
  178. NULL,
  179. &hkeyPorts,
  180. &dwDisposition)) != ERROR_SUCCESS)
  181. {
  182. DBGPRINT(("ERROR:Can't open Ports registry key %d\n",dwRetCode));
  183. break ;
  184. }
  185. //
  186. // Query the filter option, if specified. By default it is on.
  187. //
  188. dwNameLen = sizeof(RegFilter);
  189. dwRetCode = RegQueryValueEx(hkeyPorts,
  190. ATALKMON_FILTER_VALUE,
  191. NULL,
  192. &dwValueType,
  193. (PUCHAR)&RegFilter,
  194. &dwNameLen);
  195. if (dwRetCode == 0)
  196. {
  197. Filter = (RegFilter != 0);
  198. }
  199. #ifdef DEBUG_MONITOR
  200. {
  201. HKEY hkeyAtalkmonRoot;
  202. HKEY hkeyOptions;
  203. LPWSTR pszLogPath = NULL ;
  204. DWORD cbLogPath = 0 ;
  205. if ((dwRetCode = RegCreateKeyEx(
  206. HKEY_LOCAL_MACHINE,
  207. pszRegistryRoot,
  208. 0,
  209. L"",
  210. REG_OPTION_NON_VOLATILE,
  211. KEY_ALL_ACCESS,
  212. NULL,
  213. &hkeyAtalkmonRoot,
  214. &dwDisposition)) != ERROR_SUCCESS)
  215. {
  216. break ;
  217. }
  218. //
  219. // get Options subkey
  220. //
  221. if ((dwRetCode = RegCreateKeyEx(
  222. hkeyAtalkmonRoot,
  223. ATALKMON_OPTIONS_SUBKEY,
  224. 0,
  225. L"",
  226. REG_OPTION_NON_VOLATILE,
  227. KEY_READ,
  228. NULL,
  229. &hkeyOptions,
  230. &dwDisposition)) != ERROR_SUCCESS)
  231. {
  232. break ;
  233. }
  234. RegCloseKey(hkeyAtalkmonRoot) ;
  235. //
  236. // setup the log file if we have one
  237. //
  238. RegQueryValueEx(
  239. hkeyOptions,
  240. ATALKMON_LOGFILE_VALUE,
  241. NULL,
  242. &dwValueType,
  243. (LPBYTE) pszLogPath,
  244. &cbLogPath) ;
  245. if (cbLogPath > 0) {
  246. pszLogPath = LocalAlloc(LPTR, cbLogPath * sizeof(WCHAR)) ;
  247. if (pszLogPath == NULL) {
  248. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  249. break ;
  250. }
  251. }
  252. if ((dwRetCode = RegQueryValueEx(
  253. hkeyOptions,
  254. ATALKMON_LOGFILE_VALUE,
  255. NULL,
  256. &dwValueType,
  257. (LPBYTE) pszLogPath,
  258. &cbLogPath)) == ERROR_SUCCESS)
  259. {
  260. //
  261. // open the log file
  262. //
  263. hLogFile = CreateFile(
  264. pszLogPath,
  265. GENERIC_WRITE,
  266. FILE_SHARE_READ,
  267. NULL,
  268. CREATE_ALWAYS,
  269. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
  270. NULL) ;
  271. }
  272. DBGPRINT(("ATALKMON LOG FLE OPENED\n\n")) ;
  273. }
  274. #endif
  275. //
  276. // initialize global variables
  277. //
  278. pPortList = NULL;
  279. pDeleteList = NULL;
  280. if ((hmutexBlt = CreateMutex(NULL, FALSE, NULL)) == NULL)
  281. {
  282. dwRetCode = GetLastError();
  283. break;
  284. }
  285. if ((hmutexPortList = CreateMutex(NULL, FALSE, NULL)) == NULL)
  286. {
  287. dwRetCode = GetLastError();
  288. break;
  289. }
  290. if ((hmutexDeleteList = CreateMutex(NULL, FALSE, NULL)) == NULL)
  291. {
  292. dwRetCode = GetLastError();
  293. break;
  294. }
  295. //
  296. // This event should be reset automatically and created signalled
  297. // so that the config thread will capture printers on startup instead
  298. // of waiting for the capture interval
  299. //
  300. if ((hevConfigChange = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
  301. {
  302. dwRetCode = GetLastError();
  303. DBGPRINT(("sfmmon: InitializeMonitor: Error in hevConfigChange creation\n"));
  304. break;
  305. }
  306. //
  307. // This event should be reset automatically and created not signalled.
  308. // StartDocPort will signal this event when a job is started, and
  309. // WritePort() will signal the event anytime it wants to post another
  310. // read on the job.
  311. //
  312. if ((hevPrimeRead = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
  313. {
  314. dwRetCode = GetLastError();
  315. DBGPRINT(("sfmmon: InitializeMonitor: Error in hevPrimeRead creation\n"));
  316. break ;
  317. }
  318. //
  319. // Get the local computer's name.
  320. //
  321. dwNameLen = MAX_ENTITY+1;
  322. if (!GetComputerNameA(chComputerName, &dwNameLen))
  323. {
  324. dwRetCode = GetLastError();
  325. DBGPRINT(("sfmmon: InitializeMonitor: Error in GetComputerNameA call\n"));
  326. break;
  327. }
  328. strcat(chComputerName, ATALKMON_CAPTURED_TYPE);
  329. //
  330. // initialize ports from registry
  331. //
  332. if ((dwRetCode = LoadAtalkmonRegistry(hkeyPorts)) != NO_ERROR)
  333. {
  334. ReportEvent(
  335. hEventLog,
  336. EVENTLOG_ERROR_TYPE,
  337. EVENT_CATEGORY_INTERNAL,
  338. EVENT_ATALKMON_REGISTRY_ERROR,
  339. NULL,
  340. 0,
  341. sizeof(DWORD),
  342. NULL,
  343. &dwRetCode);
  344. DBGPRINT(("sfmmon: InitializeMonitor: Error in LoadAtalkmonRegistry call\n"));
  345. break;
  346. }
  347. //
  348. // Load and store status strings
  349. //
  350. if ((!LoadString(GetModuleHandle(TEXT("SFMMON")),
  351. IDS_BUSY,
  352. wchBusy,
  353. STATUS_BUFFER_SIZE)) ||
  354. (!LoadString(GetModuleHandle(TEXT("SFMMON")),
  355. IDS_PRINTING,
  356. wchPrinting,
  357. STATUS_BUFFER_SIZE)) ||
  358. (!LoadString(GetModuleHandle(TEXT("SFMMON")),
  359. IDS_PRINTER_OFFLINE,
  360. wchPrinterOffline,
  361. STATUS_BUFFER_SIZE)) ||
  362. (!LoadString(GetModuleHandle(TEXT("SFMMON")),
  363. IDS_DLL_NAME,
  364. wchDllName,
  365. STATUS_BUFFER_SIZE)) ||
  366. (!LoadString(GetModuleHandle(TEXT("SFMMON")),
  367. IDS_PORT_DESCRIPTION,
  368. wchPortDescription,
  369. STATUS_BUFFER_SIZE)) ||
  370. (!LoadString(GetModuleHandle(TEXT("SFMMON")),
  371. IDS_ERROR,
  372. wchPrinterError,
  373. STATUS_BUFFER_SIZE)))
  374. {
  375. dwRetCode = GetLastError();
  376. DBGPRINT(("sfmmon: InitializeMonitor: Error in LoadString SFMMON call\n"));
  377. break;
  378. }
  379. //
  380. // Initialize Windows Sockets
  381. //
  382. if ((dwRetCode = WSAStartup(0x0101, &WsaData)) != NO_ERROR)
  383. {
  384. DBGPRINT(("WSAStartup fails with %d\n", dwRetCode)) ;
  385. ReportEvent(
  386. hEventLog,
  387. EVENTLOG_ERROR_TYPE,
  388. EVENT_CATEGORY_INTERNAL,
  389. EVENT_ATALKMON_WINSOCK_ERROR,
  390. NULL,
  391. 0,
  392. sizeof(DWORD),
  393. NULL,
  394. &dwRetCode);
  395. DBGPRINT(("sfmmon: InitializeMonitor: Error in WSAStartup call\n"));
  396. break;
  397. }
  398. //
  399. // Start watchdog thread to keep printers captured
  400. //
  401. hCapturePrinterThread = CreateThread(
  402. NULL,
  403. 0,
  404. CapturePrinterThread,
  405. NULL,
  406. 0,
  407. &tid);
  408. if (hCapturePrinterThread == NULL)
  409. {
  410. dwRetCode = GetLastError();
  411. DBGPRINT(("sfmmon: InitializeMonitor: Error in CapturePrinterThread call\n"));
  412. break ;
  413. }
  414. //
  415. // Start an I/O thread to prime reads from
  416. //
  417. hReadThread = CreateThread( NULL,
  418. 0,
  419. ReadThread,
  420. NULL,
  421. 0,
  422. &tid);
  423. if (hReadThread == NULL)
  424. {
  425. dwRetCode = GetLastError();
  426. DBGPRINT(("sfmmon: InitializeMonitor: Error in PrimeReadThreadcreation call\n"));
  427. break;
  428. }
  429. } while(FALSE);
  430. if (lpwsPortsKeyPath != NULL)
  431. LocalFree(lpwsPortsKeyPath);
  432. if (dwRetCode != NO_ERROR)
  433. {
  434. if (hkeyPorts != NULL)
  435. {
  436. RegCloseKey(hkeyPorts);
  437. hkeyPorts=NULL;
  438. }
  439. if (hevConfigChange != NULL)
  440. {
  441. CloseHandle(hevConfigChange);
  442. hevConfigChange=NULL;
  443. }
  444. if (hevPrimeRead != NULL)
  445. {
  446. CloseHandle(hevPrimeRead);
  447. hevPrimeRead=NULL;
  448. }
  449. if (hmutexPortList != NULL)
  450. {
  451. CloseHandle(hmutexPortList);
  452. hmutexPortList=NULL;
  453. }
  454. if (hmutexDeleteList != NULL)
  455. {
  456. CloseHandle(hmutexDeleteList);
  457. hmutexDeleteList=NULL;
  458. }
  459. if (hmutexBlt != NULL)
  460. {
  461. CloseHandle(hmutexBlt);
  462. hmutexBlt=NULL;
  463. }
  464. ReportEvent(
  465. hEventLog,
  466. EVENTLOG_ERROR_TYPE,
  467. EVENT_CATEGORY_INTERNAL,
  468. EVENT_ATALKMON_REGISTRY_ERROR,
  469. NULL,
  470. 0,
  471. sizeof(DWORD),
  472. NULL,
  473. &dwRetCode);
  474. DBGPRINT(("sfmmon: Initialize Monitor was unsuccessful\n"));
  475. return(FALSE);
  476. }
  477. DBGPRINT(("sfmmon: Initialize Monitor was successful\n"));
  478. return(TRUE);
  479. }
  480. //**
  481. //
  482. // Call: CapturePrinterThread
  483. //
  484. // Returns:
  485. //
  486. // Description:
  487. //
  488. // This is the tread routine for the thread that monitors
  489. // Appletalk printers to insure that they remain in the configured
  490. // state (captured or not). It waits on an event with a timeout where
  491. // the event is signalled whenever the configuration of an Appletalk
  492. // printer is changed through the NT print manager. When the wait
  493. // completes, it walks the list of known Appletalk printers and does
  494. // an NBP lookup for the printer in the expected state. If the lookup
  495. // fails, it does another lookup for the printer in the opposite state.
  496. // If it finds the printer in the wrong state, it sends a job to change
  497. // the NBP name of the printer.
  498. //
  499. // NOTE: The spooler recognizes when it has no printers configured
  500. // to use a port, and calls ClosePort at that time. If someone
  501. // creates a printer to use a port, it then calls OpenPort.
  502. // Capturing of printers should only happen for Open ports,
  503. // so we keep a status of the port state and only do captures
  504. // on Open ports.
  505. //
  506. DWORD
  507. CapturePrinterThread(
  508. IN LPVOID pParameterBlock
  509. )
  510. {
  511. PATALKPORT pWalker;
  512. BOOL fCapture;
  513. BOOL fIsSpooler;
  514. DWORD dwIndex;
  515. DWORD dwCount;
  516. DBGPRINT(("Enter CapturePrinterThread\n")) ;
  517. while (!boolExitThread)
  518. {
  519. //
  520. // wait for timeout or a configuration change via ConfigPort.
  521. // Also, this thread will post any reads for the monitor since
  522. // asynch I/O must be handled by a thread that does not die, and
  523. // the monitor threads are all RPC threads which are only
  524. // guaranteed to be around for the duration of the function call.
  525. //
  526. DBGPRINT(("waiting for config event\n")) ;
  527. WaitForSingleObject(hevConfigChange, CONFIG_TIMEOUT);
  528. DBGPRINT(("config event or timeout occurs\n")) ;
  529. //
  530. // Delete and release ports that are pending delete.
  531. //
  532. do
  533. {
  534. WaitForSingleObject(hmutexDeleteList, INFINITE);
  535. if (pDeleteList != NULL)
  536. {
  537. pWalker = pDeleteList;
  538. pDeleteList = pDeleteList->pNext;
  539. ReleaseMutex(hmutexDeleteList);
  540. }
  541. else
  542. {
  543. ReleaseMutex(hmutexDeleteList);
  544. break;
  545. }
  546. //
  547. // If this is a spooler don't bother.
  548. //
  549. if (!(pWalker->fPortFlags & SFM_PORT_IS_SPOOLER))
  550. CapturePrinter(pWalker, FALSE);
  551. FreeAppleTalkPort(pWalker);
  552. } while(TRUE);
  553. //
  554. // Recapture or rerelease printers that have been power cycled
  555. //
  556. WaitForSingleObject(hmutexPortList, INFINITE);
  557. dwIndex = 0;
  558. do
  559. {
  560. //
  561. // Go to the ith element
  562. //
  563. for (dwCount = 0, pWalker = pPortList;
  564. ((pWalker != NULL) && (dwCount < dwIndex));
  565. pWalker = pWalker->pNext, dwCount++)
  566. ;
  567. if (pWalker == NULL)
  568. {
  569. ReleaseMutex(hmutexPortList);
  570. break;
  571. }
  572. //
  573. // Do not muck with the port if a job is using it
  574. //
  575. if (!(pWalker->fPortFlags & SFM_PORT_IN_USE) &&
  576. ((pWalker->fPortFlags & SFM_PORT_OPEN) ||
  577. (pWalker->fPortFlags & SFM_PORT_CLOSE_PENDING)))
  578. {
  579. fCapture = pWalker->fPortFlags & SFM_PORT_CAPTURED;
  580. fIsSpooler = pWalker->fPortFlags & SFM_PORT_IS_SPOOLER;
  581. if (pWalker->fPortFlags & SFM_PORT_CLOSE_PENDING)
  582. pWalker->fPortFlags &= ~SFM_PORT_CLOSE_PENDING;
  583. ReleaseMutex(hmutexPortList);
  584. //
  585. // If this is a spooler do not muck with it
  586. //
  587. if (!fIsSpooler)
  588. {
  589. //
  590. // Try to grab the port for capturing
  591. //
  592. if (WaitForSingleObject(pWalker->hmutexPort, 1) == WAIT_OBJECT_0)
  593. {
  594. CapturePrinter(pWalker, fCapture);
  595. ReleaseMutex(pWalker->hmutexPort);
  596. }
  597. }
  598. WaitForSingleObject(hmutexPortList, INFINITE);
  599. }
  600. dwIndex++;
  601. } while(TRUE);
  602. }
  603. return(NO_ERROR);
  604. }
  605. //**
  606. //
  607. // Call: ReadThread
  608. //
  609. // Returns:
  610. //
  611. // Description:
  612. //
  613. DWORD
  614. ReadThread(
  615. IN LPVOID pParameterBlock
  616. ){
  617. PATALKPORT pWalker;
  618. //
  619. // This thread goes 'till boolExitThread is set
  620. //
  621. while(!boolExitThread)
  622. {
  623. //
  624. // wait for a signal to do I/O
  625. // Wait here in an alertable fashion. This is needed so that the prime-read
  626. // apc's can be delivered to us.
  627. if (WaitForSingleObjectEx(hevPrimeRead, INFINITE, TRUE) == WAIT_IO_COMPLETION)
  628. continue;
  629. DBGPRINT(("received signal to read/close\n")) ;
  630. //
  631. // for each port in our list
  632. //
  633. WaitForSingleObject(hmutexPortList, INFINITE);
  634. for (pWalker = pPortList; pWalker != NULL; pWalker=pWalker->pNext)
  635. {
  636. if ((pWalker->fPortFlags & (SFM_PORT_IN_USE | SFM_PORT_POST_READ)) ==
  637. (SFM_PORT_POST_READ | SFM_PORT_IN_USE))
  638. {
  639. DBGPRINT(("prime read for port %ws\n", pWalker->pPortName)) ;
  640. setsockopt(pWalker->sockIo,
  641. SOL_APPLETALK,
  642. SO_PAP_PRIME_READ,
  643. pWalker->pReadBuffer,
  644. PAP_DEFAULT_BUFFER);
  645. pWalker->fPortFlags &= ~SFM_PORT_POST_READ;
  646. }
  647. }
  648. ReleaseMutex(hmutexPortList);
  649. }
  650. return NO_ERROR;
  651. }