From 2a916ce6e550ba82a413fca9d2e296140c4ac73c Mon Sep 17 00:00:00 2001 From: Yang Tse 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. --- Makefile.inc | 2 + ares.h | 16 +++--- ares_data.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++ ares_data.h | 62 ++++++++++++++++++++++ 4 files changed, 216 insertions(+), 6 deletions(-) create mode 100644 ares_data.c create mode 100644 ares_data.h diff --git a/Makefile.inc b/Makefile.inc index 8d99afdc..bf249344 100644 --- a/Makefile.inc +++ b/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.h b/ares.h index 63eb6810..d2b6cecc 100644 --- a/ares.h +++ b/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_data.c b/ares_data.c new file mode 100644 index 00000000..5d710ee6 --- /dev/null +++ b/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 + +#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_data.h b/ares_data.h new file mode 100644 index 00000000..ffe2aebb --- /dev/null +++ b/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);