Windows NT 4.0 source code leak
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.

602 lines
14 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. gethost.c
  5. Abstract:
  6. This file contains the a version of GetHostByName for IPX/SPX for
  7. dos and windows.
  8. Author:
  9. 31 May 94 AlexMit
  10. 15 Oct 94 JRoberts - changed to avoid using Novell headers and libs
  11. --*/
  12. #include "sysinc.h"
  13. #include "rpc.h"
  14. #include "rpctran.h"
  15. #include "novell.h"
  16. #include "gethost.h"
  17. #include "netcons.h"
  18. #include "ncb.h"
  19. #ifdef WIN
  20. # include "windows.h"
  21. # define I_RpcAllocate (*(RpcRuntimeInfo->Allocate))
  22. # define I_RpcFree (*(RpcRuntimeInfo->Free))
  23. #else
  24. # include "regalloc.h"
  25. #endif
  26. #define NAME_LEN 48
  27. #define SAP_ECB_COUNT 5
  28. /********************************************************************/
  29. #ifdef WIN
  30. #define CACHE_LENGTH 16
  31. #else
  32. #define CACHE_LENGTH 4
  33. #endif
  34. #define CACHE_EXPIRATION_TIME (10 * 60 * 18)
  35. struct
  36. {
  37. char Name[16];
  38. IPX_ADDRESS Address;
  39. unsigned long Time;
  40. }
  41. ServerCache[CACHE_LENGTH];
  42. /********************************************************************/
  43. extern int atoi(const char *);
  44. /********************************************************************/
  45. unsigned char chtob( unsigned char c1, unsigned char c2 )
  46. /* Convert two hex digits (stored as ascii) into one byte. */
  47. {
  48. unsigned char out;
  49. if (c1 >= '0' && c1 <= '9')
  50. out = (c1 - '0') << 4;
  51. else
  52. {
  53. if (c1 >= 'a' && c1 <= 'f')
  54. out = (c1 - 'a' + 10) << 4;
  55. else if (c1 >= 'A' && c1 <= 'F')
  56. out = (c1 - 'A' + 10) << 4;
  57. else
  58. out = 0;
  59. }
  60. if (c2 >= '0' && c2 <= '9')
  61. out |= c2 -'0';
  62. else
  63. {
  64. if (c2 >= 'a' && c2 <= 'f')
  65. out |= c2 - 'a' + 10;
  66. else if (c2 >= 'A' && c2 <= 'F')
  67. out |= c2 - 'A' + 10;
  68. else
  69. out = 0;
  70. }
  71. return out;
  72. }
  73. unsigned char chtob( unsigned char c1, unsigned char c2 );
  74. RPC_STATUS FromBindery( IPX_ADDRESS __RPC_FAR *host,
  75. RPC_CHAR __RPC_FAR *name );
  76. unsigned long
  77. DosGetTickCount(
  78. )
  79. /*++
  80. Routine Description:
  81. Returns the number of ticks since the last time it was midnight.
  82. There are 65536 ticks per hour.
  83. --*/
  84. {
  85. _asm
  86. {
  87. push bp
  88. push si
  89. push di
  90. xor ax, ax
  91. int 0x1a
  92. mov ax, dx
  93. mov dx, cx
  94. pop di
  95. pop si
  96. pop bp
  97. }
  98. }
  99. void
  100. AddServerToCache(
  101. char PAPI * Name,
  102. IPX_ADDRESS PAPI * Address
  103. )
  104. {
  105. unsigned i;
  106. //
  107. // If the server is already in the table, overwrite the existing entry.
  108. //
  109. for (i=0; i < CACHE_LENGTH; ++i)
  110. {
  111. if (0 == _fstrnicmp(ServerCache[i].Name, Name, 16))
  112. {
  113. break;
  114. }
  115. }
  116. //
  117. // If it is not in the table, try to find an empty entry to fill.
  118. //
  119. if (i == CACHE_LENGTH)
  120. {
  121. for (i=0; i < CACHE_LENGTH; ++i)
  122. {
  123. if (ServerCache[i].Name[0] == '\0')
  124. {
  125. break;
  126. }
  127. }
  128. }
  129. //
  130. // If all entries are full, overwrite the oldest one.
  131. //
  132. if (i == CACHE_LENGTH)
  133. {
  134. unsigned long BestTime = ~0;
  135. unsigned BestIndex;
  136. for (i=0; i < CACHE_LENGTH; ++i)
  137. {
  138. if (ServerCache[i].Time <= BestTime)
  139. {
  140. BestTime = ServerCache[i].Time;
  141. BestIndex = i;
  142. }
  143. }
  144. i = BestIndex;
  145. }
  146. //
  147. // Update the entry's information.
  148. //
  149. _fstrcpy(ServerCache[i].Name, Name);
  150. _fmemcpy(&ServerCache[i].Address, Address, sizeof(IPX_ADDRESS));
  151. ServerCache[i].Time = DosGetTickCount();
  152. }
  153. IPX_ADDRESS *
  154. FindServerInCache(
  155. char PAPI * Name
  156. )
  157. {
  158. unsigned i;
  159. for (i=0; i < CACHE_LENGTH; ++i)
  160. {
  161. if (0 == _fstrcmp(ServerCache[i].Name, Name))
  162. {
  163. return &ServerCache[i].Address;
  164. }
  165. }
  166. return 0;
  167. }
  168. void
  169. CachedServerContacted(
  170. char PAPI * Name
  171. )
  172. {
  173. unsigned i;
  174. for (i=0; i < CACHE_LENGTH; ++i)
  175. {
  176. if (0 == _fstrcmp(ServerCache[i].Name, Name))
  177. {
  178. ServerCache[i].Time = DosGetTickCount();
  179. break;
  180. }
  181. }
  182. }
  183. BOOL
  184. CachedServerNotContacted(
  185. char PAPI * Name
  186. )
  187. {
  188. BOOL Flushed = FALSE;
  189. unsigned i;
  190. for (i=0; i < CACHE_LENGTH; ++i)
  191. {
  192. if (0 == _fstrcmp(ServerCache[i].Name, Name))
  193. {
  194. if (DosGetTickCount() - ServerCache[i].Time > CACHE_EXPIRATION_TIME)
  195. {
  196. ServerCache[i].Name[0] = '\0';
  197. Flushed = TRUE;
  198. break;
  199. }
  200. }
  201. }
  202. return Flushed;
  203. }
  204. BOOL PreferredServerFound = FALSE;
  205. NETWARE_CONNECTION PreferredServer;
  206. RPC_STATUS
  207. SearchBindery(
  208. RPC_CHAR __RPC_FAR *name,
  209. IPX_ADDRESS __RPC_FAR *Address,
  210. unsigned BindingTimeout
  211. )
  212. {
  213. char buffer[128];
  214. unsigned SapTickCount;
  215. unsigned RetryCount = 0;
  216. //
  217. //
  218. //
  219. if (FALSE == PreferredServerFound)
  220. {
  221. reconnect:
  222. PreferredServer.TickLimit = 19;
  223. SapTickCount = 19;
  224. if (BindingTimeout > RPC_C_BINDING_DEFAULT_TIMEOUT)
  225. {
  226. PreferredServer.TickLimit <<= BindingTimeout - RPC_C_BINDING_DEFAULT_TIMEOUT;
  227. SapTickCount <<= BindingTimeout - RPC_C_BINDING_DEFAULT_TIMEOUT;
  228. }
  229. ConnectToAnyFileServer(&PreferredServer, SapTickCount);
  230. if (PreferredServer.ReturnCode || PreferredServer.ConnectionStatus)
  231. {
  232. DisconnectFromServer(&PreferredServer);
  233. PreferredServerFound = FALSE;
  234. return RPC_S_SERVER_UNAVAILABLE;
  235. }
  236. PreferredServerFound = TRUE;
  237. }
  238. //
  239. // Read from the bindery.
  240. //
  241. ReadPropertyValue(&PreferredServer,
  242. name,
  243. RPC_SAP_TYPE,
  244. "NET_ADDRESS",
  245. 1,
  246. buffer,
  247. 0,
  248. 0
  249. );
  250. if (PreferredServer.ReturnCode)
  251. {
  252. DisconnectFromServer(&PreferredServer);
  253. PreferredServerFound = FALSE;
  254. if (RetryCount++)
  255. {
  256. return RPC_S_SERVER_UNAVAILABLE;
  257. }
  258. else
  259. {
  260. goto reconnect;
  261. }
  262. }
  263. //
  264. // Save the host address.
  265. //
  266. _fmemcpy( Address, buffer, 10 );
  267. DisconnectFromServer(&PreferredServer);
  268. return RPC_S_OK;
  269. }
  270. /********************************************************************/
  271. RPC_STATUS
  272. SearchWithSap(
  273. RPC_CHAR __RPC_FAR *name,
  274. IPX_ADDRESS __RPC_FAR *host,
  275. unsigned Timeout
  276. #ifdef WIN
  277. , RPC_CLIENT_RUNTIME_INFO PAPI * RpcRuntimeInfo
  278. #endif
  279. )
  280. {
  281. WORD start;
  282. unsigned SapSocket;
  283. int result;
  284. int i;
  285. int retry;
  286. struct
  287. {
  288. ECB ecb;
  289. IPX_HEADER ipx;
  290. SAP_REQUEST req;
  291. } send;
  292. struct SAP_RESPONSE_ECB
  293. {
  294. ECB ecb;
  295. IPX_HEADER ipx;
  296. SAP_RESPONSE resp;
  297. }
  298. __RPC_FAR * mem;
  299. RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE;
  300. //
  301. // The base timeout is two seconds; max is a minute.
  302. //
  303. if (Timeout <= RPC_C_BINDING_DEFAULT_TIMEOUT)
  304. {
  305. Timeout = 18 * 2;
  306. }
  307. else
  308. {
  309. Timeout = (18 * 2) << (Timeout - RPC_C_BINDING_DEFAULT_TIMEOUT);
  310. }
  311. result = IPXOpenSocket(TASKID_C &SapSocket, 0);
  312. if (result != 0)
  313. return RPC_S_OUT_OF_RESOURCES;
  314. // Allocate memory for ECBs.
  315. #ifdef WIN
  316. mem = I_RpcAllocate( SAP_ECB_COUNT * sizeof(*mem) );
  317. #else
  318. mem = I_RpcRegisteredBufferAllocate( SAP_ECB_COUNT * sizeof(*mem) );
  319. #endif
  320. if (mem == NULL)
  321. {
  322. status = RPC_S_OUT_OF_MEMORY;
  323. goto cleanup;
  324. }
  325. _fmemset( mem, 0, SAP_ECB_COUNT * sizeof(mem) );
  326. //
  327. // Post some ECBs.
  328. //
  329. for (i = 0; i < SAP_ECB_COUNT; i++)
  330. {
  331. SetupEcb(&mem[i].ecb, SapSocket, sizeof(SAP_RESPONSE));
  332. IPXListenForPacket(TASKID_C &mem[i].ecb );
  333. }
  334. //
  335. // We want to send a SAP request and scan responses for the server
  336. // that we want. We transmit the request up to two times because
  337. // servers sometimes miss a single broadcast.
  338. //
  339. for (retry = 0; retry < 2 ; ++retry)
  340. {
  341. send.ipx.PacketType = IPX_PACKET_TYPE;
  342. send.ipx.Destination.Network = 0;
  343. send.ipx.Destination.Socket = SAP_SOCKET;
  344. _fmemset( send.ipx.Destination.Node, 0xff, sizeof(send.ipx.Destination.Node) );
  345. SetupEcb(&send.ecb, SapSocket, sizeof(send));
  346. _fmemset( send.ecb.immediateAddress, 0xff, sizeof(send.ecb.immediateAddress) );
  347. // Send the data.
  348. send.req.QueryType = SAP_GENERAL_QUERY;
  349. send.req.ServerType = RPC_SAP_TYPE_SWAPPED;
  350. IPXSendPacket(TASKID_C &send.ecb );
  351. while (send.ecb.inUseFlag)
  352. IPXRelinquishControl();
  353. // Verify that the send was successful.
  354. if (send.ecb.completionCode)
  355. {
  356. goto cleanup;
  357. }
  358. //
  359. // Get packets till timeout is returned or a good reply is returned.
  360. //
  361. start = IPXGetIntervalMarker(TASKID);
  362. do
  363. {
  364. struct SAP_RESPONSE_ECB __RPC_FAR * curr;
  365. for (curr = mem; curr < mem + SAP_ECB_COUNT; curr++)
  366. {
  367. if (curr->ecb.inUseFlag == 0)
  368. {
  369. if (curr->ecb.completionCode == 0x00)
  370. {
  371. // Verify the packet.
  372. //
  373. curr->ipx.Length = ByteSwapShort( curr->ipx.Length );
  374. curr->ipx.Length -= sizeof(IPX_HEADER);
  375. if (curr->ipx.Source.Socket == SAP_SOCKET &&
  376. curr->ipx.Length >= sizeof (SAP_RESPONSE) &&
  377. curr->resp.PacketType == SAP_GENERAL_RESPONSE )
  378. {
  379. unsigned num_entry = curr->ipx.Length / sizeof(SAP_ENTRY);
  380. for (i = 0; i < num_entry; i++)
  381. {
  382. if (0 == _fstrnicmp( name, curr->resp.Entries[i].Name, NAME_LEN))
  383. {
  384. // Only copy the network and node numbers, not the socket.
  385. //
  386. _fmemcpy( host, &curr->resp.Entries[i].Address, 10 );
  387. status = RPC_S_OK;
  388. goto cleanup;
  389. }
  390. }
  391. }
  392. }
  393. //
  394. // Repost the receive.
  395. //
  396. IPXListenForPacket( TASKID_C &curr->ecb );
  397. }
  398. }
  399. IPXRelinquishControl();
  400. }
  401. while (IPXGetIntervalMarker(TASKID) - start < Timeout);
  402. }
  403. cleanup:
  404. //
  405. // Cancel the ECBs.
  406. //
  407. if (mem)
  408. {
  409. for (i = 0; i < SAP_ECB_COUNT; i++)
  410. {
  411. if (mem[i].ecb.inUseFlag)
  412. {
  413. IPXCancelEvent( TASKID_C &mem[i].ecb );
  414. while (mem[i].ecb.inUseFlag)
  415. {
  416. IPXRelinquishControl();
  417. }
  418. }
  419. }
  420. //
  421. // Free the memory.
  422. //
  423. #ifdef WIN
  424. I_RpcFree( mem );
  425. #else
  426. I_RpcRegisteredBufferFree( mem );
  427. #endif
  428. }
  429. IPXCloseSocket(TASKID_C SapSocket);
  430. return status;
  431. }
  432. /********************************************************************/
  433. RPC_STATUS
  434. IpxGetHostByName(
  435. RPC_CHAR __RPC_FAR * name,
  436. IPX_ADDRESS __RPC_FAR * Address,
  437. RPC_CHAR __RPC_FAR * endpoint,
  438. unsigned Timeout
  439. #ifdef WIN
  440. , RPC_CLIENT_RUNTIME_INFO * RpcClientRuntimeInfo
  441. #endif
  442. )
  443. {
  444. RPC_STATUS status;
  445. int i;
  446. int length;
  447. IPX_ADDRESS * CachedAddress;
  448. // Set the endpoint.
  449. Address->Socket = ByteSwapShort(atoi(endpoint));
  450. // Fail if no address was specified.
  451. if (name == NULL || name[0] == '\0')
  452. return RPC_S_SERVER_UNAVAILABLE;
  453. // If the name starts with ~, convert it directly to a network address.
  454. length = _fstrlen(name);
  455. if (name[0] == '~')
  456. {
  457. unsigned char __RPC_FAR * Temp;
  458. if (length != 21)
  459. return RPC_S_INVALID_NET_ADDR;
  460. Temp = (unsigned char __RPC_FAR *) &Address->Network;
  461. for (i = 0; i < 4; i++)
  462. {
  463. Temp[i] = chtob( name[2*i + 1], name[2*i + 2] );
  464. }
  465. Temp = (unsigned char __RPC_FAR *) Address->Node;
  466. for (i = 0; i < 6; i++)
  467. {
  468. Temp[i] = chtob( name[2*i + 9], name[2*i + 10] );
  469. }
  470. return RPC_S_OK;
  471. }
  472. if (length > 15)
  473. {
  474. return RPC_S_INVALID_NET_ADDR;
  475. }
  476. CachedAddress = FindServerInCache(name);
  477. if (CachedAddress)
  478. {
  479. _fmemcpy(Address, CachedAddress, 10);
  480. return RPC_S_OK;
  481. }
  482. // Try the bindery.
  483. status = SearchBindery(name, Address, Timeout);
  484. if (status && !PreferredServerFound)
  485. {
  486. status = SearchWithSap(name,
  487. Address,
  488. Timeout
  489. #ifdef WIN
  490. , RpcClientRuntimeInfo
  491. #endif
  492. );
  493. }
  494. if (!status)
  495. {
  496. AddServerToCache(name, Address);
  497. }
  498. return status;
  499. }