[PATCH 1/2] dnsapi: migrating to res_nquery and partial DnsQueryEx implementation

Donat Enikeev donat at enikeev.net
Sun Jan 10 07:55:17 CST 2016


There was a note about res_query bug in MacOSX 10.4:
 /* call res_init() just once because of a bug in Mac OS X 10.4, call once per thread on systems that have per-thread _res */

I've removed it while migratign to res_nquery, let me please clarify reasons:

1. I found no proof that bug is fair for res_nquery for MacOSX 10.4
2. I believe that generally res_init was not designed to be reliable under several calls
Quote from manual: "res_init() and res_query() use some static (global) state stored in the _res structure, rendering these functions non-thread-safe"
It could be easily confirmed by massive DnsQuery calls (like in tests will follow) when res_query will use systems default DNS servers instead of passed
(any host resolve in same context could change them during the way)
3. Its always good to manage states by a resolver, at least in sense of Dnsapi.dll, when options and dns servers are not expected to be kept among consequent queries
4. All these calls are deprecated long ago, new interfaces have not been changed since 1999 (16 years)

Signed-off-by: Donat Enikeev <donat at enikeev.net>
---
 dlls/dnsapi/query.c | 110 ++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 85 insertions(+), 25 deletions(-)

diff --git a/dlls/dnsapi/query.c b/dlls/dnsapi/query.c
index a66db37..d69e6c5 100644
--- a/dlls/dnsapi/query.c
+++ b/dlls/dnsapi/query.c
@@ -46,6 +46,10 @@
 #include "winnls.h"
 #include "windns.h"
 #include "nb30.h"
+#define USE_WS_PREFIX
+#include "inaddr.h"
+#include "in6addr.h"
+#include "ws2tcpip.h"
 
 #include "dnsapi.h"
 
@@ -53,12 +57,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(dnsapi);
 
 #ifdef HAVE_RESOLV
 
-/* call res_init() just once because of a bug in Mac OS X 10.4 */
-/* call once per thread on systems that have per-thread _res */
-static void initialise_resolver( void )
+static res_state initialise_resolver( void )
 {
-    if ((_res.options & RES_INIT) == 0)
-        res_init();
+    res_state dns_res_state = NULL;
+
+    if ( !(dns_res_state = heap_alloc_zero(sizeof(struct __res_state))) )
+        return NULL;
+
+    res_ninit(dns_res_state);
+
+    return dns_res_state;
 }
 
 static const char *dns_section_to_str( ns_sect section )
@@ -543,7 +551,7 @@ exit:
 
 /* res_init() must have been called before calling these three functions.
  */
-static DNS_STATUS dns_set_serverlist( const IP4_ARRAY *addrs )
+static DNS_STATUS dns_set_serverlist( res_state dns_res_state, const IP4_ARRAY *addrs )
 {
     int i;
 
@@ -551,38 +559,39 @@ static DNS_STATUS dns_set_serverlist( const IP4_ARRAY *addrs )
     {
         WARN( "too many servers: %d only using the first: %d\n",
               addrs->AddrCount, MAXNS );
-        _res.nscount = MAXNS;
+        dns_res_state->nscount = MAXNS;
     }
-    else _res.nscount = addrs->AddrCount;
+    else
+        dns_res_state->nscount = addrs->AddrCount;
 
-    for (i = 0; i < _res.nscount; i++)
-        _res.nsaddr_list[i].sin_addr.s_addr = addrs->AddrArray[i];
+    for (i = 0; i < dns_res_state->nscount; i++)
+        dns_res_state->nsaddr_list[i].sin_addr.s_addr = addrs->AddrArray[i];
 
     return ERROR_SUCCESS;
 }
 
-static DNS_STATUS dns_get_serverlist( PIP4_ARRAY addrs, PDWORD len )
+static DNS_STATUS dns_get_serverlist( res_state dns_res_state, PIP4_ARRAY addrs, PDWORD len )
 {
     unsigned int size;
     int i;
 
-    size = FIELD_OFFSET(IP4_ARRAY, AddrArray[_res.nscount]);
+    size = FIELD_OFFSET(IP4_ARRAY, AddrArray[dns_res_state->nscount]);
     if (!addrs || *len < size)
     {
         *len = size;
         return ERROR_INSUFFICIENT_BUFFER;
     }
 
-    addrs->AddrCount = _res.nscount;
+    addrs->AddrCount = dns_res_state->nscount;
 
-    for (i = 0; i < _res.nscount; i++)
-        addrs->AddrArray[i] = _res.nsaddr_list[i].sin_addr.s_addr;
+    for (i = 0; i < dns_res_state->nscount; i++)
+        addrs->AddrArray[i] = dns_res_state->nsaddr_list[i].sin_addr.s_addr;
 
     return ERROR_SUCCESS;
 }
 
 #define DNS_MAX_PACKET_SIZE 4096
