1*00b67f09SDavid van Moolenbroek /* $NetBSD: context.c,v 1.7 2014/12/10 04:38:02 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2004, 2005, 2007-2009, 2012-2014 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek * Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek *
7*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek *
11*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek */
19*00b67f09SDavid van Moolenbroek
20*00b67f09SDavid van Moolenbroek /* Id: context.c,v 1.55 2009/09/02 23:48:03 tbox Exp */
21*00b67f09SDavid van Moolenbroek
22*00b67f09SDavid van Moolenbroek /*! \file context.c
23*00b67f09SDavid van Moolenbroek lwres_context_create() creates a #lwres_context_t structure for use in
24*00b67f09SDavid van Moolenbroek lightweight resolver operations. It holds a socket and other data
25*00b67f09SDavid van Moolenbroek needed for communicating with a resolver daemon. The new
26*00b67f09SDavid van Moolenbroek lwres_context_t is returned through contextp, a pointer to a
27*00b67f09SDavid van Moolenbroek lwres_context_t pointer. This lwres_context_t pointer must initially
28*00b67f09SDavid van Moolenbroek be NULL, and is modified to point to the newly created
29*00b67f09SDavid van Moolenbroek lwres_context_t.
30*00b67f09SDavid van Moolenbroek
31*00b67f09SDavid van Moolenbroek When the lightweight resolver needs to perform dynamic memory
32*00b67f09SDavid van Moolenbroek allocation, it will call malloc_function to allocate memory and
33*00b67f09SDavid van Moolenbroek free_function to free it. If malloc_function and free_function are
34*00b67f09SDavid van Moolenbroek NULL, memory is allocated using malloc and free. It is not
35*00b67f09SDavid van Moolenbroek permitted to have a NULL malloc_function and a non-NULL free_function
36*00b67f09SDavid van Moolenbroek or vice versa. arg is passed as the first parameter to the memory
37*00b67f09SDavid van Moolenbroek allocation functions. If malloc_function and free_function are NULL,
38*00b67f09SDavid van Moolenbroek arg is unused and should be passed as NULL.
39*00b67f09SDavid van Moolenbroek
40*00b67f09SDavid van Moolenbroek Once memory for the structure has been allocated, it is initialized
41*00b67f09SDavid van Moolenbroek using lwres_conf_init() and returned via *contextp.
42*00b67f09SDavid van Moolenbroek
43*00b67f09SDavid van Moolenbroek lwres_context_destroy() destroys a #lwres_context_t, closing its
44*00b67f09SDavid van Moolenbroek socket. contextp is a pointer to a pointer to the context that is to
45*00b67f09SDavid van Moolenbroek be destroyed. The pointer will be set to NULL when the context has
46*00b67f09SDavid van Moolenbroek been destroyed.
47*00b67f09SDavid van Moolenbroek
48*00b67f09SDavid van Moolenbroek The context holds a serial number that is used to identify resolver
49*00b67f09SDavid van Moolenbroek request packets and associate responses with the corresponding
50*00b67f09SDavid van Moolenbroek requests. This serial number is controlled using
51*00b67f09SDavid van Moolenbroek lwres_context_initserial() and lwres_context_nextserial().
52*00b67f09SDavid van Moolenbroek lwres_context_initserial() sets the serial number for context *ctx to
53*00b67f09SDavid van Moolenbroek serial. lwres_context_nextserial() increments the serial number and
54*00b67f09SDavid van Moolenbroek returns the previous value.
55*00b67f09SDavid van Moolenbroek
56*00b67f09SDavid van Moolenbroek Memory for a lightweight resolver context is allocated and freed using
57*00b67f09SDavid van Moolenbroek lwres_context_allocmem() and lwres_context_freemem(). These use
58*00b67f09SDavid van Moolenbroek whatever allocations were defined when the context was created with
59*00b67f09SDavid van Moolenbroek lwres_context_create(). lwres_context_allocmem() allocates len bytes
60*00b67f09SDavid van Moolenbroek of memory and if successful returns a pointer to the allocated
61*00b67f09SDavid van Moolenbroek storage. lwres_context_freemem() frees len bytes of space starting at
62*00b67f09SDavid van Moolenbroek location mem.
63*00b67f09SDavid van Moolenbroek
64*00b67f09SDavid van Moolenbroek lwres_context_sendrecv() performs I/O for the context ctx. Data are
65*00b67f09SDavid van Moolenbroek read and written from the context's socket. It writes data from
66*00b67f09SDavid van Moolenbroek sendbase -- typically a lightweight resolver query packet -- and waits
67*00b67f09SDavid van Moolenbroek for a reply which is copied to the receive buffer at recvbase. The
68*00b67f09SDavid van Moolenbroek number of bytes that were written to this receive buffer is returned
69*00b67f09SDavid van Moolenbroek in *recvd_len.
70*00b67f09SDavid van Moolenbroek
71*00b67f09SDavid van Moolenbroek \section context_return Return Values
72*00b67f09SDavid van Moolenbroek
73*00b67f09SDavid van Moolenbroek lwres_context_create() returns #LWRES_R_NOMEMORY if memory for the
74*00b67f09SDavid van Moolenbroek struct lwres_context could not be allocated, #LWRES_R_SUCCESS
75*00b67f09SDavid van Moolenbroek otherwise.
76*00b67f09SDavid van Moolenbroek
77*00b67f09SDavid van Moolenbroek Successful calls to the memory allocator lwres_context_allocmem()
78*00b67f09SDavid van Moolenbroek return a pointer to the start of the allocated space. It returns NULL
79*00b67f09SDavid van Moolenbroek if memory could not be allocated.
80*00b67f09SDavid van Moolenbroek
81*00b67f09SDavid van Moolenbroek #LWRES_R_SUCCESS is returned when lwres_context_sendrecv() completes
82*00b67f09SDavid van Moolenbroek successfully. #LWRES_R_IOERROR is returned if an I/O error occurs and
83*00b67f09SDavid van Moolenbroek #LWRES_R_TIMEOUT is returned if lwres_context_sendrecv() times out
84*00b67f09SDavid van Moolenbroek waiting for a response.
85*00b67f09SDavid van Moolenbroek
86*00b67f09SDavid van Moolenbroek \section context_see See Also
87*00b67f09SDavid van Moolenbroek
88*00b67f09SDavid van Moolenbroek lwres_conf_init(), malloc, free.
89*00b67f09SDavid van Moolenbroek */
90*00b67f09SDavid van Moolenbroek #include <config.h>
91*00b67f09SDavid van Moolenbroek
92*00b67f09SDavid van Moolenbroek #include <fcntl.h>
93*00b67f09SDavid van Moolenbroek #include <limits.h>
94*00b67f09SDavid van Moolenbroek #include <stdlib.h>
95*00b67f09SDavid van Moolenbroek #include <string.h>
96*00b67f09SDavid van Moolenbroek #include <time.h>
97*00b67f09SDavid van Moolenbroek #include <unistd.h>
98*00b67f09SDavid van Moolenbroek
99*00b67f09SDavid van Moolenbroek #include <lwres/lwres.h>
100*00b67f09SDavid van Moolenbroek #include <lwres/net.h>
101*00b67f09SDavid van Moolenbroek #include <lwres/platform.h>
102*00b67f09SDavid van Moolenbroek
103*00b67f09SDavid van Moolenbroek #ifdef LWRES_PLATFORM_NEEDSYSSELECTH
104*00b67f09SDavid van Moolenbroek #include <sys/select.h>
105*00b67f09SDavid van Moolenbroek #endif
106*00b67f09SDavid van Moolenbroek
107*00b67f09SDavid van Moolenbroek #include "context_p.h"
108*00b67f09SDavid van Moolenbroek #include "assert_p.h"
109*00b67f09SDavid van Moolenbroek
110*00b67f09SDavid van Moolenbroek /*!
111*00b67f09SDavid van Moolenbroek * Some systems define the socket length argument as an int, some as size_t,
112*00b67f09SDavid van Moolenbroek * some as socklen_t. The last is what the current POSIX standard mandates.
113*00b67f09SDavid van Moolenbroek * This definition is here so it can be portable but easily changed if needed.
114*00b67f09SDavid van Moolenbroek */
115*00b67f09SDavid van Moolenbroek #ifndef LWRES_SOCKADDR_LEN_T
116*00b67f09SDavid van Moolenbroek #define LWRES_SOCKADDR_LEN_T unsigned int
117*00b67f09SDavid van Moolenbroek #endif
118*00b67f09SDavid van Moolenbroek
119*00b67f09SDavid van Moolenbroek /*!
120*00b67f09SDavid van Moolenbroek * Make a socket nonblocking.
121*00b67f09SDavid van Moolenbroek */
122*00b67f09SDavid van Moolenbroek #ifndef MAKE_NONBLOCKING
123*00b67f09SDavid van Moolenbroek #define MAKE_NONBLOCKING(sd, retval) \
124*00b67f09SDavid van Moolenbroek do { \
125*00b67f09SDavid van Moolenbroek retval = fcntl(sd, F_GETFL, 0); \
126*00b67f09SDavid van Moolenbroek if (retval != -1) { \
127*00b67f09SDavid van Moolenbroek retval |= O_NONBLOCK; \
128*00b67f09SDavid van Moolenbroek retval = fcntl(sd, F_SETFL, retval); \
129*00b67f09SDavid van Moolenbroek } \
130*00b67f09SDavid van Moolenbroek } while (/*CONSTCOND*/0)
131*00b67f09SDavid van Moolenbroek #endif
132*00b67f09SDavid van Moolenbroek
133*00b67f09SDavid van Moolenbroek LIBLWRES_EXTERNAL_DATA lwres_uint16_t lwres_udp_port = LWRES_UDP_PORT;
134*00b67f09SDavid van Moolenbroek LIBLWRES_EXTERNAL_DATA const char *lwres_resolv_conf = LWRES_RESOLV_CONF;
135*00b67f09SDavid van Moolenbroek
136*00b67f09SDavid van Moolenbroek static void *
137*00b67f09SDavid van Moolenbroek lwres_malloc(void *, size_t);
138*00b67f09SDavid van Moolenbroek
139*00b67f09SDavid van Moolenbroek static void
140*00b67f09SDavid van Moolenbroek lwres_free(void *, void *, size_t);
141*00b67f09SDavid van Moolenbroek
142*00b67f09SDavid van Moolenbroek /*!
143*00b67f09SDavid van Moolenbroek * lwres_result_t
144*00b67f09SDavid van Moolenbroek */
145*00b67f09SDavid van Moolenbroek static lwres_result_t
146*00b67f09SDavid van Moolenbroek context_connect(lwres_context_t *);
147*00b67f09SDavid van Moolenbroek
148*00b67f09SDavid van Moolenbroek /*%
149*00b67f09SDavid van Moolenbroek * Creates a #lwres_context_t structure for use in
150*00b67f09SDavid van Moolenbroek * lightweight resolver operations.
151*00b67f09SDavid van Moolenbroek */
152*00b67f09SDavid van Moolenbroek lwres_result_t
lwres_context_create(lwres_context_t ** contextp,void * arg,lwres_malloc_t malloc_function,lwres_free_t free_function,unsigned int flags)153*00b67f09SDavid van Moolenbroek lwres_context_create(lwres_context_t **contextp, void *arg,
154*00b67f09SDavid van Moolenbroek lwres_malloc_t malloc_function,
155*00b67f09SDavid van Moolenbroek lwres_free_t free_function,
156*00b67f09SDavid van Moolenbroek unsigned int flags)
157*00b67f09SDavid van Moolenbroek {
158*00b67f09SDavid van Moolenbroek lwres_context_t *ctx;
159*00b67f09SDavid van Moolenbroek
160*00b67f09SDavid van Moolenbroek REQUIRE(contextp != NULL && *contextp == NULL);
161*00b67f09SDavid van Moolenbroek
162*00b67f09SDavid van Moolenbroek /*
163*00b67f09SDavid van Moolenbroek * If we were not given anything special to use, use our own
164*00b67f09SDavid van Moolenbroek * functions. These are just wrappers around malloc() and free().
165*00b67f09SDavid van Moolenbroek */
166*00b67f09SDavid van Moolenbroek if (malloc_function == NULL || free_function == NULL) {
167*00b67f09SDavid van Moolenbroek REQUIRE(malloc_function == NULL);
168*00b67f09SDavid van Moolenbroek REQUIRE(free_function == NULL);
169*00b67f09SDavid van Moolenbroek malloc_function = lwres_malloc;
170*00b67f09SDavid van Moolenbroek free_function = lwres_free;
171*00b67f09SDavid van Moolenbroek }
172*00b67f09SDavid van Moolenbroek
173*00b67f09SDavid van Moolenbroek ctx = malloc_function(arg, sizeof(lwres_context_t));
174*00b67f09SDavid van Moolenbroek if (ctx == NULL)
175*00b67f09SDavid van Moolenbroek return (LWRES_R_NOMEMORY);
176*00b67f09SDavid van Moolenbroek
177*00b67f09SDavid van Moolenbroek /*
178*00b67f09SDavid van Moolenbroek * Set up the context.
179*00b67f09SDavid van Moolenbroek */
180*00b67f09SDavid van Moolenbroek ctx->malloc = malloc_function;
181*00b67f09SDavid van Moolenbroek ctx->free = free_function;
182*00b67f09SDavid van Moolenbroek ctx->arg = arg;
183*00b67f09SDavid van Moolenbroek ctx->sock = -1;
184*00b67f09SDavid van Moolenbroek
185*00b67f09SDavid van Moolenbroek ctx->timeout = LWRES_DEFAULT_TIMEOUT;
186*00b67f09SDavid van Moolenbroek #ifndef WIN32
187*00b67f09SDavid van Moolenbroek ctx->serial = time(NULL); /* XXXMLG or BEW */
188*00b67f09SDavid van Moolenbroek #else
189*00b67f09SDavid van Moolenbroek ctx->serial = _time32(NULL);
190*00b67f09SDavid van Moolenbroek #endif
191*00b67f09SDavid van Moolenbroek
192*00b67f09SDavid van Moolenbroek ctx->use_ipv4 = 1;
193*00b67f09SDavid van Moolenbroek ctx->use_ipv6 = 1;
194*00b67f09SDavid van Moolenbroek if ((flags & (LWRES_CONTEXT_USEIPV4 | LWRES_CONTEXT_USEIPV6)) ==
195*00b67f09SDavid van Moolenbroek LWRES_CONTEXT_USEIPV6) {
196*00b67f09SDavid van Moolenbroek ctx->use_ipv4 = 0;
197*00b67f09SDavid van Moolenbroek }
198*00b67f09SDavid van Moolenbroek if ((flags & (LWRES_CONTEXT_USEIPV4 | LWRES_CONTEXT_USEIPV6)) ==
199*00b67f09SDavid van Moolenbroek LWRES_CONTEXT_USEIPV4) {
200*00b67f09SDavid van Moolenbroek ctx->use_ipv6 = 0;
201*00b67f09SDavid van Moolenbroek }
202*00b67f09SDavid van Moolenbroek
203*00b67f09SDavid van Moolenbroek /*
204*00b67f09SDavid van Moolenbroek * Init resolv.conf bits.
205*00b67f09SDavid van Moolenbroek */
206*00b67f09SDavid van Moolenbroek lwres_conf_init(ctx);
207*00b67f09SDavid van Moolenbroek
208*00b67f09SDavid van Moolenbroek *contextp = ctx;
209*00b67f09SDavid van Moolenbroek return (LWRES_R_SUCCESS);
210*00b67f09SDavid van Moolenbroek }
211*00b67f09SDavid van Moolenbroek
212*00b67f09SDavid van Moolenbroek /*%
213*00b67f09SDavid van Moolenbroek Destroys a #lwres_context_t, closing its socket.
214*00b67f09SDavid van Moolenbroek contextp is a pointer to a pointer to the context that is
215*00b67f09SDavid van Moolenbroek to be destroyed. The pointer will be set to NULL
216*00b67f09SDavid van Moolenbroek when the context has been destroyed.
217*00b67f09SDavid van Moolenbroek */
218*00b67f09SDavid van Moolenbroek void
lwres_context_destroy(lwres_context_t ** contextp)219*00b67f09SDavid van Moolenbroek lwres_context_destroy(lwres_context_t **contextp) {
220*00b67f09SDavid van Moolenbroek lwres_context_t *ctx;
221*00b67f09SDavid van Moolenbroek
222*00b67f09SDavid van Moolenbroek REQUIRE(contextp != NULL && *contextp != NULL);
223*00b67f09SDavid van Moolenbroek
224*00b67f09SDavid van Moolenbroek ctx = *contextp;
225*00b67f09SDavid van Moolenbroek *contextp = NULL;
226*00b67f09SDavid van Moolenbroek
227*00b67f09SDavid van Moolenbroek if (ctx->sock != -1) {
228*00b67f09SDavid van Moolenbroek #ifdef WIN32
229*00b67f09SDavid van Moolenbroek DestroySockets();
230*00b67f09SDavid van Moolenbroek #endif
231*00b67f09SDavid van Moolenbroek (void)close(ctx->sock);
232*00b67f09SDavid van Moolenbroek ctx->sock = -1;
233*00b67f09SDavid van Moolenbroek }
234*00b67f09SDavid van Moolenbroek
235*00b67f09SDavid van Moolenbroek CTXFREE(ctx, sizeof(lwres_context_t));
236*00b67f09SDavid van Moolenbroek }
237*00b67f09SDavid van Moolenbroek /*% Increments the serial number and returns the previous value. */
238*00b67f09SDavid van Moolenbroek lwres_uint32_t
lwres_context_nextserial(lwres_context_t * ctx)239*00b67f09SDavid van Moolenbroek lwres_context_nextserial(lwres_context_t *ctx) {
240*00b67f09SDavid van Moolenbroek REQUIRE(ctx != NULL);
241*00b67f09SDavid van Moolenbroek
242*00b67f09SDavid van Moolenbroek return (ctx->serial++);
243*00b67f09SDavid van Moolenbroek }
244*00b67f09SDavid van Moolenbroek
245*00b67f09SDavid van Moolenbroek /*% Sets the serial number for context *ctx to serial. */
246*00b67f09SDavid van Moolenbroek void
lwres_context_initserial(lwres_context_t * ctx,lwres_uint32_t serial)247*00b67f09SDavid van Moolenbroek lwres_context_initserial(lwres_context_t *ctx, lwres_uint32_t serial) {
248*00b67f09SDavid van Moolenbroek REQUIRE(ctx != NULL);
249*00b67f09SDavid van Moolenbroek
250*00b67f09SDavid van Moolenbroek ctx->serial = serial;
251*00b67f09SDavid van Moolenbroek }
252*00b67f09SDavid van Moolenbroek
253*00b67f09SDavid van Moolenbroek /*% Frees len bytes of space starting at location mem. */
254*00b67f09SDavid van Moolenbroek void
lwres_context_freemem(lwres_context_t * ctx,void * mem,size_t len)255*00b67f09SDavid van Moolenbroek lwres_context_freemem(lwres_context_t *ctx, void *mem, size_t len) {
256*00b67f09SDavid van Moolenbroek REQUIRE(mem != NULL);
257*00b67f09SDavid van Moolenbroek REQUIRE(len != 0U);
258*00b67f09SDavid van Moolenbroek
259*00b67f09SDavid van Moolenbroek CTXFREE(mem, len);
260*00b67f09SDavid van Moolenbroek }
261*00b67f09SDavid van Moolenbroek
262*00b67f09SDavid van Moolenbroek /*% Allocates len bytes of memory and if successful returns a pointer to the allocated storage. */
263*00b67f09SDavid van Moolenbroek void *
lwres_context_allocmem(lwres_context_t * ctx,size_t len)264*00b67f09SDavid van Moolenbroek lwres_context_allocmem(lwres_context_t *ctx, size_t len) {
265*00b67f09SDavid van Moolenbroek REQUIRE(len != 0U);
266*00b67f09SDavid van Moolenbroek
267*00b67f09SDavid van Moolenbroek return (CTXMALLOC(len));
268*00b67f09SDavid van Moolenbroek }
269*00b67f09SDavid van Moolenbroek
270*00b67f09SDavid van Moolenbroek static void *
lwres_malloc(void * arg,size_t len)271*00b67f09SDavid van Moolenbroek lwres_malloc(void *arg, size_t len) {
272*00b67f09SDavid van Moolenbroek void *mem;
273*00b67f09SDavid van Moolenbroek
274*00b67f09SDavid van Moolenbroek UNUSED(arg);
275*00b67f09SDavid van Moolenbroek
276*00b67f09SDavid van Moolenbroek mem = malloc(len);
277*00b67f09SDavid van Moolenbroek if (mem == NULL)
278*00b67f09SDavid van Moolenbroek return (NULL);
279*00b67f09SDavid van Moolenbroek
280*00b67f09SDavid van Moolenbroek memset(mem, 0xe5, len);
281*00b67f09SDavid van Moolenbroek
282*00b67f09SDavid van Moolenbroek return (mem);
283*00b67f09SDavid van Moolenbroek }
284*00b67f09SDavid van Moolenbroek
285*00b67f09SDavid van Moolenbroek static void
lwres_free(void * arg,void * mem,size_t len)286*00b67f09SDavid van Moolenbroek lwres_free(void *arg, void *mem, size_t len) {
287*00b67f09SDavid van Moolenbroek UNUSED(arg);
288*00b67f09SDavid van Moolenbroek
289*00b67f09SDavid van Moolenbroek memset(mem, 0xa9, len);
290*00b67f09SDavid van Moolenbroek free(mem);
291*00b67f09SDavid van Moolenbroek }
292*00b67f09SDavid van Moolenbroek
293*00b67f09SDavid van Moolenbroek static lwres_result_t
context_connect(lwres_context_t * ctx)294*00b67f09SDavid van Moolenbroek context_connect(lwres_context_t *ctx) {
295*00b67f09SDavid van Moolenbroek #ifndef WIN32
296*00b67f09SDavid van Moolenbroek int s;
297*00b67f09SDavid van Moolenbroek #else
298*00b67f09SDavid van Moolenbroek SOCKET s;
299*00b67f09SDavid van Moolenbroek #endif
300*00b67f09SDavid van Moolenbroek int ret;
301*00b67f09SDavid van Moolenbroek struct sockaddr_in sin;
302*00b67f09SDavid van Moolenbroek struct sockaddr_in6 sin6;
303*00b67f09SDavid van Moolenbroek struct sockaddr *sa;
304*00b67f09SDavid van Moolenbroek LWRES_SOCKADDR_LEN_T salen;
305*00b67f09SDavid van Moolenbroek int domain;
306*00b67f09SDavid van Moolenbroek
307*00b67f09SDavid van Moolenbroek if (ctx->confdata.lwnext != 0) {
308*00b67f09SDavid van Moolenbroek memmove(&ctx->address, &ctx->confdata.lwservers[0],
309*00b67f09SDavid van Moolenbroek sizeof(lwres_addr_t));
310*00b67f09SDavid van Moolenbroek LWRES_LINK_INIT(&ctx->address, link);
311*00b67f09SDavid van Moolenbroek } else {
312*00b67f09SDavid van Moolenbroek /* The default is the IPv4 loopback address 127.0.0.1. */
313*00b67f09SDavid van Moolenbroek memset(&ctx->address, 0, sizeof(ctx->address));
314*00b67f09SDavid van Moolenbroek ctx->address.family = LWRES_ADDRTYPE_V4;
315*00b67f09SDavid van Moolenbroek ctx->address.length = 4;
316*00b67f09SDavid van Moolenbroek ctx->address.address[0] = 127;
317*00b67f09SDavid van Moolenbroek ctx->address.address[1] = 0;
318*00b67f09SDavid van Moolenbroek ctx->address.address[2] = 0;
319*00b67f09SDavid van Moolenbroek ctx->address.address[3] = 1;
320*00b67f09SDavid van Moolenbroek }
321*00b67f09SDavid van Moolenbroek
322*00b67f09SDavid van Moolenbroek if (ctx->address.family == LWRES_ADDRTYPE_V4) {
323*00b67f09SDavid van Moolenbroek memmove(&sin.sin_addr, ctx->address.address,
324*00b67f09SDavid van Moolenbroek sizeof(sin.sin_addr));
325*00b67f09SDavid van Moolenbroek sin.sin_port = htons(lwres_udp_port);
326*00b67f09SDavid van Moolenbroek sin.sin_family = AF_INET;
327*00b67f09SDavid van Moolenbroek sa = (struct sockaddr *)&sin;
328*00b67f09SDavid van Moolenbroek salen = sizeof(sin);
329*00b67f09SDavid van Moolenbroek domain = PF_INET;
330*00b67f09SDavid van Moolenbroek } else if (ctx->address.family == LWRES_ADDRTYPE_V6) {
331*00b67f09SDavid van Moolenbroek memmove(&sin6.sin6_addr, ctx->address.address,
332*00b67f09SDavid van Moolenbroek sizeof(sin6.sin6_addr));
333*00b67f09SDavid van Moolenbroek sin6.sin6_port = htons(lwres_udp_port);
334*00b67f09SDavid van Moolenbroek sin6.sin6_family = AF_INET6;
335*00b67f09SDavid van Moolenbroek sa = (struct sockaddr *)&sin6;
336*00b67f09SDavid van Moolenbroek salen = sizeof(sin6);
337*00b67f09SDavid van Moolenbroek domain = PF_INET6;
338*00b67f09SDavid van Moolenbroek } else
339*00b67f09SDavid van Moolenbroek return (LWRES_R_IOERROR);
340*00b67f09SDavid van Moolenbroek
341*00b67f09SDavid van Moolenbroek #ifdef WIN32
342*00b67f09SDavid van Moolenbroek InitSockets();
343*00b67f09SDavid van Moolenbroek #endif
344*00b67f09SDavid van Moolenbroek s = socket(domain, SOCK_DGRAM, IPPROTO_UDP);
345*00b67f09SDavid van Moolenbroek #ifndef WIN32
346*00b67f09SDavid van Moolenbroek if (s < 0) {
347*00b67f09SDavid van Moolenbroek return (LWRES_R_IOERROR);
348*00b67f09SDavid van Moolenbroek }
349*00b67f09SDavid van Moolenbroek #else
350*00b67f09SDavid van Moolenbroek if (s == INVALID_SOCKET) {
351*00b67f09SDavid van Moolenbroek DestroySockets();
352*00b67f09SDavid van Moolenbroek return (LWRES_R_IOERROR);
353*00b67f09SDavid van Moolenbroek }
354*00b67f09SDavid van Moolenbroek #endif
355*00b67f09SDavid van Moolenbroek
356*00b67f09SDavid van Moolenbroek ret = connect(s, sa, salen);
357*00b67f09SDavid van Moolenbroek if (ret != 0) {
358*00b67f09SDavid van Moolenbroek #ifdef WIN32
359*00b67f09SDavid van Moolenbroek DestroySockets();
360*00b67f09SDavid van Moolenbroek #endif
361*00b67f09SDavid van Moolenbroek (void)close(s);
362*00b67f09SDavid van Moolenbroek return (LWRES_R_IOERROR);
363*00b67f09SDavid van Moolenbroek }
364*00b67f09SDavid van Moolenbroek
365*00b67f09SDavid van Moolenbroek MAKE_NONBLOCKING(s, ret);
366*00b67f09SDavid van Moolenbroek if (ret < 0) {
367*00b67f09SDavid van Moolenbroek #ifdef WIN32
368*00b67f09SDavid van Moolenbroek DestroySockets();
369*00b67f09SDavid van Moolenbroek #endif
370*00b67f09SDavid van Moolenbroek (void)close(s);
371*00b67f09SDavid van Moolenbroek return (LWRES_R_IOERROR);
372*00b67f09SDavid van Moolenbroek }
373*00b67f09SDavid van Moolenbroek
374*00b67f09SDavid van Moolenbroek ctx->sock = (int)s;
375*00b67f09SDavid van Moolenbroek
376*00b67f09SDavid van Moolenbroek return (LWRES_R_SUCCESS);
377*00b67f09SDavid van Moolenbroek }
378*00b67f09SDavid van Moolenbroek
379*00b67f09SDavid van Moolenbroek int
lwres_context_getsocket(lwres_context_t * ctx)380*00b67f09SDavid van Moolenbroek lwres_context_getsocket(lwres_context_t *ctx) {
381*00b67f09SDavid van Moolenbroek return (ctx->sock);
382*00b67f09SDavid van Moolenbroek }
383*00b67f09SDavid van Moolenbroek
384*00b67f09SDavid van Moolenbroek lwres_result_t
lwres_context_send(lwres_context_t * ctx,void * sendbase,int sendlen)385*00b67f09SDavid van Moolenbroek lwres_context_send(lwres_context_t *ctx,
386*00b67f09SDavid van Moolenbroek void *sendbase, int sendlen) {
387*00b67f09SDavid van Moolenbroek int ret;
388*00b67f09SDavid van Moolenbroek lwres_result_t lwresult;
389*00b67f09SDavid van Moolenbroek
390*00b67f09SDavid van Moolenbroek if (ctx->sock == -1) {
391*00b67f09SDavid van Moolenbroek lwresult = context_connect(ctx);
392*00b67f09SDavid van Moolenbroek if (lwresult != LWRES_R_SUCCESS)
393*00b67f09SDavid van Moolenbroek return (lwresult);
394*00b67f09SDavid van Moolenbroek INSIST(ctx->sock >= 0);
395*00b67f09SDavid van Moolenbroek }
396*00b67f09SDavid van Moolenbroek
397*00b67f09SDavid van Moolenbroek ret = sendto(ctx->sock, sendbase, sendlen, 0, NULL, 0);
398*00b67f09SDavid van Moolenbroek if (ret < 0)
399*00b67f09SDavid van Moolenbroek return (LWRES_R_IOERROR);
400*00b67f09SDavid van Moolenbroek if (ret != sendlen)
401*00b67f09SDavid van Moolenbroek return (LWRES_R_IOERROR);
402*00b67f09SDavid van Moolenbroek
403*00b67f09SDavid van Moolenbroek return (LWRES_R_SUCCESS);
404*00b67f09SDavid van Moolenbroek }
405*00b67f09SDavid van Moolenbroek
406*00b67f09SDavid van Moolenbroek lwres_result_t
lwres_context_recv(lwres_context_t * ctx,void * recvbase,int recvlen,int * recvd_len)407*00b67f09SDavid van Moolenbroek lwres_context_recv(lwres_context_t *ctx,
408*00b67f09SDavid van Moolenbroek void *recvbase, int recvlen,
409*00b67f09SDavid van Moolenbroek int *recvd_len)
410*00b67f09SDavid van Moolenbroek {
411*00b67f09SDavid van Moolenbroek LWRES_SOCKADDR_LEN_T fromlen;
412*00b67f09SDavid van Moolenbroek struct sockaddr_in sin;
413*00b67f09SDavid van Moolenbroek struct sockaddr_in6 sin6;
414*00b67f09SDavid van Moolenbroek struct sockaddr *sa;
415*00b67f09SDavid van Moolenbroek int ret;
416*00b67f09SDavid van Moolenbroek
417*00b67f09SDavid van Moolenbroek if (ctx->address.family == LWRES_ADDRTYPE_V4) {
418*00b67f09SDavid van Moolenbroek sa = (struct sockaddr *)&sin;
419*00b67f09SDavid van Moolenbroek fromlen = sizeof(sin);
420*00b67f09SDavid van Moolenbroek } else {
421*00b67f09SDavid van Moolenbroek sa = (struct sockaddr *)&sin6;
422*00b67f09SDavid van Moolenbroek fromlen = sizeof(sin6);
423*00b67f09SDavid van Moolenbroek }
424*00b67f09SDavid van Moolenbroek
425*00b67f09SDavid van Moolenbroek /*
426*00b67f09SDavid van Moolenbroek * The address of fromlen is cast to void * to shut up compiler
427*00b67f09SDavid van Moolenbroek * warnings, namely on systems that have the sixth parameter
428*00b67f09SDavid van Moolenbroek * prototyped as a signed int when LWRES_SOCKADDR_LEN_T is
429*00b67f09SDavid van Moolenbroek * defined as unsigned.
430*00b67f09SDavid van Moolenbroek */
431*00b67f09SDavid van Moolenbroek ret = recvfrom(ctx->sock, recvbase, recvlen, 0, sa, (void *)&fromlen);
432*00b67f09SDavid van Moolenbroek
433*00b67f09SDavid van Moolenbroek if (ret < 0)
434*00b67f09SDavid van Moolenbroek return (LWRES_R_IOERROR);
435*00b67f09SDavid van Moolenbroek
436*00b67f09SDavid van Moolenbroek if (ret == recvlen)
437*00b67f09SDavid van Moolenbroek return (LWRES_R_TOOLARGE);
438*00b67f09SDavid van Moolenbroek
439*00b67f09SDavid van Moolenbroek /*
440*00b67f09SDavid van Moolenbroek * If we got something other than what we expect, have the caller
441*00b67f09SDavid van Moolenbroek * wait for another packet. This can happen if an old result
442*00b67f09SDavid van Moolenbroek * comes in, or if someone is sending us random stuff.
443*00b67f09SDavid van Moolenbroek */
444*00b67f09SDavid van Moolenbroek if (ctx->address.family == LWRES_ADDRTYPE_V4) {
445*00b67f09SDavid van Moolenbroek if (fromlen != sizeof(sin)
446*00b67f09SDavid van Moolenbroek || memcmp(&sin.sin_addr, ctx->address.address,
447*00b67f09SDavid van Moolenbroek sizeof(sin.sin_addr)) != 0
448*00b67f09SDavid van Moolenbroek || sin.sin_port != htons(lwres_udp_port))
449*00b67f09SDavid van Moolenbroek return (LWRES_R_RETRY);
450*00b67f09SDavid van Moolenbroek } else {
451*00b67f09SDavid van Moolenbroek if (fromlen != sizeof(sin6)
452*00b67f09SDavid van Moolenbroek || memcmp(&sin6.sin6_addr, ctx->address.address,
453*00b67f09SDavid van Moolenbroek sizeof(sin6.sin6_addr)) != 0
454*00b67f09SDavid van Moolenbroek || sin6.sin6_port != htons(lwres_udp_port))
455*00b67f09SDavid van Moolenbroek return (LWRES_R_RETRY);
456*00b67f09SDavid van Moolenbroek }
457*00b67f09SDavid van Moolenbroek
458*00b67f09SDavid van Moolenbroek if (recvd_len != NULL)
459*00b67f09SDavid van Moolenbroek *recvd_len = ret;
460*00b67f09SDavid van Moolenbroek
461*00b67f09SDavid van Moolenbroek return (LWRES_R_SUCCESS);
462*00b67f09SDavid van Moolenbroek }
463*00b67f09SDavid van Moolenbroek
464*00b67f09SDavid van Moolenbroek /*% performs I/O for the context ctx. */
465*00b67f09SDavid van Moolenbroek lwres_result_t
lwres_context_sendrecv(lwres_context_t * ctx,void * sendbase,int sendlen,void * recvbase,int recvlen,int * recvd_len)466*00b67f09SDavid van Moolenbroek lwres_context_sendrecv(lwres_context_t *ctx,
467*00b67f09SDavid van Moolenbroek void *sendbase, int sendlen,
468*00b67f09SDavid van Moolenbroek void *recvbase, int recvlen,
469*00b67f09SDavid van Moolenbroek int *recvd_len)
470*00b67f09SDavid van Moolenbroek {
471*00b67f09SDavid van Moolenbroek lwres_result_t result;
472*00b67f09SDavid van Moolenbroek int ret2;
473*00b67f09SDavid van Moolenbroek fd_set readfds;
474*00b67f09SDavid van Moolenbroek struct timeval timeout;
475*00b67f09SDavid van Moolenbroek
476*00b67f09SDavid van Moolenbroek /*
477*00b67f09SDavid van Moolenbroek * Type of tv_sec is 32 bits long.
478*00b67f09SDavid van Moolenbroek */
479*00b67f09SDavid van Moolenbroek if (ctx->timeout <= 0x7FFFFFFFU)
480*00b67f09SDavid van Moolenbroek timeout.tv_sec = (int)ctx->timeout;
481*00b67f09SDavid van Moolenbroek else
482*00b67f09SDavid van Moolenbroek timeout.tv_sec = 0x7FFFFFFF;
483*00b67f09SDavid van Moolenbroek
484*00b67f09SDavid van Moolenbroek timeout.tv_usec = 0;
485*00b67f09SDavid van Moolenbroek
486*00b67f09SDavid van Moolenbroek result = lwres_context_send(ctx, sendbase, sendlen);
487*00b67f09SDavid van Moolenbroek if (result != LWRES_R_SUCCESS)
488*00b67f09SDavid van Moolenbroek return (result);
489*00b67f09SDavid van Moolenbroek
490*00b67f09SDavid van Moolenbroek /*
491*00b67f09SDavid van Moolenbroek * If this is not checked, select() can overflow,
492*00b67f09SDavid van Moolenbroek * causing corruption elsewhere.
493*00b67f09SDavid van Moolenbroek */
494*00b67f09SDavid van Moolenbroek if (ctx->sock >= (int)FD_SETSIZE) {
495*00b67f09SDavid van Moolenbroek close(ctx->sock);
496*00b67f09SDavid van Moolenbroek ctx->sock = -1;
497*00b67f09SDavid van Moolenbroek return (LWRES_R_IOERROR);
498*00b67f09SDavid van Moolenbroek }
499*00b67f09SDavid van Moolenbroek
500*00b67f09SDavid van Moolenbroek again:
501*00b67f09SDavid van Moolenbroek FD_ZERO(&readfds);
502*00b67f09SDavid van Moolenbroek FD_SET(ctx->sock, &readfds);
503*00b67f09SDavid van Moolenbroek ret2 = select(ctx->sock + 1, &readfds, NULL, NULL, &timeout);
504*00b67f09SDavid van Moolenbroek
505*00b67f09SDavid van Moolenbroek /*
506*00b67f09SDavid van Moolenbroek * What happened with select?
507*00b67f09SDavid van Moolenbroek */
508*00b67f09SDavid van Moolenbroek if (ret2 < 0)
509*00b67f09SDavid van Moolenbroek return (LWRES_R_IOERROR);
510*00b67f09SDavid van Moolenbroek if (ret2 == 0)
511*00b67f09SDavid van Moolenbroek return (LWRES_R_TIMEOUT);
512*00b67f09SDavid van Moolenbroek
513*00b67f09SDavid van Moolenbroek result = lwres_context_recv(ctx, recvbase, recvlen, recvd_len);
514*00b67f09SDavid van Moolenbroek if (result == LWRES_R_RETRY)
515*00b67f09SDavid van Moolenbroek goto again;
516*00b67f09SDavid van Moolenbroek
517*00b67f09SDavid van Moolenbroek return (result);
518*00b67f09SDavid van Moolenbroek }
519