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 $ */
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 lwres_uint16_t lwres_udp_port
= LWRES_UDP_PORT
;
64 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) {
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 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
;
355 timeout
.tv_sec
= LONG_MAX
;
359 result
= lwres_context_send(ctx
, sendbase
, sendlen
);
360 if (result
!= LWRES_R_SUCCESS
)
364 FD_SET(ctx
->sock
, &readfds
);
365 ret2
= select(ctx
->sock
+ 1, &readfds
, NULL
, NULL
, &timeout
);
368 * What happened with select?
371 return (LWRES_R_IOERROR
);
373 return (LWRES_R_TIMEOUT
);
375 result
= lwres_context_recv(ctx
, recvbase
, recvlen
, recvd_len
);
376 if (result
== LWRES_R_RETRY
)