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.

534 lines
18 KiB

  1. // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
  2. //
  3. // Copyright (c) 1998-2000 Microsoft Corporation
  4. //
  5. // This file is part of the Microsoft Research IPv6 Network Protocol Stack.
  6. // You should have received a copy of the Microsoft End-User License Agreement
  7. // for this software along with this release; see the file "license.txt".
  8. // If not, please see http://www.research.microsoft.com/msripv6/license.htm,
  9. // or write to Microsoft Research, One Microsoft Way, Redmond, WA 98052-6399.
  10. //
  11. // Abstract:
  12. //
  13. // Test program for IPv6 APIs.
  14. //
  15. #include <winsock2.h>
  16. #include <ws2tcpip.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. //
  20. // Prototypes for local functions.
  21. //
  22. int Test_getaddrinfo(int argc, char **argv);
  23. int Test_getnameinfo();
  24. //
  25. // getaddrinfo flags
  26. // This array maps values to names for pretty-printing purposes.
  27. // Used by DecodeAIFlags().
  28. //
  29. // TBD: When we add support for AI_NUMERICSERV, AI_V4MAPPED, AI_ALL, and
  30. // TBD: AI_ADDRCONFIG to getaddrinfo (and thus define them in ws2tcpip.h),
  31. // TBD: we'll need to add them here too.
  32. //
  33. // Note when adding flags: all the string names plus connecting OR symbols
  34. // must fit into the buffer in DecodeAIFlags() below. Enlarge as required.
  35. //
  36. typedef struct GAIFlagsArrayEntry {
  37. int Flag;
  38. char *Name;
  39. } GAIFlagsArrayEntry;
  40. GAIFlagsArrayEntry GAIFlagsArray [] = {
  41. {AI_PASSIVE, "AI_PASSIVE"},
  42. {AI_CANONNAME, "AI_CANONNAME"},
  43. {AI_NUMERICHOST, "AI_NUMERICHOST"}
  44. };
  45. #define NUMBER_FLAGS (sizeof(GAIFlagsArray) / sizeof(GAIFlagsArrayEntry))
  46. //
  47. // Global variables.
  48. //
  49. IN_ADDR v4Address = {157, 55, 254, 211};
  50. IN6_ADDR v6Address = {0x3f, 0xfe, 0x1c, 0xe1, 0x00, 0x00, 0xfe, 0x01,
  51. 0x02, 0xa0, 0xcc, 0xff, 0xfe, 0x3b, 0xce, 0xef};
  52. IN6_ADDR DeadBeefCafeBabe = {0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe,
  53. 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
  54. IN6_ADDR MostlyZero = {0x3f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  55. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
  56. IN6_ADDR v4Mapped = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  57. 0x00, 0x00, 0xff, 0xff, 157, 55, 254, 211};
  58. SOCKADDR_IN
  59. v4SockAddr = {AF_INET, 6400, {157, 55, 254, 211}, 0};
  60. SOCKADDR_IN6
  61. v6SockAddr = {AF_INET6, 2, 0,
  62. {0x3f, 0xfe, 0x1c, 0xe1, 0x00, 0x00, 0xfe, 0x01,
  63. 0x02, 0xa0, 0xcc, 0xff, 0xfe, 0x3b, 0xce, 0xef},
  64. 0};
  65. SOCKADDR_IN6
  66. DBCBSockAddr = {AF_INET6, 2, 0,
  67. {0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe,
  68. 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
  69. 0};
  70. SOCKADDR_IN6
  71. LinkLocalSockAddr = {AF_INET6, 0x1500, 0,
  72. {0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  73. 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
  74. 3};
  75. //
  76. // Description of a getaddrinfo test.
  77. // Contains the values of each of the arguments passed to getaddrinfo.
  78. //
  79. typedef struct GAITestEntry {
  80. char *NodeName;
  81. char *ServiceName;
  82. ADDRINFO Hints;
  83. } GAITestEntry;
  84. #define TAKE_FROM_USER ((char *)1)
  85. //
  86. // getaddrinfo test array
  87. //
  88. // One entry per test.
  89. // Each entry specifies the arguments to give to getaddrinfo for that test.
  90. //
  91. GAITestEntry GAITestArray[] = {
  92. {TAKE_FROM_USER, NULL, {0, 0, 0, 0, 0, NULL, NULL, NULL}},
  93. {TAKE_FROM_USER, NULL, {AI_PASSIVE, 0, 0, 0, 0, NULL, NULL, NULL}},
  94. {TAKE_FROM_USER, NULL, {AI_CANONNAME, 0, 0, 0, 0, NULL, NULL, NULL}},
  95. {TAKE_FROM_USER, NULL, {AI_NUMERICHOST, 0, 0, 0, 0, NULL, NULL, NULL}},
  96. {TAKE_FROM_USER, NULL, {0, PF_INET, 0, 0, 0, NULL, NULL, NULL}},
  97. {NULL, "ftp", {AI_PASSIVE, 0, SOCK_STREAM, 0, 0, NULL, NULL, NULL}},
  98. {TAKE_FROM_USER, "ftp", {AI_PASSIVE, 0, SOCK_STREAM, 0, 0, NULL, NULL, NULL}},
  99. {TAKE_FROM_USER, "smtp", {0, 0, SOCK_STREAM, 0, 0, NULL, NULL, NULL}},
  100. {"1111:2222:3333:4444:5555:6666:7777:8888", "42",
  101. {0, 0, 0, 0, 0, NULL, NULL, NULL}},
  102. {"fe80::0123:4567:89ab:cdef%3", "telnet",
  103. {AI_NUMERICHOST, 0, SOCK_STREAM, 0, 0, NULL, NULL, NULL}},
  104. {"157.55.254.211", "exec",
  105. {AI_PASSIVE | AI_NUMERICHOST, PF_INET, 0, 0, 0, NULL, NULL, NULL}},
  106. // Ask for a stream-only service on a datagram socket.
  107. {NULL, "exec", {AI_PASSIVE, 0, SOCK_DGRAM, 0, 0, NULL, NULL, NULL}},
  108. // Ask for a numeric-only lookup, but give an ascii name.
  109. {"localhost", "pop3",
  110. {AI_PASSIVE | AI_NUMERICHOST, 0, 0, 0, 0, NULL, NULL, NULL}},
  111. };
  112. #define NUMBER_GAI_TESTS (sizeof(GAITestArray) / sizeof(GAITestEntry))
  113. //* main - various startup stuff.
  114. //
  115. int __cdecl
  116. main(int argc, char **argv)
  117. {
  118. WSADATA wsaData;
  119. int Failed = 0;
  120. //
  121. // Initialize Winsock.
  122. //
  123. if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
  124. printf("WSAStartup failed\n");
  125. exit(1);
  126. }
  127. printf("\nThis program tests getaddrinfo functionality.\n");
  128. #ifdef _WSPIAPI_H_
  129. //
  130. // Including wspiapi.h will insert code to search the appropriate
  131. // system libraries for an implementation of getaddrinfo et. al.
  132. // If they're not found on the system, it will back off to using
  133. // statically compiled in versions that handle IPv4 only.
  134. // Force getaddrinfo and friends to load now so we can report
  135. // which ones we are using.
  136. //
  137. printf("Compiled with wspiapi.h for backwards compatibility.\n\n");
  138. if (WspiapiLoad(0) == WspiapiLegacyGetAddrInfo) {
  139. printf("Using statically compiled-in (IPv4 only) version of getaddrinfo.\n");
  140. } else {
  141. printf("Using dynamically loaded version of getaddrinfo.\n");
  142. }
  143. #else
  144. printf("Compiled without wspiapi.h. "
  145. "Will not work on systems without getaddrinfo.\n");
  146. #endif
  147. printf("\n");
  148. //
  149. // Run tests.
  150. //
  151. Failed += Test_getaddrinfo(argc, argv);
  152. // Failed += Test_getnameinfo();
  153. // printf("%d of the tests failed\n", Failed);
  154. return 0;
  155. }
  156. //* inet6_ntoa - Converts a binary IPv6 address into a string.
  157. //
  158. // Returns a pointer to the output string.
  159. //
  160. char *
  161. inet6_ntoa(const struct in6_addr *Address)
  162. {
  163. static char buffer[128]; // REVIEW: Use 128 or INET6_ADDRSTRLEN?
  164. DWORD buflen = sizeof buffer;
  165. struct sockaddr_in6 sin6;
  166. memset(&sin6, 0, sizeof sin6);
  167. sin6.sin6_family = AF_INET6;
  168. sin6.sin6_addr = *Address;
  169. if (WSAAddressToString((struct sockaddr *) &sin6,
  170. sizeof sin6,
  171. NULL, // LPWSAPROTOCOL_INFO
  172. buffer,
  173. &buflen) == SOCKET_ERROR)
  174. strcpy(buffer, "<invalid>");
  175. return buffer;
  176. }
  177. //* DecodeAIFlags - converts flag bits to a symbolic string.
  178. // (i.e. 0x03 returns "AI_PASSIVE | AI_CANONNAME")
  179. //
  180. char *
  181. DecodeAIFlags(unsigned int Flags)
  182. {
  183. static char Buffer[1024];
  184. char *Pos;
  185. BOOL First = TRUE;
  186. int Loop;
  187. Pos = Buffer;
  188. for (Loop = 0; Loop < NUMBER_FLAGS; Loop++) {
  189. if (Flags & GAIFlagsArray[Loop].Flag) {
  190. if (!First)
  191. Pos += sprintf(Pos, " | ");
  192. Pos += sprintf(Pos, GAIFlagsArray[Loop].Name);
  193. First = FALSE;
  194. }
  195. }
  196. if (First)
  197. return "NONE";
  198. else
  199. return Buffer;
  200. }
  201. //* DecodeAIFamily - converts address family value to a symbolic string.
  202. //
  203. char *
  204. DecodeAIFamily(unsigned int Family)
  205. {
  206. if (Family == PF_INET)
  207. return "PF_INET";
  208. else if (Family == PF_INET6)
  209. return "PF_INET6";
  210. else if (Family == PF_UNSPEC)
  211. return "PF_UNSPEC";
  212. else
  213. return "UNKNOWN";
  214. }
  215. //* DecodeAISocktype - converts socktype value to a symbolic string.
  216. //
  217. char *
  218. DecodeAISocktype(unsigned int Socktype)
  219. {
  220. if (Socktype == SOCK_STREAM)
  221. return "SOCK_STREAM";
  222. else if (Socktype == SOCK_DGRAM)
  223. return "SOCK_DGRAM";
  224. else if (Socktype == SOCK_RAW)
  225. return "SOCK_RAW";
  226. else if (Socktype == SOCK_RDM)
  227. return "SOCK_RDM";
  228. else if (Socktype == SOCK_SEQPACKET)
  229. return "SOCK_SEQPACKET";
  230. else if (Socktype == 0)
  231. return "UNSPECIFIED";
  232. else
  233. return "UNKNOWN";
  234. }
  235. //* DecodeAIProtocol - converts protocol value to a symbolic string.
  236. //
  237. char *
  238. DecodeAIProtocol(unsigned int Protocol)
  239. {
  240. if (Protocol == IPPROTO_TCP)
  241. return "IPPROTO_TCP";
  242. else if (Protocol == IPPROTO_UDP)
  243. return "IPPROTO_UDP";
  244. else if (Protocol == 0)
  245. return "UNSPECIFIED";
  246. else
  247. return "UNKNOWN";
  248. }
  249. //* DumpAddrInfo - print the contents of an addrinfo structure to standard out.
  250. //
  251. void
  252. DumpAddrInfo(ADDRINFO *AddrInfo)
  253. {
  254. int Count;
  255. if (AddrInfo == NULL) {
  256. printf("AddrInfo = (null)\n");
  257. return;
  258. }
  259. for (Count = 1; AddrInfo != NULL; AddrInfo = AddrInfo->ai_next) {
  260. if ((Count != 1) || (AddrInfo->ai_next != NULL))
  261. printf("Record #%u:\n", Count++);
  262. printf(" ai_flags = %s\n", DecodeAIFlags(AddrInfo->ai_flags));
  263. printf(" ai_family = %s\n", DecodeAIFamily(AddrInfo->ai_family));
  264. printf(" ai_socktype = %s\n", DecodeAISocktype(AddrInfo->ai_socktype));
  265. printf(" ai_protocol = %s\n", DecodeAIProtocol(AddrInfo->ai_protocol));
  266. printf(" ai_addrlen = %u\n", AddrInfo->ai_addrlen);
  267. printf(" ai_canonname = %s\n", AddrInfo->ai_canonname);
  268. if (AddrInfo->ai_addr != NULL) {
  269. if (AddrInfo->ai_addr->sa_family == AF_INET) {
  270. struct sockaddr_in *sin;
  271. sin = (struct sockaddr_in *)AddrInfo->ai_addr;
  272. printf(" ai_addr->sin_family = AF_INET\n");
  273. printf(" ai_addr->sin_port = %u\n", ntohs(sin->sin_port));
  274. printf(" ai_addr->sin_addr = %s\n", inet_ntoa(sin->sin_addr));
  275. } else if (AddrInfo->ai_addr->sa_family == AF_INET6) {
  276. struct sockaddr_in6 *sin6;
  277. sin6 = (struct sockaddr_in6 *)AddrInfo->ai_addr;
  278. printf(" ai_addr->sin6_family = AF_INET6\n");
  279. printf(" ai_addr->sin6_port = %u\n", ntohs(sin6->sin6_port));
  280. printf(" ai_addr->sin6_flowinfo = %u\n", sin6->sin6_flowinfo);
  281. printf(" ai_addr->sin6_scope_id = %u\n", sin6->sin6_scope_id);
  282. printf(" ai_addr->sin6_addr = %s\n",
  283. inet6_ntoa(&sin6->sin6_addr));
  284. } else {
  285. printf(" ai_addr->sa_family = %u\n",
  286. AddrInfo->ai_addr->sa_family);
  287. }
  288. } else {
  289. printf(" ai_addr = (null)\n");
  290. }
  291. }
  292. }
  293. //* Test_getaddrinfo - Test getaddrinfo.
  294. //
  295. // Note that getaddrinfo returns an error value,
  296. // instead of setting last error.
  297. //
  298. int
  299. Test_getaddrinfo(int argc, char **argv)
  300. {
  301. char *NodeName, *TestName, *ServiceName;
  302. int ReturnValue;
  303. ADDRINFO *AddrInfo;
  304. int Loop;
  305. if (argc < 2)
  306. NodeName = "localhost";
  307. else
  308. NodeName = argv[1];
  309. for (Loop = 0; Loop < NUMBER_GAI_TESTS; Loop++) {
  310. printf("Running test #%u\n", Loop);
  311. if (GAITestArray[Loop].NodeName == TAKE_FROM_USER) {
  312. GAITestArray[Loop].NodeName = NodeName;
  313. }
  314. printf("Hints contains:\n");
  315. DumpAddrInfo(&GAITestArray[Loop].Hints);
  316. printf("Calling getaddrinfo(\"%s\", \"%s\", &Hints, &AddrInfo)\n",
  317. GAITestArray[Loop].NodeName,
  318. GAITestArray[Loop].ServiceName);
  319. ReturnValue = getaddrinfo(GAITestArray[Loop].NodeName,
  320. GAITestArray[Loop].ServiceName,
  321. &GAITestArray[Loop].Hints,
  322. &AddrInfo);
  323. printf("Returns %d (%s)\n", ReturnValue,
  324. ReturnValue ? gai_strerror(ReturnValue) : "no error");
  325. if (AddrInfo != NULL) {
  326. printf("AddrInfo contains:\n");
  327. DumpAddrInfo(AddrInfo);
  328. freeaddrinfo(AddrInfo);
  329. }
  330. printf("\n");
  331. }
  332. return 0;
  333. };
  334. #if 0
  335. //* Test_getnameinfo - Test getnameinfo.
  336. //
  337. // Note that getnameinfo returns an error value,
  338. // instead of setting last error.
  339. //
  340. int
  341. Test_getnameinfo()
  342. {
  343. int ReturnValue;
  344. char NodeName[NI_MAXHOST];
  345. char ServiceName[NI_MAXSERV];
  346. char Tiny[2];
  347. int Error;
  348. printf("\ngetnameinfo:\n\n");
  349. // Test with reasonable input:
  350. memset(NodeName, 0, sizeof NodeName);
  351. memset(ServiceName, 0, sizeof ServiceName);
  352. ReturnValue = getnameinfo((struct sockaddr *)&v4SockAddr,
  353. sizeof v4SockAddr, NodeName, sizeof NodeName,
  354. ServiceName, sizeof ServiceName, 0);
  355. printf("getnameinfo((struct sockaddr *)&v4SockAddr, "
  356. "sizeof v4SockAddr, NodeName, sizeof NodeName, "
  357. "ServiceName, sizeof ServiceName, 0)\nReturns %d\n"
  358. "NodeName = %s\nServiceName = %s\n", ReturnValue,
  359. NodeName, ServiceName);
  360. printf("\n");
  361. memset(NodeName, 0, sizeof NodeName);
  362. memset(ServiceName, 0, sizeof ServiceName);
  363. ReturnValue = getnameinfo((struct sockaddr *)&v6SockAddr,
  364. sizeof v6SockAddr, NodeName, sizeof NodeName,
  365. ServiceName, sizeof ServiceName, 0);
  366. printf("getnameinfo((struct sockaddr *)&v6SockAddr, "
  367. "sizeof v6SockAddr, NodeName, sizeof NodeName, "
  368. "ServiceName, sizeof ServiceName, 0)\nReturns %d\n"
  369. "NodeName = %s\nServiceName = %s\n", ReturnValue,
  370. NodeName, ServiceName);
  371. printf("\n");
  372. memset(NodeName, 0, sizeof NodeName);
  373. memset(ServiceName, 0, sizeof ServiceName);
  374. ReturnValue = getnameinfo((struct sockaddr *)&DBCBSockAddr,
  375. sizeof DBCBSockAddr, NodeName, sizeof NodeName,
  376. ServiceName, sizeof ServiceName, NI_DGRAM);
  377. printf("getnameinfo((struct sockaddr *)&DBCBSockAddr, "
  378. "sizeof DBCBSockAddr, NodeName, sizeof NodeName, "
  379. "ServiceName, sizeof ServiceName, NI_DGRAM)\nReturns %d\n"
  380. "NodeName = %s\nServiceName = %s\n", ReturnValue,
  381. NodeName, ServiceName);
  382. printf("\n");
  383. memset(NodeName, 0, sizeof NodeName);
  384. memset(ServiceName, 0, sizeof ServiceName);
  385. ReturnValue = getnameinfo((struct sockaddr *)&LinkLocalSockAddr,
  386. sizeof LinkLocalSockAddr, NodeName,
  387. sizeof NodeName, ServiceName,
  388. sizeof ServiceName, NI_NUMERICHOST);
  389. printf("getnameinfo((struct sockaddr *)&LinkLocalSockAddr, "
  390. "sizeof LinkLocalSockAddr, NodeName, sizeof NodeName, "
  391. "ServiceName, sizeof ServiceName, NI_NUMERICHOST)\nReturns %d\n"
  392. "NodeName = %s\nServiceName = %s\n", ReturnValue,
  393. NodeName, ServiceName);
  394. printf("\n");
  395. memset(NodeName, 0, sizeof NodeName);
  396. memset(ServiceName, 0, sizeof ServiceName);
  397. ReturnValue = getnameinfo((struct sockaddr *)&LinkLocalSockAddr,
  398. sizeof LinkLocalSockAddr, NodeName,
  399. sizeof NodeName, ServiceName,
  400. sizeof ServiceName, NI_NUMERICSERV);
  401. printf("getnameinfo((struct sockaddr *)&LinkLocalSockAddr, "
  402. "sizeof LinkLocalSockAddr, NodeName, sizeof NodeName, "
  403. "ServiceName, sizeof ServiceName, NI_NUMERICSERV)\nReturns %d\n"
  404. "NodeName = %s\nServiceName = %s\n", ReturnValue,
  405. NodeName, ServiceName);
  406. printf("\n");
  407. memset(NodeName, 0, sizeof NodeName);
  408. memset(ServiceName, 0, sizeof ServiceName);
  409. ReturnValue = getnameinfo((struct sockaddr *)&v4SockAddr,
  410. sizeof v4SockAddr, NodeName, sizeof NodeName,
  411. ServiceName, sizeof ServiceName,
  412. NI_NUMERICHOST | NI_NUMERICSERV);
  413. printf("getnameinfo((struct sockaddr *)&v4SockAddr, "
  414. "sizeof v4SockAddr, NodeName, sizeof NodeName, "
  415. "ServiceName, sizeof ServiceName, "
  416. "NI_NUMERICHOST | NI_NUMERICSERV)\nReturns %d\n"
  417. "NodeName = %s\nServiceName = %s\n", ReturnValue,
  418. NodeName, ServiceName);
  419. printf("\n");
  420. // Try to shoehorn too much into too little.
  421. memset(Tiny, 0, sizeof Tiny);
  422. memset(ServiceName, 0, sizeof ServiceName);
  423. ReturnValue = getnameinfo((struct sockaddr *)&DBCBSockAddr,
  424. sizeof DBCBSockAddr, Tiny, sizeof Tiny,
  425. ServiceName, sizeof ServiceName, 0);
  426. printf("getnameinfo((struct sockaddr *)&DBCBSockAddr, "
  427. "sizeof DBCBSockAddr, Tiny, sizeof Tiny, "
  428. "ServiceName, sizeof ServiceName, 0)\nReturns %d\n"
  429. "Tiny = %s\nServiceName = %s\n", ReturnValue,
  430. Tiny, ServiceName);
  431. printf("\n");
  432. memset(Tiny, 0, sizeof Tiny);
  433. memset(ServiceName, 0, sizeof ServiceName);
  434. ReturnValue = getnameinfo((struct sockaddr *)&DBCBSockAddr,
  435. sizeof DBCBSockAddr, Tiny, sizeof Tiny,
  436. ServiceName, sizeof ServiceName, NI_NUMERICHOST);
  437. printf("getnameinfo((struct sockaddr *)&DBCBSockAddr, "
  438. "sizeof DBCBSockAddr, Tiny, sizeof Tiny, "
  439. "ServiceName, sizeof ServiceName, NI_NUMERICHOST)\nReturns %d\n"
  440. "Tiny = %s\nServiceName = %s\n", ReturnValue,
  441. Tiny, ServiceName);
  442. printf("\n");
  443. memset(NodeName, 0, sizeof NodeName);
  444. memset(Tiny, 0, sizeof Tiny);
  445. ReturnValue = getnameinfo((struct sockaddr *)&v4SockAddr,
  446. sizeof v4SockAddr, NodeName, sizeof NodeName,
  447. Tiny, sizeof Tiny, 0);
  448. printf("getnameinfo((struct sockaddr *)&v4SockAddr, "
  449. "sizeof v4SockAddr, NodeName, sizeof NodeName, "
  450. "Tiny, sizeof Tiny, 0)\nReturns %d\n"
  451. "NodeName = %s\nTiny = %s\n", ReturnValue,
  452. NodeName, Tiny);
  453. printf("\n");
  454. memset(NodeName, 0, sizeof NodeName);
  455. memset(Tiny, 0, sizeof Tiny);
  456. ReturnValue = getnameinfo((struct sockaddr *)&v4SockAddr,
  457. sizeof v4SockAddr, NodeName, sizeof NodeName,
  458. Tiny, sizeof Tiny, NI_NUMERICSERV);
  459. printf("getnameinfo((struct sockaddr *)&v4SockAddr, "
  460. "sizeof v4SockAddr, NodeName, sizeof NodeName, "
  461. "Tiny, sizeof Tiny, NI_NUMERICSERV)\nReturns %d\n"
  462. "NodeName = %s\nTiny = %s\n", ReturnValue,
  463. NodeName, Tiny);
  464. printf("\n");
  465. return 0;
  466. };
  467. #endif