-static DNS_STATUS dns_do_query( PCSTR name, WORD type, DWORD options, PDNS_RECORDA *result )
+static DNS_STATUS dns_do_query( res_state dns_res_state, PCSTR name, WORD type, DWORD options, PDNS_RECORDA *result )
 {
     DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
 
@@ -597,7 +606,9 @@ static DNS_STATUS dns_do_query( PCSTR name, WORD type, DWORD options, PDNS_RECOR
 
     DNS_RRSET_INIT( rrset );
 
-    len = res_query( name, ns_c_in, type, answer, sizeof(answer) );
+    TRACE("Perfoming res_nquery(%p, %s, %u, %u, %p)\n",dns_res_state, name, type, options, result);
+
+    len = res_nquery( dns_res_state, name, ns_c_in, type, answer, sizeof(answer) );
     if (len < 0)
     {
         ret = dns_map_h_errno( h_errno );
@@ -652,14 +663,57 @@ static const char *debugstr_query_request(const DNS_QUERY_REQUEST *req)
             req->InterfaceIndex, req->pQueryCompletionCallback, req->pQueryContext);
 }
 
+
+
 /******************************************************************************
  * DnsQueryEx           [DNSAPI.@]
  *
  */
 DNS_STATUS WINAPI DnsQueryEx(DNS_QUERY_REQUEST *request, DNS_QUERY_RESULT *result, DNS_QUERY_CANCEL *cancel)
 {
-    FIXME("(%s %p %p)\n", debugstr_query_request(request), result, cancel);
-    return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
+    DNS_STATUS status;
+    PIP4_ARRAY p_dns_server = NULL;
+
+    TRACE("(%s %p %p)\n", debugstr_query_request(request), result, cancel);
+    if (!request || !result)
+        return ERROR_INVALID_PARAMETER;
+
+    if (request->pQueryCompletionCallback)
+        FIXME("Asynchronous DNS queries not implemented. (%s %p)\n", debugstr_query_request(request), result);
+
+    if (request->pDnsServerList && request->pDnsServerList->AddrCount)
+    {
+        if ( request->pDnsServerList->Family == AF_INET )
+        {
+            SOCKADDR_IN *p_sockaddr;
+
+            if (request->pDnsServerList->AddrCount > 1)
+                FIXME("Only first DNS server from the list will be used, %d given \n", request->pDnsServerList->AddrCount);
+
+            p_sockaddr = (SOCKADDR_IN *)&request->pDnsServerList->AddrArray[0].MaxSa;
+
+            p_dns_server = heap_alloc(sizeof(IP4_ARRAY));
+            if ( !p_dns_server ) return ERROR_NOT_ENOUGH_MEMORY;
+
+            p_dns_server->AddrArray[0] = p_sockaddr->sin_addr.WS_s_addr;
+            p_dns_server->AddrCount = 1;
+
+            TRACE("DNS address to use %hu.%hu.%hu.%hu (%u) \n",
+                p_sockaddr->sin_addr.WS_s_impno, p_sockaddr->sin_addr.WS_s_lh,
+                p_sockaddr->sin_addr.WS_s_host, p_sockaddr->sin_addr.WS_s_net, p_sockaddr->sin_addr.WS_s_addr);
+        } else
+            FIXME("Families other than IPv4 (AF_INET) are not implemented so far, %d given \n", request->pDnsServerList->Family );
+    }
+
+    status = DnsQuery_W( request->QueryName, request->QueryType, request->QueryOptions, p_dns_server, &result->pQueryRecords, NULL);
+
+    result->Version = DNS_QUERY_RESULTS_VERSION1;
+    result->QueryStatus = status;
+    result->QueryOptions = request->QueryOptions;
+
+    heap_free(p_dns_server);
+
+    return status;
 }
 
 /******************************************************************************
@@ -706,6 +760,7 @@ DNS_STATUS WINAPI DnsQuery_UTF8( PCSTR name, WORD type, DWORD options, PVOID ser
 {
     DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
 #ifdef HAVE_RESOLV
+    res_state dns_res_state;
 
     TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_a(name), dns_type_to_str( type ),
            options, servers, result, reserved );
@@ -713,13 +768,15 @@ DNS_STATUS WINAPI DnsQuery_UTF8( PCSTR name, WORD type, DWORD options, PVOID ser
     if (!name || !result)
         return ERROR_INVALID_PARAMETER;
 
-    initialise_resolver();
-    _res.options |= dns_map_options( options );
+    dns_res_state = initialise_resolver();
+    if ( !dns_res_state ) return ERROR_NOT_ENOUGH_MEMORY;
+
+    dns_res_state->options |= dns_map_options( options );
 
-    if (servers && (ret = dns_set_serverlist( servers )))
+    if (servers && (ret = dns_set_serverlist( dns_res_state, servers )))
         return ret;
 
-    ret = dns_do_query( name, type, options, result );
+    ret = dns_do_query( dns_res_state, name, type, options, result );
 
     if (ret == DNS_ERROR_RCODE_NAME_ERROR && type == DNS_TYPE_A &&
         !(options & DNS_QUERY_NO_NETBT))
@@ -728,6 +785,8 @@ DNS_STATUS WINAPI DnsQuery_UTF8( PCSTR name, WORD type, DWORD options, PVOID ser
         ret = dns_do_query_netbios( name, result );
     }
 
+    heap_free(dns_res_state);
+
 #endif
     return ret;
 }
@@ -824,8 +883,9 @@ DNS_STATUS WINAPI DnsQueryConfig( DNS_CONFIG_TYPE config, DWORD flag, PCWSTR ada
     case DnsConfigDnsServerList:
     {
 #ifdef HAVE_RESOLV
-        initialise_resolver();
-        ret = dns_get_serverlist( buffer, len );
+        res_state dns_res_state = initialise_resolver();
+        ret = dns_get_serverlist( dns_res_state, buffer, len );
+        heap_free(dns_res_state);
         break;
 #else
         WARN( "compiled without resolver support\n" );
-- 
2.5.0




More information about the wine-patches mailing list