xref: /minix/external/bsd/bind/dist/lib/lwres/context.c (revision 00b67f09)
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