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.

868 lines
18 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. svcapis.cxx
  5. Abstract:
  6. Contains code that implements the service location apis.
  7. Author:
  8. Madan Appiah (madana) 15-May-1995
  9. Environment:
  10. User Mode - Win32
  11. Revision History:
  12. --*/
  13. #include <svcloc.hxx>
  14. DWORD
  15. WINAPI
  16. INetDiscoverServers(
  17. IN ULONGLONG ServicesMask,
  18. IN DWORD WaitTime,
  19. OUT LPINET_SERVERS_LIST *ServersList
  20. )
  21. /*++
  22. Routine Description:
  23. This API discovers all servers on the network that support and run the
  24. internet services specified.
  25. This API is called by the client side code, such as the internet admin
  26. tool or wininet.dll.
  27. Arguments:
  28. SevicesMask : A bit mask that specifies to discover servers with the
  29. these services running.
  30. ex: 0x0000000E, will discovers all servers running any of the
  31. following services :
  32. 1. FTP_SERVICE
  33. 2. GOPHER_SERVICE
  34. 3. WEB_SERVICE
  35. DiscoverBindings : if this flag is set, this API talks to each of the
  36. discovered server and queries the services and bindings
  37. supported. If the flag is set to FALSE, it quickly returns with
  38. the list of servers only.
  39. WaitTime : Response wait time in secs. If this value is zero, it
  40. returns what ever discovered so far by the previous invocation of
  41. this APIs, otherwise it waits for the specified secs to collect
  42. responses from the servers.
  43. ServersList : Pointer to a location where the pointer to list of
  44. servers info is returned. The API allocates dynamic memory for
  45. this return data, the caller should free it by calling
  46. INetFreeDiscoverServerList after it has been used.
  47. Return Value:
  48. Windows Error Code.
  49. --*/
  50. {
  51. DWORD Error;
  52. BOOL SvcLockLocked = FALSE;
  53. //
  54. // WSAStartup().
  55. //
  56. LOCK_SVC_GLOBAL_DATA();
  57. SvcLockLocked = TRUE;
  58. if ( !GlobalWinsockStarted ) {
  59. Error = WSAStartup( WS_VERSION_REQUIRED, &GlobalWinsockStartupData );
  60. if( Error != ERROR_SUCCESS ) {
  61. goto Cleanup;
  62. }
  63. GlobalWinsockStarted = TRUE;
  64. }
  65. //
  66. // make a discovery message, if it is not made before.
  67. //
  68. Error = MakeClientQueryMesage( ServicesMask );
  69. if( Error != ERROR_SUCCESS ) {
  70. goto Cleanup;
  71. }
  72. //
  73. // now check to see the discovery is in progress.
  74. //
  75. DWORD EventState;
  76. EventState = WaitForSingleObject( GlobalDiscoveryInProgressEvent, 0 );
  77. switch( EventState ) {
  78. case WAIT_OBJECT_0:
  79. break;
  80. case WAIT_TIMEOUT:
  81. //
  82. // discovery is in progress.
  83. //
  84. if( WaitTime == 0 ) {
  85. //
  86. // the caller does not want to wait, return available data.
  87. //
  88. goto ProcessResponse;
  89. }
  90. //
  91. // wait until the discovery is done or the specified delay is
  92. // over. Release global lock before wait, otherwise it will
  93. // get into a dead lock.
  94. //
  95. UNLOCK_SVC_GLOBAL_DATA();
  96. SvcLockLocked = FALSE;
  97. EventState = WaitForSingleObject( GlobalDiscoveryInProgressEvent, WaitTime * 1000 );
  98. switch( EventState ) {
  99. case WAIT_OBJECT_0:
  100. case WAIT_TIMEOUT:
  101. goto ProcessResponse;
  102. default:
  103. Error = GetLastError();
  104. goto Cleanup;
  105. }
  106. default:
  107. Error = GetLastError();
  108. goto Cleanup;
  109. }
  110. //
  111. // now check to see we have done the discovery recently. if so, don't
  112. // do discovery again, just return the available data.
  113. //
  114. time_t CurrentTime;
  115. CurrentTime = time( NULL );
  116. if( CurrentTime <
  117. GlobalLastDiscoveryTime + INET_DISCOVERY_RETRY_TIMEOUT ) {
  118. goto ProcessResponse;
  119. }
  120. //
  121. // reset GlobalDiscoveryInProgressEvent to signal that discovery is in
  122. // progress.
  123. //
  124. if( !ResetEvent( GlobalDiscoveryInProgressEvent ) ) {
  125. Error = GetLastError();
  126. goto Cleanup;
  127. }
  128. UNLOCK_SVC_GLOBAL_DATA();
  129. SvcLockLocked = FALSE;
  130. //
  131. // send discovery query message to all IPX servers.
  132. //
  133. Error = DiscoverIpxServers( NULL );
  134. //
  135. // now send a message to IP servers.
  136. //
  137. DWORD Error1;
  138. if( GlobalPlatformType == VER_PLATFORM_WIN32_NT ) {
  139. Error1 = DiscoverIpServers( NULL );
  140. // discover using 1C group name.
  141. }
  142. else {
  143. Error1 = DiscoverNetBiosServers( NULL );
  144. // discover using 1C group name.
  145. }
  146. TcpsvcsDbgAssert( Error1 == ERROR_SUCCESS );
  147. //
  148. // if we have not successfully sent query message in either of the
  149. // protocol, simply bail out.
  150. //
  151. if( (Error != ERROR_SUCCESS) && (Error1 != ERROR_SUCCESS) ) {
  152. goto Cleanup;
  153. }
  154. if( GlobalPlatformType == VER_PLATFORM_WIN32s ) {
  155. //
  156. // for windows 3.1 we can't create thread so we discover in user
  157. // thread.
  158. //
  159. WaitTime = RESPONSE_WAIT_TIMEOUT;
  160. }
  161. if( WaitTime == 0 ) {
  162. //
  163. // if the client is not willing to wait, setup a thread that
  164. // receives query response.
  165. //
  166. LOCK_SVC_GLOBAL_DATA();
  167. SvcLockLocked = TRUE;
  168. if( GlobalCliDiscoverThreadHandle == NULL ) {
  169. DWORD ThreadId;
  170. GlobalCliDiscoverThreadHandle =
  171. CreateThread(
  172. NULL, // default security
  173. 0, // default stack size
  174. (LPTHREAD_START_ROUTINE)ServerDiscoverThread,
  175. NULL, // no parameter
  176. 0, // create flag, no suspend
  177. &ThreadId );
  178. if( GlobalCliDiscoverThreadHandle == NULL ) {
  179. Error = GetLastError();
  180. goto Cleanup;
  181. }
  182. }
  183. UNLOCK_SVC_GLOBAL_DATA();
  184. SvcLockLocked = FALSE;
  185. }
  186. else {
  187. //
  188. // Wait for WaitTime secs for query responses
  189. // to arrive.
  190. //
  191. Error = ReceiveResponses( (WORD)WaitTime, TRUE );
  192. if( Error != ERROR_SUCCESS ) {
  193. goto Cleanup;
  194. }
  195. }
  196. ProcessResponse:
  197. Error = ProcessDiscoveryResponses( ServicesMask, ServersList );
  198. if( Error != ERROR_SUCCESS ) {
  199. goto Cleanup;
  200. }
  201. //
  202. // done.
  203. //
  204. Error = ERROR_SUCCESS;
  205. Cleanup:
  206. if( SvcLockLocked ) {
  207. UNLOCK_SVC_GLOBAL_DATA();
  208. }
  209. return( Error );
  210. }
  211. DWORD
  212. WINAPI
  213. INetGetServerInfo(
  214. IN LPSTR ServerName,
  215. IN ULONGLONG ServicesMask,
  216. IN DWORD WaitTime,
  217. OUT LPINET_SERVER_INFO *ServerInfo
  218. )
  219. /*++
  220. Routine Description:
  221. This API returns the server info and a list of services supported by
  222. the server and lists of bindings supported by each of the services.
  223. Arguments:
  224. ServerName : name of the server whose info to be queried.
  225. ServicesMask : services to be queried
  226. WaitTime : Time in secs to wait.
  227. ServerInfo : pointer to a location where the pointer to the server
  228. info structure will be returned. The caller should call
  229. INetFreeServerInfo to free up the list after use.
  230. Return Value:
  231. Windows Error Code.
  232. --*/
  233. {
  234. DWORD Error;
  235. BOOL SvcLockLocked = FALSE;
  236. CHAR NBServerName[NETBIOS_NAME_LENGTH + 1];
  237. //
  238. // WSAStartup().
  239. //
  240. LOCK_SVC_GLOBAL_DATA();
  241. SvcLockLocked = TRUE;
  242. if ( !GlobalWinsockStarted ) {
  243. Error = WSAStartup( WS_VERSION_REQUIRED, &GlobalWinsockStartupData );
  244. if( Error != ERROR_SUCCESS ) {
  245. goto Cleanup;
  246. }
  247. GlobalWinsockStarted = TRUE;
  248. }
  249. //
  250. // make a discovery message, if it is not made before.
  251. //
  252. Error = MakeClientQueryMesage( ServicesMask );
  253. if( Error != ERROR_SUCCESS ) {
  254. goto Cleanup;
  255. }
  256. //
  257. // now check to see the discovery is in progress.
  258. //
  259. DWORD EventState;
  260. EventState = WaitForSingleObject( GlobalDiscoveryInProgressEvent, 0 );
  261. switch( EventState ) {
  262. case WAIT_OBJECT_0:
  263. break;
  264. case WAIT_TIMEOUT:
  265. //
  266. // discovery is in progress.
  267. //
  268. if( WaitTime == 0 ) {
  269. //
  270. // the caller does not want to wait, return available data.
  271. //
  272. goto GetServerResponse;
  273. }
  274. //
  275. // wait until the discovery is done or the specified delay is
  276. // over. Release global lock before wait, otherwise it will
  277. // get into a dead lock.
  278. //
  279. UNLOCK_SVC_GLOBAL_DATA();
  280. SvcLockLocked = FALSE;
  281. EventState = WaitForSingleObject( GlobalDiscoveryInProgressEvent, WaitTime * 1000 );
  282. switch( EventState ) {
  283. case WAIT_OBJECT_0:
  284. case WAIT_TIMEOUT:
  285. goto GetServerResponse;
  286. default:
  287. Error = GetLastError();
  288. goto Cleanup;
  289. }
  290. default:
  291. Error = GetLastError();
  292. goto Cleanup;
  293. }
  294. //
  295. // now check to see we have done the discovery recently. if so, don't
  296. // do discovery again, just return the available data.
  297. //
  298. time_t CurrentTime;
  299. CurrentTime = time( NULL );
  300. if( CurrentTime <
  301. GlobalLastDiscoveryTime + INET_DISCOVERY_RETRY_TIMEOUT ) {
  302. goto GetServerResponse;
  303. }
  304. //
  305. // reset GlobalDiscoveryInProgressEvent to signal that discovery is in
  306. // progress.
  307. //
  308. if( !ResetEvent( GlobalDiscoveryInProgressEvent ) ) {
  309. Error = GetLastError();
  310. goto Cleanup;
  311. }
  312. UNLOCK_SVC_GLOBAL_DATA();
  313. SvcLockLocked = FALSE;
  314. //
  315. // upper case the server name.
  316. //
  317. _strupr( ServerName );
  318. //
  319. // make unique server name.
  320. //
  321. MakeUniqueServerName(
  322. (LPBYTE)NBServerName,
  323. NETBIOS_NAME_LENGTH,
  324. ServerName );
  325. //
  326. // terminate the string.
  327. //
  328. NBServerName[ NETBIOS_NAME_LENGTH ] = '\0';
  329. //
  330. // send discovery query message to all IPX servers.
  331. //
  332. Error = DiscoverIpxServers( ServerName );
  333. //
  334. // now send a message to IP servers.
  335. //
  336. DWORD Error1;
  337. if( GlobalPlatformType == VER_PLATFORM_WIN32_NT ) {
  338. Error1 = DiscoverIpServers( NBServerName );
  339. // discover using specified server name.
  340. }
  341. else {
  342. Error1 = DiscoverNetBiosServers( NBServerName );
  343. // discover using specified server name.
  344. }
  345. TcpsvcsDbgAssert( Error1 == ERROR_SUCCESS );
  346. //
  347. // if we have successfully sent query message in either of the
  348. // protocol, simply bail out.
  349. //
  350. if( (Error != ERROR_SUCCESS) && (Error1 != ERROR_SUCCESS) ) {
  351. goto Cleanup;
  352. }
  353. if( WaitTime == 0 ) {
  354. //
  355. // if the client is not willing to wait, setup a thread that
  356. // receives query response.
  357. //
  358. LOCK_SVC_GLOBAL_DATA();
  359. SvcLockLocked = TRUE;
  360. if( GlobalCliDiscoverThreadHandle == NULL ) {
  361. DWORD ThreadId;
  362. GlobalCliDiscoverThreadHandle =
  363. CreateThread(
  364. NULL, // default security
  365. 0, // default stack size
  366. (LPTHREAD_START_ROUTINE)ServerDiscoverThread,
  367. NULL, // no parameter
  368. 0, // create flag, no suspend
  369. &ThreadId );
  370. if( GlobalCliDiscoverThreadHandle == NULL ) {
  371. Error = GetLastError();
  372. goto Cleanup;
  373. }
  374. }
  375. UNLOCK_SVC_GLOBAL_DATA();
  376. SvcLockLocked = FALSE;
  377. }
  378. else {
  379. //
  380. // Wait for WaitTime secs for query responses
  381. // to arrive.
  382. //
  383. Error = ReceiveResponses( (WORD)WaitTime, FALSE );
  384. if( Error != ERROR_SUCCESS ) {
  385. goto Cleanup;
  386. }
  387. }
  388. GetServerResponse:
  389. Error = GetDiscoveredServerInfo( ServerName, ServicesMask, ServerInfo );
  390. if( Error != ERROR_SUCCESS ) {
  391. goto Cleanup;
  392. }
  393. //
  394. // done.
  395. //
  396. Error = ERROR_SUCCESS;
  397. Cleanup:
  398. if( SvcLockLocked ) {
  399. UNLOCK_SVC_GLOBAL_DATA();
  400. }
  401. return( Error );
  402. }
  403. VOID
  404. WINAPI
  405. INetFreeDiscoverServersList(
  406. IN OUT LPINET_SERVERS_LIST *ServersList
  407. )
  408. /*++
  409. Routine Description:
  410. This API frees the memory chunks that were allotted for the servers
  411. list by the INetDiscoverServers call.
  412. Arguments:
  413. ServersList : pointer to a location where the pointer to the server
  414. list to be freed is stored.
  415. Return Value:
  416. NONE.
  417. --*/
  418. {
  419. FreeServersList( *ServersList );
  420. *ServersList = NULL;
  421. return;
  422. }
  423. VOID
  424. WINAPI
  425. INetFreeServerInfo(
  426. IN OUT LPINET_SERVER_INFO *ServerInfo
  427. )
  428. /*++
  429. Routine Description:
  430. This API frees the memory chunks that were allotted for the server
  431. info structure by the INetGetServerInfo call.
  432. Arguments:
  433. ServerInfo : pointer to a location where the pointer to the server
  434. info structure to be freed is stored.
  435. Return Value:
  436. NONE.
  437. --*/
  438. {
  439. FreeServerInfo( *ServerInfo );
  440. *ServerInfo = NULL;
  441. return;
  442. }
  443. DWORD
  444. WINAPI
  445. INetRegisterService(
  446. IN ULONGLONG ServiceMask,
  447. IN INET_SERVICE_STATE ServiceState,
  448. IN LPSTR ServiceComment,
  449. IN LPINET_BINDINGS Bindings
  450. )
  451. /*++
  452. Routine Description:
  453. This API registers an internet service. The service writers should
  454. call this API just after successfully started the service and the
  455. service is ready to accept incoming RPC calls. This API accepts an
  456. array of RPC binding strings that the service is listening on for the
  457. incoming RPC connections. This list will be distributed to the
  458. clients that are discovering this service.
  459. Arguments:
  460. ServiceMask : service mask, such as 0x00000001 (GATEWAY_SERVICE)
  461. ServiceState : State of the service, INetServiceRunning and
  462. INetServicePaused are valid states to pass.
  463. ServiceComment : Service comment specified by the admin.
  464. Bindings : list of bindings that are supported by the service. The
  465. bindings can be binding strings are those returned by the
  466. RpcBindingToStringBinding call or the sockaddrs.
  467. Return Value:
  468. Windows Error Code.
  469. --*/
  470. {
  471. DWORD Error;
  472. INET_SERVICE_INFO ServiceInfo;
  473. //
  474. // if the server object is not created, do so.
  475. //
  476. LOCK_SVC_GLOBAL_DATA();
  477. if( GlobalSrvInfoObj == NULL ) {
  478. DWORD ComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
  479. //
  480. // read computer name.
  481. //
  482. if( !GetComputerNameA(
  483. GlobalComputerName,
  484. &ComputerNameLength ) ) {
  485. Error = GetLastError();
  486. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  487. "GetComputerNameA failed, %ld.\n", Error ));
  488. goto Cleanup;
  489. }
  490. GlobalComputerName[ComputerNameLength] = '\0';
  491. GlobalSrvInfoObj = new EMBED_SERVER_INFO(
  492. INET_MAJOR_VERSION, // major version number,
  493. INET_MINOR_VERSION, // minor version number
  494. GlobalComputerName );
  495. if( GlobalSrvInfoObj == NULL ) {
  496. Error = ERROR_NOT_ENOUGH_MEMORY;
  497. goto Cleanup;
  498. }
  499. Error = GlobalSrvInfoObj->GetStatus();
  500. if( Error != ERROR_SUCCESS ) {
  501. delete GlobalSrvInfoObj;
  502. GlobalSrvInfoObj = NULL;
  503. goto Cleanup;
  504. }
  505. }
  506. //
  507. // allocate memory for the receive buffer, if it is not alotted before.
  508. //
  509. if( GlobalSrvRecvBuf == NULL ) {
  510. GlobalSrvRecvBuf =
  511. (LPBYTE)SvclocHeap->Alloc( SVCLOC_SRV_RECV_BUFFER_SIZE );
  512. if( GlobalSrvRecvBuf == NULL ) {
  513. Error = ERROR_NOT_ENOUGH_MEMORY;
  514. goto Cleanup;
  515. }
  516. GlobalSrvRecvBufLength = SVCLOC_SRV_RECV_BUFFER_SIZE;
  517. }
  518. //
  519. // check to see the server registered its location and it is listening
  520. // to the client discovery. If not do so.
  521. //
  522. if( !GlobalSrvRegistered ) {
  523. Error = ServerRegisterAndListen();
  524. if( Error != ERROR_SUCCESS ) {
  525. goto Cleanup;
  526. }
  527. GlobalSrvRegistered = TRUE;
  528. }
  529. //
  530. // make a new service info.
  531. //
  532. ServiceInfo.ServiceMask = ServiceMask;
  533. ServiceInfo.ServiceState = ServiceState;
  534. ServiceInfo.ServiceComment = ServiceComment;
  535. ServiceInfo.Bindings = *Bindings;
  536. //
  537. // add this new service to server list.
  538. //
  539. Error = GlobalSrvInfoObj->AddService( &ServiceInfo );
  540. if( Error != ERROR_SUCCESS ) {
  541. goto Cleanup;
  542. }
  543. //
  544. // make response buffer.
  545. //
  546. Error = MakeResponseBuffer();
  547. if( Error != ERROR_SUCCESS ) {
  548. goto Cleanup;
  549. }
  550. Error = ERROR_SUCCESS;
  551. Cleanup:
  552. UNLOCK_SVC_GLOBAL_DATA();
  553. return( Error );
  554. }
  555. DWORD
  556. WINAPI
  557. INetDeregisterService(
  558. IN ULONGLONG ServiceMask
  559. )
  560. /*++
  561. Routine Description:
  562. This API de-registers an internet service from being announced to the
  563. discovering clients. The service writers should call this API just
  564. before shutting down the service.
  565. Arguments:
  566. ServiceMask : service mask, such as 0x00000001 (GATEWAY_SERVICE)
  567. Return Value:
  568. Windows Error Code.
  569. --*/
  570. {
  571. DWORD Error;
  572. INET_SERVICE_INFO ServiceInfo;
  573. //
  574. // remove the service if exists.
  575. //
  576. Error = GlobalSrvInfoObj->RemoveService( ServiceMask );
  577. if( Error != ERROR_SUCCESS ) {
  578. if( Error != ERROR_SERVICE_NOT_FOUND ) {
  579. return( Error );
  580. }
  581. Error = ERROR_SUCCESS;
  582. }
  583. //
  584. // add the service back to the list with service state set to
  585. // INetServiceStopped and no bindings.
  586. //
  587. ServiceInfo.ServiceMask = ServiceMask;
  588. ServiceInfo.ServiceState = INetServiceStopped;
  589. ServiceInfo.ServiceComment = NULL;
  590. ServiceInfo.Bindings.NumBindings = 0;
  591. ServiceInfo.Bindings.BindingsInfo = NULL;
  592. //
  593. // readd the service to server list.
  594. //
  595. Error = GlobalSrvInfoObj->AddService( &ServiceInfo );
  596. if( Error != ERROR_SUCCESS ) {
  597. DWORD LocalError;
  598. //
  599. // recreate response buffer.
  600. //
  601. LocalError = MakeResponseBuffer();
  602. TcpsvcsDbgAssert( LocalError == ERROR_SUCCESS );
  603. return( Error );
  604. }
  605. //
  606. // recreate response buffer.
  607. //
  608. Error = MakeResponseBuffer();
  609. return( Error );
  610. }