Detect FPU by checking CPUID features.
[dragonfly.git] / contrib / bind-9.5.2 / lib / lwres / lwres_gabn.c
blob3363e66b89b4eef99c0e24172e9aa34e015933ee
1 /*
2 * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or 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: lwres_gabn.c,v 1.33 2007/06/19 23:47:22 tbox Exp $ */
20 /*! \file lwres_gabn.c
21 These are low-level routines for creating and parsing lightweight
22 resolver name-to-address lookup request and response messages.
24 There are four main functions for the getaddrbyname opcode. One render
25 function converts a getaddrbyname request structure --
26 lwres_gabnrequest_t -- to the lighweight resolver's canonical format.
27 It is complemented by a parse function that converts a packet in this
28 canonical format to a getaddrbyname request structure. Another render
29 function converts the getaddrbyname response structure --
30 lwres_gabnresponse_t -- to the canonical format. This is complemented
31 by a parse function which converts a packet in canonical format to a
32 getaddrbyname response structure.
34 These structures are defined in \link lwres.h <lwres/lwres.h>.\endlink They are shown below.
36 \code
37 #define LWRES_OPCODE_GETADDRSBYNAME 0x00010001U
39 typedef struct lwres_addr lwres_addr_t;
40 typedef LWRES_LIST(lwres_addr_t) lwres_addrlist_t;
42 typedef struct {
43 lwres_uint32_t flags;
44 lwres_uint32_t addrtypes;
45 lwres_uint16_t namelen;
46 char *name;
47 } lwres_gabnrequest_t;
49 typedef struct {
50 lwres_uint32_t flags;
51 lwres_uint16_t naliases;
52 lwres_uint16_t naddrs;
53 char *realname;
54 char **aliases;
55 lwres_uint16_t realnamelen;
56 lwres_uint16_t *aliaslen;
57 lwres_addrlist_t addrs;
58 void *base;
59 size_t baselen;
60 } lwres_gabnresponse_t;
61 \endcode
63 lwres_gabnrequest_render() uses resolver context ctx to convert
64 getaddrbyname request structure req to canonical format. The packet
65 header structure pkt is initialised and transferred to buffer b. The
66 contents of *req are then appended to the buffer in canonical format.
67 lwres_gabnresponse_render() performs the same task, except it converts
68 a getaddrbyname response structure lwres_gabnresponse_t to the
69 lightweight resolver's canonical format.
71 lwres_gabnrequest_parse() uses context ctx to convert the contents of
72 packet pkt to a lwres_gabnrequest_t structure. Buffer b provides space
73 to be used for storing this structure. When the function succeeds, the
74 resulting lwres_gabnrequest_t is made available through *structp.
75 lwres_gabnresponse_parse() offers the same semantics as
76 lwres_gabnrequest_parse() except it yields a lwres_gabnresponse_t
77 structure.
79 lwres_gabnresponse_free() and lwres_gabnrequest_free() release the
80 memory in resolver context ctx that was allocated to the
81 lwres_gabnresponse_t or lwres_gabnrequest_t structures referenced via
82 structp. Any memory associated with ancillary buffers and strings for
83 those structures is also discarded.
85 \section lwres_gabn_return Return Values
87 The getaddrbyname opcode functions lwres_gabnrequest_render(),
88 lwres_gabnresponse_render() lwres_gabnrequest_parse() and
89 lwres_gabnresponse_parse() all return #LWRES_R_SUCCESS on success. They
90 return #LWRES_R_NOMEMORY if memory allocation fails.
91 #LWRES_R_UNEXPECTEDEND is returned if the available space in the buffer
92 b is too small to accommodate the packet header or the
93 lwres_gabnrequest_t and lwres_gabnresponse_t structures.
94 lwres_gabnrequest_parse() and lwres_gabnresponse_parse() will return
95 #LWRES_R_UNEXPECTEDEND if the buffer is not empty after decoding the
96 received packet. These functions will return #LWRES_R_FAILURE if
97 pktflags in the packet header structure #lwres_lwpacket_t indicate that
98 the packet is not a response to an earlier query.
100 \section lwres_gabn_see See Also
102 \link lwpacket.c lwres_lwpacket \endlink
105 #include <config.h>
107 #include <assert.h>
108 #include <stdlib.h>
109 #include <string.h>
111 #include <lwres/lwbuffer.h>
112 #include <lwres/lwpacket.h>
113 #include <lwres/lwres.h>
114 #include <lwres/result.h>
116 #include "context_p.h"
117 #include "assert_p.h"
119 /*% uses resolver context ctx to convert getaddrbyname request structure req to canonical format. */
120 lwres_result_t
121 lwres_gabnrequest_render(lwres_context_t *ctx, lwres_gabnrequest_t *req,
122 lwres_lwpacket_t *pkt, lwres_buffer_t *b)
124 unsigned char *buf;
125 size_t buflen;
126 int ret;
127 size_t payload_length;
128 lwres_uint16_t datalen;
130 REQUIRE(ctx != NULL);
131 REQUIRE(req != NULL);
132 REQUIRE(req->name != NULL);
133 REQUIRE(pkt != NULL);
134 REQUIRE(b != NULL);
136 datalen = strlen(req->name);
138 payload_length = 4 + 4 + 2 + req->namelen + 1;
140 buflen = LWRES_LWPACKET_LENGTH + payload_length;
141 buf = CTXMALLOC(buflen);
142 if (buf == NULL)
143 return (LWRES_R_NOMEMORY);
145 lwres_buffer_init(b, buf, buflen);
147 pkt->length = buflen;
148 pkt->version = LWRES_LWPACKETVERSION_0;
149 pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
150 pkt->opcode = LWRES_OPCODE_GETADDRSBYNAME;
151 pkt->result = 0;
152 pkt->authtype = 0;
153 pkt->authlength = 0;
155 ret = lwres_lwpacket_renderheader(b, pkt);
156 if (ret != LWRES_R_SUCCESS) {
157 lwres_buffer_invalidate(b);
158 CTXFREE(buf, buflen);
159 return (ret);
162 INSIST(SPACE_OK(b, payload_length));
165 * Flags.
167 lwres_buffer_putuint32(b, req->flags);
170 * Address types we'll accept.
172 lwres_buffer_putuint32(b, req->addrtypes);
175 * Put the length and the data. We know this will fit because we
176 * just checked for it.
178 lwres_buffer_putuint16(b, datalen);
179 lwres_buffer_putmem(b, (unsigned char *)req->name, datalen);
180 lwres_buffer_putuint8(b, 0); /* trailing NUL */
182 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
184 return (LWRES_R_SUCCESS);
186 /*% converts a getaddrbyname response structure lwres_gabnresponse_t to the lightweight resolver's canonical format. */
187 lwres_result_t
188 lwres_gabnresponse_render(lwres_context_t *ctx, lwres_gabnresponse_t *req,
189 lwres_lwpacket_t *pkt, lwres_buffer_t *b)
191 unsigned char *buf;
192 size_t buflen;
193 int ret;
194 size_t payload_length;
195 lwres_uint16_t datalen;
196 lwres_addr_t *addr;
197 int x;
199 REQUIRE(ctx != NULL);
200 REQUIRE(req != NULL);
201 REQUIRE(pkt != NULL);
202 REQUIRE(b != NULL);
204 /* naliases, naddrs */
205 payload_length = 4 + 2 + 2;
206 /* real name encoding */
207 payload_length += 2 + req->realnamelen + 1;
208 /* each alias */
209 for (x = 0; x < req->naliases; x++)
210 payload_length += 2 + req->aliaslen[x] + 1;
211 /* each address */
212 x = 0;
213 addr = LWRES_LIST_HEAD(req->addrs);
214 while (addr != NULL) {
215 payload_length += 4 + 2;
216 payload_length += addr->length;
217 addr = LWRES_LIST_NEXT(addr, link);
218 x++;
220 INSIST(x == req->naddrs);
222 buflen = LWRES_LWPACKET_LENGTH + payload_length;
223 buf = CTXMALLOC(buflen);
224 if (buf == NULL)
225 return (LWRES_R_NOMEMORY);
226 lwres_buffer_init(b, buf, buflen);
228 pkt->length = buflen;
229 pkt->version = LWRES_LWPACKETVERSION_0;
230 pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
231 pkt->opcode = LWRES_OPCODE_GETADDRSBYNAME;
232 pkt->authtype = 0;
233 pkt->authlength = 0;
235 ret = lwres_lwpacket_renderheader(b, pkt);
236 if (ret != LWRES_R_SUCCESS) {
237 lwres_buffer_invalidate(b);
238 CTXFREE(buf, buflen);
239 return (ret);
243 * Check space needed here.
245 INSIST(SPACE_OK(b, payload_length));
247 /* Flags. */
248 lwres_buffer_putuint32(b, req->flags);
250 /* encode naliases and naddrs */
251 lwres_buffer_putuint16(b, req->naliases);
252 lwres_buffer_putuint16(b, req->naddrs);
254 /* encode the real name */
255 datalen = req->realnamelen;
256 lwres_buffer_putuint16(b, datalen);
257 lwres_buffer_putmem(b, (unsigned char *)req->realname, datalen);
258 lwres_buffer_putuint8(b, 0);
260 /* encode the aliases */
261 for (x = 0; x < req->naliases; x++) {
262 datalen = req->aliaslen[x];
263 lwres_buffer_putuint16(b, datalen);
264 lwres_buffer_putmem(b, (unsigned char *)req->aliases[x],
265 datalen);
266 lwres_buffer_putuint8(b, 0);
269 /* encode the addresses */
270 addr = LWRES_LIST_HEAD(req->addrs);
271 while (addr != NULL) {
272 lwres_buffer_putuint32(b, addr->family);
273 lwres_buffer_putuint16(b, addr->length);
274 lwres_buffer_putmem(b, addr->address, addr->length);
275 addr = LWRES_LIST_NEXT(addr, link);
278 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
279 INSIST(LWRES_BUFFER_USEDCOUNT(b) == pkt->length);
281 return (LWRES_R_SUCCESS);
283 /*% Uses context ctx to convert the contents of packet pkt to a lwres_gabnrequest_t structure. */
284 lwres_result_t
285 lwres_gabnrequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
286 lwres_lwpacket_t *pkt, lwres_gabnrequest_t **structp)
288 int ret;
289 char *name;
290 lwres_gabnrequest_t *gabn;
291 lwres_uint32_t addrtypes;
292 lwres_uint32_t flags;
293 lwres_uint16_t namelen;
295 REQUIRE(ctx != NULL);
296 REQUIRE(pkt != NULL);
297 REQUIRE(b != NULL);
298 REQUIRE(structp != NULL && *structp == NULL);
300 if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
301 return (LWRES_R_FAILURE);
303 if (!SPACE_REMAINING(b, 4 + 4))
304 return (LWRES_R_UNEXPECTEDEND);
306 flags = lwres_buffer_getuint32(b);
307 addrtypes = lwres_buffer_getuint32(b);
310 * Pull off the name itself
312 ret = lwres_string_parse(b, &name, &namelen);
313 if (ret != LWRES_R_SUCCESS)
314 return (ret);
316 if (LWRES_BUFFER_REMAINING(b) != 0)
317 return (LWRES_R_TRAILINGDATA);
319 gabn = CTXMALLOC(sizeof(lwres_gabnrequest_t));
320 if (gabn == NULL)
321 return (LWRES_R_NOMEMORY);
323 gabn->flags = flags;
324 gabn->addrtypes = addrtypes;
325 gabn->name = name;
326 gabn->namelen = namelen;
328 *structp = gabn;
329 return (LWRES_R_SUCCESS);
332 /*% Offers the same semantics as lwres_gabnrequest_parse() except it yields a lwres_gabnresponse_t structure. */
334 lwres_result_t
335 lwres_gabnresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
336 lwres_lwpacket_t *pkt, lwres_gabnresponse_t **structp)
338 lwres_result_t ret;
339 unsigned int x;
340 lwres_uint32_t flags;
341 lwres_uint16_t naliases;
342 lwres_uint16_t naddrs;
343 lwres_gabnresponse_t *gabn;
344 lwres_addrlist_t addrlist;
345 lwres_addr_t *addr;
347 REQUIRE(ctx != NULL);
348 REQUIRE(pkt != NULL);
349 REQUIRE(b != NULL);
350 REQUIRE(structp != NULL && *structp == NULL);
352 gabn = NULL;
354 if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
355 return (LWRES_R_FAILURE);
358 * Pull off the name itself
360 if (!SPACE_REMAINING(b, 4 + 2 + 2))
361 return (LWRES_R_UNEXPECTEDEND);
362 flags = lwres_buffer_getuint32(b);
363 naliases = lwres_buffer_getuint16(b);
364 naddrs = lwres_buffer_getuint16(b);
366 gabn = CTXMALLOC(sizeof(lwres_gabnresponse_t));
367 if (gabn == NULL)
368 return (LWRES_R_NOMEMORY);
369 gabn->aliases = NULL;
370 gabn->aliaslen = NULL;
371 LWRES_LIST_INIT(gabn->addrs);
372 gabn->base = NULL;
374 gabn->flags = flags;
375 gabn->naliases = naliases;
376 gabn->naddrs = naddrs;
378 LWRES_LIST_INIT(addrlist);
380 if (naliases > 0) {
381 gabn->aliases = CTXMALLOC(sizeof(char *) * naliases);
382 if (gabn->aliases == NULL) {
383 ret = LWRES_R_NOMEMORY;
384 goto out;
387 gabn->aliaslen = CTXMALLOC(sizeof(lwres_uint16_t) * naliases);
388 if (gabn->aliaslen == NULL) {
389 ret = LWRES_R_NOMEMORY;
390 goto out;
394 for (x = 0; x < naddrs; x++) {
395 addr = CTXMALLOC(sizeof(lwres_addr_t));
396 if (addr == NULL) {
397 ret = LWRES_R_NOMEMORY;
398 goto out;
400 LWRES_LINK_INIT(addr, link);
401 LWRES_LIST_APPEND(addrlist, addr, link);
405 * Now, pull off the real name.
407 ret = lwres_string_parse(b, &gabn->realname, &gabn->realnamelen);
408 if (ret != LWRES_R_SUCCESS)
409 goto out;
412 * Parse off the aliases.
414 for (x = 0; x < gabn->naliases; x++) {
415 ret = lwres_string_parse(b, &gabn->aliases[x],
416 &gabn->aliaslen[x]);
417 if (ret != LWRES_R_SUCCESS)
418 goto out;
422 * Pull off the addresses. We already strung the linked list
423 * up above.
425 addr = LWRES_LIST_HEAD(addrlist);
426 for (x = 0; x < gabn->naddrs; x++) {
427 INSIST(addr != NULL);
428 ret = lwres_addr_parse(b, addr);
429 if (ret != LWRES_R_SUCCESS)
430 goto out;
431 addr = LWRES_LIST_NEXT(addr, link);
434 if (LWRES_BUFFER_REMAINING(b) != 0) {
435 ret = LWRES_R_TRAILINGDATA;
436 goto out;
439 gabn->addrs = addrlist;
441 *structp = gabn;
442 return (LWRES_R_SUCCESS);
444 out:
445 if (gabn != NULL) {
446 if (gabn->aliases != NULL)
447 CTXFREE(gabn->aliases, sizeof(char *) * naliases);
448 if (gabn->aliaslen != NULL)
449 CTXFREE(gabn->aliaslen,
450 sizeof(lwres_uint16_t) * naliases);
451 addr = LWRES_LIST_HEAD(addrlist);
452 while (addr != NULL) {
453 LWRES_LIST_UNLINK(addrlist, addr, link);
454 CTXFREE(addr, sizeof(lwres_addr_t));
455 addr = LWRES_LIST_HEAD(addrlist);
457 CTXFREE(gabn, sizeof(lwres_gabnresponse_t));
460 return (ret);
463 /*% Release the memory in resolver context ctx that was allocated to the lwres_gabnrequest_t. */
464 void
465 lwres_gabnrequest_free(lwres_context_t *ctx, lwres_gabnrequest_t **structp)
467 lwres_gabnrequest_t *gabn;
469 REQUIRE(ctx != NULL);
470 REQUIRE(structp != NULL && *structp != NULL);
472 gabn = *structp;
473 *structp = NULL;
475 CTXFREE(gabn, sizeof(lwres_gabnrequest_t));
478 /*% Release the memory in resolver context ctx that was allocated to the lwres_gabnresponse_t. */
479 void
480 lwres_gabnresponse_free(lwres_context_t *ctx, lwres_gabnresponse_t **structp)
482 lwres_gabnresponse_t *gabn;
483 lwres_addr_t *addr;
485 REQUIRE(ctx != NULL);
486 REQUIRE(structp != NULL && *structp != NULL);
488 gabn = *structp;
489 *structp = NULL;
491 if (gabn->naliases > 0) {
492 CTXFREE(gabn->aliases, sizeof(char *) * gabn->naliases);
493 CTXFREE(gabn->aliaslen,
494 sizeof(lwres_uint16_t) * gabn->naliases);
496 addr = LWRES_LIST_HEAD(gabn->addrs);
497 while (addr != NULL) {
498 LWRES_LIST_UNLINK(gabn->addrs, addr, link);
499 CTXFREE(addr, sizeof(lwres_addr_t));
500 addr = LWRES_LIST_HEAD(gabn->addrs);
502 if (gabn->base != NULL)
503 CTXFREE(gabn->base, gabn->baselen);
504 CTXFREE(gabn, sizeof(lwres_gabnresponse_t));