wined3d/glsl: Flush NaN to zero in ftoi.
[wine.git] / dlls / dnsapi / libresolv.c
blobd68ca1fd9bf2752c13f834401db0e6e7af53511d
1 /*
2 * Unix interface for libresolv
4 * Copyright 2021 Hans Leidekker for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
27 #ifdef HAVE_RESOLV
28 #include <stdarg.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/types.h>
34 #ifdef HAVE_NETINET_IN_H
35 # include <netinet/in.h>
36 #endif
37 #ifdef HAVE_ARPA_NAMESER_H
38 # include <arpa/nameser.h>
39 #endif
40 #ifdef HAVE_RESOLV_H
41 # include <resolv.h>
42 #endif
43 #ifdef HAVE_NETDB_H
44 # include <netdb.h>
45 #endif
47 #include "ntstatus.h"
48 #define WIN32_NO_STATUS
49 #include "windef.h"
50 #include "winternl.h"
51 #include "winbase.h"
52 #include "windns.h"
53 #define USE_WS_PREFIX
54 #include "ws2def.h"
55 #include "ws2ipdef.h"
57 #include "wine/debug.h"
58 #include "dnsapi.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi);
62 /* call res_init() just once because of a bug in Mac OS X 10.4 */
63 /* call once per thread on systems that have per-thread _res */
64 static void init_resolver( void )
66 if (!(_res.options & RES_INIT)) res_init();
69 static unsigned long map_options( DWORD options )
71 unsigned long ret = 0;
73 if (options == DNS_QUERY_STANDARD)
74 return RES_DEFAULT;
76 if (options & DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE)
77 ret |= RES_IGNTC;
78 if (options & DNS_QUERY_USE_TCP_ONLY)
79 ret |= RES_USEVC;
80 if (options & DNS_QUERY_NO_RECURSION)
81 ret &= ~RES_RECURSE;
82 if (options & DNS_QUERY_NO_LOCAL_NAME)
83 ret &= ~RES_DNSRCH;
84 if (options & DNS_QUERY_NO_HOSTS_FILE)
85 ret |= RES_NOALIASES;
86 if (options & DNS_QUERY_TREAT_AS_FQDN)
87 ret &= ~RES_DEFNAMES;
89 if (options & DNS_QUERY_DONT_RESET_TTL_VALUES)
90 FIXME( "option DNS_QUERY_DONT_RESET_TTL_VALUES not implemented\n" );
91 if (options & DNS_QUERY_RESERVED)
92 FIXME( "option DNS_QUERY_RESERVED not implemented\n" );
93 if (options & DNS_QUERY_WIRE_ONLY)
94 FIXME( "option DNS_QUERY_WIRE_ONLY not implemented\n" );
95 if (options & DNS_QUERY_NO_WIRE_QUERY)
96 FIXME( "option DNS_QUERY_NO_WIRE_QUERY not implemented\n" );
97 if (options & DNS_QUERY_BYPASS_CACHE)
98 FIXME( "option DNS_QUERY_BYPASS_CACHE not implemented\n" );
99 if (options & DNS_QUERY_RETURN_MESSAGE)
100 FIXME( "option DNS_QUERY_RETURN_MESSAGE not implemented\n" );
102 if (options & DNS_QUERY_NO_NETBT)
103 TRACE( "netbios query disabled\n" );
105 return ret;
108 static DNS_STATUS map_h_errno( int error )
110 switch (error)
112 case NO_DATA:
113 case HOST_NOT_FOUND: return DNS_ERROR_RCODE_NAME_ERROR;
114 case TRY_AGAIN: return DNS_ERROR_RCODE_SERVER_FAILURE;
115 case NO_RECOVERY: return DNS_ERROR_RCODE_REFUSED;
116 #ifdef NETDB_INTERNAL
117 case NETDB_INTERNAL: return DNS_ERROR_RCODE;
118 #endif
119 default:
120 FIXME( "unmapped error code: %d\n", error );
121 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
125 static NTSTATUS resolv_get_searchlist( void *args )
127 const struct get_searchlist_params *params = args;
128 WCHAR *list = params->list;
129 DWORD i, needed = 0;
130 WCHAR *ptr, *end;
132 init_resolver();
134 for (i = 0; i < MAXDNSRCH + 1 && _res.dnsrch[i]; i++)
135 needed += (strlen(_res.dnsrch[i]) + 1) * sizeof(WCHAR);
136 needed += sizeof(WCHAR); /* null terminator */
138 if (!list || *params->len < needed)
140 *params->len = needed;
141 return !list ? ERROR_SUCCESS : ERROR_MORE_DATA;
144 *params->len = needed;
146 ptr = list;
147 end = ptr + needed / sizeof(WCHAR);
148 for (i = 0; i < MAXDNSRCH + 1 && _res.dnsrch[i]; i++)
149 ptr += ntdll_umbstowcs( _res.dnsrch[i], strlen(_res.dnsrch[i]) + 1, ptr, end - ptr );
150 *ptr = 0; /* null terminator */
151 return ERROR_SUCCESS;
155 static inline int filter( unsigned short sin_family, USHORT family )
157 if (sin_family != AF_INET && sin_family != AF_INET6) return TRUE;
158 if (sin_family == AF_INET6 && family == WS_AF_INET) return TRUE;
159 if (sin_family == AF_INET && family == WS_AF_INET6) return TRUE;
161 return FALSE;
164 #ifdef HAVE_RES_GETSERVERS
166 static NTSTATUS resolv_get_serverlist( void *args )
168 const struct get_serverlist_params *params = args;
169 DNS_ADDR_ARRAY *addrs = params->addrs;
170 struct __res_state *state = &_res;
171 DWORD i, found, total, needed;
172 union res_sockaddr_union *buf;
174 init_resolver();
176 total = res_getservers( state, NULL, 0 );
177 if (!total) return DNS_ERROR_NO_DNS_SERVERS;
179 if (!addrs && params->family != WS_AF_INET && params->family != WS_AF_INET6)
181 *params->len = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[total]);
182 return ERROR_SUCCESS;
185 buf = malloc( total * sizeof(union res_sockaddr_union) );
186 if (!buf) return ERROR_NOT_ENOUGH_MEMORY;
188 total = res_getservers( state, buf, total );
190 for (i = 0, found = 0; i < total; i++)
192 if (filter( buf[i].sin.sin_family, params->family )) continue;
193 found++;
195 if (!found) return DNS_ERROR_NO_DNS_SERVERS;
197 needed = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[found]);
198 if (!addrs || *params->len < needed)
200 *params->len = needed;
201 return !addrs ? ERROR_SUCCESS : ERROR_MORE_DATA;
203 *params->len = needed;
204 memset( addrs, 0, needed );
205 addrs->AddrCount = addrs->MaxCount = found;
207 for (i = 0, found = 0; i < total; i++)
209 if (filter( buf[i].sin.sin_family, params->family )) continue;
211 if (buf[i].sin6.sin6_family == AF_INET6)
213 SOCKADDR_IN6 *sa = (SOCKADDR_IN6 *)addrs->AddrArray[found].MaxSa;
214 sa->sin6_family = WS_AF_INET6;
215 memcpy( &sa->sin6_addr, &buf[i].sin6.sin6_addr, sizeof(sa->sin6_addr) );
216 addrs->AddrArray[found].Data.DnsAddrUserDword[0] = sizeof(*sa);
218 else
220 SOCKADDR_IN *sa = (SOCKADDR_IN *)addrs->AddrArray[found].MaxSa;
221 sa->sin_family = WS_AF_INET;
222 sa->sin_addr.WS_s_addr = buf[i].sin.sin_addr.s_addr;
223 addrs->AddrArray[found].Data.DnsAddrUserDword[0] = sizeof(*sa);
225 found++;
228 free( buf );
229 return ERROR_SUCCESS;
232 #else
234 static NTSTATUS resolv_get_serverlist( void *args )
236 const struct get_serverlist_params *params = args;
237 DNS_ADDR_ARRAY *addrs = params->addrs;
238 DWORD needed, found, i;
240 init_resolver();
242 if (!_res.nscount) return DNS_ERROR_NO_DNS_SERVERS;
243 if (!addrs && params->family != WS_AF_INET && params->family != WS_AF_INET6)
245 *params->len = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[_res.nscount]);
246 return ERROR_SUCCESS;
249 for (i = 0, found = 0; i < _res.nscount; i++)
251 unsigned short sin_family = AF_INET;
252 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
253 if (_res._u._ext.nsaddrs[i]) sin_family = _res._u._ext.nsaddrs[i]->sin6_family;
254 #endif
255 if (filter( sin_family, params->family )) continue;
256 found++;
258 if (!found) return DNS_ERROR_NO_DNS_SERVERS;
260 needed = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[found]);
261 if (!addrs || *params->len < needed)
263 *params->len = needed;
264 return !addrs ? ERROR_SUCCESS : ERROR_MORE_DATA;
266 *params->len = needed;
267 memset( addrs, 0, needed );
268 addrs->AddrCount = addrs->MaxCount = found;
270 for (i = 0, found = 0; i < _res.nscount; i++)
272 unsigned short sin_family = AF_INET;
273 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
274 if (_res._u._ext.nsaddrs[i]) sin_family = _res._u._ext.nsaddrs[i]->sin6_family;
275 #endif
276 if (filter( sin_family, params->family )) continue;
278 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
279 if (sin_family == AF_INET6)
281 SOCKADDR_IN6 *sa = (SOCKADDR_IN6 *)addrs->AddrArray[found].MaxSa;
282 sa->sin6_family = WS_AF_INET6;
283 memcpy( &sa->sin6_addr, &_res._u._ext.nsaddrs[i]->sin6_addr, sizeof(sa->sin6_addr) );
284 addrs->AddrArray[found].Data.DnsAddrUserDword[0] = sizeof(*sa);
286 else
287 #endif
289 SOCKADDR_IN *sa = (SOCKADDR_IN *)addrs->AddrArray[found].MaxSa;
290 sa->sin_family = WS_AF_INET;
291 sa->sin_addr.WS_s_addr = _res.nsaddr_list[i].sin_addr.s_addr;
292 addrs->AddrArray[found].Data.DnsAddrUserDword[0] = sizeof(*sa);
294 found++;
297 return ERROR_SUCCESS;
299 #endif
301 static NTSTATUS resolv_set_serverlist( void *args )
303 const IP4_ARRAY *addrs = args;
304 int i;
306 init_resolver();
308 if (!addrs || !addrs->AddrCount) return ERROR_SUCCESS;
309 if (addrs->AddrCount > MAXNS)
311 WARN( "too many servers: %d only using the first: %d\n",
312 (UINT)addrs->AddrCount, MAXNS );
313 _res.nscount = MAXNS;
315 else _res.nscount = addrs->AddrCount;
317 for (i = 0; i < _res.nscount; i++)
318 _res.nsaddr_list[i].sin_addr.s_addr = addrs->AddrArray[i];
320 return ERROR_SUCCESS;
323 static NTSTATUS resolv_query( void *args )
325 const struct query_params *params = args;
326 DNS_STATUS ret = ERROR_SUCCESS;
327 int len;
329 init_resolver();
330 _res.options |= map_options( params->options );
332 if ((len = res_query( params->name, ns_c_in, params->type, params->buf, *params->len )) < 0)
333 ret = map_h_errno( h_errno );
334 else
335 *params->len = len;
336 return ret;
339 const unixlib_entry_t __wine_unix_call_funcs[] =
341 resolv_get_searchlist,
342 resolv_get_serverlist,
343 resolv_set_serverlist,
344 resolv_query,
347 C_ASSERT( ARRAYSIZE(__wine_unix_call_funcs) == unix_funcs_count );
349 #ifdef _WIN64
351 typedef ULONG PTR32;
353 static NTSTATUS wow64_resolv_get_searchlist( void *args )
355 struct
357 PTR32 list;
358 PTR32 len;
359 } const *params32 = args;
361 struct get_searchlist_params params =
363 ULongToPtr(params32->list),
364 ULongToPtr(params32->len)
367 return resolv_get_searchlist( &params );
370 static NTSTATUS wow64_resolv_get_serverlist( void *args )
372 struct
374 USHORT family;
375 PTR32 addrs;
376 PTR32 len;
377 } const *params32 = args;
379 struct get_serverlist_params params =
381 params32->family,
382 ULongToPtr(params32->addrs),
383 ULongToPtr(params32->len)
386 return resolv_get_serverlist( &params );
389 static NTSTATUS wow64_resolv_query( void *args )
391 struct
393 PTR32 name;
394 WORD type;
395 DWORD options;
396 PTR32 buf;
397 PTR32 len;
398 } const *params32 = args;
400 struct query_params params =
402 ULongToPtr(params32->name),
403 params32->type,
404 params32->options,
405 ULongToPtr(params32->buf),
406 ULongToPtr(params32->len)
409 return resolv_query( &params );
412 const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
414 wow64_resolv_get_searchlist,
415 wow64_resolv_get_serverlist,
416 resolv_set_serverlist,
417 wow64_resolv_query,
420 C_ASSERT( ARRAYSIZE(__wine_unix_call_wow64_funcs) == unix_funcs_count );
422 #endif /* _WIN64 */
424 #endif /* HAVE_RESOLV */