From 5a0a473c30925d63e1695a7b8b1cee8f73ad6e68 Mon Sep 17 00:00:00 2001
From: Yang Tse <yangsita@gmail.com>
Date: Fri, 20 Nov 2009 08:50:03 +0000
Subject: [PATCH] Initial support for the generic ares_free_data() function
 that will allow applications to free memory allocated and returned by some
 c-ares funtions.

---
 ares/Makefile.inc |   2 +
 ares/ares.h       |  16 ++++--
 ares/ares_data.c  | 142 ++++++++++++++++++++++++++++++++++++++++++++++
 ares/ares_data.h  |  62 ++++++++++++++++++++
 4 files changed, 216 insertions(+), 6 deletions(-)
 create mode 100644 ares/ares_data.c
 create mode 100644 ares/ares_data.h

diff --git a/ares/Makefile.inc b/ares/Makefile.inc
index 8d99afdcb7..bf249344b0 100644
--- a/ares/Makefile.inc
+++ b/ares/Makefile.inc
@@ -4,6 +4,7 @@ CSOURCES = ares__close_sockets.c	\
   ares__read_line.c			\
   ares__timeval.c			\
   ares_cancel.c				\
+  ares_data.c				\
   ares_destroy.c			\
   ares_expand_name.c			\
   ares_expand_string.c			\
@@ -41,6 +42,7 @@ CSOURCES = ares__close_sockets.c	\
 
 HHEADERS = ares.h			\
   ares_build.h				\
+  ares_data.h				\
   ares_dns.h				\
   ares_ipv6.h				\
   ares_library_init.h			\
