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.1.2.4 2004/09/17 05:50:31 marka Exp $ */
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>
37 #include "context_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
50 * Make a socket nonblocking.
52 #ifndef MAKE_NONBLOCKING
53 #define MAKE_NONBLOCKING(sd, retval) \
55 retval = fcntl(sd, F_GETFL, 0); \
57 retval |= O_NONBLOCK; \
58 retval = fcntl(sd, F_SETFL, retval); \
63 LIBLWRES_EXTERNAL_DATA lwres_uint16_t lwres_udp_port = LWRES_UDP_PORT;
64 LIBLWRES_EXTERNAL_DATA const char *lwres_resolv_conf = LWRES_RESOLV_CONF;
67 lwres_malloc(void *, size_t);
70 lwres_free(void *, void *, size_t);
73 context_connect(lwres_context_t *);
76 lwres_context_create(lwres_context_t **contextp, void *arg,
77 lwres_malloc_t malloc_function,
78 lwres_free_t free_function,
83 REQUIRE(contextp != NULL && *contextp == NULL);
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));
99 return (LWRES_R_NOMEMORY);
102 * Set up the context.
104 ctx->malloc = malloc_function;
105 ctx->free = free_function;
109 ctx->timeout = LWRES_DEFAULT_TIMEOUT;
110 ctx->serial = time(NULL); /* XXXMLG or BEW */
113 * Init resolv.conf bits.
115 lwres_conf_init(ctx);
118 return (LWRES_R_SUCCESS);
122 lwres_context_destroy(lwres_context_t **contextp) {
123 lwres_context_t *ctx;
125 REQUIRE(contextp != NULL && *contextp != NULL);
130 if (ctx->sock != -1) {
131 (void)close(ctx->sock);
135 CTXFREE(ctx, sizeof(lwres_context_t));
139 lwres_context_nextserial(lwres_context_t *ctx) {
140 REQUIRE(ctx != NULL);
142 return (ctx->serial++);
146 lwres_context_initserial(lwres_context_t *ctx, lwres_uint32_t serial) {
147 REQUIRE(ctx != NULL);
149 ctx->serial = serial;
153 lwres_context_freemem(lwres_context_t *ctx, void *mem, size_t len) {
154 REQUIRE(mem != NULL);
161 lwres_context_allocmem(lwres_context_t *ctx, size_t len) {
164 return (CTXMALLOC(len));
168 lwres_malloc(void *arg, size_t len) {
177 memset(mem, 0xe5, len);
183 lwres_free(void *arg, void *mem, size_t len) {
186 memset(mem, 0xa9, len);
190 static lwres_result_t
191 context_connect(lwres_context_t *ctx) {
194 struct sockaddr_in sin;
195 struct sockaddr_in6 sin6;
197 LWRES_SOCKADDR_LEN_T salen;
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);
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;
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);
232 return (LWRES_R_IOERROR);
234 s = socket(domain, SOCK_DGRAM, IPPROTO_UDP);
236 return (LWRES_R_IOERROR);
238 ret = connect(s, sa, salen);
241 return (LWRES_R_IOERROR);
244 MAKE_NONBLOCKING(s, ret);
246 return (LWRES_R_IOERROR);
250 return (LWRES_R_SUCCESS);
254 lwres_context_getsocket(lwres_context_t *ctx) {
259 lwres_context_send(lwres_context_t *ctx,
260 void *sendbase, int sendlen) {
262 lwres_result_t lwresult;
264 if (ctx->sock == -1) {
265 lwresult = context_connect(ctx);
266 if (lwresult != LWRES_R_SUCCESS)
270 ret = sendto(ctx->sock, sendbase, sendlen, 0, NULL, 0);
272 return (LWRES_R_IOERROR);
274 return (LWRES_R_IOERROR);
276 return (LWRES_R_SUCCESS);
280 lwres_context_recv(lwres_context_t *ctx,
281 void *recvbase, int recvlen,
284 LWRES_SOCKADDR_LEN_T fromlen;
285 struct sockaddr_in sin;
286 struct sockaddr_in6 sin6;
290 if (ctx->address.family == LWRES_ADDRTYPE_V4) {
291 sa = (struct sockaddr *)&sin;
292 fromlen = sizeof(sin);
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);
307 return (LWRES_R_IOERROR);
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);
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)
334 return (LWRES_R_SUCCESS);
338 lwres_context_sendrecv(lwres_context_t *ctx,
339 void *sendbase, int sendlen,
340 void *recvbase, int recvlen,
343 lwres_result_t result;
346 struct timeval timeout;
349 * Type of tv_sec is 32 bits long.
351 if (ctx->timeout <= 0x7FFFFFFFU)
352 timeout.tv_sec = (int)ctx->timeout;
354 timeout.tv_sec = 0x7FFFFFFF;
358 result = lwres_context_send(ctx, sendbase, sendlen);
359 if (result != LWRES_R_SUCCESS)
363 FD_SET(ctx->sock, &readfds);
364 ret2 = select(ctx->sock + 1, &readfds, NULL, NULL, &timeout);
367 * What happened with select?
370 return (LWRES_R_IOERROR);
372 return (LWRES_R_TIMEOUT);
374 result = lwres_context_recv(ctx, recvbase, recvlen, recvd_len);
375 if (result == LWRES_R_RETRY)