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.

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