From 2aebcef93d77244fc8a6418c3986d1bad615eff7 Mon Sep 17 00:00:00 2001
From: Lubos Slovak <lubos.slovak@nic.cz>
Date: Tue, 9 Nov 2010 18:05:11 +0100
Subject: [PATCH] First RDATA API functions and their implementation

- creating RDATA structure (empty, possibly with reserving space)
- setting and getting particular items
- setting all items (only if empty)
- deallocating

refs #5, #88
---
 src/dnslib/rdata.c |  89 ++++++++++++++++++++++++++++++++++++
 src/dnslib/rdata.h | 111 ++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 194 insertions(+), 6 deletions(-)

diff --git a/src/dnslib/rdata.c b/src/dnslib/rdata.c
index e69de29bb..85d6788bc 100644
--- a/src/dnslib/rdata.c
+++ b/src/dnslib/rdata.c
@@ -0,0 +1,89 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include "common.h"
+#include "rdata.h"
+
+/*----------------------------------------------------------------------------*/
+/* API functions                                                              */
+/*----------------------------------------------------------------------------*/
+
+dnslib_rdata_t *dnslib_rdata_new( uint count )
+{
+	dnslib_rdata_t *rdata = (dnslib_rdata_t *)malloc(sizeof(dnslib_rdata_t));
+	if (rdata == NULL) {
+		ERR_ALLOC_FAILED;
+		return NULL;
+	}
+
+	rdata->items = NULL;
+
+	if (count > 0 (rdata->items = (dnslib_rdata_item_t *)calloc(
+			count * sizeof(dnslib_rdata_item_t)) == NULL)) {
+		ERR_ALLOC_FAILED;
+		free(rdata);
+		return NULL;
+	}
+
+	rdata->count = count;
+
+	return rdata;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int dnslib_rdata_set_item( dnslib_rdata *rdata, uint pos,
+						   dnslib_rdata_item_t item )
+{
+	if (pos >= rdata->count) {
+		return -1;
+	}
+	rdata->items[pos] = item;	// this should copy the union; or use memcpy?
+	return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int dnslib_rdata_set_items( dnslib_rdata *rdata,
+							const dnslib_rdata_item_t *items, uint count )
+{
+	if (count == 0) {
+		return 1;
+	}
+
+	if (rdata->count == 0) {	// empty so far, allocate new space
+		assert(rdata->items == NULL);
+		if ((rdata->items = (dnslib_rdata_item_t *)malloc(
+				count * sizeof(dnslib_rdata_item_t)) == NULL)) {
+			ERR_ALLOC_FAILED;
+			return -1;
+		}
+	} else if (rdata->count != count) {
+		return -2;
+	}
+
+	memcpy(rdata->items, items, count * sizeof(dnslib_rdata_item_t));
+	rdata->count = count;
+
+	return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const dnslib_rdata_item_t *dnslib_rdata_get_item( dnslib_rdata_t *rdata,
+												  uint pos )
+{
+	if (pos >= rdata->count) {
+		return NULL;
+	}
+	else return &rdata->items[pos];
+}
+
+/*----------------------------------------------------------------------------*/
+
+void dnslib_rdata_free( dnslib_rdata_t *rdata )
+{
+	free(rdata->items);
+	free(rdata);
+}
diff --git a/src/dnslib/rdata.h b/src/dnslib/rdata.h
index 86c4d92d3..d99f3b87c 100644
--- a/src/dnslib/rdata.h
+++ b/src/dnslib/rdata.h
@@ -5,21 +5,120 @@
 #include "dname.h"
 #include "common.h"
 
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief RDATA item structure.
+ *
+ * Each RDATA may be logically divided into items, each of possible different
+ * type. This structure distinguishes between general data (\a raw_data)
+ * represented as an array of octets, and domain name (\a dname) as domain names
+ * require special treatment within some RDATA (e.g. compressing in packets).
+ */
 union dnslib_rdata_item {
-	uint8_t *raw_data;	// will this be convenient enough? what about parsing?
-	dnslib_dname_t *dname;
+	/*!
+	 * \brief RDATA item represented as raw array of octets.
+	 * \note Will this be convenient enough? What about parsing? (in runtime?)
+	 */
+	uint8_t *raw_data;
+	dnslib_dname_t *dname; /*!< RDATA item represented as a domain name. */
 };
 
 typedef union dnslib_rdata_item dnslib_rdata_item_t;
 
 /*----------------------------------------------------------------------------*/
-
+/*!
+ * \brief RDATA structure.
+ *
+ * Each RDATA may be logically divided into items, each of possible different
+ * type (see dnslib_rdata_item). This structure stores an array of such items.
+ * It is not dynamic, so any RDATA structure may hold either 0 or one specified
+ * number of items which cannot be changed later.
+ *
+ * This structure does not hold information about the RDATA items, such as
+ * what type is which item or how long are they. This information should be
+ * stored elsewhere (probably globally) as it is RR-specific and given for each
+ * RR type.
+ */
 struct dnslib_rdata {
-	dnslib_rdata_item_t *items;
-	uint *item_lengths;
-	uint item_count;
+	dnslib_rdata_item_t *items;	/*!< RDATA items comprising this RDATA. */
+	uint count;	/*! < Count of RDATA items in this RDATA. */
 };
 
 typedef struct dnslib_rdata dnslib_rdata_t;
 
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Creates an empty RDATA structure and possibly reserves space for data.
+ *
+ * \param count Number of RDATA items to be later stored in this structure.
+ *
+ * If \a count > 0, all RDATA items are initialized to 0.
+ *
+ * \return Pointer to the new RDATA structure or NULL if an error occured.
+ */
+dnslib_rdata_t *dnslib_rdata_new( uint count );
+
+/*!
+ * \brief Sets the RDATA item on position \a pos.
+ *
+ * \param rdata RDATA structure in which the item should be set.
+ * \param pos Position of the RDATA item to be set.
+ * \param item RDATA item value to be set.
+ *
+ * \retval 0 if successful.
+ * \retval < 0 on error. (-1 if the allocation was not successful).
+ *
+ * \todo Use the union or a pointer to it as parameter? IMHO there is always
+ *       only one pointer that is copied, so it doesn't matter.
+ */
+int dnslib_rdata_set_item( dnslib_rdata *rdata, uint pos,
+						   dnslib_rdata_item_t item );
+
+/*!
+ * \brief Sets all RDATA items within the given RDATA structure.
+ *
+ * \param rdata RDATA structure to store the items in.
+ * \param items An array of RDATA items to be stored in this RDATA structure.
+ * \param count Count of RDATA items to be stored.
+ *
+ * If \a rdata has been empty so far (\a rdata->count == 0), the necessary space
+ * is allocated. Otherwise \a rdata->count must be equal to \a count. If it is
+ * not, this function does not alter the stored items and returns an error.
+ *
+ * This function copies the array of RDATA items from \a items to \a rdata.
+ *
+ * \retval 0 if successful.
+ * \retval 1 if the \a count is 0, i.e. nothing was done.
+ * \retval -1 if allocation of necessary space was not successful.
+ * \retval -2 if \a rdata->count != \a count.
+ */
+int dnslib_rdata_set_items( dnslib_rdata *rdata,
+							const dnslib_rdata_item_t *items, uint count );
+
+/*!
+ * \brief Returns the RDATA item on position \a pos.
+ *
+ * \param rdata RDATA structure to get the item from.
+ * \param pos Position of the item to retrieve.
+ *
+ * \return The RDATA item on position \a pos, or NULL if such position does not
+ *         exist within the given RDATA structure.
+ *
+ * \note Although returning union would be OK (no overhead), we need to be able
+ *       to distinguish errors (in this case by returning NULL).
+ */
+const dnslib_rdata_item_t *dnslib_rdata_get_item( dnslib_rdata_t *rdata,
+												  uint pos );
+
+/*!
+ * \brief Destroys the RDATA structure.
+ *
+ * \param rdata RDATA structure to be destroyed.
+ *
+ * Contents of RDATA items are not deallocated, as it is not clear whether the
+ * particular item is a domain name (which cannot be deallocated here) or raw
+ * data (which could have been).
+ */
+void dnslib_rdata_free( dnslib_rdata_t *rdata );
+
 #endif /* _CUTEDNS_RDATA_H */
-- 
GitLab