diff --git a/ares/ares.h b/ares/ares.h
index 63eb6810e7..d2b6cecc55 100644
--- a/ares/ares.h
+++ b/ares/ares.h
@@ -430,15 +430,17 @@ struct addr6ttl {
 };
 
 struct ares_srv_reply {
-  unsigned short weight;
-  unsigned short priority;
-  unsigned short port;
-  char *host;
+  struct ares_srv_reply  *next;
+  char                   *host;
+  unsigned short          priority;
+  unsigned short          weight;
+  unsigned short          port;
 };
 
 struct ares_txt_reply {
-  size_t         length;  /* length excludes null termination */
-  unsigned char *txt;
+  struct ares_txt_reply  *next;
+  unsigned char          *txt;
+  size_t                  length;  /* length excludes null termination */
 };
 
 /*
@@ -486,6 +488,8 @@ CARES_EXTERN void ares_free_string(void *str);
 
 CARES_EXTERN void ares_free_hostent(struct hostent *host);
 
+CARES_EXTERN void ares_free_data(void *dataptr);
+
 CARES_EXTERN const char *ares_strerror(int code);
 
 #ifdef  __cplusplus
diff --git a/ares/ares_data.c b/ares/ares_data.c
new file mode 100644
index 0000000000..5d710ee65e
--- /dev/null
+++ b/ares/ares_data.c
@@ -0,0 +1,142 @@
+/* $Id$ */
+
+/* Copyright (C) 2009 by Daniel Stenberg
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ */
+
+
+#include "ares_setup.h"
+
+#include <stddef.h>
+
+#include "ares.h"
+#include "ares_data.h"
+#include "ares_private.h"
+
+
+/*
+** ares_free_data() - c-ares external API function.
+**
+** This function must be used by the application to free data memory that
+** has been internally allocated by some c-ares function and for which a
+** pointer has already been returned to the calling application. The list
+** of c-ares functions returning pointers that must be free'ed using this
+** function is:
+**
+**   FIXME: specify function list.
+*/
+
+void ares_free_data(void *dataptr)
+{
+  struct ares_data *ptr;
+
+  if (!dataptr)
+    return;
+
+  ptr = (void *)((char *)dataptr - offsetof(struct ares_data, data));
+
+  if (ptr->mark != ARES_DATATYPE_MARK)
+    return;
+
+  switch (ptr->type)
+    {
+      case ARES_DATATYPE_SRV_REPLY:
+
+        if (ptr->data.srv_reply.next)
+          ares_free_data(ptr->data.srv_reply.next);
+        if (ptr->data.srv_reply.host)
+          free(ptr->data.srv_reply.host);
+        break;
+
+      case ARES_DATATYPE_TXT_REPLY:
+
+        if (ptr->data.txt_reply.next)
+          ares_free_data(ptr->data.txt_reply.next);
+        if (ptr->data.txt_reply.txt)
+          free(ptr->data.txt_reply.txt);
+        break;
+
+      default:
+        return;
+    }
+
+  free(ptr);
+}
+
+
+/*
+** ares_malloc_data() - c-ares internal helper function.
+**
+** This function allocates memory for a c-ares private ares_data struct
+** for the specified ares_datatype, initializes c-ares private fields
+** and zero initializes those which later might be used from the public
+** API. It returns an interior pointer which can be passed by c-ares
+** functions to the calling application, and that must be free'ed using
+** c-ares external API function ares_free_data().
+*/
+
+void *ares_malloc_data(ares_datatype type)
+{
+  struct ares_data *ptr;
+
+  ptr = malloc(sizeof(struct ares_data));
+  if (!ptr)
+    return NULL;
+
+  switch (type)
+    {
+      case ARES_DATATYPE_SRV_REPLY:
+        ptr->data.srv_reply.next = NULL;
+        ptr->data.srv_reply.host = NULL;
+        ptr->data.srv_reply.priority = 0;
+        ptr->data.srv_reply.weight = 0;
+        ptr->data.srv_reply.port = 0;
+        break;
+
+      case ARES_DATATYPE_TXT_REPLY:
+        ptr->data.txt_reply.next = NULL;
+        ptr->data.txt_reply.txt = NULL;
+        ptr->data.txt_reply.length  = 0;
+        break;
+
+      default:
+        free(ptr);
+        return NULL;
+    }
+
+  ptr->mark = ARES_DATATYPE_MARK;
+  ptr->type = type;
+
+  return &ptr->data;
+}
+
+
+/*
+** ares_get_datatype() - c-ares internal helper function.
+**
+** This function returns the ares_datatype of the data stored in a
+** private ares_data struct when given the public API pointer.
+*/
+
+ares_datatype ares_get_datatype(void * dataptr)
+{
+  struct ares_data *ptr;
+
+  ptr = (void *)((char *)dataptr - offsetof(struct ares_data, data));
+
+  if (ptr->mark == ARES_DATATYPE_MARK)
+    return ptr->type;
+
+  return ARES_DATATYPE_UNKNOWN;
+}
diff --git a/ares/ares_data.h b/ares/ares_data.h
new file mode 100644
index 0000000000..ffe2aebb0d
--- /dev/null
+++ b/ares/ares_data.h
@@ -0,0 +1,62 @@
+/* $Id$ */
+
+/* Copyright (C) 2009 by Daniel Stenberg
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ */
+
+typedef enum {
+  ARES_DATATYPE_UNKNOWN = 1,   /* unknown data type     */
+#if 0
+  ARES_DATATYPE_ADDR6TTL,      /* struct ares_addrttl   */
+  ARES_DATATYPE_ADDRTTL,       /* struct ares_addr6ttl  */
+  ARES_DATATYPE_HOSTENT,       /* struct hostent        */
+  ARES_DATATYPE_OPTIONS,       /* struct ares_options   */
+#endif
+  ARES_DATATYPE_SRV_REPLY,     /* struct ares_srv_reply */
+  ARES_DATATYPE_TXT_REPLY,     /* struct ares_txt_reply */
+  ARES_DATATYPE_LAST           /* not used              */
+} ares_datatype;
+
+#define ARES_DATATYPE_MARK 0xbead
+
+/*
+ * ares_data struct definition is internal to c-ares and shall not
+ * be exposed by the public API in order to allow future changes
+ * and extensions to it without breaking ABI.  This will be used
+ * internally by c-ares as the container of multiple types of data
+ * dynamically allocated for which a reference will be returned
+ * to the calling application.
+ *
+ * c-ares API functions returning a pointer to c-ares internally
+ * allocated data will actually be returning an interior pointer
+ * into this ares_data struct.
+ *
+ * All this is 'invisible' to the calling application, the only
+ * requirement is that this kind of data must be free'ed by the
+ * calling application using ares_free_data() with the pointer
+ * it has received from a previous c-ares function call.
+ */
+
+struct ares_data {
+  ares_datatype type;  /* Actual data type identifier. */
+  unsigned int  mark;  /* Private ares_data signature. */
+  union {
+    struct ares_txt_reply txt_reply;
+    struct ares_srv_reply srv_reply;
+  } data;
+};
+
+void *ares_malloc_data(ares_datatype type);
+
+ares_datatype ares_get_datatype(void * dataptr);
-- 
GitLab