1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS WinSock 2 API 4 * FILE: dll/win32/ws2_32/src/addrinfo.c 5 * PURPOSE: Protocol-Independent Address Resolution 6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <ws2_32.h> 12 13 #include <ws2tcpip.h> 14 15 #define NDEBUG 16 #include <debug.h> 17 18 /* DEFINES *******************************************************************/ 19 20 #define Swap(a, b, c) { (c) = (a); (a) = (b); (b) = (c); } 21 #define FreeAddrInfoW(a) freeaddrinfo((LPADDRINFO)a) 22 23 /* FUNCTIONS *****************************************************************/ 24 25 /* FIXME: put into dnslib */ 26 VOID 27 WSAAPI 28 Dns_Ip4AddressToReverseName_W(IN LPWSTR AddressBuffer, 29 IN IN_ADDR Address) 30 { 31 /* Convert the address into IPv4 format */ 32 wsprintfW(AddressBuffer, L"%u.%u.%u.%u.in-addr.arpa.", 33 Address.S_un.S_un_b.s_b4, 34 Address.S_un.S_un_b.s_b3, 35 Address.S_un.S_un_b.s_b2, 36 Address.S_un.S_un_b.s_b1); 37 } 38 39 VOID 40 WINAPI 41 Dns_SplitHostFromDomainNameW(IN LPWSTR DomainName) 42 { 43 /* FIXME */ 44 } 45 46 static 47 INT 48 WINAPI 49 ConvertAddrinfoFromUnicodeToAnsi(IN PADDRINFOW Addrinfo) 50 { 51 LPSTR AnsiName; 52 LPWSTR *UnicodeName; 53 54 /* Make sure we have a valid pointer */ 55 if (Addrinfo) 56 { 57 do 58 { 59 /* Get the name */ 60 UnicodeName = &Addrinfo->ai_canonname; 61 62 /* Check if it exists */ 63 if (*UnicodeName) 64 { 65 /* Convert it */ 66 AnsiName = AnsiDupFromUnicode(*UnicodeName); 67 if (AnsiName) 68 { 69 /* Free the old one */ 70 HeapFree(WsSockHeap, 0, *UnicodeName); 71 72 /* Set the new one */ 73 *UnicodeName = (LPWSTR)AnsiName; 74 } 75 else 76 { 77 return GetLastError(); 78 } 79 } 80 } while ((Addrinfo = Addrinfo->ai_next)); 81 } 82 83 /* All done */ 84 return ERROR_SUCCESS; 85 } 86 87 static 88 BOOL 89 WINAPI 90 ParseV4Address(IN PCWSTR AddressString, 91 OUT PDWORD pAddress) 92 { 93 CHAR AnsiAddressString[MAX_HOSTNAME_LEN]; 94 CHAR * cp = AnsiAddressString; 95 DWORD val, base; 96 unsigned char c; 97 DWORD parts[4], *pp = parts; 98 if (!AddressString) 99 return FALSE; 100 WideCharToMultiByte(CP_ACP, 101 0, 102 AddressString, 103 -1, 104 AnsiAddressString, 105 sizeof(AnsiAddressString), 106 NULL, 107 0); 108 if (!isdigit(*cp)) return FALSE; 109 110 again: 111 /* 112 * Collect number up to ``.''. 113 * Values are specified as for C: 114 * 0x=hex, 0=octal, other=decimal. 115 */ 116 val = 0; base = 10; 117 if (*cp == '0') { 118 if (*++cp == 'x' || *cp == 'X') 119 base = 16, cp++; 120 else 121 base = 8; 122 } 123 while ((c = *cp)) { 124 if (isdigit(c)) { 125 val = (val * base) + (c - '0'); 126 cp++; 127 continue; 128 } 129 if (base == 16 && isxdigit(c)) { 130 val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A')); 131 cp++; 132 continue; 133 } 134 break; 135 } 136 if (*cp == '.') { 137 /* 138 * Internet format: 139 * a.b.c.d 140 */ 141 if (pp >= parts + 4) return FALSE; 142 *pp++ = val; 143 cp++; 144 goto again; 145 } 146 /* 147 * Check for trailing characters. 148 */ 149 if (*cp) return FALSE; 150 151 if (pp >= parts + 4) return FALSE; 152 *pp++ = val; 153 /* 154 * Concoct the address according to 155 * the number of parts specified. 156 */ 157 if ((DWORD)(pp - parts) != 4) return FALSE; 158 if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xff || parts[3] > 0xff) return FALSE; 159 val = (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]; 160 161 if (pAddress) 162 *pAddress = htonl(val); 163 164 return TRUE; 165 } 166 167 static 168 PADDRINFOW 169 WINAPI 170 NewAddrInfo(IN INT SocketType, 171 IN INT Protocol, 172 IN WORD Port, 173 IN DWORD Address) 174 { 175 PADDRINFOW AddrInfo; 176 PSOCKADDR_IN SockAddress; 177 178 /* Allocate a structure */ 179 AddrInfo = HeapAlloc(WsSockHeap, 0, sizeof(ADDRINFOW)); 180 if (!AddrInfo) return NULL; 181 182 /* Allocate a sockaddr */ 183 SockAddress = HeapAlloc(WsSockHeap, 0, sizeof(SOCKADDR_IN)); 184 if (!SockAddress) 185 { 186 /* Free the addrinfo and fail */ 187 HeapFree(WsSockHeap, 0, AddrInfo); 188 return NULL; 189 } 190 191 /* Write data for socket address */ 192 SockAddress->sin_family = AF_INET; 193 SockAddress->sin_port = Port; 194 SockAddress->sin_addr.s_addr = Address; 195 ZeroMemory(SockAddress->sin_zero, sizeof(SockAddress->sin_zero)); 196 197 /* Fill out the addrinfo */ 198 AddrInfo->ai_family = PF_INET; 199 AddrInfo->ai_socktype = SocketType; 200 AddrInfo->ai_protocol = Protocol; 201 AddrInfo->ai_flags = 0; 202 AddrInfo->ai_next = 0; 203 AddrInfo->ai_canonname = NULL; 204 AddrInfo->ai_addrlen = sizeof(SOCKADDR_IN); 205 AddrInfo->ai_addr = (PSOCKADDR)SockAddress; 206 207 /* Return it */ 208 return AddrInfo; 209 } 210 211 static 212 INT 213 WINAPI 214 CloneAddrInfo(IN WORD Port, 215 IN PADDRINFOW ptResult) 216 { 217 PADDRINFOW Next = NULL; 218 PADDRINFOW New = NULL; 219 220 /* Loop the chain */ 221 for (Next = ptResult; Next;) 222 { 223 /* Create a new structure */ 224 New = NewAddrInfo(SOCK_DGRAM, 225 Next->ai_protocol, 226 Port, 227 ((PSOCKADDR_IN)Next->ai_addr)->sin_addr.s_addr); 228 if (!New) break; 229 230 /* Link them */ 231 New->ai_next = Next->ai_next; 232 Next->ai_next = New; 233 Next = New->ai_next; 234 } 235 236 /* Check if we ran out of memory */ 237 if (Next) return EAI_MEMORY; 238 239 /* Return success */ 240 return 0; 241 } 242 243 static 244 INT 245 WINAPI 246 QueryDNS(IN LPCSTR NodeName, 247 IN INT SocketType, 248 IN INT Protocol, 249 IN WORD Port, 250 OUT CHAR Alias[NI_MAXHOST], 251 OUT PADDRINFOW *pptResult) 252 { 253 PADDRINFOW *Next = pptResult; 254 PHOSTENT Hostent = NULL; 255 PCHAR *Addresses; 256 257 /* Assume nothing found */ 258 *Next = NULL; 259 Alias[0] = '\0'; 260 261 /* Get the hostent */ 262 Hostent = gethostbyname(NodeName); 263 if (Hostent) 264 { 265 /* Check for valid addresses */ 266 if ((Hostent->h_addrtype == AF_INET) && 267 (Hostent->h_length == sizeof(IN_ADDR))) 268 { 269 /* Loop every address in it */ 270 for (Addresses = Hostent->h_addr_list; *Addresses; Addresses++) 271 { 272 /* Create an addrinfo structure for it*/ 273 *Next = NewAddrInfo(SocketType, 274 Protocol, 275 Port, 276 ((PIN_ADDR)*Addresses)->s_addr); 277 if (!*Next) return EAI_MEMORY; 278 279 /* Move to the next entry */ 280 Next = &((*Next)->ai_next); 281 } 282 } 283 284 /* Copy the canonical name */ 285 strcpy(Alias, Hostent->h_name); 286 287 /* Return success */ 288 return 0; 289 } 290 291 /* Find out what the error was */ 292 switch (GetLastError()) 293 { 294 /* Convert the Winsock Error to an EAI error */ 295 case WSAHOST_NOT_FOUND: return EAI_NONAME; 296 case WSATRY_AGAIN: return EAI_AGAIN; 297 case WSANO_RECOVERY: return EAI_FAIL; 298 case WSANO_DATA: return EAI_NODATA; 299 default: return EAI_NONAME; 300 } 301 } 302 303 static 304 INT 305 WINAPI 306 LookupNodeByAddr(IN LPWSTR pNodeBuffer, 307 IN DWORD NodeBufferSize, 308 IN BOOLEAN OnlyNodeName, 309 IN PVOID Addr, 310 IN DWORD AddrSize, 311 IN INT AddressFamily) 312 { 313 GUID LookupGuid = SVCID_DNS_TYPE_PTR; 314 PIN_ADDR Ip4Addr = Addr; 315 WCHAR ReverseBuffer[76]; 316 WSAQUERYSETW Restrictions, Reply; 317 DWORD BufferLength; 318 INT ErrorCode; 319 HANDLE LookupHandle; 320 321 /* Validate the address */ 322 if (!Addr) return WSAEFAULT; 323 324 /* Make sure the family and address size match */ 325 if (AddressFamily == AF_INET6) 326 { 327 /* Check the address size for this type */ 328 if (AddrSize != sizeof(IN6_ADDR)) return WSAEFAULT; 329 Ip4Addr = (PIN_ADDR)&((PIN6_ADDR)Addr)->u.Byte[12]; 330 } 331 else if (AddressFamily == AF_INET) 332 { 333 /* Check the address size for this type */ 334 if (AddrSize != sizeof(IN_ADDR)) return WSAEFAULT; 335 } 336 else 337 { 338 /* Address family not supported */ 339 return WSAEAFNOSUPPORT; 340 } 341 342 /* Check if this is a mapped V4 IPv6 or pure IPv4 */ 343 if (((AddressFamily == AF_INET6) && (IN6_IS_ADDR_V4MAPPED(Addr))) || 344 (AddressFamily == AF_INET)) 345 { 346 /* Get the reverse name */ 347 Dns_Ip4AddressToReverseName_W(ReverseBuffer, *Ip4Addr); 348 } 349 /* FIXME: Not implemented for now 350 else if ( */ 351 352 /* By this point we have the Reverse Name, so prepare for lookup */ 353 RtlZeroMemory(&Restrictions, sizeof(Restrictions)); 354 Restrictions.dwSize = sizeof(Restrictions); 355 Restrictions.lpszServiceInstanceName = ReverseBuffer; 356 Restrictions.lpServiceClassId = &LookupGuid; 357 Restrictions.dwNameSpace = NS_DNS; 358 359 /* Now do the lookup */ 360 ErrorCode = WSALookupServiceBeginW(&Restrictions, 361 LUP_RETURN_NAME, 362 &LookupHandle); 363 if (ErrorCode == ERROR_SUCCESS) 364 { 365 /* Lookup successful, now get the data */ 366 BufferLength = (NI_MAXHOST - 1) * sizeof(WCHAR) + sizeof(Restrictions); 367 ErrorCode = WSALookupServiceNextW(LookupHandle, 368 0, 369 &BufferLength, 370 &Restrictions); 371 if (ErrorCode == ERROR_SUCCESS) 372 { 373 /* Now check if we have a name back */ 374 Reply = Restrictions; 375 if (!Reply.lpszServiceInstanceName) 376 { 377 /* Fail */ 378 ErrorCode = WSAHOST_NOT_FOUND; 379 } 380 else 381 { 382 /* Check if the caller only wants the node name */ 383 if (OnlyNodeName) 384 { 385 /* Split it and get only the partial host name */ 386 Dns_SplitHostFromDomainNameW(Reply.lpszServiceInstanceName); 387 } 388 389 /* Check the length and see if it's within our limit */ 390 if (wcslen(Reply.lpszServiceInstanceName) + 1 > 391 NodeBufferSize) 392 { 393 /* It's not, so fail */ 394 ErrorCode = WSAEFAULT; 395 } 396 else 397 { 398 /* It will fit, let's copy it*/ 399 wcscpy(pNodeBuffer, Reply.lpszServiceInstanceName); 400 } 401 } 402 } 403 } 404 else if (ErrorCode == WSASERVICE_NOT_FOUND) 405 { 406 /* Normalize the error code */ 407 ErrorCode = WSAHOST_NOT_FOUND; 408 } 409 410 /* Finish the lookup if one was in progress */ 411 if (LookupHandle) WSALookupServiceEnd(LookupHandle); 412 413 /* Return the error code */ 414 return ErrorCode; 415 } 416 417 static 418 INT 419 WINAPI 420 GetServiceNameForPort(IN LPWSTR pServiceBuffer, 421 IN DWORD ServiceBufferSize, 422 IN WORD Port, 423 IN DWORD Flags) 424 { 425 return ERROR_SUCCESS; 426 } 427 428 static 429 INT 430 WINAPI 431 LookupAddressForName(IN LPCSTR NodeName, 432 IN INT SocketType, 433 IN INT Protocol, 434 IN WORD Port, 435 IN BOOL bAI_CANONNAME, 436 OUT PADDRINFOW *pptResult) 437 { 438 INT iError = 0; 439 INT AliasCount = 0; 440 CHAR szFQDN1[NI_MAXHOST] = ""; 441 CHAR szFQDN2[NI_MAXHOST] = ""; 442 PCHAR Name = szFQDN1; 443 PCHAR Alias = szFQDN2; 444 PCHAR Scratch = NULL; 445 446 /* Make a copy of the name */ 447 strcpy(Name, NodeName); 448 449 /* Loop */ 450 while (TRUE) 451 { 452 /* Do a DNS Query for the name */ 453 iError = QueryDNS(NodeName, 454 SocketType, 455 Protocol, 456 Port, 457 Alias, 458 pptResult); 459 if (iError) break; 460 461 /* Exit if we have a result */ 462 if (*pptResult) break; 463 464 /* Don't loop continuously if this is a DNS misconfiguration */ 465 if ((!strlen(Alias)) || (!strcmp(Name, Alias)) || (++AliasCount == 16)) 466 { 467 /* Exit the loop with a failure */ 468 iError = EAI_FAIL; 469 break; 470 } 471 472 /* Restart loopup if we got a CNAME */ 473 Swap(Name, Alias, Scratch); 474 } 475 476 /* Check if we succeeded and the canonical name is requested */ 477 if (!iError && bAI_CANONNAME) 478 { 479 /* Allocate memory for a copy */ 480 (*pptResult)->ai_canonname = HeapAlloc(WsSockHeap, 0, 512); 481 482 /* Check if we had enough memory */ 483 if (!(*pptResult)->ai_canonname) 484 { 485 /* Set failure code */ 486 iError = EAI_MEMORY; 487 } 488 else 489 { 490 /* Convert the alias to UNICODE */ 491 MultiByteToWideChar(CP_ACP, 492 0, 493 Alias, 494 -1, 495 (*pptResult)->ai_canonname, 496 256); 497 } 498 } 499 500 /* Return to caller */ 501 return iError; 502 } 503 504 /* 505 * @implemented 506 */ 507 INT 508 WSAAPI 509 GetAddrInfoW(IN PCWSTR pszNodeName, 510 IN PCWSTR pszServiceName, 511 IN const ADDRINFOW *ptHints, 512 OUT PADDRINFOW *pptResult) 513 { 514 INT iError = 0; 515 INT iFlags = 0; 516 INT iFamily = PF_UNSPEC; 517 INT iSocketType = 0; 518 INT iProtocol = 0; 519 WORD wPort = 0; 520 DWORD dwAddress = 0; 521 PSERVENT ptService = NULL; 522 PCHAR pc = NULL; 523 BOOL bClone = FALSE; 524 WORD wTcpPort = 0; 525 WORD wUdpPort = 0; 526 WCHAR CanonicalName[0x42]; 527 CHAR AnsiServiceName[256]; 528 CHAR AnsiNodeName[256]; 529 DPRINT("GetAddrInfoW: %S, %S, %p, %p\n", pszNodeName, pszServiceName, ptHints, pptResult); 530 531 /* Assume error */ 532 *pptResult = NULL; 533 534 /* We must have at least one name to work with */ 535 if (!(pszNodeName) && !(pszServiceName)) 536 { 537 /* Fail */ 538 SetLastError(EAI_NONAME); 539 return EAI_NONAME; 540 } 541 542 /* Check if we got hints */ 543 if (ptHints) 544 { 545 /* Make sure these are empty */ 546 if ((ptHints->ai_addrlen) || 547 (ptHints->ai_canonname) || 548 (ptHints->ai_addr) || 549 (ptHints->ai_next)) 550 { 551 /* Fail if they aren't */ 552 SetLastError(EAI_FAIL); 553 return EAI_FAIL; 554 } 555 556 /* Save the flags and validate them */ 557 iFlags = ptHints->ai_flags; 558 if ((iFlags & AI_CANONNAME) && !pszNodeName) 559 { 560 SetLastError(EAI_BADFLAGS); 561 return EAI_BADFLAGS; 562 } 563 564 /* Save family and validate it */ 565 iFamily = ptHints->ai_family; 566 if ((iFamily != PF_UNSPEC) && (iFamily != PF_INET)) 567 { 568 SetLastError(EAI_FAMILY); 569 return EAI_FAMILY; 570 } 571 572 /* Save socket type and validate it */ 573 iSocketType = ptHints->ai_socktype; 574 if ((iSocketType != 0) && 575 (iSocketType != SOCK_STREAM) && 576 (iSocketType != SOCK_DGRAM) && 577 (iSocketType != SOCK_RAW)) 578 { 579 SetLastError(EAI_SOCKTYPE); 580 return EAI_SOCKTYPE; 581 } 582 583 /* Save the protocol */ 584 iProtocol = ptHints->ai_protocol; 585 } 586 587 /* Check if we have a service name */ 588 if (pszServiceName) 589 { 590 /* We need to convert it to ANSI */ 591 WideCharToMultiByte(CP_ACP, 592 0, 593 pszServiceName, 594 -1, 595 AnsiServiceName, 596 sizeof(AnsiServiceName), 597 NULL, 598 0); 599 600 /* Get the port */ 601 wPort = (WORD)strtoul(AnsiServiceName, &pc, 10); 602 603 /* Check if the port string is numeric */ 604 if (*pc == '\0') 605 { 606 /* Get the port directly */ 607 wPort = wTcpPort = wUdpPort = htons(wPort); 608 609 #if 0 610 /* Check if this is both TCP and UDP */ 611 if (iSocketType == 0) 612 { 613 /* Set it to TCP for now, but remember to clone */ 614 bClone = TRUE; 615 iSocketType = SOCK_STREAM; 616 } 617 #endif 618 } 619 else 620 { 621 wPort = 0; 622 /* The port name was a string. Check if this is a UDP socket */ 623 if ((iSocketType == 0) || (iSocketType == SOCK_DGRAM)) 624 { 625 /* It's UDP, do a getservbyname */ 626 ptService = getservbyname(AnsiServiceName, "udp"); 627 628 /* If we got a servent, return the port from it */ 629 if (ptService) wPort = wUdpPort = ptService->s_port; 630 } 631 632 /* Check if this is a TCP socket */ 633 if ((iSocketType == 0) || (iSocketType == SOCK_STREAM)) 634 { 635 /* It's TCP, do a getserbyname */ 636 ptService = getservbyname(AnsiServiceName, "tcp"); 637 638 /* Return the port from the servent */ 639 if (ptService) wPort = wTcpPort = ptService->s_port; 640 } 641 642 /* If we got 0, then fail */ 643 if (wPort == 0) 644 { 645 SetLastError(EAI_SERVICE); 646 return EAI_SERVICE; 647 } 648 649 /* Check if this was for both */ 650 if (iSocketType == 0) 651 { 652 /* Do the TCP case right now */ 653 if (wTcpPort && !wUdpPort) 654 iSocketType = SOCK_STREAM; 655 if (!wTcpPort && wUdpPort) 656 iSocketType = SOCK_DGRAM; 657 //bClone = (wTcpPort && wUdpPort); 658 } 659 } 660 } 661 662 /* Check if no node was given or if this is is a valid IPv4 address */ 663 if ((!pszNodeName) || (ParseV4Address(pszNodeName, &dwAddress))) 664 { 665 /* Check if we don't have a node name */ 666 if (!pszNodeName) 667 { 668 /* Make one up based on the flags */ 669 dwAddress = htonl((iFlags & AI_PASSIVE) ? 670 INADDR_ANY : INADDR_LOOPBACK); 671 } 672 673 /* Create the Addr Info */ 674 *pptResult = NewAddrInfo(iSocketType, iProtocol, wPort, dwAddress); 675 676 /* If we didn't get one back, assume out of memory */ 677 if (!(*pptResult)) iError = EAI_MEMORY; 678 679 /* Check if we have success and a nodename */ 680 if (!iError && pszNodeName) 681 { 682 /* Set AI_NUMERICHOST since this is a numeric string */ 683 (*pptResult)->ai_flags |= AI_NUMERICHOST; 684 685 /* Check if the canonical name was requested */ 686 if (iFlags & AI_CANONNAME) 687 { 688 /* Get the canonical name */ 689 GetNameInfoW((*pptResult)->ai_addr, 690 (socklen_t)(*pptResult)->ai_addrlen, 691 CanonicalName, 692 0x41, 693 NULL, 694 0, 695 2); 696 697 /* Allocate memory for a copy */ 698 (*pptResult)->ai_canonname = HeapAlloc(WsSockHeap, 699 0, 700 wcslen(CanonicalName)); 701 702 if (!(*pptResult)->ai_canonname) 703 { 704 /* No memory for the copy */ 705 iError = EAI_MEMORY; 706 } 707 else 708 { 709 /* Duplicate the string */ 710 RtlMoveMemory((*pptResult)->ai_canonname, 711 CanonicalName, 712 wcslen(CanonicalName)); 713 } 714 } 715 } 716 } 717 else if (iFlags & AI_NUMERICHOST) 718 { 719 /* No name for this request (we have a non-numeric name) */ 720 iError = EAI_NONAME; 721 } 722 else 723 { 724 /* We need to convert it to ANSI */ 725 WideCharToMultiByte(CP_ACP, 726 0, 727 pszNodeName, 728 -1, 729 AnsiNodeName, 730 sizeof(AnsiNodeName), 731 NULL, 732 0); 733 734 /* Non-numeric name, do DNS lookup */ 735 iError = LookupAddressForName(AnsiNodeName, 736 iSocketType, 737 iProtocol, 738 wPort, 739 (iFlags & AI_CANONNAME), 740 pptResult); 741 } 742 743 /* If all was good and the caller requested UDP and TCP */ 744 if (!iError && bClone) 745 { 746 /* Process UDP now, we already did TCP */ 747 iError = CloneAddrInfo(wUdpPort, *pptResult); 748 } 749 750 /* If we've hit an error till here */ 751 if (iError) 752 { 753 /* Free the address info and return nothing */ 754 FreeAddrInfoW(*pptResult); 755 *pptResult = NULL; 756 } 757 758 /* Return to caller */ 759 SetLastError(iError); 760 return iError; 761 } 762 763 #undef freeaddrinfo 764 /* 765 * @implemented 766 */ 767 VOID 768 WINAPI 769 freeaddrinfo(PADDRINFOA AddrInfo) 770 { 771 PADDRINFOA NextInfo; 772 773 /* Loop the chain of structures */ 774 for (NextInfo = AddrInfo; NextInfo; NextInfo = AddrInfo) 775 { 776 /* Check if there is a canonical name */ 777 if (NextInfo->ai_canonname) 778 { 779 /* Free it */ 780 HeapFree(WsSockHeap, 0, NextInfo->ai_canonname); 781 } 782 783 /* Check if there is an address */ 784 if (NextInfo->ai_addr) 785 { 786 /* Free it */ 787 HeapFree(WsSockHeap, 0, NextInfo->ai_addr); 788 } 789 790 /* Move to the next entry */ 791 AddrInfo = NextInfo->ai_next; 792 793 /* Free this entry */ 794 HeapFree(WsSockHeap, 0, NextInfo); 795 } 796 } 797 798 #undef getaddrinfo 799 /* 800 * @implemented 801 */ 802 INT 803 WINAPI 804 getaddrinfo(const char FAR *nodename, 805 const char FAR *servname, 806 const struct addrinfo FAR *hints, 807 struct addrinfo FAR * FAR *res) 808 { 809 INT ErrorCode; 810 LPWSTR UnicodeNodeName = NULL; 811 LPWSTR UnicodeServName = NULL; 812 DPRINT("getaddrinfo: %s, %s, %p, %p\n", nodename, servname, hints, res); 813 814 /* Check for WSAStartup */ 815 if ((ErrorCode = WsQuickProlog()) != ERROR_SUCCESS) return ErrorCode; 816 817 /* Convert the node name */ 818 if (nodename) 819 { 820 UnicodeNodeName = UnicodeDupFromAnsi(nodename); 821 if (!UnicodeNodeName) 822 { 823 /* Prepare to fail */ 824 ErrorCode = GetLastError(); 825 goto Quickie; 826 } 827 } 828 829 /* Convert the servname too, if we have one */ 830 if (servname) 831 { 832 UnicodeServName = UnicodeDupFromAnsi(servname); 833 if (!UnicodeServName) 834 { 835 /* Prepare to fail */ 836 ErrorCode = GetLastError(); 837 goto Quickie; 838 } 839 } 840 841 /* Now call the unicode function */ 842 ErrorCode = GetAddrInfoW(UnicodeNodeName, 843 UnicodeServName, 844 (PADDRINFOW)hints, 845 (PADDRINFOW*)res); 846 847 /* Convert it to ANSI if we succeeded */ 848 if (ErrorCode == ERROR_SUCCESS) ConvertAddrinfoFromUnicodeToAnsi((PADDRINFOW)*res); 849 850 Quickie: 851 /* Check if we have a unicode node name and serv name */ 852 if (UnicodeNodeName) HeapFree(WsSockHeap, 0, UnicodeNodeName); 853 if (UnicodeServName) HeapFree(WsSockHeap, 0, UnicodeServName); 854 855 /* Check if we are in error */ 856 if (ErrorCode != ERROR_SUCCESS) 857 { 858 /* Free the structure and return nothing */ 859 freeaddrinfo(*res); 860 *res = NULL; 861 } 862 863 /* Set the last error and return */ 864 SetLastError(ErrorCode); 865 return ErrorCode; 866 } 867 868 /* 869 * @implemented 870 */ 871 INT 872 WSAAPI 873 GetNameInfoW(IN CONST SOCKADDR *pSockaddr, 874 IN socklen_t SockaddrLength, 875 OUT PWCHAR pNodeBuffer, 876 IN DWORD NodeBufferSize, 877 OUT PWCHAR pServiceBuffer, 878 IN DWORD ServiceBufferSize, 879 IN INT Flags) 880 { 881 DWORD AddressLength, AddrSize; 882 PVOID Addr; 883 SOCKADDR_IN6 Address; 884 INT ErrorCode = ERROR_SUCCESS; 885 886 DPRINT("GetNameInfoW: %p, %d, %p, %ld, %p, %ld, %d\n", 887 pSockaddr, 888 SockaddrLength, 889 pNodeBuffer, 890 NodeBufferSize, 891 pServiceBuffer, 892 ServiceBufferSize, 893 Flags); 894 895 /* Check for valid socket */ 896 if (!pSockaddr) 897 return WSAEFAULT; 898 899 /* Check which family this is */ 900 if (pSockaddr->sa_family == AF_INET) 901 { 902 /* IPv4 */ 903 AddressLength = sizeof(SOCKADDR_IN); 904 Addr = &((PSOCKADDR_IN)pSockaddr)->sin_addr; 905 AddrSize = sizeof(IN_ADDR); 906 } 907 else if (pSockaddr->sa_family == AF_INET6) 908 { 909 /* IPv6 */ 910 AddressLength = sizeof(SOCKADDR_IN6); 911 Addr = &((PSOCKADDR_IN6)pSockaddr)->sin6_addr; 912 AddrSize = sizeof(IN6_ADDR); 913 } 914 else 915 { 916 /* Unsupported family */ 917 SetLastError(EAI_FAMILY); 918 return EAI_FAMILY; 919 } 920 921 /* Check for valid socket address length */ 922 if ((DWORD)SockaddrLength < AddressLength) 923 return WSAEFAULT; 924 925 /* Check if we have a node name */ 926 if (pNodeBuffer) 927 { 928 /* Check if only the numeric host is wanted */ 929 if (!(Flags & NI_NUMERICHOST)) 930 { 931 /* Do the lookup by addr */ 932 ErrorCode = LookupNodeByAddr(pNodeBuffer, 933 NodeBufferSize, 934 Flags & NI_NOFQDN, 935 Addr, 936 AddrSize, 937 pSockaddr->sa_family); 938 /* Check if we failed */ 939 if (ErrorCode != ERROR_SUCCESS) 940 { 941 /* Fail if the caller REALLY wants the NAME itself? */ 942 if (Flags & NI_NAMEREQD) goto quickie; 943 } 944 else 945 { 946 /* We succeeded, no need to get the numeric address */ 947 goto SkipNumeric; 948 } 949 } 950 951 /* Copy the address */ 952 RtlMoveMemory(&Address, pSockaddr, AddressLength); 953 954 /* Get the numeric address */ 955 if (pSockaddr->sa_family == AF_INET) 956 { 957 /* IPv4 */ 958 ((PSOCKADDR_IN)&Address)->sin_port = 0; 959 } 960 else if (pSockaddr->sa_family == AF_INET6) 961 { 962 /* IPv6 */ 963 ((PSOCKADDR_IN6)&Address)->sin6_port = 0; 964 } 965 ErrorCode = WSAAddressToStringW((LPSOCKADDR)&Address, 966 AddressLength, 967 NULL, 968 pNodeBuffer, 969 &NodeBufferSize); 970 if (ErrorCode == SOCKET_ERROR) 971 { 972 /* Get the error code and exit with it */ 973 ErrorCode = GetLastError(); 974 goto quickie; 975 } 976 } 977 978 SkipNumeric: 979 /* Check if we got a service name */ 980 if (pServiceBuffer) 981 { 982 /* Handle this request */ 983 ErrorCode = GetServiceNameForPort(pServiceBuffer, 984 ServiceBufferSize, 985 ((PSOCKADDR_IN)pSockaddr)->sin_port, 986 Flags); 987 } 988 989 /* Set the error and return it (or success) */ 990 quickie: 991 SetLastError(ErrorCode); 992 return ErrorCode; 993 } 994 995 #undef getnameinfo 996 /* 997 * @implemented 998 */ 999 INT 1000 WINAPI 1001 getnameinfo(const struct sockaddr FAR *sa, 1002 socklen_t salen, 1003 char FAR *host, 1004 DWORD hostlen, 1005 char FAR *serv, 1006 DWORD servlen, 1007 INT flags) 1008 { 1009 INT ErrorCode; 1010 WCHAR Buffer[256]; 1011 WCHAR ServiceBuffer[17]; 1012 DWORD HostLength = 0, ServLength = 0; 1013 PWCHAR ServiceString = NULL, HostString = NULL; 1014 DPRINT("getnameinfo: %p, %p, %p, %lx\n", host, serv, sa, salen); 1015 1016 /* Check for WSAStartup */ 1017 if ((ErrorCode = WsQuickProlog()) != ERROR_SUCCESS) return ErrorCode; 1018 1019 /* Check if we have a host pointer */ 1020 if (host) 1021 { 1022 /* Setup the data for it */ 1023 HostString = Buffer; 1024 HostLength = sizeof(Buffer) / sizeof(WCHAR); 1025 } 1026 1027 /* Check if we have a service pointer */ 1028 if (serv) 1029 { 1030 /* Setup the data for it */ 1031 ServiceString = ServiceBuffer; 1032 ServLength = sizeof(ServiceBuffer) / sizeof(WCHAR); 1033 } 1034 1035 /* Now call the unicode function */ 1036 ErrorCode = GetNameInfoW(sa, 1037 salen, 1038 HostString, 1039 HostLength, 1040 ServiceString, 1041 ServLength, 1042 flags); 1043 1044 /* Check for success */ 1045 if (ErrorCode == ERROR_SUCCESS) 1046 { 1047 /* Check if we had a host pointer */ 1048 if (HostString) 1049 { 1050 /* Convert it back to ANSI */ 1051 ErrorCode = WideCharToMultiByte(CP_ACP, 1052 0, 1053 HostString, 1054 -1, 1055 host, 1056 hostlen, 1057 NULL, 1058 NULL); 1059 if (!ErrorCode) goto Quickie; 1060 } 1061 1062 /* Check if we have a service pointer */ 1063 if (ServiceString) 1064 { 1065 /* Convert it back to ANSI */ 1066 ErrorCode = WideCharToMultiByte(CP_ACP, 1067 0, 1068 ServiceString, 1069 -1, 1070 serv, 1071 servlen, 1072 NULL, 1073 NULL); 1074 if (!ErrorCode) goto Quickie; 1075 } 1076 1077 /* Return success */ 1078 return ERROR_SUCCESS; 1079 } 1080 1081 /* Set the last error and return */ 1082 Quickie: 1083 SetLastError(ErrorCode); 1084 return ErrorCode; 1085 } 1086