[WS2_32]
authorCameron Gutman <aicommander@gmail.com>
Sun, 25 Apr 2010 20:01:59 +0000 (20:01 +0000)
committerCameron Gutman <aicommander@gmail.com>
Sun, 25 Apr 2010 20:01:59 +0000 (20:01 +0000)
- Add support for reading the hosts file
- Fix an off-by-one error which prevented reading the last value in the services file
- Fixes bug 4410 and bug 4880

svn path=/trunk/; revision=47020

reactos/dll/win32/ws2_32/misc/ns.c

index bb89ead..fee4f03 100644 (file)
@@ -640,7 +640,199 @@ void free_servent(struct servent* s)
     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
@@ -661,6 +853,7 @@ gethostbyname(IN  CONST CHAR FAR* name)
     /* include/WinDNS.h -- look up DNS_RECORD on MSDN */
     PDNS_RECORD dp = 0;
     PWINSOCK_THREAD_BLOCK p;
+    LPHOSTENT Hostent;
 
     addr = GH_INVALID;
 
@@ -726,6 +919,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,
@@ -993,7 +1192,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++;
@@ -1174,7 +1373,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++;