[WS2_32]
[reactos.git] / reactos / dll / win32 / ws2_32 / misc / ns.c
index f6103b0..04e5b4b 100644 (file)
@@ -7,7 +7,6 @@
  * REVISIONS:
  *   CSH 01/09-2000 Created
  */
-#define __NO_CTYPE_INLINES
 #include <ctype.h>
 #include <ws2_32.h>
 #include <winbase.h>
@@ -33,8 +32,43 @@ WSAAddressToStringA(IN      LPSOCKADDR lpsaAddress,
                     OUT     LPSTR lpszAddressString,
                     IN OUT  LPDWORD lpdwAddressStringLength)
 {
-    UNIMPLEMENTED
+    DWORD size;
+    CHAR buffer[54]; /* 32 digits + 7':' + '[' + '%" + 5 digits + ']:' + 5 digits + '\0' */
+    CHAR *p;
+
+    if (!lpsaAddress) return SOCKET_ERROR;
+    if (!lpszAddressString || !lpdwAddressStringLength) return SOCKET_ERROR;
+
+    switch(lpsaAddress->sa_family)
+    {
+    case AF_INET:
+        if (dwAddressLength < sizeof(SOCKADDR_IN)) return SOCKET_ERROR;
+        sprintf( buffer, "%u.%u.%u.%u:%u",
+               (unsigned int)(ntohl( ((SOCKADDR_IN *)lpsaAddress)->sin_addr.s_addr ) >> 24 & 0xff),
+               (unsigned int)(ntohl( ((SOCKADDR_IN *)lpsaAddress)->sin_addr.s_addr ) >> 16 & 0xff),
+               (unsigned int)(ntohl( ((SOCKADDR_IN *)lpsaAddress)->sin_addr.s_addr ) >> 8 & 0xff),
+               (unsigned int)(ntohl( ((SOCKADDR_IN *)lpsaAddress)->sin_addr.s_addr ) & 0xff),
+               ntohs( ((SOCKADDR_IN *)lpsaAddress)->sin_port ) );
+
+        p = strchr( buffer, ':' );
+        if (!((SOCKADDR_IN *)lpsaAddress)->sin_port) *p = 0;
+        break;
+    default:
+        WSASetLastError(WSAEINVAL);
+        return SOCKET_ERROR;
+    }
+
+    size = strlen( buffer ) + 1;
 
+    if (*lpdwAddressStringLength <  size)
+    {
+        *lpdwAddressStringLength = size;
+        WSASetLastError(WSAEFAULT);
+        return SOCKET_ERROR;
+    }
+
+    *lpdwAddressStringLength = size;
+    strcpy( lpszAddressString, buffer );
     return 0;
 }
 
@@ -50,8 +84,27 @@ WSAAddressToStringW(IN      LPSOCKADDR lpsaAddress,
                     OUT     LPWSTR lpszAddressString,
                     IN OUT  LPDWORD lpdwAddressStringLength)
 {
-    UNIMPLEMENTED
+    INT   ret;
+    DWORD size;
+    WCHAR buffer[54]; /* 32 digits + 7':' + '[' + '%" + 5 digits + ']:' + 5 digits + '\0' */
+    CHAR bufAddr[54];
+
+    size = *lpdwAddressStringLength;
+    ret = WSAAddressToStringA(lpsaAddress, dwAddressLength, NULL, bufAddr, &size);
+
+    if (ret) return ret;
 
+    MultiByteToWideChar( CP_ACP, 0, bufAddr, size, buffer, sizeof( buffer )/sizeof(WCHAR));
+
+    if (*lpdwAddressStringLength <  size)
+    {
+        *lpdwAddressStringLength = size;
+        WSASetLastError(WSAEFAULT);
+        return SOCKET_ERROR;
+    }
+
+    *lpdwAddressStringLength = size;
+    lstrcpyW( lpszAddressString, buffer );
     return 0;
 }
 
