PageRenderTime 67ms CodeModel.GetById 25ms app.highlight 38ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bind9/lib/lwres/lwres_noop.c

https://bitbucket.org/freebsd/freebsd-head/
C | 342 lines | 175 code | 54 blank | 113 comment | 54 complexity | 760ffe5d9c4ade5df21731cad8615d76 MD5 | raw file
  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. */
115lwres_result_t
116lwres_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
168lwres_result_t
169lwres_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. */
219lwres_result_t
220lwres_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. */
267lwres_result_t
268lwres_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. */
315void
316lwres_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. */
330void
331lwres_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}