369fe4e18f7154a407e3b33d886dc29e1df6daed
[dragonfly.git] / contrib / bind-9.5.2 / lib / lwres / lwres_noop.c
1 /*
2  * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000, 2001  Internet Software Consortium.
4  *
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.
8  *
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.
16  */
17
18 /* $Id: lwres_noop.c,v 1.19 2007/06/19 23:47:22 tbox Exp $ */
19
20 /*! \file */
21
22 /**
23  *    These are low-level routines for creating and parsing lightweight
24  *    resolver no-op request and response messages.
25  * 
26  *    The no-op message is analogous to a ping packet: a packet is sent to
27  *    the resolver daemon and is simply echoed back. The opcode is intended
28  *    to allow a client to determine if the server is operational or not.
29  * 
30  *    There are four main functions for the no-op opcode. One render
31  *    function converts a no-op request structure -- lwres_nooprequest_t --
32  *    to the lighweight resolver's canonical format. It is complemented by a
33  *    parse function that converts a packet in this canonical format to a
34  *    no-op request structure. Another render function converts the no-op
35  *    response structure -- lwres_noopresponse_t to the canonical format.
36  *    This is complemented by a parse function which converts a packet in
37  *    canonical format to a no-op response structure.
38  * 
39  *    These structures are defined in \link lwres.h <lwres/lwres.h.> \endlink They are shown below.
40  * 
41  * \code
42  * #define LWRES_OPCODE_NOOP       0x00000000U
43  * 
44  * typedef struct {
45  *         lwres_uint16_t  datalength;
46  *         unsigned char   *data;
47  * } lwres_nooprequest_t;
48  * 
49  * typedef struct {
50  *         lwres_uint16_t  datalength;
51  *         unsigned char   *data;
52  * } lwres_noopresponse_t;
53  * \endcode
54  * 
55  *    Although the structures have different types, they are identical. This
56  *    is because the no-op opcode simply echos whatever data was sent: the
57  *    response is therefore identical to the request.
58  * 
59  *    lwres_nooprequest_render() uses resolver context ctx to convert no-op
60  *    request structure req to canonical format. The packet header structure
61  *    pkt is initialised and transferred to buffer b. The contents of *req
62  *    are then appended to the buffer in canonical format.
63  *    lwres_noopresponse_render() performs the same task, except it converts
64  *    a no-op response structure lwres_noopresponse_t to the lightweight
65  *    resolver's canonical format.
66  * 
67  *    lwres_nooprequest_parse() uses context ctx to convert the contents of
68  *    packet pkt to a lwres_nooprequest_t structure. Buffer b provides space
69  *    to be used for storing this structure. When the function succeeds, the
70  *    resulting lwres_nooprequest_t is made available through *structp.
71  *    lwres_noopresponse_parse() offers the same semantics as
72  *    lwres_nooprequest_parse() except it yields a lwres_noopresponse_t
73  *    structure.
74  * 
75  *    lwres_noopresponse_free() and lwres_nooprequest_free() release the
76  *    memory in resolver context ctx that was allocated to the
77  *    lwres_noopresponse_t or lwres_nooprequest_t structures referenced via
78  *    structp.
79  * 
80  * \section lwres_noop_return Return Values
81  * 
82  *    The no-op opcode functions lwres_nooprequest_render(),
83  *    lwres_noopresponse_render() lwres_nooprequest_parse() and
84  *    lwres_noopresponse_parse() all return #LWRES_R_SUCCESS on success. They
85  *    return #LWRES_R_NOMEMORY if memory allocation fails.
86  *    #LWRES_R_UNEXPECTEDEND is returned if the available space in the buffer
87  *    b is too small to accommodate the packet header or the
88  *    lwres_nooprequest_t and lwres_noopresponse_t structures.
89  *    lwres_nooprequest_parse() and lwres_noopresponse_parse() will return
90  *    #LWRES_R_UNEXPECTEDEND if the buffer is not empty after decoding the
91  *    received packet. These functions will return #LWRES_R_FAILURE if
92  *    pktflags in the packet header structure #lwres_lwpacket_t indicate that
93  *    the packet is not a response to an earlier query.
94  * 
95  * \section lwres_noop_see See Also
96  * 
97  *    lwpacket.c
98  */
99
100 #include <config.h>
101
102 #include <assert.h>
103 #include <stdlib.h>
104 #include <string.h>
105
106 #include <lwres/lwbuffer.h>
107 #include <lwres/lwpacket.h>
108 #include <lwres/lwres.h>
109 #include <lwres/result.h>
110
111 #include "context_p.h"
112 #include "assert_p.h"
113
114 /*% Uses resolver context ctx to convert no-op request structure req to canonical format. */
115 lwres_result_t
116 lwres_nooprequest_render(lwres_context_t *ctx, lwres_nooprequest_t *req,
117                          lwres_lwpacket_t *pkt, lwres_buffer_t *b)
118 {
119         unsigned char *buf;
120         size_t buflen;
121         int ret;
122         size_t payload_length;
123
124         REQUIRE(ctx != NULL);
125         REQUIRE(req != NULL);
126         REQUIRE(pkt != NULL);
127         REQUIRE(b != NULL);
128
129         payload_length = sizeof(lwres_uint16_t) + req->datalength;
130
131         buflen = LWRES_LWPACKET_LENGTH + payload_length;
132         buf = CTXMALLOC(buflen);
133         if (buf == NULL)
134                 return (LWRES_R_NOMEMORY);
135         lwres_buffer_init(b, buf, buflen);
136
137         pkt->length = buflen;
138         pkt->version = LWRES_LWPACKETVERSION_0;
139         pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
140         pkt->opcode = LWRES_OPCODE_NOOP;
141         pkt->result = 0;
142         pkt->authtype = 0;
143         pkt->authlength = 0;
144
145         ret = lwres_lwpacket_renderheader(b, pkt);
146         if (ret != LWRES_R_SUCCESS) {
147                 lwres_buffer_invalidate(b);
148                 CTXFREE(buf, buflen);
149                 return (ret);
150         }
151
152         INSIST(SPACE_OK(b, payload_length));
153
154         /*
155          * Put the length and the data.  We know this will fit because we
156          * just checked for it.
157          */
158         lwres_buffer_putuint16(b, req->datalength);
159         lwres_buffer_putmem(b, req->data, req->datalength);
160
161         INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
162
163         return (LWRES_R_SUCCESS);
164 }
165
166 /*% Converts a no-op response structure lwres_noopresponse_t to the lightweight resolver's canonical format. */
167
168 lwres_result_t
169 lwres_noopresponse_render(lwres_context_t *ctx, lwres_noopresponse_t *req,
170                           lwres_lwpacket_t *pkt, lwres_buffer_t *b)
171 {
172         unsigned char *buf;
173         size_t buflen;
174         int ret;
175         size_t payload_length;
176
177         REQUIRE(ctx != NULL);
178         REQUIRE(req != NULL);
179         REQUIRE(pkt != NULL);
180         REQUIRE(b != NULL);
181
182         payload_length = sizeof(lwres_uint16_t) + req->datalength;
183
184         buflen = LWRES_LWPACKET_LENGTH + payload_length;
185         buf = CTXMALLOC(buflen);
186         if (buf == NULL)
187                 return (LWRES_R_NOMEMORY);
188         lwres_buffer_init(b, buf, buflen);
189
190         pkt->length = buflen;
191         pkt->version = LWRES_LWPACKETVERSION_0;
192         pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
193         pkt->opcode = LWRES_OPCODE_NOOP;
194         pkt->authtype = 0;
195         pkt->authlength = 0;
196
197         ret = lwres_lwpacket_renderheader(b, pkt);
198         if (ret != LWRES_R_SUCCESS) {
199                 lwres_buffer_invalidate(b);
200                 CTXFREE(buf, buflen);
201                 return (ret);
202         }
203
204         INSIST(SPACE_OK(b, payload_length));
205
206         /*
207          * Put the length and the data.  We know this will fit because we
208          * just checked for it.
209          */
210         lwres_buffer_putuint16(b, req->datalength);
211         lwres_buffer_putmem(b, req->data, req->datalength);
212
213         INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
214
215         return (LWRES_R_SUCCESS);
216 }
217
218 /*% Uses context ctx to convert the contents of packet pkt to a lwres_nooprequest_t structure. */
219 lwres_result_t
220 lwres_nooprequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
221                         lwres_lwpacket_t *pkt, lwres_nooprequest_t **structp)
222 {
223         int ret;
224         lwres_nooprequest_t *req;
225
226         REQUIRE(ctx != NULL);
227         REQUIRE(b != NULL);
228         REQUIRE(pkt != NULL);
229         REQUIRE(structp != NULL && *structp == NULL);
230
231         if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
232                 return (LWRES_R_FAILURE);
233
234         req = CTXMALLOC(sizeof(lwres_nooprequest_t));
235         if (req == NULL)
236                 return (LWRES_R_NOMEMORY);
237
238         if (!SPACE_REMAINING(b, sizeof(lwres_uint16_t))) {
239                 ret = LWRES_R_UNEXPECTEDEND;
240                 goto out;
241         }
242         req->datalength = lwres_buffer_getuint16(b);
243
244         if (!SPACE_REMAINING(b, req->datalength)) {
245                 ret = LWRES_R_UNEXPECTEDEND;
246                 goto out;
247         }
248         req->data = b->base + b->current;
249         lwres_buffer_forward(b, req->datalength);
250
251         if (LWRES_BUFFER_REMAINING(b) != 0) {
252                 ret = LWRES_R_TRAILINGDATA;
253                 goto out;
254         }
255
256         /* success! */
257         *structp = req;
258         return (LWRES_R_SUCCESS);
259
260         /* Error return */
261  out:
262         CTXFREE(req, sizeof(lwres_nooprequest_t));
263         return (ret);
264 }
265
266 /*% Offers the same semantics as lwres_nooprequest_parse() except it yields a lwres_noopresponse_t structure. */
267 lwres_result_t
268 lwres_noopresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
269                          lwres_lwpacket_t *pkt, lwres_noopresponse_t **structp)
270 {
271         int ret;
272         lwres_noopresponse_t *req;
273
274         REQUIRE(ctx != NULL);
275         REQUIRE(b != NULL);
276         REQUIRE(pkt != NULL);
277         REQUIRE(structp != NULL && *structp == NULL);
278
279         if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
280                 return (LWRES_R_FAILURE);
281
282         req = CTXMALLOC(sizeof(lwres_noopresponse_t));
283         if (req == NULL)
284                 return (LWRES_R_NOMEMORY);
285
286         if (!SPACE_REMAINING(b, sizeof(lwres_uint16_t))) {
287                 ret = LWRES_R_UNEXPECTEDEND;
288                 goto out;
289         }
290         req->datalength = lwres_buffer_getuint16(b);
291
292         if (!SPACE_REMAINING(b, req->datalength)) {
293                 ret = LWRES_R_UNEXPECTEDEND;
294                 goto out;
295         }
296         req->data = b->base + b->current;
297
298         lwres_buffer_forward(b, req->datalength);
299         if (LWRES_BUFFER_REMAINING(b) != 0) {
300                 ret = LWRES_R_TRAILINGDATA;
301                 goto out;
302         }
303
304         /* success! */
305         *structp = req;
306         return (LWRES_R_SUCCESS);
307
308         /* Error return */
309  out:
310         CTXFREE(req, sizeof(lwres_noopresponse_t));
311         return (ret);
312 }
313
314 /*% Release the memory in resolver context ctx. */
315 void
316 lwres_noopresponse_free(lwres_context_t *ctx, lwres_noopresponse_t **structp)
317 {
318         lwres_noopresponse_t *noop;
319
320         REQUIRE(ctx != NULL);
321         REQUIRE(structp != NULL && *structp != NULL);
322
323         noop = *structp;
324         *structp = NULL;
325
326         CTXFREE(noop, sizeof(lwres_noopresponse_t));
327 }
328
329 /*% Release the memory in resolver context ctx. */
330 void
331 lwres_nooprequest_free(lwres_context_t *ctx, lwres_nooprequest_t **structp)
332 {
333         lwres_nooprequest_t *noop;
334
335         REQUIRE(ctx != NULL);
336         REQUIRE(structp != NULL && *structp != NULL);
337
338         noop = *structp;
339         *structp = NULL;
340
341         CTXFREE(noop, sizeof(lwres_nooprequest_t));
342 }