4 * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000-2002 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: lwres_gnba.c,v 1.28 2007/09/24 17:18:25 each Exp */
22 /*! \file lwres_gnba.c
23 These are low-level routines for creating and parsing lightweight
24 resolver address-to-name lookup request and response messages.
26 There are four main functions for the getnamebyaddr opcode. One
27 render function converts a getnamebyaddr request structure --
28 lwres_gnbarequest_t -- to the lightweight resolver's canonical
29 format. It is complemented by a parse function that converts a
30 packet in this canonical format to a getnamebyaddr request
31 structure. Another render function converts the getnamebyaddr
32 response structure -- lwres_gnbaresponse_t to the canonical format.
33 This is complemented by a parse function which converts a packet in
34 canonical format to a getnamebyaddr response structure.
36 These structures are defined in \link lwres.h <lwres/lwres.h.>\endlink They are shown
40 #define LWRES_OPCODE_GETNAMEBYADDR 0x00010002U
45 } lwres_gnbarequest_t;
49 lwres_uint16_t naliases;
52 lwres_uint16_t realnamelen;
53 lwres_uint16_t *aliaslen;
56 } lwres_gnbaresponse_t;
59 lwres_gnbarequest_render() uses resolver context ctx to convert
60 getnamebyaddr request structure req to canonical format. The packet
61 header structure pkt is initialised and transferred to buffer b.
62 The contents of *req are then appended to the buffer in canonical
63 format. lwres_gnbaresponse_render() performs the same task, except
64 it converts a getnamebyaddr response structure lwres_gnbaresponse_t
65 to the lightweight resolver's canonical format.
67 lwres_gnbarequest_parse() uses context ctx to convert the contents
68 of packet pkt to a lwres_gnbarequest_t structure. Buffer b provides
69 space to be used for storing this structure. When the function
70 succeeds, the resulting lwres_gnbarequest_t is made available
71 through *structp. lwres_gnbaresponse_parse() offers the same
72 semantics as lwres_gnbarequest_parse() except it yields a
73 lwres_gnbaresponse_t structure.
75 lwres_gnbaresponse_free() and lwres_gnbarequest_free() release the
76 memory in resolver context ctx that was allocated to the
77 lwres_gnbaresponse_t or lwres_gnbarequest_t structures referenced
78 via structp. Any memory associated with ancillary buffers and
79 strings for those structures is also discarded.
81 \section lwres_gbna_return Return Values
83 The getnamebyaddr opcode functions lwres_gnbarequest_render(),
84 lwres_gnbaresponse_render() lwres_gnbarequest_parse() and
85 lwres_gnbaresponse_parse() all return #LWRES_R_SUCCESS on success.
86 They return #LWRES_R_NOMEMORY if memory allocation fails.
87 #LWRES_R_UNEXPECTEDEND is returned if the available space in the
88 buffer b is too small to accommodate the packet header or the
89 lwres_gnbarequest_t and lwres_gnbaresponse_t structures.
90 lwres_gnbarequest_parse() and lwres_gnbaresponse_parse() will
91 return #LWRES_R_UNEXPECTEDEND if the buffer is not empty after
92 decoding the received packet. These functions will return
93 #LWRES_R_FAILURE if pktflags in the packet header structure
94 #lwres_lwpacket_t indicate that the packet is not a response to an
97 \section lwres_gbna_see See Also
99 \link lwpacket.c lwres_packet\endlink
109 #include <lwres/lwbuffer.h>
110 #include <lwres/lwpacket.h>
111 #include <lwres/lwres.h>
112 #include <lwres/result.h>
114 #include "context_p.h"
115 #include "assert_p.h"
117 /*% Uses resolver context ctx to convert getnamebyaddr request structure req to canonical format. */
119 lwres_gnbarequest_render(lwres_context_t
*ctx
, lwres_gnbarequest_t
*req
,
120 lwres_lwpacket_t
*pkt
, lwres_buffer_t
*b
)
125 size_t payload_length
;
127 REQUIRE(ctx
!= NULL
);
128 REQUIRE(req
!= NULL
);
129 REQUIRE(req
->addr
.family
!= 0);
130 REQUIRE(req
->addr
.length
!= 0);
131 REQUIRE(pkt
!= NULL
);
134 payload_length
= 4 + 4 + 2 + + req
->addr
.length
;
136 buflen
= LWRES_LWPACKET_LENGTH
+ payload_length
;
137 buf
= CTXMALLOC(buflen
);
139 return (LWRES_R_NOMEMORY
);
140 lwres_buffer_init(b
, buf
, buflen
);
142 pkt
->length
= buflen
;
143 pkt
->version
= LWRES_LWPACKETVERSION_0
;
144 pkt
->pktflags
&= ~LWRES_LWPACKETFLAG_RESPONSE
;
145 pkt
->opcode
= LWRES_OPCODE_GETNAMEBYADDR
;
150 ret
= lwres_lwpacket_renderheader(b
, pkt
);
151 if (ret
!= LWRES_R_SUCCESS
) {
152 lwres_buffer_invalidate(b
);
153 CTXFREE(buf
, buflen
);
157 INSIST(SPACE_OK(b
, payload_length
));
160 * Put the length and the data. We know this will fit because we
161 * just checked for it.
163 lwres_buffer_putuint32(b
, req
->flags
);
164 lwres_buffer_putuint32(b
, req
->addr
.family
);
165 lwres_buffer_putuint16(b
, req
->addr
.length
);
166 lwres_buffer_putmem(b
, (unsigned char *)req
->addr
.address
,
169 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b
) == 0);
171 return (LWRES_R_SUCCESS
);
174 /*% Converts a getnamebyaddr response structure lwres_gnbaresponse_t to the lightweight resolver's canonical format. */
176 lwres_gnbaresponse_render(lwres_context_t
*ctx
, lwres_gnbaresponse_t
*req
,
177 lwres_lwpacket_t
*pkt
, lwres_buffer_t
*b
)
182 size_t payload_length
;
183 lwres_uint16_t datalen
;
186 REQUIRE(ctx
!= NULL
);
187 REQUIRE(req
!= NULL
);
188 REQUIRE(pkt
!= NULL
);
192 * Calculate packet size.
194 payload_length
= 4; /* flags */
195 payload_length
+= 2; /* naliases */
196 payload_length
+= 2 + req
->realnamelen
+ 1; /* real name encoding */
197 for (x
= 0; x
< req
->naliases
; x
++) /* each alias */
198 payload_length
+= 2 + req
->aliaslen
[x
] + 1;
200 buflen
= LWRES_LWPACKET_LENGTH
+ payload_length
;
201 buf
= CTXMALLOC(buflen
);
203 return (LWRES_R_NOMEMORY
);
204 lwres_buffer_init(b
, buf
, buflen
);
206 pkt
->length
= buflen
;
207 pkt
->version
= LWRES_LWPACKETVERSION_0
;
208 pkt
->pktflags
|= LWRES_LWPACKETFLAG_RESPONSE
;
209 pkt
->opcode
= LWRES_OPCODE_GETNAMEBYADDR
;
213 ret
= lwres_lwpacket_renderheader(b
, pkt
);
214 if (ret
!= LWRES_R_SUCCESS
) {
215 lwres_buffer_invalidate(b
);
216 CTXFREE(buf
, buflen
);
220 INSIST(SPACE_OK(b
, payload_length
));
221 lwres_buffer_putuint32(b
, req
->flags
);
223 /* encode naliases */
224 lwres_buffer_putuint16(b
, req
->naliases
);
226 /* encode the real name */
227 datalen
= req
->realnamelen
;
228 lwres_buffer_putuint16(b
, datalen
);
229 lwres_buffer_putmem(b
, (unsigned char *)req
->realname
, datalen
);
230 lwres_buffer_putuint8(b
, 0);
232 /* encode the aliases */
233 for (x
= 0; x
< req
->naliases
; x
++) {
234 datalen
= req
->aliaslen
[x
];
235 lwres_buffer_putuint16(b
, datalen
);
236 lwres_buffer_putmem(b
, (unsigned char *)req
->aliases
[x
],
238 lwres_buffer_putuint8(b
, 0);
241 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b
) == 0);
243 return (LWRES_R_SUCCESS
);
246 /*% Uses context ctx to convert the contents of packet pkt to a lwres_gnbarequest_t structure. */
248 lwres_gnbarequest_parse(lwres_context_t
*ctx
, lwres_buffer_t
*b
,
249 lwres_lwpacket_t
*pkt
, lwres_gnbarequest_t
**structp
)
252 lwres_gnbarequest_t
*gnba
;
254 REQUIRE(ctx
!= NULL
);
255 REQUIRE(pkt
!= NULL
);
257 REQUIRE(structp
!= NULL
&& *structp
== NULL
);
259 if ((pkt
->pktflags
& LWRES_LWPACKETFLAG_RESPONSE
) != 0)
260 return (LWRES_R_FAILURE
);
262 if (!SPACE_REMAINING(b
, 4))
263 return (LWRES_R_UNEXPECTEDEND
);
265 gnba
= CTXMALLOC(sizeof(lwres_gnbarequest_t
));
267 return (LWRES_R_NOMEMORY
);
269 gnba
->flags
= lwres_buffer_getuint32(b
);
271 ret
= lwres_addr_parse(b
, &gnba
->addr
);
272 if (ret
!= LWRES_R_SUCCESS
)
275 if (LWRES_BUFFER_REMAINING(b
) != 0) {
276 ret
= LWRES_R_TRAILINGDATA
;
281 return (LWRES_R_SUCCESS
);
285 lwres_gnbarequest_free(ctx
, &gnba
);
290 /*% Offers the same semantics as lwres_gnbarequest_parse() except it yields a lwres_gnbaresponse_t structure. */
293 lwres_gnbaresponse_parse(lwres_context_t
*ctx
, lwres_buffer_t
*b
,
294 lwres_lwpacket_t
*pkt
, lwres_gnbaresponse_t
**structp
)
298 lwres_uint32_t flags
;
299 lwres_uint16_t naliases
;
300 lwres_gnbaresponse_t
*gnba
;
302 REQUIRE(ctx
!= NULL
);
303 REQUIRE(pkt
!= NULL
);
305 REQUIRE(structp
!= NULL
&& *structp
== NULL
);
309 if ((pkt
->pktflags
& LWRES_LWPACKETFLAG_RESPONSE
) == 0)
310 return (LWRES_R_FAILURE
);
313 * Pull off flags & naliases
315 if (!SPACE_REMAINING(b
, 4 + 2))
316 return (LWRES_R_UNEXPECTEDEND
);
317 flags
= lwres_buffer_getuint32(b
);
318 naliases
= lwres_buffer_getuint16(b
);
320 gnba
= CTXMALLOC(sizeof(lwres_gnbaresponse_t
));
322 return (LWRES_R_NOMEMORY
);
324 gnba
->aliases
= NULL
;
325 gnba
->aliaslen
= NULL
;
328 gnba
->naliases
= naliases
;
331 gnba
->aliases
= CTXMALLOC(sizeof(char *) * naliases
);
332 if (gnba
->aliases
== NULL
) {
333 ret
= LWRES_R_NOMEMORY
;
337 gnba
->aliaslen
= CTXMALLOC(sizeof(lwres_uint16_t
) * naliases
);
338 if (gnba
->aliaslen
== NULL
) {
339 ret
= LWRES_R_NOMEMORY
;
345 * Now, pull off the real name.
347 ret
= lwres_string_parse(b
, &gnba
->realname
, &gnba
->realnamelen
);
348 if (ret
!= LWRES_R_SUCCESS
)
352 * Parse off the aliases.
354 for (x
= 0; x
< gnba
->naliases
; x
++) {
355 ret
= lwres_string_parse(b
, &gnba
->aliases
[x
],
357 if (ret
!= LWRES_R_SUCCESS
)
361 if (LWRES_BUFFER_REMAINING(b
) != 0) {
362 ret
= LWRES_R_TRAILINGDATA
;
367 return (LWRES_R_SUCCESS
);
371 if (gnba
->aliases
!= NULL
)
372 CTXFREE(gnba
->aliases
, sizeof(char *) * naliases
);
373 if (gnba
->aliaslen
!= NULL
)
374 CTXFREE(gnba
->aliaslen
,
375 sizeof(lwres_uint16_t
) * naliases
);
376 CTXFREE(gnba
, sizeof(lwres_gnbaresponse_t
));
382 /*% Release the memory in resolver context ctx that was allocated to the lwres_gnbarequest_t. */
384 lwres_gnbarequest_free(lwres_context_t
*ctx
, lwres_gnbarequest_t
**structp
)
386 lwres_gnbarequest_t
*gnba
;
388 REQUIRE(ctx
!= NULL
);
389 REQUIRE(structp
!= NULL
&& *structp
!= NULL
);
394 CTXFREE(gnba
, sizeof(lwres_gnbarequest_t
));
397 /*% Release the memory in resolver context ctx that was allocated to the lwres_gnbaresponse_t. */
399 lwres_gnbaresponse_free(lwres_context_t
*ctx
, lwres_gnbaresponse_t
**structp
)
401 lwres_gnbaresponse_t
*gnba
;
403 REQUIRE(ctx
!= NULL
);
404 REQUIRE(structp
!= NULL
&& *structp
!= NULL
);
409 if (gnba
->naliases
> 0) {
410 CTXFREE(gnba
->aliases
, sizeof(char *) * gnba
->naliases
);
411 CTXFREE(gnba
->aliaslen
,
412 sizeof(lwres_uint16_t
) * gnba
->naliases
);
414 if (gnba
->base
!= NULL
)
415 CTXFREE(gnba
->base
, gnba
->baselen
);
416 CTXFREE(gnba
, sizeof(lwres_gnbaresponse_t
));