@@ -66,7 +119,8 @@ WSAEnumNameSpaceProvidersA(IN OUT  LPDWORD lpdwBufferLength,
 {
     UNIMPLEMENTED
 
-    return 0;
+    WSASetLastError(WSASYSCALLFAILURE);
+    return SOCKET_ERROR;
 }
 
 
@@ -80,7 +134,8 @@ WSAEnumNameSpaceProvidersW(IN OUT  LPDWORD lpdwBufferLength,
 {
     UNIMPLEMENTED
 
-    return 0;
+    WSASetLastError(WSASYSCALLFAILURE);
+    return SOCKET_ERROR;
 }
 
 
@@ -96,7 +151,8 @@ WSAGetServiceClassInfoA(IN      LPGUID lpProviderId,
 {
     UNIMPLEMENTED
 
-    return 0;
+    WSASetLastError(WSASYSCALLFAILURE);
+    return SOCKET_ERROR;
 }
 
 
@@ -112,7 +168,8 @@ WSAGetServiceClassInfoW(IN      LPGUID lpProviderId,
 {
     UNIMPLEMENTED
 
-    return 0;
+    WSASetLastError(WSASYSCALLFAILURE);
+    return SOCKET_ERROR;
 }
 
 
@@ -127,7 +184,8 @@ WSAGetServiceClassNameByClassIdA(IN      LPGUID lpServiceClassId,
 {
     UNIMPLEMENTED
 
-    return 0;
+    WSASetLastError(WSASYSCALLFAILURE);
+    return SOCKET_ERROR;
 }
 
 
@@ -142,7 +200,8 @@ WSAGetServiceClassNameByClassIdW(IN      LPGUID lpServiceClassId,
 {
     UNIMPLEMENTED
 
-    return 0;
+    WSASetLastError(WSASYSCALLFAILURE);
+    return SOCKET_ERROR;
 }
 
 
@@ -155,7 +214,8 @@ WSAInstallServiceClassA(IN  LPWSASERVICECLASSINFOA lpServiceClassInfo)
 {
     UNIMPLEMENTED
 
-    return 0;
+    WSASetLastError(WSASYSCALLFAILURE);
+    return SOCKET_ERROR;
 }
 
 
@@ -168,7 +228,8 @@ WSAInstallServiceClassW(IN  LPWSASERVICECLASSINFOW lpServiceClassInfo)
 {
     UNIMPLEMENTED
 
-    return 0;
+    WSASetLastError(WSASYSCALLFAILURE);
+    return SOCKET_ERROR;
 }
 
 
@@ -183,7 +244,8 @@ WSALookupServiceBeginA(IN  LPWSAQUERYSETA lpqsRestrictions,
 {
     UNIMPLEMENTED
 
-    return 0;
+    WSASetLastError(WSASYSCALLFAILURE);
+    return SOCKET_ERROR;
 }
 
 
@@ -198,7 +260,8 @@ WSALookupServiceBeginW(IN  LPWSAQUERYSETW lpqsRestrictions,
 {
     UNIMPLEMENTED
 
-    return 0;
+    WSASetLastError(WSASYSCALLFAILURE);
+    return SOCKET_ERROR;
 }
 
 
@@ -211,7 +274,8 @@ WSALookupServiceEnd(IN  HANDLE hLookup)
 {
     UNIMPLEMENTED
 
-    return 0;
+    WSASetLastError(WSASYSCALLFAILURE);
+    return SOCKET_ERROR;
 }
 
 
@@ -227,7 +291,8 @@ WSALookupServiceNextA(IN      HANDLE hLookup,
 {
     UNIMPLEMENTED
 
-    return 0;
+    WSASetLastError(WSASYSCALLFAILURE);
+    return SOCKET_ERROR;
 }
 
 
@@ -243,7 +308,8 @@ WSALookupServiceNextW(IN      HANDLE hLookup,
 {
     UNIMPLEMENTED
 
-    return 0;
+    WSASetLastError(WSASYSCALLFAILURE);
+    return SOCKET_ERROR;
 }
 
 
@@ -256,7 +322,8 @@ WSARemoveServiceClass(IN  LPGUID lpServiceClassId)
 {
     UNIMPLEMENTED
 
-    return 0;
+    WSASetLastError(WSASYSCALLFAILURE);
+    return SOCKET_ERROR;
 }
 
 
@@ -271,7 +338,8 @@ WSASetServiceA(IN  LPWSAQUERYSETA lpqsRegInfo,
 {
     UNIMPLEMENTED
 
-    return 0;
+    WSASetLastError(WSASYSCALLFAILURE);
+    return SOCKET_ERROR;
 }
 
 
@@ -286,7 +354,8 @@ WSASetServiceW(IN  LPWSAQUERYSETW lpqsRegInfo,
 {
     UNIMPLEMENTED
 
-    return 0;
+    WSASetLastError(WSASYSCALLFAILURE);
+    return SOCKET_ERROR;
 }
 
 
@@ -364,7 +433,7 @@ WSAStringToAddressA(IN     LPSTR AddressString,
 
 
 /*
- * @implement
+ * @implemented
  */
 INT
 EXPORT
@@ -378,14 +447,15 @@ WSAStringToAddressW(IN      LPWSTR AddressString,
     int res=0;
     LONG inetaddr = 0;
     LPWSTR *bp=NULL;
+    SOCKADDR_IN *sockaddr;
 
-    SOCKADDR_IN *sockaddr = (SOCKADDR_IN *) lpAddress;
-
-    if (!lpAddressLength || !lpAddress)
+    if (!lpAddressLength || !lpAddress || !AddressString)
+    {
+        WSASetLastError(WSAEINVAL);
         return SOCKET_ERROR;
+    }
 
-    if (AddressString==NULL)
-        return WSAEINVAL;
+    sockaddr = (SOCKADDR_IN *) lpAddress;
 
     /* Set right adress family */
     if (lpProtocolInfo!=NULL)
@@ -403,46 +473,41 @@ WSAStringToAddressW(IN      LPWSTR AddressString,
         }
         else
         {
-            if (!lpAddress)
-                res = WSAEINVAL;
-            else
-            {
-                // translate now ip string to ip
+            // translate ip string to ip
 
-                /* rest sockaddr.sin_addr.s_addr
+            /* rest sockaddr.sin_addr.s_addr
                    for we need to be sure it is zero when we come to while */
-                memset(lpAddress,0,sizeof(SOCKADDR_IN));
-
-                /* Set right adress family */
-                sockaddr->sin_family = AF_INET;
+            memset(lpAddress,0,sizeof(SOCKADDR_IN));
 
-                /* Get port number */
-                pos = wcscspn(AddressString,L":") + 1;
+            /* Set right adress family */
+            sockaddr->sin_family = AF_INET;
 
-                if (pos < (int)wcslen(AddressString))
-                    sockaddr->sin_port = wcstol(&AddressString[pos],
-                                                bp,
-                                                10);
+            /* Get port number */
+            pos = wcscspn(AddressString,L":") + 1;
 
-                else
-                    sockaddr->sin_port = 0;
+            if (pos < (int)wcslen(AddressString))
+                sockaddr->sin_port = wcstol(&AddressString[pos],
+                                            bp,
+                                            10);
 
-                /* Get ip number */
-                pos=0;
-                inetaddr=0;
+            else
+                sockaddr->sin_port = 0;
 
-                while (pos < (int)wcslen(AddressString))
-                {
-                    inetaddr = (inetaddr<<8) + ((UCHAR)wcstol(&AddressString[pos],
-                                                              bp,
-                                                              10));
-                    pos += wcscspn( &AddressString[pos],L".") +1 ;
-                }
+            /* Get ip number */
+            pos=0;
+            inetaddr=0;
 
-                res = 0;
-                sockaddr->sin_addr.s_addr = inetaddr;
+            while (pos < (int)wcslen(AddressString))
+            {
+                inetaddr = (inetaddr<<8) + ((UCHAR)wcstol(&AddressString[pos],
+                                                          bp,
+                                                          10));
+                pos += wcscspn( &AddressString[pos],L".") +1 ;
             }
 
+            res = 0;
+            sockaddr->sin_addr.s_addr = inetaddr;
+
         }
     }
 
@@ -523,8 +588,8 @@ void free_hostent(struct hostent *he)
     {
        char *next = 0;
         HFREE(he->h_name);
-        if(he->h_aliases) 
-       { 
+        if(he->h_aliases)
+       {
            next = he->h_aliases[0];
            while(next) { HFREE(next); next++; }
        }
@@ -618,15 +683,208 @@ struct hostent defined in w32api/include/winsock2.h
 
 void free_servent(struct servent* s)
 {
+    char* next;
     HFREE(s->s_name);
-    char* next = s->s_aliases[0];
+    next = s->s_aliases[0];
     while(next) { HFREE(next); next++; }
     s->s_port = 0;
     HFREE(s->s_proto);
     HFREE(s);
 }
 
+/* This function is far from perfect but it works enough */
+static
+LPHOSTENT
+FindEntryInHosts(IN CONST CHAR FAR* name)
+{
+    BOOL Found = FALSE;
+    HANDLE HostsFile;
+    CHAR HostsDBData[BUFSIZ] = { 0 };
+    PCHAR SystemDirectory = HostsDBData;
+    PCHAR HostsLocation = "\\drivers\\etc\\hosts";
+    PCHAR AddressStr, DnsName = NULL, AddrTerm, NameSt, NextLine, ThisLine, Comment;
+    UINT SystemDirSize = sizeof(HostsDBData) - 1, ValidData = 0;
+    DWORD ReadSize;
+    ULONG Address;
+    PWINSOCK_THREAD_BLOCK p = NtCurrentTeb()->WinSockData;
+
+    /* We assume that the parameters are valid */
+
+    if (!GetSystemDirectoryA(SystemDirectory, SystemDirSize))
+    {
+        WSASetLastError(WSANO_RECOVERY);
+        WS_DbgPrint(MIN_TRACE, ("Could not get windows system directory.\n"));
+        return NULL; /* Can't get system directory */
+    }
+
+    strncat(SystemDirectory,
+            HostsLocation,
+            SystemDirSize );
+
+    HostsFile = CreateFileA(SystemDirectory,
+                            GENERIC_READ,
+                            FILE_SHARE_READ,
+                            NULL,
+                            OPEN_EXISTING,
+                            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
+                            NULL);
+    if (HostsFile == INVALID_HANDLE_VALUE)
+    {
+        WSASetLastError(WSANO_RECOVERY);
+        return NULL;
+    }
+
+    while(!Found &&
+          ReadFile(HostsFile,
+                   HostsDBData + ValidData,
+                   sizeof(HostsDBData) - ValidData,
+                   &ReadSize,
+                   NULL))
+    {
+        ValidData += ReadSize;
+        ReadSize = 0;
+        NextLine = ThisLine = HostsDBData;
+
+        /* Find the beginning of the next line */
+        while(NextLine < HostsDBData + ValidData &&
+              *NextLine != '\r' && *NextLine != '\n' )
+        {
+            NextLine++;
+        }
+
+        /* Zero and skip, so we can treat what we have as a string */
+        if( NextLine > HostsDBData + ValidData )
+            break;
+
+        *NextLine = 0; NextLine++;
+
+        Comment = strchr( ThisLine, '#' );
+        if( Comment ) *Comment = 0; /* Terminate at comment start */
+
+        AddressStr = ThisLine;
+        /* Find the first space separating the IP address from the DNS name */
+        AddrTerm = strchr(ThisLine, ' ');
+        if (AddrTerm)
+        {
+           /* Terminate the address string */
+           *AddrTerm = 0;
+
+           /* Find the last space before the DNS name */
+           NameSt = strrchr(ThisLine, ' ');
+
+           /* If there is only one space (the one we removed above), then just use the address terminator */
+           if (!NameSt)
+               NameSt = AddrTerm;
+
+           /* Move from the space to the first character of the DNS name */
+           NameSt++;
+
+           DnsName = NameSt;
+
+           if (!strcmp(name, DnsName))
+           {
+               Found = TRUE;
+               break;
+           }
+        }
+
+        /* Get rid of everything we read so far */
+        while( NextLine <= HostsDBData + ValidData &&
+               isspace (*NextLine))
+        {
+            NextLine++;
+        }
+
+        if (HostsDBData + ValidData - NextLine <= 0)
+            break;
+
+        WS_DbgPrint(MAX_TRACE,("About to move %d chars\n",
+                    HostsDBData + ValidData - NextLine));
+
+        memmove(HostsDBData,
+                NextLine,
+                HostsDBData + ValidData - NextLine );
+        ValidData -= NextLine - HostsDBData;
+        WS_DbgPrint(MAX_TRACE,("Valid bytes: %d\n", ValidData));
+    }
+
+    CloseHandle(HostsFile);
+
+    if (!Found)
+    {
+        WS_DbgPrint(MAX_TRACE,("Not found\n"));
+        WSASetLastError(WSANO_DATA);
+        return NULL;
+    }
+
+    if( !p->Hostent )
+    {
+        p->Hostent = HeapAlloc(GlobalHeap, 0, sizeof(*p->Hostent));
+        if( !p->Hostent )
+        {
+            WSASetLastError( WSATRY_AGAIN );
+            return NULL;
+        }
+    }
+
+    p->Hostent->h_name = HeapAlloc(GlobalHeap, 0, strlen(DnsName));
+    if( !p->Hostent->h_name )
+    {
+        WSASetLastError( WSATRY_AGAIN );
+        return NULL;
+    }
 
+    RtlCopyMemory(p->Hostent->h_name,
+                  DnsName,
+                  strlen(DnsName));
+
+    p->Hostent->h_aliases = HeapAlloc(GlobalHeap, 0, sizeof(char *));
+    if( !p->Hostent->h_aliases )
+    {
+        WSASetLastError( WSATRY_AGAIN );
+        return NULL;
+    }
+
+    p->Hostent->h_aliases[0] = 0;
+
+    if (strstr(AddressStr, ":"))
+    {
+       DbgPrint("AF_INET6 NOT SUPPORTED!\n");
+       WSASetLastError(WSAEINVAL);
+       return NULL;
+    }
+    else
+       p->Hostent->h_addrtype = AF_INET;
+
+    p->Hostent->h_addr_list = HeapAlloc(GlobalHeap, 0, sizeof(char *));
+    if( !p->Hostent->h_addr_list )
+    {
+        WSASetLastError( WSATRY_AGAIN );
+        return NULL;
+    }
+
+    Address = inet_addr(AddressStr);
+    if (Address == INADDR_NONE)
+    {
+        WSASetLastError(WSAEINVAL);
+        return NULL;
+    }
+
+    p->Hostent->h_addr_list[0] = HeapAlloc(GlobalHeap, 0, sizeof(Address));
+    if( !p->Hostent->h_addr_list[0] )
+    {
+        WSASetLastError( WSATRY_AGAIN );
+        return NULL;
+    }
+
+    RtlCopyMemory(p->Hostent->h_addr_list[0],
+                  &Address,
+                  sizeof(Address));
+
+    p->Hostent->h_length = sizeof(Address);
+
+    return p->Hostent;
+}
 
 LPHOSTENT
 EXPORT
@@ -646,10 +904,12 @@ gethostbyname(IN  CONST CHAR FAR* name)
     DNS_STATUS dns_status = {0};
     /* include/WinDNS.h -- look up DNS_RECORD on MSDN */
     PDNS_RECORD dp = 0;
+    PWINSOCK_THREAD_BLOCK p;
+    LPHOSTENT Hostent;
 
     addr = GH_INVALID;
 
-    PWINSOCK_THREAD_BLOCK p = NtCurrentTeb()->WinSockData;
+    p = NtCurrentTeb()->WinSockData;
 
     if( !p )
     {
@@ -711,6 +971,12 @@ gethostbyname(IN  CONST CHAR FAR* name)
         case GH_RFC1123_DNS:
         /* DNS_TYPE_A: include/WinDNS.h */
         /* DnsQuery -- lib/dnsapi/dnsapi/query.c */
+
+        /* Look for the DNS name in the hosts file */
+        Hostent = FindEntryInHosts(name);
+        if (Hostent)
+           return Hostent;
+
         dns_status = DnsQuery_A(name,
                                 DNS_TYPE_A,
                                 DNS_QUERY_STANDARD,
@@ -798,25 +1064,27 @@ gethostname(OUT CHAR FAR* name,
  *
  * @unimplemented
  */
+static CHAR *no_aliases = 0;
+static PROTOENT protocols[] =
+{
+    {"icmp",&no_aliases, IPPROTO_ICMP},
+    {"tcp", &no_aliases, IPPROTO_TCP},
+    {"udp", &no_aliases, IPPROTO_UDP},
+    {NULL, NULL, 0}
+};
 LPPROTOENT
 EXPORT
 getprotobyname(IN  CONST CHAR FAR* name)
 {
-    static CHAR *udp_aliases = 0;
-    static PROTOENT udp = { "udp", &udp_aliases, 17 };
-    static CHAR *tcp_aliases = 0;
-    static PROTOENT tcp = { "tcp", &tcp_aliases, 6 };
-
-    if(!_stricmp(name, "udp"))
-    {
-        return &udp;
-    }
-    else if (!_stricmp( name, "tcp"))
+    UINT i;
+    for (i = 0; protocols[i].p_name; i++)
     {
-        return &tcp;
+       if (_stricmp(protocols[i].p_name, name) == 0)
+         return &protocols[i];
     }
-
-    return 0;
+    return NULL;
 }
 
 /*
@@ -826,9 +1094,13 @@ LPPROTOENT
 EXPORT
 getprotobynumber(IN  INT number)
 {
-    UNIMPLEMENTED
-
-    return (LPPROTOENT)NULL;
+    UINT i;
+    for (i = 0; protocols[i].p_name; i++)
+    {
+       if (protocols[i].p_proto == number)
+         return &protocols[i];
+    }
+    return NULL;
 }
 
 #define SKIPWS(ptr,act) \
@@ -972,7 +1244,7 @@ getservbyname(IN  CONST CHAR FAR* name,
         }
 
         /* Zero and skip, so we can treat what we have as a string */
-        if( NextLine >= ServiceDBData + ValidData )
+        if( NextLine > ServiceDBData + ValidData )
             break;
 
         *NextLine = 0; NextLine++;
@@ -1153,7 +1425,7 @@ getservbyport(IN  INT port,
                *NextLine != '\r' && *NextLine != '\n' ) NextLine++;
 
         /* Zero and skip, so we can treat what we have as a string */
-        if( NextLine >= ServiceDBData + ValidData )
+        if( NextLine > ServiceDBData + ValidData )
             break;
 
         *NextLine = 0; NextLine++;
@@ -1274,6 +1546,12 @@ inet_addr(IN  CONST CHAR FAR* cp)
 
     p = (PCHAR)cp;
 
+    if (!p)
+    {
+        WSASetLastError(WSAEFAULT);
+        return INADDR_NONE;
+    }
+
     if (strlen(p) == 0)
         return INADDR_NONE;
 
@@ -1325,108 +1603,196 @@ inet_ntoa(IN  IN_ADDR in)
 
 
 /*
- * @unimplemented
- */
-HANDLE
-EXPORT
-WSAAsyncGetHostByAddr(IN  HWND hWnd,
-                      IN  UINT wMsg,
-                      IN  CONST CHAR FAR* addr,
-                      IN  INT len,
-                      IN  INT type,
-                      OUT CHAR FAR* buf,
-                      IN  INT buflen)
-{
-    UNIMPLEMENTED
-
-    return (HANDLE)0;
-}
-
-
-/*
- * @unimplemented
- */
-HANDLE
-EXPORT
-WSAAsyncGetHostByName(IN  HWND hWnd,
-                      IN  UINT wMsg,
-                      IN  CONST CHAR FAR* name,
-                      OUT CHAR FAR* buf,
-                      IN  INT buflen)
-{
-    UNIMPLEMENTED
-
-    return (HANDLE)0;
-}
-
-
-/*
- * @unimplemented
+ * @implemented
  */
-HANDLE
+VOID
 EXPORT
-WSAAsyncGetProtoByName(IN  HWND hWnd,
-                       IN  UINT wMsg,
-                       IN  CONST CHAR FAR* name,
-                       OUT CHAR FAR* buf,
-                       IN  INT buflen)
+freeaddrinfo(struct addrinfo *pAddrInfo)
 {
-    UNIMPLEMENTED
-
-    return (HANDLE)0;
+    struct addrinfo *next, *cur;
+    cur = pAddrInfo;
+    while (cur)
+    {
+        next = cur->ai_next;
+        if (cur->ai_addr)
+          HeapFree(GetProcessHeap(), 0, cur->ai_addr);
+        if (cur->ai_canonname)
+          HeapFree(GetProcessHeap(), 0, cur->ai_canonname);
+        HeapFree(GetProcessHeap(), 0, cur);
+        cur = next;
+    }
 }
 
 
-/*
- * @unimplemented
- */
-HANDLE
-EXPORT
-WSAAsyncGetProtoByNumber(IN  HWND hWnd,
-                         IN  UINT wMsg,
-                         IN  INT number,
-                         OUT CHAR FAR* buf,
-                         IN  INT buflen)
+struct addrinfo *
+new_addrinfo(struct addrinfo *prev)
 {
-    UNIMPLEMENTED
-
-    return (HANDLE)0;
+    struct addrinfo *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct addrinfo));
+    if (prev)
+      prev->ai_next = ret;
+    return ret;
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
-HANDLE
+INT
 EXPORT
-WSAAsyncGetServByName(IN  HWND hWnd,
-                      IN  UINT wMsg,
-                      IN  CONST CHAR FAR* name,
-                      IN  CONST CHAR FAR* proto,
-                      OUT CHAR FAR* buf,
-                      IN  INT buflen)
+getaddrinfo(const char FAR * nodename,
+            const char FAR * servname,
+            const struct addrinfo FAR * hints,
+            struct addrinfo FAR * FAR * res)
 {
-    UNIMPLEMENTED
+    struct addrinfo *ret = NULL, *ai;
+    ULONG addr;
+    USHORT port;
+    struct servent *se;
+    char *proto;
+    LPPROTOENT pent;
+    DNS_STATUS dns_status;
+    PDNS_RECORD dp, currdns;
+    struct sockaddr_in *sin;
+
+    if (res == NULL)
+        return WSAEINVAL;
+    if (nodename == NULL && servname == NULL)
+        return WSAHOST_NOT_FOUND;
+        
+    if (!WSAINITIALIZED)
+        return WSANOTINITIALISED;
 
-    return (HANDLE)0;
-}
+    if (servname)
+    {
+        /* converting port number */
+        port = strtoul(servname, NULL, 10);
+        /* service name was specified? */
+        if (port == 0)
+        {
+            /* protocol was specified? */
+            if (hints && hints->ai_protocol)
+            {
+                pent = getprotobynumber(hints->ai_protocol);
+                if (pent == NULL)
+                  return WSAEINVAL;
+                proto = pent->p_name;
+            }
+            else
+                proto = NULL;
+            se = getservbyname(servname, proto);
+            if (se == NULL)
+                return WSATYPE_NOT_FOUND;
+            port = se->s_port;
+        }
+        else
+            port = htons(port);
+    }
+    else
+        port = 0;
 
+    if (nodename)
+    {
+        /* Is it an IPv6 address? */
+        if (strstr(nodename, ":"))
+            return WSAHOST_NOT_FOUND;
+            
+        /* Is it an IPv4 address? */
+        addr = inet_addr(nodename);
+        if (addr != INADDR_NONE)
+        {
+            ai = new_addrinfo(NULL);
+            ai->ai_family = PF_INET;
+            ai->ai_addrlen = sizeof(struct sockaddr_in);
+            ai->ai_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ai->ai_addrlen);
+            sin = (struct sockaddr_in *)ai->ai_addr;
+            sin->sin_family = AF_INET;
+            sin->sin_port = port;
+            RtlCopyMemory(&sin->sin_addr, &addr, sizeof(sin->sin_addr));
+            if (hints)
+            {
+                if (ai->ai_socktype == 0)
+                    ai->ai_socktype = hints->ai_socktype;
+                if (ai->ai_protocol == 0)
+                    ai->ai_protocol = hints->ai_protocol;
+            }
+            ret = ai;
+        }
+        else
+        {
+           /* resolving host name */
+            dns_status = DnsQuery_A(nodename,
+                                    DNS_TYPE_A,
+                                    DNS_QUERY_STANDARD,
+                                    0,
+                                    /* extra dns servers */ &dp,
+                                    0);
+
+            if (dns_status == 0)
+            {
+                ai = NULL;
+                for (currdns = dp; currdns; currdns = currdns->pNext )
+                {
+                    /* accept only A records */
+                    if (currdns->wType != DNS_TYPE_A) continue;
+                    
+                    ai = new_addrinfo(ai);
+                    if (ret == NULL)
+                      ret = ai;
+                    ai->ai_family = PF_INET;
+                    ai->ai_addrlen = sizeof(struct sockaddr_in);
+                    ai->ai_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ai->ai_addrlen);
+                    sin = (struct sockaddr_in *)ret->ai_addr;
+                    sin->sin_family = AF_INET;
+                    sin->sin_port = port;
+                    RtlCopyMemory(&sin->sin_addr, &currdns->Data.A.IpAddress, sizeof(sin->sin_addr));
+                    if (hints)
+                    {
+                        if (ai->ai_socktype == 0)
+                            ai->ai_socktype = hints->ai_socktype;
+                        if (ai->ai_protocol == 0)
+                            ai->ai_protocol = hints->ai_protocol;
+                    }
+                }
+                DnsRecordListFree(dp, DnsFreeRecordList);
+            }
+        }
+    }
+    else
+    {
+        ai = new_addrinfo(NULL);
+        ai->ai_family = PF_INET;
+        ai->ai_addrlen = sizeof(struct sockaddr_in);
+        ai->ai_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ai->ai_addrlen);
+        sin = (struct sockaddr_in *)ai->ai_addr;
+        sin->sin_family = AF_INET;
+        sin->sin_port = port;
+        if (hints)
+        {
+            if (!(hints->ai_flags & AI_PASSIVE))
+            {
+                sin->sin_addr.S_un.S_un_b.s_b1 = 127;
+                sin->sin_addr.S_un.S_un_b.s_b2 = 0;
+                sin->sin_addr.S_un.S_un_b.s_b3 = 0;
+                sin->sin_addr.S_un.S_un_b.s_b4 = 1;
+            }
+            if (ai->ai_socktype == 0)
+                ai->ai_socktype = hints->ai_socktype;
+            if (ai->ai_protocol == 0)
+                ai->ai_protocol = hints->ai_protocol;
+        }
+        ret = ai;
+    }
 
-/*
- * @unimplemented
- */
-HANDLE
-EXPORT
-WSAAsyncGetServByPort(IN  HWND hWnd,
-                      IN  UINT wMsg,
-                      IN  INT port,
-                      IN  CONST CHAR FAR* proto,
-                      OUT CHAR FAR* buf,
-                      IN  INT buflen)
-{
-    UNIMPLEMENTED
+    if (ret == NULL)
+        return WSAHOST_NOT_FOUND;
+        
+    if (hints && hints->ai_family != PF_UNSPEC && hints->ai_family != PF_INET)
+    {
+        freeaddrinfo(ret);
+        return WSAEAFNOSUPPORT;
+    }
 
-    return (HANDLE)0;
+    *res = ret;
+    return 0;
 }
 
 /* EOF */
-