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.

466 lines
12 KiB

  1. /*++
  2. Copyright (c) 1990 - 1995 Microsoft Corporation
  3. Module Name:
  4. server.c
  5. Abstract:
  6. Browsing
  7. This module contains the thread for notifying all Printer Servers
  8. Author:
  9. Dave Snipp (DaveSn) 2-Aug-1992
  10. Revision History:
  11. --*/
  12. #include <precomp.h>
  13. #include <lm.h>
  14. DWORD ServerThreadRunning = FALSE;
  15. HANDLE ServerThreadSemaphore = NULL;
  16. DWORD ServerThreadTimeout = TEN_MINUTES;
  17. DWORD RefreshTimesPerDecayPeriod = DEFAULT_REFRESH_TIMES_PER_DECAY_PERIOD;
  18. DWORD BrowsePrintWorkstations = DEFAULT_NUMBER_BROWSE_WORKSTATIONS;
  19. BOOL bNetInfoReady = FALSE; // TRUE when the browse list is "valid"
  20. #define NT_SERVER ( SV_TYPE_SERVER_NT | SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_BAKCTRL )
  21. extern FARPROC pfnNetServerEnum;
  22. extern FARPROC pfnNetApiBufferFree;
  23. DWORD
  24. ServerThread(
  25. PVOID
  26. );
  27. BOOL
  28. UpdateServer(
  29. LPCTSTR pszServer
  30. );
  31. BOOL
  32. CreateServerThread(
  33. VOID
  34. )
  35. {
  36. HANDLE ThreadHandle;
  37. DWORD ThreadId;
  38. SplInSem();
  39. if (!ServerThreadRunning) {
  40. ServerThreadSemaphore = CreateEvent( NULL, FALSE, FALSE, NULL );
  41. ThreadHandle = CreateThread( NULL, INITIAL_STACK_COMMIT,
  42. (LPTHREAD_START_ROUTINE)ServerThread,
  43. NULL,
  44. 0, &ThreadId );
  45. if (!SetThreadPriority(ThreadHandle,
  46. dwServerThreadPriority))
  47. DBGMSG(DBG_WARNING, ("Setting thread priority failed %d\n",
  48. GetLastError()));
  49. ServerThreadRunning = TRUE;
  50. CloseHandle( ThreadHandle );
  51. }
  52. if( ServerThreadSemaphore != NULL ){
  53. // CreateServerThread is called each time a printer is shared out
  54. // see net.c ShareThisPrinter.
  55. // So if the ServerThread is sleeping wake prematurely so it can start
  56. // to tell the world about this new shared printer.
  57. SetEvent( ServerThreadSemaphore );
  58. }
  59. return TRUE;
  60. }
  61. DWORD
  62. ServerThread(
  63. PVOID pv
  64. )
  65. /*++
  66. Routine Description:
  67. Notify other machines in our domain about our shared printers.
  68. We are going to have to enter and leave, revalidate, enter and leave our
  69. semaphore inside the loop.
  70. Arguments:
  71. Return Value:
  72. --*/
  73. {
  74. DWORD NoReturned, i, Total;
  75. PSERVER_INFO_101 pserver_info_101;
  76. PINIPRINTER pIniPrinter;
  77. PINISPOOLER pIniSpooler;
  78. DWORD ReturnValue=FALSE;
  79. WCHAR ServerName[128];
  80. DWORD StartTickCount;
  81. DWORD TimeForAllServers;
  82. DWORD dwActualWaitTime = ServerThreadTimeout;
  83. UINT cPrintWorkstations;
  84. UINT cPrintServers;
  85. UINT cServersToInform;
  86. UINT cWorkStationsToInform;
  87. ServerName[0] = ServerName[1] = '\\';
  88. while (TRUE) {
  89. SplOutSem();
  90. DBGMSG( DBG_TRACE, ("ServerThread sleeping for %d\n", dwActualWaitTime));
  91. WaitForSingleObject( ServerThreadSemaphore, dwActualWaitTime );
  92. // Wait for a couple of minutes more to avoid the boot time crunch
  93. Sleep(TWO_MINUTES);
  94. if ( !ServerThreadRunning ) {
  95. return FALSE;
  96. }
  97. SPLASSERT( pfnNetServerEnum != NULL );
  98. if (!(*pfnNetServerEnum)(NULL, 101, (LPBYTE *)&pserver_info_101, -1,
  99. &NoReturned, &Total, SV_TYPE_PRINTQ_SERVER,
  100. NULL, NULL)) {
  101. EnterSplSem();
  102. StartTickCount = GetTickCount();
  103. //
  104. // 1 Master + 3 Backup + 1 Backup per 32 Printer Servers.
  105. //
  106. cServersToInform = DEFAULT_NUMBER_MASTER_AND_BACKUP + NoReturned/32 ;
  107. cWorkStationsToInform = BrowsePrintWorkstations;
  108. //
  109. // Count the NT Server and Workstation machines ( which have a printq )
  110. //
  111. for ( i = 0, cPrintServers = 0, cPrintWorkstations = 0;
  112. i < NoReturned;
  113. i++ ) {
  114. if ( pserver_info_101[i].sv101_type & NT_SERVER ) {
  115. cPrintServers++;
  116. } else if ( pserver_info_101[i].sv101_type & SV_TYPE_NT ) {
  117. cPrintWorkstations++;
  118. }
  119. }
  120. //
  121. // If there are no NT Servers to inform then up the number of Workstations
  122. //
  123. if ( cPrintServers == 0 ) {
  124. cWorkStationsToInform = max( cWorkStationsToInform, cServersToInform );
  125. cServersToInform = 0;
  126. } else if ( cPrintServers < cServersToInform ) {
  127. cWorkStationsToInform = max( cWorkStationsToInform, cServersToInform - cPrintServers );
  128. }
  129. DBGMSG( DBG_TRACE, ("ServerThread NetServerEnum returned %d printer servers will inform %d, workstations %d\n", NoReturned, cServersToInform, cWorkStationsToInform ));
  130. //
  131. // Loop Until we have informed the correct Number of WorkStations and Servers
  132. //
  133. for ( i = 0,
  134. cPrintServers = 0,
  135. cPrintWorkstations = 0;
  136. i < NoReturned &&
  137. ( cPrintServers < cServersToInform || cPrintWorkstations < cWorkStationsToInform );
  138. i++ ) {
  139. DBGMSG( DBG_TRACE, ("ServerThread Loop Count %d cPrintServer %d cServersToInform %d cPrintWorkstations %d cWorkStationsToInform %d\n",
  140. i, cPrintServers, cServersToInform, cPrintWorkstations, cWorkStationsToInform ));
  141. DBGMSG( DBG_TRACE, ("ServerThread %ws type %x\n",pserver_info_101[i].sv101_name, pserver_info_101[i].sv101_type ));
  142. if (( pserver_info_101[i].sv101_type & NT_SERVER ) ||
  143. ( pserver_info_101[i].sv101_type & SV_TYPE_NT && cPrintWorkstations < cWorkStationsToInform )) {
  144. StringCchPrintf(&ServerName[2], COUNTOF(ServerName) - 2, pserver_info_101[i].sv101_name);
  145. if( UpdateServer( ServerName )){
  146. // Servers are also counted as WorkStations
  147. cPrintWorkstations++;
  148. if ( pserver_info_101[i].sv101_type & NT_SERVER ) {
  149. cPrintServers++;
  150. }
  151. }
  152. }
  153. }
  154. TimeForAllServers = GetTickCount() - StartTickCount;
  155. DBGMSG( DBG_TRACE, ("ServerThread took %d milliseconds for %d Workstations %d Servers\n",
  156. TimeForAllServers, cPrintWorkstations, cPrintServers ));
  157. //
  158. // Calculate time to wait before we try again.
  159. //
  160. if ( NetPrinterDecayPeriod > TimeForAllServers ) {
  161. dwActualWaitTime = max( ServerThreadTimeout, ( NetPrinterDecayPeriod - TimeForAllServers ) / RefreshTimesPerDecayPeriod );
  162. } else {
  163. dwActualWaitTime = ServerThreadTimeout;
  164. }
  165. //
  166. // Remove WAS Shared Bits
  167. //
  168. //
  169. // Do this for all spoolers.
  170. //
  171. for( pIniSpooler = pLocalIniSpooler;
  172. pIniSpooler;
  173. pIniSpooler = pIniSpooler->pIniNextSpooler ){
  174. for ( pIniPrinter = pIniSpooler->pIniPrinter;
  175. pIniPrinter != NULL;
  176. pIniPrinter = pIniPrinter->pNext ) {
  177. SplInSem();
  178. pIniPrinter->Status &= ~PRINTER_WAS_SHARED;
  179. }
  180. }
  181. LeaveSplSem();
  182. (*pfnNetApiBufferFree)((LPVOID)pserver_info_101);
  183. }
  184. }
  185. return FALSE;
  186. }
  187. typedef struct _UPDATE_SERVER_MAP_DATA {
  188. LPCWSTR pszServer;
  189. BOOL bSuccessfulAdd;
  190. } UPDATE_SERVER_MAP_DATA, *PUPDATE_SERVER_MAP_DATA;
  191. BOOL
  192. UpdateServerPrinterMap(
  193. HANDLE h,
  194. PINIPRINTER pIniPrinter
  195. )
  196. /*++
  197. Routine Description:
  198. Update the a browser server with one pIniPrinter.
  199. Leaves Spooler Section--pIniPrinter may be invalid on return
  200. unless explicitly refcounted by callee.
  201. Arguments:
  202. pIniPrinter - Printer that should be sent to the server.
  203. pszServer - Server that needs to be updated.
  204. pbSuccessfulAdd - Indicates whether the add was successful.
  205. Return Value:
  206. Succes or failure?
  207. --*/
  208. {
  209. PUPDATE_SERVER_MAP_DATA pData = (PUPDATE_SERVER_MAP_DATA)h;
  210. WCHAR string[MAX_PRINTER_BROWSE_NAME];
  211. WCHAR Name[MAX_UNC_PRINTER_NAME];
  212. PRINTER_INFO_1 Printer1;
  213. HANDLE hPrinter;
  214. PINISPOOLER pIniSpooler;
  215. DWORD dwLastError;
  216. Printer1.Flags = 0;
  217. if (( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED ) ||
  218. ( pIniPrinter->Status & PRINTER_WAS_SHARED )) {
  219. //
  220. // Pass our Printer Attributes so that AddNetPrinter can remove
  221. // this printer from the browse list if it is not shared.
  222. //
  223. Printer1.Flags = pIniPrinter->Attributes | PRINTER_ATTRIBUTE_NETWORK;
  224. StringCchPrintf(string, COUNTOF(string), L"%ws\\%ws,%ws,%ws",
  225. pIniPrinter->pIniSpooler->pMachineName,
  226. pIniPrinter->pName,
  227. pIniPrinter->pIniDriver->pName,
  228. pIniPrinter->pLocation ? pIniPrinter->pLocation : L"");
  229. Printer1.pDescription = string;
  230. StringCchPrintf(Name, COUNTOF(Name), L"%ws\\%ws",
  231. pIniPrinter->pIniSpooler->pMachineName,
  232. pIniPrinter->pName);
  233. Printer1.pName = Name;
  234. Printer1.pComment = AllocSplStr(pIniPrinter->pComment);
  235. SplInSem();
  236. LeaveSplSem();
  237. //
  238. // Keep trying until the server is not Too Busy.
  239. //
  240. for ( hPrinter = NULL;
  241. hPrinter == NULL;
  242. Sleep( GetTickCount() & 0xfff ) ) {
  243. hPrinter = AddPrinter( (LPTSTR)pData->pszServer, 1, (LPBYTE)&Printer1 );
  244. dwLastError = GetLastError();
  245. if ( hPrinter == NULL && dwLastError != RPC_S_SERVER_TOO_BUSY ) {
  246. if ( dwLastError != ERROR_PRINTER_ALREADY_EXISTS ) {
  247. pData->bSuccessfulAdd = FALSE;
  248. }
  249. break;
  250. }
  251. }
  252. FreeSplStr(Printer1.pComment);
  253. if ( hPrinter != NULL ) {
  254. DBGMSG( DBG_TRACE,
  255. ( "ServerThread AddPrinter(%ws, %ws) hPrinter %x Flags %x OK\n",
  256. pData->pszServer, Printer1.pName, hPrinter, Printer1.Flags));
  257. ClosePrinter( hPrinter );
  258. }
  259. EnterSplSem();
  260. if ( hPrinter == NULL ) {
  261. if ( GetLastError() != ERROR_PRINTER_ALREADY_EXISTS ) {
  262. DBGMSG( DBG_TRACE,
  263. ( "ServerThread AddPrinter(%ws, 1) Flags %x failed %d\n",
  264. pData->pszServer, Printer1.Flags, GetLastError()));
  265. // Don't bother with this server if we get an error
  266. return FALSE;
  267. } else {
  268. //
  269. // 3.51 will return a NULL handle ( so it doesn't need closing
  270. // and ERROR_PRINTER_ALREADY_EXISTS on success ( see printer.c addnetprinter )
  271. //
  272. DBGMSG( DBG_TRACE,
  273. ( "pszServerThread AddPrinter(%ws, %ws) hPrinter %x Flags %x OK\n",
  274. pData->pszServer, Printer1.pName, hPrinter, Printer1.Flags));
  275. }
  276. }
  277. }
  278. return TRUE;
  279. }
  280. BOOL
  281. UpdateServerSpoolerMap(
  282. HANDLE h,
  283. PINISPOOLER pIniSpooler
  284. )
  285. {
  286. //
  287. // Do this only for spoolers that want this "feature."
  288. //
  289. if( pIniSpooler->SpoolerFlags & SPL_SERVER_THREAD ){
  290. RunForEachPrinter( pIniSpooler, h, UpdateServerPrinterMap );
  291. }
  292. return TRUE;
  293. }
  294. BOOL
  295. UpdateServer(
  296. LPCTSTR pszServer
  297. )
  298. /*++
  299. Routine Description:
  300. Update a server about all the printers on this node.
  301. Arguments:
  302. pszServer - Server to update in the form "\\server."
  303. Return Value:
  304. TRUE - Successfully added.
  305. FALSE - Not.
  306. --*/
  307. {
  308. UPDATE_SERVER_MAP_DATA Data;
  309. Data.bSuccessfulAdd = TRUE;
  310. Data.pszServer = pszServer;
  311. RunForEachSpooler( &Data, UpdateServerSpoolerMap );
  312. return Data.bSuccessfulAdd;
  313. }