]> git.ipfire.org Git - people/ms/strongswan.git/blob - src/libfreeswan/liblwres/async.c
- started to rebuild source layout
[people/ms/strongswan.git] / src / libfreeswan / liblwres / async.c
1 /*
2 * Copyright (C) 2003, Michael Richardson <mcr@freeswawn.org>
3 * Derived from code: Copyright (C) 2000, 2001 Internet Software Consortium.
4 *
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.
8 *
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.
17 */
18
19 /* $Id: async.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
20
21 #include <config.h>
22
23 #include <string.h>
24 #include <errno.h>
25 #include <stdlib.h>
26
27 #include <lwres/lwres.h>
28 #include <lwres/net.h>
29 #include <lwres/netdb.h> /* XXX #include <netdb.h> */
30 #include <lwres/async.h>
31
32 #include "assert_p.h"
33 #include "context_p.h"
34
35 /*
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.
39 */
40
41 static void *
42 sane_malloc(size_t size) {
43 if (size == 0)
44 size = 1;
45 return (malloc(size));
46 }
47
48 static void *
49 sane_calloc(size_t number, size_t size) {
50 size_t len = number * size;
51 void *mem = sane_malloc(len);
52 if (mem != NULL)
53 memset(mem, 0, len);
54 return (mem);
55 }
56
57 int
58 lwres_async_init(lwres_context_t **pctx)
59 {
60 lwres_result_t lwresult;
61 lwres_context_t *ctx = NULL;
62 int result;
63
64 lwresult = lwres_context_create(&ctx, NULL, NULL, NULL, 0);
65 if (lwresult != LWRES_R_SUCCESS) {
66 result = lwresult_to_result(lwresult);
67 return(result);
68 }
69 (void) lwres_conf_parse(ctx, lwres_resolv_conf);
70
71 *pctx = ctx;
72 return (ERRSET_SUCCESS);
73 }
74
75 int
76 lwres_getrrsetbyname_init(const char *hostname, unsigned int rdclass,
77 unsigned int rdtype, unsigned int flags,
78 lwres_context_t *ctx,
79 struct lwres_async_state *las)
80 {
81 lwres_result_t lwresult;
82 unsigned int i;
83 unsigned int lwflags;
84 unsigned int result;
85
86 int ret;
87 lwres_lwpacket_t pkt;
88 lwres_grbnrequest_t request;
89 char target_name[1024];
90 unsigned int target_length;
91
92 int ret2;
93
94 if (rdclass > 0xffff || rdtype > 0xffff) {
95 result = ERRSET_INVAL;
96 return result;
97 }
98
99 /*
100 * Don't allow queries of class or type ANY
101 */
102 if (rdclass == 0xff || rdtype == 0xff) {
103 result = ERRSET_INVAL;
104 return result;
105 }
106
107 /*
108 * If any input flags were defined, lwflags would be set here
109 * based on them
110 */
111 UNUSED(flags);
112 lwflags = 0;
113
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;
118
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 */
123
124 /*
125 * Set up our request and render it to a buffer.
126 */
127 request.rdclass = rdclass;
128 request.rdtype = rdtype;
129 request.flags = lwflags;
130 request.name = target_name;
131 request.namelen = target_length;
132 pkt.pktflags = 0;
133 pkt.serial = las->serial;
134 pkt.result = 0;
135 pkt.recvlength = LWRES_RECVLENGTH;
136
137 /* set up async system */
138 las->next = ctx->pending;
139 ctx->pending = las;
140
141 ret = lwres_grbnrequest_render(ctx, &request, &pkt, &las->b_out);
142
143 return ret;
144 }
145
146 int
147 lwres_getrrsetbyname_xmit(lwres_context_t *ctx,
148 struct lwres_async_state *las)
149 {
150 lwres_result_t lwresult;
151 int ret;
152
153 lwresult = lwres_context_send(ctx, las->b_out.base, las->b_out.length);
154
155 return(lwresult_to_result(lwresult));
156 }
157
158
159
160 unsigned long
161 lwres_async_timeout(lwres_context_t *ctx)
162 {
163 unsigned long tv_sec;
164
165 /*
166 * Type of tv_sec is long, so make sure the unsigned long timeout
167 * does not overflow it.
168 */
169 if (ctx->timeout <= LONG_MAX)
170 tv_sec = (long)ctx->timeout;
171 else
172 tv_sec = LONG_MAX;
173
174 return tv_sec;
175 }
176
177 int
178 lwres_async_fd(lwres_context_t *ctx)
179 {
180 return (ctx->sock);
181 }
182
183
184 /*
185 const char *hostname, unsigned int rdclass,
186 unsigned int rdtype, unsigned int flags,
187 */
188
189 int
190 lwres_getrrsetbyname_read(struct lwres_async_state **plas,
191 lwres_context_t *ctx,
192 struct rrsetinfo **res)
193 {
194 lwres_result_t lwresult;
195 lwres_grbnresponse_t *response = NULL;
196 char *buffer;
197 struct rrsetinfo *rrset = NULL;
198 int recvlen;
199 int ret, result, i;
200 lwres_buffer_t b_in;
201 struct lwres_async_state *las;
202 struct lwres_async_state **las_prev;
203 lwres_lwpacket_t pkt;
204
205 buffer = NULL;
206 buffer = CTXMALLOC(LWRES_RECVLENGTH);
207 if (buffer == NULL) {
208 return ERRSET_NOMEMORY;
209 }
210
211 ret = LWRES_R_SUCCESS;
212 lwresult = lwres_context_recv(ctx, buffer, LWRES_RECVLENGTH, &recvlen);
213 if (lwresult == LWRES_R_RETRY) {
214 ret = LWRES_R_RETRY;
215 goto out;
216 }
217
218 if (ret != LWRES_R_SUCCESS)
219 goto out;
220
221 lwres_buffer_init(&b_in, buffer, recvlen);
222 b_in.used = recvlen;
223
224 /*
225 * Parse the packet header.
226 */
227 ret = lwres_lwpacket_parseheader(&b_in, &pkt);
228 if (ret != LWRES_R_SUCCESS)
229 goto out;
230
231 /*
232 * find an appropriate waiting las entry. This is a linear search.
233 * we can do MUCH better, since we control the serial number!
234 * do that later.
235 */
236 las_prev = &ctx->pending;
237 las = ctx->pending;
238 while(las && las->serial != pkt.serial) {
239 las_prev=&las->next;
240 las=las->next;
241 }
242
243 if(las == NULL) {
244 /* no matching serial number! */
245 return(LWRES_R_RETRY);
246 }
247
248 /* okay, remove it from the receive queue */
249 *las_prev = las->next;
250 las->next = NULL;
251
252 *plas = las;
253
254 /*
255 * Free what we've transmitted, long ago.
256 */
257 CTXFREE(las->b_out.base, las->b_out.length);
258 las->b_out.base = NULL;
259 las->b_out.length = 0;
260
261 if (pkt.result != LWRES_R_SUCCESS) {
262 ret = pkt.result;
263 goto out;
264 }
265
266 /*
267 * Parse the response.
268 */
269 ret = lwres_grbnresponse_parse(ctx, &b_in, &pkt, &response);
270 if (ret != LWRES_R_SUCCESS) {
271 out:
272 if (buffer != NULL)
273 CTXFREE(buffer, LWRES_RECVLENGTH);
274 if (response != NULL)
275 lwres_grbnresponse_free(ctx, &response);
276 result = lwresult_to_result(ret);
277 goto fail;
278 }
279
280 response->base = buffer;
281 response->baselen = LWRES_RECVLENGTH;
282 buffer = NULL; /* don't free this below */
283
284 lwresult = LWRES_R_SUCCESS;
285
286 rrset = sane_malloc(sizeof(struct rrsetinfo));
287 if (rrset == NULL) {
288 result = ERRSET_NOMEMORY;
289 goto fail;
290 }
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;
300
301 rrset->rri_name = sane_malloc(response->realnamelen + 1);
302 if (rrset->rri_name == NULL) {
303 result = ERRSET_NOMEMORY;
304 goto fail;
305 }
306 strncpy(rrset->rri_name, response->realname, response->realnamelen);
307 rrset->rri_name[response->realnamelen] = 0;
308
309 if ((response->flags & LWRDATA_VALIDATED) != 0)
310 rrset->rri_flags |= RRSET_VALIDATED;
311
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;
317 goto fail;
318 }
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;
325 goto fail;
326 }
327 memcpy(rrset->rri_rdatas[i].rdi_data, response->rdatas[i],
328 rrset->rri_rdatas[i].rdi_length);
329 }
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;
335 goto fail;
336 }
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;
343 goto fail;
344 }
345 memcpy(rrset->rri_sigs[i].rdi_data, response->sigs[i],
346 rrset->rri_sigs[i].rdi_length);
347 }
348
349 lwres_grbnresponse_free(ctx, &response);
350
351 *res = rrset;
352 return (ERRSET_SUCCESS);
353 fail:
354 if (rrset != NULL)
355 lwres_freerrset(rrset);
356 if (response != NULL)
357 lwres_grbnresponse_free(ctx, &response);
358 return (result);
359
360 }
361