Commit da65aa5b authored by Alexandre Julliard's avatar Alexandre Julliard

dnsapi: Convert the Unix library to the __wine_unix_call interface.

parent d193c164
MODULE = dnsapi.dll
UNIXLIB = dnsapi.so
IMPORTLIB = dnsapi
DELAYIMPORTS = netapi32
EXTRALIBS = $(RESOLV_LIBS)
......
......@@ -18,7 +18,12 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "winternl.h"
#include "wine/heap.h"
#include "wine/unixlib.h"
static inline char *strdup_a( const char *src )
{
......@@ -121,12 +126,41 @@ static inline char *strdup_ua( const char *src )
extern const char *debugstr_type( unsigned short ) DECLSPEC_HIDDEN;
struct resolv_funcs
struct get_searchlist_params
{
DNS_STATUS (CDECL *get_searchlist)( DNS_TXT_DATAW *list, DWORD *len );
DNS_STATUS (CDECL *get_serverlist)( USHORT family, DNS_ADDR_ARRAY *addrs, DWORD *len );
DNS_STATUS (CDECL *query)( const char *name, WORD type, DWORD options, void *buf, DWORD *len );
DNS_STATUS (CDECL *set_serverlist)( const IP4_ARRAY *addrs );
DNS_TXT_DATAW *list;
DWORD *len;
};
extern const struct resolv_funcs *resolv_funcs;
struct get_serverlist_params
{
USHORT family;
DNS_ADDR_ARRAY *addrs;
DWORD *len;
};
struct set_serverlist_params
{
const IP4_ARRAY *addrs;
};
struct query_params
{
const char *name;
WORD type;
DWORD options;
void *buf;
DWORD *len;
};
enum unix_funcs
{
unix_get_searchlist,
unix_get_serverlist,
unix_set_serverlist,
unix_query,
};
extern unixlib_handle_t resolv_handle;
#define RESOLV_CALL( func, params ) __wine_unix_call( resolv_handle, unix_ ## func, params )
......@@ -49,66 +49,16 @@
#include "windef.h"
#include "winternl.h"
#include "winbase.h"
#include "winnls.h"
#include "windns.h"
#define USE_WS_PREFIX
#include "ws2def.h"
#include "ws2ipdef.h"
#include "wine/debug.h"
#include "wine/heap.h"
#include "dnsapi.h"
WINE_DEFAULT_DEBUG_CHANNEL(dnsapi);
static CPTABLEINFO unix_cptable;
static ULONG unix_cp = CP_UTF8;
static DWORD WINAPI get_unix_codepage_once( RTL_RUN_ONCE *once, void *param, void **context )
{
static const WCHAR wineunixcpW[] = { 'W','I','N','E','U','N','I','X','C','P',0 };
UNICODE_STRING name, value;
WCHAR value_buffer[13];
SIZE_T size;
void *ptr;
RtlInitUnicodeString( &name, wineunixcpW );
value.Buffer = value_buffer;
value.MaximumLength = sizeof(value_buffer);
if (!RtlQueryEnvironmentVariable_U( NULL, &name, &value ))
RtlUnicodeStringToInteger( &value, 10, &unix_cp );
if (unix_cp != CP_UTF8 && !NtGetNlsSectionPtr( 11, unix_cp, NULL, &ptr, &size ))
RtlInitCodePageTable( ptr, &unix_cptable );
return TRUE;
}
static BOOL get_unix_codepage( void )
{
static RTL_RUN_ONCE once = RTL_RUN_ONCE_INIT;
return !RtlRunOnceExecuteOnce( &once, get_unix_codepage_once, NULL, NULL );
}
static DWORD dnsapi_umbstowcs( const char *src, WCHAR *dst, DWORD dstlen )
{
DWORD srclen = strlen( src ) + 1;
DWORD len;
get_unix_codepage();
if (unix_cp == CP_UTF8)
{
RtlUTF8ToUnicodeN( dst, dstlen, &len, src, srclen );
return len;
}
else
{
len = srclen * sizeof(WCHAR);
if (dst) RtlCustomCPToUnicodeN( &unix_cptable, dst, dstlen, &len, src, srclen );
return len;
}
}
/* 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 init_resolver( void )
......@@ -172,25 +122,27 @@ static DNS_STATUS map_h_errno( int error )
}
}
static DNS_STATUS CDECL resolv_get_searchlist( DNS_TXT_DATAW *list, DWORD *len )
static NTSTATUS resolv_get_searchlist( void *args )
{
struct get_searchlist_params *params = args;
DNS_TXT_DATAW *list = params->list;
DWORD i, needed, str_needed = 0;
char *ptr, *end;
init_resolver();
for (i = 0; i < MAXDNSRCH + 1 && _res.dnsrch[i]; i++)
str_needed += dnsapi_umbstowcs( _res.dnsrch[i], NULL, 0 );
str_needed += (strlen(_res.dnsrch[i]) + 1) * sizeof(WCHAR);
needed = FIELD_OFFSET(DNS_TXT_DATAW, pStringArray[i]) + str_needed;
if (!list || *len < needed)
if (!list || *params->len < needed)
{
*len = needed;
*params->len = needed;
return !list ? ERROR_SUCCESS : ERROR_MORE_DATA;
}
*len = needed;
*params->len = needed;
list->dwStringCount = i;
ptr = (char *)(list->pStringArray + i);
......@@ -198,7 +150,8 @@ static DNS_STATUS CDECL resolv_get_searchlist( DNS_TXT_DATAW *list, DWORD *len )
for (i = 0; i < MAXDNSRCH + 1 && _res.dnsrch[i]; i++)
{
list->pStringArray[i] = (WCHAR *)ptr;
ptr += dnsapi_umbstowcs( _res.dnsrch[i], list->pStringArray[i], end - ptr );
ptr += ntdll_umbstowcs( _res.dnsrch[i], strlen(_res.dnsrch[i]) + 1,
list->pStringArray[i], end - ptr );
}
return ERROR_SUCCESS;
}
......@@ -215,8 +168,10 @@ static inline int filter( unsigned short sin_family, USHORT family )
#ifdef HAVE_RES_GETSERVERS
static DNS_STATUS CDECL resolv_get_serverlist( USHORT family, DNS_ADDR_ARRAY *addrs, DWORD *len )
static NTSTATUS resolv_get_serverlist( void *args )
{
struct get_serverlist_params *params = args;
DNS_ADDR_ARRAY *addrs = params->addrs;
struct __res_state *state = &_res;
DWORD i, found, total, needed;
union res_sockaddr_union *buf;
......@@ -226,9 +181,9 @@ static DNS_STATUS CDECL resolv_get_serverlist( USHORT family, DNS_ADDR_ARRAY *ad
total = res_getservers( state, NULL, 0 );
if (!total) return DNS_ERROR_NO_DNS_SERVERS;
if (!addrs && family != WS_AF_INET && family != WS_AF_INET6)
if (!addrs && params->family != WS_AF_INET && params->family != WS_AF_INET6)
{
*len = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[total]);
*params->len = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[total]);
return ERROR_SUCCESS;
}
......@@ -239,24 +194,24 @@ static DNS_STATUS CDECL resolv_get_serverlist( USHORT family, DNS_ADDR_ARRAY *ad
for (i = 0, found = 0; i < total; i++)
{
if (filter( buf[i].sin.sin_family, family )) continue;
if (filter( buf[i].sin.sin_family, params->family )) continue;
found++;
}
if (!found) return DNS_ERROR_NO_DNS_SERVERS;
needed = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[found]);
if (!addrs || *len < needed)
if (!addrs || *params->len < needed)
{
*len = needed;
*params->len = needed;
return !addrs ? ERROR_SUCCESS : ERROR_MORE_DATA;
}
*len = needed;
*params->len = needed;
memset( addrs, 0, needed );
addrs->AddrCount = addrs->MaxCount = found;
for (i = 0, found = 0; i < total; i++)
{
if (filter( buf[i].sin.sin_family, family )) continue;
if (filter( buf[i].sin.sin_family, params->family )) continue;
if (buf[i].sin6.sin6_family == AF_INET6)
{
......@@ -281,16 +236,18 @@ static DNS_STATUS CDECL resolv_get_serverlist( USHORT family, DNS_ADDR_ARRAY *ad
#else
static DNS_STATUS CDECL resolv_get_serverlist( USHORT family, DNS_ADDR_ARRAY *addrs, DWORD *len )
static NTSTATUS resolv_get_serverlist( void *args )
{
struct get_serverlist_params *params = args;
DNS_ADDR_ARRAY *addrs = params->addrs;
DWORD needed, found, i;
init_resolver();
if (!_res.nscount) return DNS_ERROR_NO_DNS_SERVERS;
if (!addrs && family != WS_AF_INET && family != WS_AF_INET6)
if (!addrs && params->family != WS_AF_INET && params->family != WS_AF_INET6)
{
*len = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[_res.nscount]);
*params->len = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[_res.nscount]);
return ERROR_SUCCESS;
}
......@@ -300,18 +257,18 @@ static DNS_STATUS CDECL resolv_get_serverlist( USHORT family, DNS_ADDR_ARRAY *ad
#ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
if (_res._u._ext.nsaddrs[i]) sin_family = _res._u._ext.nsaddrs[i]->sin6_family;
#endif
if (filter( sin_family, family )) continue;
if (filter( sin_family, params->family )) continue;
found++;
}
if (!found) return DNS_ERROR_NO_DNS_SERVERS;
needed = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[found]);
if (!addrs || *len < needed)
if (!addrs || *params->len < needed)
{
*len = needed;
*params->len = needed;
return !addrs ? ERROR_SUCCESS : ERROR_MORE_DATA;
}
*len = needed;
*params->len = needed;
memset( addrs, 0, needed );
addrs->AddrCount = addrs->MaxCount = found;
......@@ -321,7 +278,7 @@ static DNS_STATUS CDECL resolv_get_serverlist( USHORT family, DNS_ADDR_ARRAY *ad
#ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
if (_res._u._ext.nsaddrs[i]) sin_family = _res._u._ext.nsaddrs[i]->sin6_family;
#endif
if (filter( sin_family, family )) continue;
if (filter( sin_family, params->family )) continue;
#ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
if (sin_family == AF_INET6)
......@@ -346,8 +303,10 @@ static DNS_STATUS CDECL resolv_get_serverlist( USHORT family, DNS_ADDR_ARRAY *ad
}
#endif
static DNS_STATUS CDECL resolv_set_serverlist( const IP4_ARRAY *addrs )
static NTSTATUS resolv_set_serverlist( void *args )
{
struct set_serverlist_params *params = args;
const IP4_ARRAY *addrs = params->addrs;
int i;
init_resolver();
......@@ -367,34 +326,28 @@ static DNS_STATUS CDECL resolv_set_serverlist( const IP4_ARRAY *addrs )
return ERROR_SUCCESS;
}
static DNS_STATUS CDECL resolv_query( const char *name, WORD type, DWORD options, void *answer, DWORD *retlen )
static NTSTATUS resolv_query( void *args )
{
struct query_params *params = args;
DNS_STATUS ret = ERROR_SUCCESS;
int len;
init_resolver();
_res.options |= map_options( options );
_res.options |= map_options( params->options );
if ((len = res_query( name, ns_c_in, type, answer, *retlen )) < 0)
if ((len = res_query( params->name, ns_c_in, params->type, params->buf, *params->len )) < 0)
ret = map_h_errno( h_errno );
else
*retlen = len;
*params->len = len;
return ret;
}
static const struct resolv_funcs funcs =
unixlib_entry_t __wine_unix_call_funcs[] =
{
resolv_get_searchlist,
resolv_get_serverlist,
resolv_set_serverlist,
resolv_query,
resolv_set_serverlist
};
NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
{
if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS;
*(const struct resolv_funcs **)ptr_out = &funcs;
return STATUS_SUCCESS;
}
#endif /* HAVE_RESOLV */
......@@ -26,12 +26,13 @@
#include "winbase.h"
#include "winerror.h"
#include "windns.h"
#include "dnsapi.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dnsapi);
const struct resolv_funcs *resolv_funcs = NULL;
unixlib_handle_t resolv_handle = 0;
BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
{
......@@ -41,7 +42,8 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls( hinst );
if (__wine_init_unix_lib( hinst, reason, NULL, &resolv_funcs ))
if (NtQueryVirtualMemory( GetCurrentProcess(), hinst, MemoryWineUnixFuncs,
&resolv_handle, sizeof(resolv_handle), NULL ))
ERR( "No libresolv support, expect problems\n" );
break;
case DLL_PROCESS_DETACH:
......
......@@ -170,6 +170,8 @@ DNS_STATUS WINAPI DnsQuery_UTF8( PCSTR name, WORD type, DWORD options, PVOID ser
DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
unsigned char answer[4096];
DWORD len = sizeof(answer);
struct set_serverlist_params servlist_params = { servers };
struct query_params query_params = { name, type, options, answer, &len };
TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_a(name), debugstr_type( type ),
options, servers, result, reserved );
......@@ -177,9 +179,9 @@ DNS_STATUS WINAPI DnsQuery_UTF8( PCSTR name, WORD type, DWORD options, PVOID ser
if (!name || !result)
return ERROR_INVALID_PARAMETER;
if ((ret = resolv_funcs->set_serverlist( servers ))) return ret;
if ((ret = RESOLV_CALL( set_serverlist, &servlist_params ))) return ret;
ret = resolv_funcs->query( name, type, options, answer, &len );
ret = RESOLV_CALL( query, &query_params );
if (!ret)
{
DNS_MESSAGE_BUFFER *buffer = (DNS_MESSAGE_BUFFER *)answer;
......@@ -289,10 +291,10 @@ static DNS_STATUS get_dns_server_list( IP4_ARRAY *out, DWORD *len )
char buf[FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[3])];
DNS_ADDR_ARRAY *servers = (DNS_ADDR_ARRAY *)buf;
DWORD ret, needed, i, num, array_len = sizeof(buf);
struct get_serverlist_params params = { AF_INET, servers, &array_len };
for (;;)
{
ret = resolv_funcs->get_serverlist( AF_INET, servers, &array_len );
ret = RESOLV_CALL( get_serverlist, &params );
if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) goto err;
num = (array_len - FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[0])) / sizeof(DNS_ADDR);
needed = FIELD_OFFSET(IP4_ARRAY, AddrArray[num]);
......@@ -375,15 +377,25 @@ DNS_STATUS WINAPI DnsQueryConfig( DNS_CONFIG_TYPE config, DWORD flag, PCWSTR ada
break;
case DnsConfigDnsServersUnspec:
return resolv_funcs->get_serverlist( AF_UNSPEC, buffer, len );
{
struct get_serverlist_params params = { AF_UNSPEC, buffer, len };
return RESOLV_CALL( get_serverlist, &params );
}
case DnsConfigDnsServersIpv4:
return resolv_funcs->get_serverlist( AF_INET, buffer, len );
{
struct get_serverlist_params params = { AF_INET, buffer, len };
return RESOLV_CALL( get_serverlist, &params );
}
case DnsConfigDnsServersIpv6:
return resolv_funcs->get_serverlist( AF_INET6, buffer, len );
{
struct get_serverlist_params params = { AF_INET6, buffer, len };
return RESOLV_CALL( get_serverlist, &params );
}
case DnsConfigSearchList:
return resolv_funcs->get_searchlist( buffer, len );
{
struct get_searchlist_params params = { buffer, len };
return RESOLV_CALL( get_searchlist, &params );
}
default:
WARN( "unknown config type: %d\n", config );
break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment