4 * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: context.c,v 1.55 2009/09/02 23:48:03 tbox Exp */
23 lwres_context_create() creates a #lwres_context_t structure for use in
24 lightweight resolver operations. It holds a socket and other data
25 needed for communicating with a resolver daemon. The new
26 lwres_context_t is returned through contextp, a pointer to a
27 lwres_context_t pointer. This lwres_context_t pointer must initially
28 be NULL, and is modified to point to the newly created
31 When the lightweight resolver needs to perform dynamic memory
32 allocation, it will call malloc_function to allocate memory and
33 free_function to free it. If malloc_function and free_function are
34 NULL, memory is allocated using malloc and free. It is not
35 permitted to have a NULL malloc_function and a non-NULL free_function
36 or vice versa. arg is passed as the first parameter to the memory
37 allocation functions. If malloc_function and free_function are NULL,
38 arg is unused and should be passed as NULL.
40 Once memory for the structure has been allocated, it is initialized
41 using lwres_conf_init() and returned via *contextp.
43 lwres_context_destroy() destroys a #lwres_context_t, closing its
44 socket. contextp is a pointer to a pointer to the context that is to
45 be destroyed. The pointer will be set to NULL when the context has
48 The context holds a serial number that is used to identify resolver
49 request packets and associate responses with the corresponding
50 requests. This serial number is controlled using
51 lwres_context_initserial() and lwres_context_nextserial().
52 lwres_context_initserial() sets the serial number for context *ctx to
53 serial. lwres_context_nextserial() increments the serial number and
54 returns the previous value.
56 Memory for a lightweight resolver context is allocated and freed using
57 lwres_context_allocmem() and lwres_context_freemem(). These use
58 whatever allocations were defined when the context was created with
59 lwres_context_create(). lwres_context_allocmem() allocates len bytes
60 of memory and if successful returns a pointer to the allocated
61 storage. lwres_context_freemem() frees len bytes of space starting at
64 lwres_context_sendrecv() performs I/O for the context ctx. Data are
65 read and written from the context's socket. It writes data from
66 sendbase -- typically a lightweight resolver query packet -- and waits
67 for a reply which is copied to the receive buffer at recvbase. The
68 number of bytes that were written to this receive buffer is returned
71 \section context_return Return Values
73 lwres_context_create() returns #LWRES_R_NOMEMORY if memory for the
74 struct lwres_context could not be allocated, #LWRES_R_SUCCESS
77 Successful calls to the memory allocator lwres_context_allocmem()
78 return a pointer to the start of the allocated space. It returns NULL
79 if memory could not be allocated.
81 #LWRES_R_SUCCESS is returned when lwres_context_sendrecv() completes
82 successfully. #LWRES_R_IOERROR is returned if an I/O error occurs and
83 #LWRES_R_TIMEOUT is returned if lwres_context_sendrecv() times out
84 waiting for a response.
86 \section context_see See Also
88 lwres_conf_init(), malloc, free.
99 #include <lwres/lwres.h>
100 #include <lwres/net.h>
101 #include <lwres/platform.h>
103 #ifdef LWRES_PLATFORM_NEEDSYSSELECTH
104 #include <sys/select.h>
107 #include "context_p.h"
108 #include "assert_p.h"
111 * Some systems define the socket length argument as an int, some as size_t,
112 * some as socklen_t. The last is what the current POSIX standard mandates.
113 * This definition is here so it can be portable but easily changed if needed.
115 #ifndef LWRES_SOCKADDR_LEN_T
116 #define LWRES_SOCKADDR_LEN_T unsigned int
120 * Make a socket nonblocking.
122 #ifndef MAKE_NONBLOCKING
123 #define MAKE_NONBLOCKING(sd, retval) \
125 retval = fcntl(sd, F_GETFL, 0); \
126 if (retval != -1) { \
127 retval |= O_NONBLOCK; \
128 retval = fcntl(sd, F_SETFL, retval); \
133 LIBLWRES_EXTERNAL_DATA lwres_uint16_t lwres_udp_port
= LWRES_UDP_PORT
;
134 LIBLWRES_EXTERNAL_DATA
const char *lwres_resolv_conf
= LWRES_RESOLV_CONF
;
137 lwres_malloc(void *, size_t);
140 lwres_free(void *, void *, size_t);
145 static lwres_result_t
146 context_connect(lwres_context_t
*);
149 * Creates a #lwres_context_t structure for use in
150 * lightweight resolver operations.
153 lwres_context_create(lwres_context_t
**contextp
, void *arg
,
154 lwres_malloc_t malloc_function
,
155 lwres_free_t free_function
,
158 lwres_context_t
*ctx
;
160 REQUIRE(contextp
!= NULL
&& *contextp
== NULL
);
163 * If we were not given anything special to use, use our own
164 * functions. These are just wrappers around malloc() and free().
166 if (malloc_function
== NULL
|| free_function
== NULL
) {
167 REQUIRE(malloc_function
== NULL
);
168 REQUIRE(free_function
== NULL
);
169 malloc_function
= lwres_malloc
;
170 free_function
= lwres_free
;
173 ctx
= malloc_function(arg
, sizeof(lwres_context_t
));
175 return (LWRES_R_NOMEMORY
);
178 * Set up the context.
180 ctx
->malloc
= malloc_function
;
181 ctx
->free
= free_function
;
185 ctx
->timeout
= LWRES_DEFAULT_TIMEOUT
;
186 ctx
->serial
= time(NULL
); /* XXXMLG or BEW */
190 if ((flags
& (LWRES_CONTEXT_USEIPV4
| LWRES_CONTEXT_USEIPV6
)) ==
191 LWRES_CONTEXT_USEIPV6
) {
194 if ((flags
& (LWRES_CONTEXT_USEIPV4
| LWRES_CONTEXT_USEIPV6
)) ==
195 LWRES_CONTEXT_USEIPV4
) {
200 * Init resolv.conf bits.
202 lwres_conf_init(ctx
);
205 return (LWRES_R_SUCCESS
);
209 Destroys a #lwres_context_t, closing its socket.
210 contextp is a pointer to a pointer to the context that is
211 to be destroyed. The pointer will be set to NULL
212 when the context has been destroyed.
215 lwres_context_destroy(lwres_context_t
**contextp
) {
216 lwres_context_t
*ctx
;
218 REQUIRE(contextp
!= NULL
&& *contextp
!= NULL
);
223 if (ctx
->sock
!= -1) {
227 (void)close(ctx
->sock
);
231 CTXFREE(ctx
, sizeof(lwres_context_t
));
233 /*% Increments the serial number and returns the previous value. */
235 lwres_context_nextserial(lwres_context_t
*ctx
) {
236 REQUIRE(ctx
!= NULL
);
238 return (ctx
->serial
++);
241 /*% Sets the serial number for context *ctx to serial. */
243 lwres_context_initserial(lwres_context_t
*ctx
, lwres_uint32_t serial
) {
244 REQUIRE(ctx
!= NULL
);
246 ctx
->serial
= serial
;
249 /*% Frees len bytes of space starting at location mem. */
251 lwres_context_freemem(lwres_context_t
*ctx
, void *mem
, size_t len
) {
252 REQUIRE(mem
!= NULL
);
258 /*% Allocates len bytes of memory and if successful returns a pointer to the allocated storage. */
260 lwres_context_allocmem(lwres_context_t
*ctx
, size_t len
) {
263 return (CTXMALLOC(len
));
267 lwres_malloc(void *arg
, size_t len
) {
276 memset(mem
, 0xe5, len
);
282 lwres_free(void *arg
, void *mem
, size_t len
) {
285 memset(mem
, 0xa9, len
);
289 static lwres_result_t
290 context_connect(lwres_context_t
*ctx
) {
293 struct sockaddr_in sin
;
294 struct sockaddr_in6 sin6
;
296 LWRES_SOCKADDR_LEN_T salen
;
299 if (ctx
->confdata
.lwnext
!= 0) {
300 memcpy(&ctx
->address
, &ctx
->confdata
.lwservers
[0],
301 sizeof(lwres_addr_t
));
302 LWRES_LINK_INIT(&ctx
->address
, link
);
304 /* The default is the IPv4 loopback address 127.0.0.1. */
305 memset(&ctx
->address
, 0, sizeof(ctx
->address
));
306 ctx
->address
.family
= LWRES_ADDRTYPE_V4
;
307 ctx
->address
.length
= 4;
308 ctx
->address
.address
[0] = 127;
309 ctx
->address
.address
[1] = 0;
310 ctx
->address
.address
[2] = 0;
311 ctx
->address
.address
[3] = 1;
314 if (ctx
->address
.family
== LWRES_ADDRTYPE_V4
) {
315 memcpy(&sin
.sin_addr
, ctx
->address
.address
,
316 sizeof(sin
.sin_addr
));
317 sin
.sin_port
= htons(lwres_udp_port
);
318 sin
.sin_family
= AF_INET
;
319 sa
= (struct sockaddr
*)&sin
;
322 } else if (ctx
->address
.family
== LWRES_ADDRTYPE_V6
) {
323 memcpy(&sin6
.sin6_addr
, ctx
->address
.address
,
324 sizeof(sin6
.sin6_addr
));
325 sin6
.sin6_port
= htons(lwres_udp_port
);
326 sin6
.sin6_family
= AF_INET6
;
327 sa
= (struct sockaddr
*)&sin6
;
328 salen
= sizeof(sin6
);
331 return (LWRES_R_IOERROR
);
336 s
= socket(domain
, SOCK_DGRAM
, IPPROTO_UDP
);
341 return (LWRES_R_IOERROR
);
344 ret
= connect(s
, sa
, salen
);
350 return (LWRES_R_IOERROR
);
353 MAKE_NONBLOCKING(s
, ret
);
359 return (LWRES_R_IOERROR
);
364 return (LWRES_R_SUCCESS
);
368 lwres_context_getsocket(lwres_context_t
*ctx
) {
373 lwres_context_send(lwres_context_t
*ctx
,
374 void *sendbase
, int sendlen
) {
376 lwres_result_t lwresult
;
378 if (ctx
->sock
== -1) {
379 lwresult
= context_connect(ctx
);
380 if (lwresult
!= LWRES_R_SUCCESS
)
384 ret
= sendto(ctx
->sock
, sendbase
, sendlen
, 0, NULL
, 0);
386 return (LWRES_R_IOERROR
);
388 return (LWRES_R_IOERROR
);
390 return (LWRES_R_SUCCESS
);
394 lwres_context_recv(lwres_context_t
*ctx
,
395 void *recvbase
, int recvlen
,
398 LWRES_SOCKADDR_LEN_T fromlen
;
399 struct sockaddr_in sin
;
400 struct sockaddr_in6 sin6
;
404 if (ctx
->address
.family
== LWRES_ADDRTYPE_V4
) {
405 sa
= (struct sockaddr
*)&sin
;
406 fromlen
= sizeof(sin
);
408 sa
= (struct sockaddr
*)&sin6
;
409 fromlen
= sizeof(sin6
);
413 * The address of fromlen is cast to void * to shut up compiler
414 * warnings, namely on systems that have the sixth parameter
415 * prototyped as a signed int when LWRES_SOCKADDR_LEN_T is
416 * defined as unsigned.
418 ret
= recvfrom(ctx
->sock
, recvbase
, recvlen
, 0, sa
, (void *)&fromlen
);
421 return (LWRES_R_IOERROR
);
424 return (LWRES_R_TOOLARGE
);
427 * If we got something other than what we expect, have the caller
428 * wait for another packet. This can happen if an old result
429 * comes in, or if someone is sending us random stuff.
431 if (ctx
->address
.family
== LWRES_ADDRTYPE_V4
) {
432 if (fromlen
!= sizeof(sin
)
433 || memcmp(&sin
.sin_addr
, ctx
->address
.address
,
434 sizeof(sin
.sin_addr
)) != 0
435 || sin
.sin_port
!= htons(lwres_udp_port
))
436 return (LWRES_R_RETRY
);
438 if (fromlen
!= sizeof(sin6
)
439 || memcmp(&sin6
.sin6_addr
, ctx
->address
.address
,
440 sizeof(sin6
.sin6_addr
)) != 0
441 || sin6
.sin6_port
!= htons(lwres_udp_port
))
442 return (LWRES_R_RETRY
);
445 if (recvd_len
!= NULL
)
448 return (LWRES_R_SUCCESS
);
451 /*% performs I/O for the context ctx. */
453 lwres_context_sendrecv(lwres_context_t
*ctx
,
454 void *sendbase
, int sendlen
,
455 void *recvbase
, int recvlen
,
458 lwres_result_t result
;
461 struct timeval timeout
;
464 * Type of tv_sec is 32 bits long.
466 if (ctx
->timeout
<= 0x7FFFFFFFU
)
467 timeout
.tv_sec
= (int)ctx
->timeout
;
469 timeout
.tv_sec
= 0x7FFFFFFF;
473 result
= lwres_context_send(ctx
, sendbase
, sendlen
);
474 if (result
!= LWRES_R_SUCCESS
)
478 * If this is not checked, select() can overflow,
479 * causing corruption elsewhere.
481 if (ctx
->sock
>= (int)FD_SETSIZE
) {
484 return (LWRES_R_IOERROR
);
489 FD_SET(ctx
->sock
, &readfds
);
490 ret2
= select(ctx
->sock
+ 1, &readfds
, NULL
, NULL
, &timeout
);
493 * What happened with select?
496 return (LWRES_R_IOERROR
);
498 return (LWRES_R_TIMEOUT
);
500 result
= lwres_context_recv(ctx
, recvbase
, recvlen
, recvd_len
);
501 if (result
== LWRES_R_RETRY
)