2 * Copyright (C) 2003, Michael Richardson <mcr@freeswawn.org>
3 * Derived from code: Copyright (C) 2000, 2001 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 INTERNET SOFTWARE CONSORTIUM
10 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
11 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 /* $Id: async.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
27 #include <lwres/lwres.h>
28 #include <lwres/net.h>
29 #include <lwres/netdb.h> /* XXX #include <netdb.h> */
30 #include <lwres/async.h>
33 #include "context_p.h"
36 * malloc / calloc functions that guarantee to only
37 * return NULL if there is an error, like they used
38 * to before the ANSI C committee broke them.
42 sane_malloc(size_t size
) {
45 return (malloc(size
));
49 sane_calloc(size_t number
, size_t size
) {
50 size_t len
= number
* size
;
51 void *mem
= sane_malloc(len
);
58 lwres_async_init(lwres_context_t
**pctx
)
60 lwres_result_t lwresult
;
61 lwres_context_t
*ctx
= NULL
;
64 lwresult
= lwres_context_create(&ctx
, NULL
, NULL
, NULL
, 0);
65 if (lwresult
!= LWRES_R_SUCCESS
) {
66 result
= lwresult_to_result(lwresult
);
69 (void) lwres_conf_parse(ctx
, lwres_resolv_conf
);
72 return (ERRSET_SUCCESS
);
76 lwres_getrrsetbyname_init(const char *hostname
, unsigned int rdclass
,
77 unsigned int rdtype
, unsigned int flags
,
79 struct lwres_async_state
*las
)
81 lwres_result_t lwresult
;
88 lwres_grbnrequest_t request
;
89 char target_name
[1024];
90 unsigned int target_length
;
94 if (rdclass
> 0xffff || rdtype
> 0xffff) {
95 result
= ERRSET_INVAL
;
100 * Don't allow queries of class or type ANY
102 if (rdclass
== 0xff || rdtype
== 0xff) {
103 result
= ERRSET_INVAL
;
108 * If any input flags were defined, lwflags would be set here
114 las
->b_in
.base
= NULL
;
115 las
->b_out
.base
= NULL
;
116 las
->serial
= lwres_context_nextserial(ctx
);
117 las
->opcode
= LWRES_OPCODE_GETRDATABYNAME
;
119 target_length
= strlen(hostname
);
120 if (target_length
>= sizeof(target_name
))
121 return (LWRES_R_FAILURE
);
122 strcpy(target_name
, hostname
); /* strcpy is safe */
125 * Set up our request and render it to a buffer.
127 request
.rdclass
= rdclass
;
128 request
.rdtype
= rdtype
;
129 request
.flags
= lwflags
;
130 request
.name
= target_name
;
131 request
.namelen
= target_length
;
133 pkt
.serial
= las
->serial
;
135 pkt
.recvlength
= LWRES_RECVLENGTH
;
137 /* set up async system */
138 las
->next
= ctx
->pending
;
141 ret
= lwres_grbnrequest_render(ctx
, &request
, &pkt
, &las
->b_out
);
147 lwres_getrrsetbyname_xmit(lwres_context_t
*ctx
,
148 struct lwres_async_state
*las
)
150 lwres_result_t lwresult
;
153 lwresult
= lwres_context_send(ctx
, las
->b_out
.base
, las
->b_out
.length
);
155 return(lwresult_to_result(lwresult
));
161 lwres_async_timeout(lwres_context_t
*ctx
)
163 unsigned long tv_sec
;
166 * Type of tv_sec is long, so make sure the unsigned long timeout
167 * does not overflow it.
169 if (ctx
->timeout
<= LONG_MAX
)
170 tv_sec
= (long)ctx
->timeout
;
178 lwres_async_fd(lwres_context_t
*ctx
)
185 const char *hostname, unsigned int rdclass,
186 unsigned int rdtype, unsigned int flags,
190 lwres_getrrsetbyname_read(struct lwres_async_state
**plas
,
191 lwres_context_t
*ctx
,
192 struct rrsetinfo
**res
)
194 lwres_result_t lwresult
;
195 lwres_grbnresponse_t
*response
= NULL
;
197 struct rrsetinfo
*rrset
= NULL
;
201 struct lwres_async_state
*las
;
202 struct lwres_async_state
**las_prev
;
203 lwres_lwpacket_t pkt
;
206 buffer
= CTXMALLOC(LWRES_RECVLENGTH
);
207 if (buffer
== NULL
) {
208 return ERRSET_NOMEMORY
;
211 ret
= LWRES_R_SUCCESS
;
212 lwresult
= lwres_context_recv(ctx
, buffer
, LWRES_RECVLENGTH
, &recvlen
);
213 if (lwresult
== LWRES_R_RETRY
) {
218 if (ret
!= LWRES_R_SUCCESS
)
221 lwres_buffer_init(&b_in
, buffer
, recvlen
);
225 * Parse the packet header.
227 ret
= lwres_lwpacket_parseheader(&b_in
, &pkt
);
228 if (ret
!= LWRES_R_SUCCESS
)
232 * find an appropriate waiting las entry. This is a linear search.
233 * we can do MUCH better, since we control the serial number!
236 las_prev
= &ctx
->pending
;
238 while(las
&& las
->serial
!= pkt
.serial
) {
244 /* no matching serial number! */
245 return(LWRES_R_RETRY
);
248 /* okay, remove it from the receive queue */
249 *las_prev
= las
->next
;
255 * Free what we've transmitted, long ago.
257 CTXFREE(las
->b_out
.base
, las
->b_out
.length
);
258 las
->b_out
.base
= NULL
;
259 las
->b_out
.length
= 0;
261 if (pkt
.result
!= LWRES_R_SUCCESS
) {
267 * Parse the response.
269 ret
= lwres_grbnresponse_parse(ctx
, &b_in
, &pkt
, &response
);
270 if (ret
!= LWRES_R_SUCCESS
) {
273 CTXFREE(buffer
, LWRES_RECVLENGTH
);
274 if (response
!= NULL
)
275 lwres_grbnresponse_free(ctx
, &response
);
276 result
= lwresult_to_result(ret
);
280 response
->base
= buffer
;
281 response
->baselen
= LWRES_RECVLENGTH
;
282 buffer
= NULL
; /* don't free this below */
284 lwresult
= LWRES_R_SUCCESS
;
286 rrset
= sane_malloc(sizeof(struct rrsetinfo
));
288 result
= ERRSET_NOMEMORY
;
291 rrset
->rri_name
= NULL
;
292 rrset
->rri_rdclass
= response
->rdclass
;
293 rrset
->rri_rdtype
= response
->rdtype
;
294 rrset
->rri_ttl
= response
->ttl
;
295 rrset
->rri_flags
= 0;
296 rrset
->rri_nrdatas
= 0;
297 rrset
->rri_rdatas
= NULL
;
298 rrset
->rri_nsigs
= 0;
299 rrset
->rri_sigs
= NULL
;
301 rrset
->rri_name
= sane_malloc(response
->realnamelen
+ 1);
302 if (rrset
->rri_name
== NULL
) {
303 result
= ERRSET_NOMEMORY
;
306 strncpy(rrset
->rri_name
, response
->realname
, response
->realnamelen
);
307 rrset
->rri_name
[response
->realnamelen
] = 0;
309 if ((response
->flags
& LWRDATA_VALIDATED
) != 0)
310 rrset
->rri_flags
|= RRSET_VALIDATED
;
312 rrset
->rri_nrdatas
= response
->nrdatas
;
313 rrset
->rri_rdatas
= sane_calloc(rrset
->rri_nrdatas
,
314 sizeof(struct rdatainfo
));
315 if (rrset
->rri_rdatas
== NULL
) {
316 result
= ERRSET_NOMEMORY
;
319 for (i
= 0; i
< rrset
->rri_nrdatas
; i
++) {
320 rrset
->rri_rdatas
[i
].rdi_length
= response
->rdatalen
[i
];
321 rrset
->rri_rdatas
[i
].rdi_data
=
322 sane_malloc(rrset
->rri_rdatas
[i
].rdi_length
);
323 if (rrset
->rri_rdatas
[i
].rdi_data
== NULL
) {
324 result
= ERRSET_NOMEMORY
;
327 memcpy(rrset
->rri_rdatas
[i
].rdi_data
, response
->rdatas
[i
],
328 rrset
->rri_rdatas
[i
].rdi_length
);
330 rrset
->rri_nsigs
= response
->nsigs
;
331 rrset
->rri_sigs
= sane_calloc(rrset
->rri_nsigs
,
332 sizeof(struct rdatainfo
));
333 if (rrset
->rri_sigs
== NULL
) {
334 result
= ERRSET_NOMEMORY
;
337 for (i
= 0; i
< rrset
->rri_nsigs
; i
++) {
338 rrset
->rri_sigs
[i
].rdi_length
= response
->siglen
[i
];
339 rrset
->rri_sigs
[i
].rdi_data
=
340 sane_malloc(rrset
->rri_sigs
[i
].rdi_length
);
341 if (rrset
->rri_sigs
[i
].rdi_data
== NULL
) {
342 result
= ERRSET_NOMEMORY
;
345 memcpy(rrset
->rri_sigs
[i
].rdi_data
, response
->sigs
[i
],
346 rrset
->rri_sigs
[i
].rdi_length
);
349 lwres_grbnresponse_free(ctx
, &response
);
352 return (ERRSET_SUCCESS
);
355 lwres_freerrset(rrset
);
356 if (response
!= NULL
)
357 lwres_grbnresponse_free(ctx
, &response
);