diff options
Diffstat (limited to '')
-rw-r--r-- | lib/lwres/lwres_noop.c | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/lib/lwres/lwres_noop.c b/lib/lwres/lwres_noop.c new file mode 100644 index 0000000..062c2d1 --- /dev/null +++ b/lib/lwres/lwres_noop.c @@ -0,0 +1,337 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* $Id: lwres_noop.c,v 1.19 2007/06/19 23:47:22 tbox Exp $ */ + +/*! \file */ + +/** + * These are low-level routines for creating and parsing lightweight + * resolver no-op request and response messages. + * + * The no-op message is analogous to a ping packet: a packet is sent to + * the resolver daemon and is simply echoed back. The opcode is intended + * to allow a client to determine if the server is operational or not. + * + * There are four main functions for the no-op opcode. One render + * function converts a no-op request structure -- lwres_nooprequest_t -- + * to the lighweight resolver's canonical format. It is complemented by a + * parse function that converts a packet in this canonical format to a + * no-op request structure. Another render function converts the no-op + * response structure -- lwres_noopresponse_t to the canonical format. + * This is complemented by a parse function which converts a packet in + * canonical format to a no-op response structure. + * + * These structures are defined in \link lwres.h <lwres/lwres.h.> \endlink They are shown below. + * + * \code + * #define LWRES_OPCODE_NOOP 0x00000000U + * + * typedef struct { + * uint16_t datalength; + * unsigned char *data; + * } lwres_nooprequest_t; + * + * typedef struct { + * uint16_t datalength; + * unsigned char *data; + * } lwres_noopresponse_t; + * \endcode + * + * Although the structures have different types, they are identical. This + * is because the no-op opcode simply echos whatever data was sent: the + * response is therefore identical to the request. + * + * lwres_nooprequest_render() uses resolver context ctx to convert no-op + * request structure req to canonical format. The packet header structure + * pkt is initialised and transferred to buffer b. The contents of *req + * are then appended to the buffer in canonical format. + * lwres_noopresponse_render() performs the same task, except it converts + * a no-op response structure lwres_noopresponse_t to the lightweight + * resolver's canonical format. + * + * lwres_nooprequest_parse() uses context ctx to convert the contents of + * packet pkt to a lwres_nooprequest_t structure. Buffer b provides space + * to be used for storing this structure. When the function succeeds, the + * resulting lwres_nooprequest_t is made available through *structp. + * lwres_noopresponse_parse() offers the same semantics as + * lwres_nooprequest_parse() except it yields a lwres_noopresponse_t + * structure. + * + * lwres_noopresponse_free() and lwres_nooprequest_free() release the + * memory in resolver context ctx that was allocated to the + * lwres_noopresponse_t or lwres_nooprequest_t structures referenced via + * structp. + * + * \section lwres_noop_return Return Values + * + * The no-op opcode functions lwres_nooprequest_render(), + * lwres_noopresponse_render() lwres_nooprequest_parse() and + * lwres_noopresponse_parse() all return #LWRES_R_SUCCESS on success. They + * return #LWRES_R_NOMEMORY if memory allocation fails. + * #LWRES_R_UNEXPECTEDEND is returned if the available space in the buffer + * b is too small to accommodate the packet header or the + * lwres_nooprequest_t and lwres_noopresponse_t structures. + * lwres_nooprequest_parse() and lwres_noopresponse_parse() will return + * #LWRES_R_UNEXPECTEDEND if the buffer is not empty after decoding the + * received packet. These functions will return #LWRES_R_FAILURE if + * pktflags in the packet header structure #lwres_lwpacket_t indicate that + * the packet is not a response to an earlier query. + * + * \section lwres_noop_see See Also + * + * lwpacket.c + */ + +#include <config.h> + +#include <assert.h> +#include <inttypes.h> +#include <stdlib.h> +#include <string.h> + +#include <lwres/lwbuffer.h> +#include <lwres/lwpacket.h> +#include <lwres/lwres.h> +#include <lwres/result.h> + +#include "context_p.h" +#include "assert_p.h" + +/*% Uses resolver context ctx to convert no-op request structure req to canonical format. */ +lwres_result_t +lwres_nooprequest_render(lwres_context_t *ctx, lwres_nooprequest_t *req, + lwres_lwpacket_t *pkt, lwres_buffer_t *b) +{ + unsigned char *buf; + size_t buflen; + int ret; + size_t payload_length; + + REQUIRE(ctx != NULL); + REQUIRE(req != NULL); + REQUIRE(pkt != NULL); + REQUIRE(b != NULL); + + payload_length = sizeof(uint16_t) + req->datalength; + + buflen = LWRES_LWPACKET_LENGTH + payload_length; + buf = CTXMALLOC(buflen); + if (buf == NULL) + return (LWRES_R_NOMEMORY); + lwres_buffer_init(b, buf, (unsigned int)buflen); + + pkt->length = (uint32_t)buflen; + pkt->version = LWRES_LWPACKETVERSION_0; + pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE; + pkt->opcode = LWRES_OPCODE_NOOP; + pkt->result = 0; + pkt->authtype = 0; + pkt->authlength = 0; + + ret = lwres_lwpacket_renderheader(b, pkt); + if (ret != LWRES_R_SUCCESS) { + lwres_buffer_invalidate(b); + CTXFREE(buf, buflen); + return (ret); + } + + INSIST(SPACE_OK(b, payload_length)); + + /* + * Put the length and the data. We know this will fit because we + * just checked for it. + */ + lwres_buffer_putuint16(b, req->datalength); + lwres_buffer_putmem(b, req->data, req->datalength); + + INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0); + + return (LWRES_R_SUCCESS); +} + +/*% Converts a no-op response structure lwres_noopresponse_t to the lightweight resolver's canonical format. */ + +lwres_result_t +lwres_noopresponse_render(lwres_context_t *ctx, lwres_noopresponse_t *req, + lwres_lwpacket_t *pkt, lwres_buffer_t *b) +{ + unsigned char *buf; + size_t buflen; + int ret; + size_t payload_length; + + REQUIRE(ctx != NULL); + REQUIRE(req != NULL); + REQUIRE(pkt != NULL); + REQUIRE(b != NULL); + + payload_length = sizeof(uint16_t) + req->datalength; + + buflen = LWRES_LWPACKET_LENGTH + payload_length; + buf = CTXMALLOC(buflen); + if (buf == NULL) + return (LWRES_R_NOMEMORY); + lwres_buffer_init(b, buf, (unsigned int)buflen); + + pkt->length = (uint32_t)buflen; + pkt->version = LWRES_LWPACKETVERSION_0; + pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE; + pkt->opcode = LWRES_OPCODE_NOOP; + pkt->authtype = 0; + pkt->authlength = 0; + + ret = lwres_lwpacket_renderheader(b, pkt); + if (ret != LWRES_R_SUCCESS) { + lwres_buffer_invalidate(b); + CTXFREE(buf, buflen); + return (ret); + } + + INSIST(SPACE_OK(b, payload_length)); + + /* + * Put the length and the data. We know this will fit because we + * just checked for it. + */ + lwres_buffer_putuint16(b, req->datalength); + lwres_buffer_putmem(b, req->data, req->datalength); + + INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0); + + return (LWRES_R_SUCCESS); +} + +/*% Uses context ctx to convert the contents of packet pkt to a lwres_nooprequest_t structure. */ +lwres_result_t +lwres_nooprequest_parse(lwres_context_t *ctx, lwres_buffer_t *b, + lwres_lwpacket_t *pkt, lwres_nooprequest_t **structp) +{ + int ret; + lwres_nooprequest_t *req; + + REQUIRE(ctx != NULL); + REQUIRE(b != NULL); + REQUIRE(pkt != NULL); + REQUIRE(structp != NULL && *structp == NULL); + + if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0) + return (LWRES_R_FAILURE); + + req = CTXMALLOC(sizeof(lwres_nooprequest_t)); + if (req == NULL) + return (LWRES_R_NOMEMORY); + + if (!SPACE_REMAINING(b, sizeof(uint16_t))) { + ret = LWRES_R_UNEXPECTEDEND; + goto out; + } + req->datalength = lwres_buffer_getuint16(b); + + if (!SPACE_REMAINING(b, req->datalength)) { + ret = LWRES_R_UNEXPECTEDEND; + goto out; + } + req->data = b->base + b->current; + lwres_buffer_forward(b, req->datalength); + + if (LWRES_BUFFER_REMAINING(b) != 0) { + ret = LWRES_R_TRAILINGDATA; + goto out; + } + + /* success! */ + *structp = req; + return (LWRES_R_SUCCESS); + + /* Error return */ + out: + CTXFREE(req, sizeof(lwres_nooprequest_t)); + return (ret); +} + +/*% Offers the same semantics as lwres_nooprequest_parse() except it yields a lwres_noopresponse_t structure. */ +lwres_result_t +lwres_noopresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b, + lwres_lwpacket_t *pkt, lwres_noopresponse_t **structp) +{ + int ret; + lwres_noopresponse_t *req; + + REQUIRE(ctx != NULL); + REQUIRE(b != NULL); + REQUIRE(pkt != NULL); + REQUIRE(structp != NULL && *structp == NULL); + + if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0) + return (LWRES_R_FAILURE); + + req = CTXMALLOC(sizeof(lwres_noopresponse_t)); + if (req == NULL) + return (LWRES_R_NOMEMORY); + + if (!SPACE_REMAINING(b, sizeof(uint16_t))) { + ret = LWRES_R_UNEXPECTEDEND; + goto out; + } + req->datalength = lwres_buffer_getuint16(b); + + if (!SPACE_REMAINING(b, req->datalength)) { + ret = LWRES_R_UNEXPECTEDEND; + goto out; + } + req->data = b->base + b->current; + + lwres_buffer_forward(b, req->datalength); + if (LWRES_BUFFER_REMAINING(b) != 0) { + ret = LWRES_R_TRAILINGDATA; + goto out; + } + + /* success! */ + *structp = req; + return (LWRES_R_SUCCESS); + + /* Error return */ + out: + CTXFREE(req, sizeof(lwres_noopresponse_t)); + return (ret); +} + +/*% Release the memory in resolver context ctx. */ +void +lwres_noopresponse_free(lwres_context_t *ctx, lwres_noopresponse_t **structp) +{ + lwres_noopresponse_t *noop; + + REQUIRE(ctx != NULL); + REQUIRE(structp != NULL && *structp != NULL); + + noop = *structp; + *structp = NULL; + + CTXFREE(noop, sizeof(lwres_noopresponse_t)); +} + +/*% Release the memory in resolver context ctx. */ +void +lwres_nooprequest_free(lwres_context_t *ctx, lwres_nooprequest_t **structp) +{ + lwres_nooprequest_t *noop; + + REQUIRE(ctx != NULL); + REQUIRE(structp != NULL && *structp != NULL); + + noop = *structp; + *structp = NULL; + + CTXFREE(noop, sizeof(lwres_nooprequest_t)); +} |