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_noop.c,v 1.19 2007/06/19 23:47:22 tbox Exp $ */
23 * These are low-level routines for creating and parsing lightweight
24 * resolver no-op request and response messages.
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.
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.
39 * These structures are defined in \link lwres.h <lwres/lwres.h.> \endlink They are shown below.
42 * #define LWRES_OPCODE_NOOP 0x00000000U
45 * lwres_uint16_t datalength;
46 * unsigned char *data;
47 * } lwres_nooprequest_t;
50 * lwres_uint16_t datalength;
51 * unsigned char *data;
52 * } lwres_noopresponse_t;
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.
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.
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
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
80 * \section lwres_noop_return Return Values
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.
95 * \section lwres_noop_see See Also
106 #include <lwres/lwbuffer.h>
107 #include <lwres/lwpacket.h>
108 #include <lwres/lwres.h>
109 #include <lwres/result.h>
111 #include "context_p.h"
112 #include "assert_p.h"
114 /*% Uses resolver context ctx to convert no-op request structure req to canonical format. */
116 lwres_nooprequest_render(lwres_context_t *ctx, lwres_nooprequest_t *req,
117 lwres_lwpacket_t *pkt, lwres_buffer_t *b)
122 size_t payload_length;
124 REQUIRE(ctx != NULL);
125 REQUIRE(req != NULL);
126 REQUIRE(pkt != NULL);
129 payload_length = sizeof(lwres_uint16_t) + req->datalength;
131 buflen = LWRES_LWPACKET_LENGTH + payload_length;
132 buf = CTXMALLOC(buflen);
134 return (LWRES_R_NOMEMORY);
135 lwres_buffer_init(b, buf, buflen);
137 pkt->length = buflen;
138 pkt->version = LWRES_LWPACKETVERSION_0;
139 pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
140 pkt->opcode = LWRES_OPCODE_NOOP;
145 ret = lwres_lwpacket_renderheader(b, pkt);
146 if (ret != LWRES_R_SUCCESS) {
147 lwres_buffer_invalidate(b);
148 CTXFREE(buf, buflen);
152 INSIST(SPACE_OK(b, payload_length));
155 * Put the length and the data. We know this will fit because we
156 * just checked for it.
158 lwres_buffer_putuint16(b, req->datalength);
159 lwres_buffer_putmem(b, req->data, req->datalength);
161 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
163 return (LWRES_R_SUCCESS);
166 /*% Converts a no-op response structure lwres_noopresponse_t to the lightweight resolver's canonical format. */
169 lwres_noopresponse_render(lwres_context_t *ctx, lwres_noopresponse_t *req,
170 lwres_lwpacket_t *pkt, lwres_buffer_t *b)
175 size_t payload_length;
177 REQUIRE(ctx != NULL);
178 REQUIRE(req != NULL);
179 REQUIRE(pkt != NULL);
182 payload_length = sizeof(lwres_uint16_t) + req->datalength;
184 buflen = LWRES_LWPACKET_LENGTH + payload_length;
185 buf = CTXMALLOC(buflen);
187 return (LWRES_R_NOMEMORY);
188 lwres_buffer_init(b, buf, buflen);
190 pkt->length = buflen;
191 pkt->version = LWRES_LWPACKETVERSION_0;
192 pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
193 pkt->opcode = LWRES_OPCODE_NOOP;
197 ret = lwres_lwpacket_renderheader(b, pkt);
198 if (ret != LWRES_R_SUCCESS) {
199 lwres_buffer_invalidate(b);
200 CTXFREE(buf, buflen);
204 INSIST(SPACE_OK(b, payload_length));
207 * Put the length and the data. We know this will fit because we
208 * just checked for it.
210 lwres_buffer_putuint16(b, req->datalength);
211 lwres_buffer_putmem(b, req->data, req->datalength);
213 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
215 return (LWRES_R_SUCCESS);
218 /*% Uses context ctx to convert the contents of packet pkt to a lwres_nooprequest_t structure. */
220 lwres_nooprequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
221 lwres_lwpacket_t *pkt, lwres_nooprequest_t **structp)
224 lwres_nooprequest_t *req;
226 REQUIRE(ctx != NULL);
228 REQUIRE(pkt != NULL);
229 REQUIRE(structp != NULL && *structp == NULL);
231 if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
232 return (LWRES_R_FAILURE);
234 req = CTXMALLOC(sizeof(lwres_nooprequest_t));
236 return (LWRES_R_NOMEMORY);
238 if (!SPACE_REMAINING(b, sizeof(lwres_uint16_t))) {
239 ret = LWRES_R_UNEXPECTEDEND;
242 req->datalength = lwres_buffer_getuint16(b);
244 if (!SPACE_REMAINING(b, req->datalength)) {
245 ret = LWRES_R_UNEXPECTEDEND;
248 req->data = b->base + b->current;
249 lwres_buffer_forward(b, req->datalength);
251 if (LWRES_BUFFER_REMAINING(b) != 0) {
252 ret = LWRES_R_TRAILINGDATA;
258 return (LWRES_R_SUCCESS);
262 CTXFREE(req, sizeof(lwres_nooprequest_t));
266 /*% Offers the same semantics as lwres_nooprequest_parse() except it yields a lwres_noopresponse_t structure. */
268 lwres_noopresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
269 lwres_lwpacket_t *pkt, lwres_noopresponse_t **structp)
272 lwres_noopresponse_t *req;
274 REQUIRE(ctx != NULL);
276 REQUIRE(pkt != NULL);
277 REQUIRE(structp != NULL && *structp == NULL);
279 if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
280 return (LWRES_R_FAILURE);
282 req = CTXMALLOC(sizeof(lwres_noopresponse_t));
284 return (LWRES_R_NOMEMORY);
286 if (!SPACE_REMAINING(b, sizeof(lwres_uint16_t))) {
287 ret = LWRES_R_UNEXPECTEDEND;
290 req->datalength = lwres_buffer_getuint16(b);
292 if (!SPACE_REMAINING(b, req->datalength)) {
293 ret = LWRES_R_UNEXPECTEDEND;
296 req->data = b->base + b->current;
298 lwres_buffer_forward(b, req->datalength);
299 if (LWRES_BUFFER_REMAINING(b) != 0) {
300 ret = LWRES_R_TRAILINGDATA;
306 return (LWRES_R_SUCCESS);
310 CTXFREE(req, sizeof(lwres_noopresponse_t));
314 /*% Release the memory in resolver context ctx. */
316 lwres_noopresponse_free(lwres_context_t *ctx, lwres_noopresponse_t **structp)
318 lwres_noopresponse_t *noop;
320 REQUIRE(ctx != NULL);
321 REQUIRE(structp != NULL && *structp != NULL);
326 CTXFREE(noop, sizeof(lwres_noopresponse_t));
329 /*% Release the memory in resolver context ctx. */
331 lwres_nooprequest_free(lwres_context_t *ctx, lwres_nooprequest_t **structp)
333 lwres_nooprequest_t *noop;
335 REQUIRE(ctx != NULL);
336 REQUIRE(structp != NULL && *structp != NULL);
341 CTXFREE(noop, sizeof(lwres_nooprequest_t));