Add BIND 9.2.4rc7.
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / lwres / context.c
blobb76c9ab5b5880de6e33cbe88a85c8a41474b851e
1 /*
2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: context.c,v 1.41.2.3 2004/03/09 06:12:32 marka Exp $ */
20 #include <config.h>
22 #include <fcntl.h>
23 #include <limits.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 #include <unistd.h>
29 #include <lwres/lwres.h>
30 #include <lwres/net.h>
31 #include <lwres/platform.h>
33 #ifdef LWRES_PLATFORM_NEEDSYSSELECTH
34 #include <sys/select.h>
35 #endif
37 #include "context_p.h"
38 #include "assert_p.h"
41 * Some systems define the socket length argument as an int, some as size_t,
42 * some as socklen_t. The last is what the current POSIX standard mandates.
43 * This definition is here so it can be portable but easily changed if needed.
45 #ifndef LWRES_SOCKADDR_LEN_T
46 #define LWRES_SOCKADDR_LEN_T unsigned int
47 #endif
50 * Make a socket nonblocking.
52 #ifndef MAKE_NONBLOCKING
53 #define MAKE_NONBLOCKING(sd, retval) \
54 do { \
55 retval = fcntl(sd, F_GETFL, 0); \
56 if (retval != -1) { \
57 retval |= O_NONBLOCK; \
58 retval = fcntl(sd, F_SETFL, retval); \
59 } \
60 } while (0)
61 #endif
63 lwres_uint16_t lwres_udp_port = LWRES_UDP_PORT;
64 const char *lwres_resolv_conf = LWRES_RESOLV_CONF;
66 static void *
67 lwres_malloc(void *, size_t);
69 static void
70 lwres_free(void *, void *, size_t);
72 static lwres_result_t
73 context_connect(lwres_context_t *);
75 lwres_result_t
76 lwres_context_create(lwres_context_t **contextp, void *arg,
77 lwres_malloc_t malloc_function,
78 lwres_free_t free_function,
79 unsigned int flags)
81 lwres_context_t *ctx;
83 REQUIRE(contextp != NULL && *contextp == NULL);
84 UNUSED(flags);
87 * If we were not given anything special to use, use our own
88 * functions. These are just wrappers around malloc() and free().
90 if (malloc_function == NULL || free_function == NULL) {
91 REQUIRE(malloc_function == NULL);
92 REQUIRE(free_function == NULL);
93 malloc_function = lwres_malloc;
94 free_function = lwres_free;
97 ctx = malloc_function(arg, sizeof(lwres_context_t));
98 if (ctx == NULL)
99 return (LWRES_R_NOMEMORY);
102 * Set up the context.
104 ctx->malloc = malloc_function;
105 ctx->free = free_function;
106 ctx->arg = arg;
107 ctx->sock = -1;
109 ctx->timeout = LWRES_DEFAULT_TIMEOUT;
110 ctx->serial = time(NULL); /* XXXMLG or BEW */
113 * Init resolv.conf bits.
115 lwres_conf_init(ctx);
117 *contextp = ctx;
118 return (LWRES_R_SUCCESS);
121 void
122 lwres_context_destroy(lwres_context_t **contextp) {
123 lwres_context_t *ctx;
125 REQUIRE(contextp != NULL && *contextp != NULL);
127 ctx = *contextp;
128 *contextp = NULL;
130 if (ctx->sock != -1) {
131 close(ctx->sock);
132 ctx->sock = -1;
135 CTXFREE(ctx, sizeof(lwres_context_t));
138 lwres_uint32_t
139 lwres_context_nextserial(lwres_context_t *ctx) {
140 REQUIRE(ctx != NULL);
142 return (ctx->serial++);
145 void
146 lwres_context_initserial(lwres_context_t *ctx, lwres_uint32_t serial) {
147 REQUIRE(ctx != NULL);
149 ctx->serial = serial;
152 void
153 lwres_context_freemem(lwres_context_t *ctx, void *mem, size_t len) {
154 REQUIRE(mem != NULL);
155 REQUIRE(len != 0U);
157 CTXFREE(mem, len);
160 void *
161 lwres_context_allocmem(lwres_context_t *ctx, size_t len) {
162 REQUIRE(len != 0U);
164 return (CTXMALLOC(len));
167 static void *
168 lwres_malloc(void *arg, size_t len) {
169 void *mem;
171 UNUSED(arg);
173 mem = malloc(len);
174 if (mem == NULL)
175 return (NULL);
177 memset(mem, 0xe5, len);
179 return (mem);
182 static void
183 lwres_free(void *arg, void *mem, size_t len) {
184 UNUSED(arg);
186 memset(mem, 0xa9, len);
187 free(mem);
190 static lwres_result_t
191 context_connect(lwres_context_t *ctx) {
192 int s;
193 int ret;
194 struct sockaddr_in sin;
195 struct sockaddr_in6 sin6;
196 struct sockaddr *sa;
197 LWRES_SOCKADDR_LEN_T salen;
198 int domain;
200 if (ctx->confdata.lwnext != 0) {
201 memcpy(&ctx->address, &ctx->confdata.lwservers[0],
202 sizeof(lwres_addr_t));
203 LWRES_LINK_INIT(&ctx->address, link);
204 } else {
205 /* The default is the IPv4 loopback address 127.0.0.1. */
206 memset(&ctx->address, 0, sizeof(ctx->address));
207 ctx->address.family = LWRES_ADDRTYPE_V4;
208 ctx->address.length = 4;
209 ctx->address.address[0] = 127;
210 ctx->address.address[1] = 0;
211 ctx->address.address[2] = 0;
212 ctx->address.address[3] = 1;
215 if (ctx->address.family == LWRES_ADDRTYPE_V4) {
216 memcpy(&sin.sin_addr, ctx->address.address,
217 sizeof(sin.sin_addr));
218 sin.sin_port = htons(lwres_udp_port);
219 sin.sin_family = AF_INET;
220 sa = (struct sockaddr *)&sin;
221 salen = sizeof(sin);
222 domain = PF_INET;
223 } else if (ctx->address.family == LWRES_ADDRTYPE_V6) {
224 memcpy(&sin6.sin6_addr, ctx->address.address,
225 sizeof(sin6.sin6_addr));
226 sin6.sin6_port = htons(lwres_udp_port);
227 sin6.sin6_family = AF_INET6;
228 sa = (struct sockaddr *)&sin6;
229 salen = sizeof(sin6);
230 domain = PF_INET6;
231 } else
232 return (LWRES_R_IOERROR);
234 s = socket(domain, SOCK_DGRAM, IPPROTO_UDP);
235 if (s < 0)
236 return (LWRES_R_IOERROR);
238 ret = connect(s, sa, salen);
239 if (ret != 0) {
240 close(s);
241 return (LWRES_R_IOERROR);
244 MAKE_NONBLOCKING(s, ret);
245 if (ret < 0)
246 return (LWRES_R_IOERROR);
248 ctx->sock = s;
250 return (LWRES_R_SUCCESS);
254 lwres_context_getsocket(lwres_context_t *ctx) {
255 return (ctx->sock);
258 lwres_result_t
259 lwres_context_send(lwres_context_t *ctx,
260 void *sendbase, int sendlen) {
261 int ret;
262 lwres_result_t lwresult;
264 if (ctx->sock == -1) {
265 lwresult = context_connect(ctx);
266 if (lwresult != LWRES_R_SUCCESS)
267 return (lwresult);
270 ret = sendto(ctx->sock, sendbase, sendlen, 0, NULL, 0);
271 if (ret < 0)
272 return (LWRES_R_IOERROR);
273 if (ret != sendlen)
274 return (LWRES_R_IOERROR);
276 return (LWRES_R_SUCCESS);
279 lwres_result_t
280 lwres_context_recv(lwres_context_t *ctx,
281 void *recvbase, int recvlen,
282 int *recvd_len)
284 LWRES_SOCKADDR_LEN_T fromlen;
285 struct sockaddr_in sin;
286 struct sockaddr_in6 sin6;
287 struct sockaddr *sa;
288 int ret;
290 if (ctx->address.family == LWRES_ADDRTYPE_V4) {
291 sa = (struct sockaddr *)&sin;
292 fromlen = sizeof(sin);
293 } else {
294 sa = (struct sockaddr *)&sin6;
295 fromlen = sizeof(sin6);
299 * The address of fromlen is cast to void * to shut up compiler
300 * warnings, namely on systems that have the sixth parameter
301 * prototyped as a signed int when LWRES_SOCKADDR_LEN_T is
302 * defined as unsigned.
304 ret = recvfrom(ctx->sock, recvbase, recvlen, 0, sa, (void *)&fromlen);
306 if (ret < 0)
307 return (LWRES_R_IOERROR);
309 if (ret == recvlen)
310 return (LWRES_R_TOOLARGE);
313 * If we got something other than what we expect, have the caller
314 * wait for another packet. This can happen if an old result
315 * comes in, or if someone is sending us random stuff.
317 if (ctx->address.family == LWRES_ADDRTYPE_V4) {
318 if (fromlen != sizeof(sin)
319 || memcmp(&sin.sin_addr, ctx->address.address,
320 sizeof(sin.sin_addr)) != 0
321 || sin.sin_port != htons(lwres_udp_port))
322 return (LWRES_R_RETRY);
323 } else {
324 if (fromlen != sizeof(sin6)
325 || memcmp(&sin6.sin6_addr, ctx->address.address,
326 sizeof(sin6.sin6_addr)) != 0
327 || sin6.sin6_port != htons(lwres_udp_port))
328 return (LWRES_R_RETRY);
331 if (recvd_len != NULL)
332 *recvd_len = ret;
334 return (LWRES_R_SUCCESS);
337 lwres_result_t
338 lwres_context_sendrecv(lwres_context_t *ctx,
339 void *sendbase, int sendlen,
340 void *recvbase, int recvlen,
341 int *recvd_len)
343 lwres_result_t result;
344 int ret2;
345 fd_set readfds;
346 struct timeval timeout;
349 * Type of tv_sec is long, so make sure the unsigned long timeout
350 * does not overflow it.
352 if (ctx->timeout <= (unsigned int)LONG_MAX)
353 timeout.tv_sec = (long)ctx->timeout;
354 else
355 timeout.tv_sec = LONG_MAX;
357 timeout.tv_usec = 0;
359 result = lwres_context_send(ctx, sendbase, sendlen);
360 if (result != LWRES_R_SUCCESS)
361 return (result);
362 again:
363 FD_ZERO(&readfds);
364 FD_SET(ctx->sock, &readfds);
365 ret2 = select(ctx->sock + 1, &readfds, NULL, NULL, &timeout);
368 * What happened with select?
370 if (ret2 < 0)
371 return (LWRES_R_IOERROR);
372 if (ret2 == 0)
373 return (LWRES_R_TIMEOUT);
375 result = lwres_context_recv(ctx, recvbase, recvlen, recvd_len);
376 if (result == LWRES_R_RETRY)
377 goto again;
379 return (result);