-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 12/02/2009 03:07 PM, Martin Nagy wrote: > > I think we should just push these patches (after the review is done) and > then disable them in the build & configure system like Stephen did for > ELAPI (although FWIW, I think it would be nice to keep the tests > running). >
OK, I just think this should be a separate patch - hence 0003. >> [PATCH 1/2] Change ares usage to be c-ares 1.7.0 compatible >> * Rename structure accordingly to ares upstream >> * Use new ares parsing functions in the wrappers >> * fix tests for ares 1.7 > >>From rewrite_talloc_srv_reply(): > + if (ptr->host == NULL) { > + talloc_free(ptr); > return ENOMEM; > } > + > I believe this should be talloc_free(new_list), otherwise you might try > to free a pointer pointing into middle of a talloc'ed memory. Also, is Thanks, fixed. > it wise to allocate an array for a linked list? I would recommend > allocating each list item separately using mem_ctx and maybe provide a > free function that would free all the items. OK, each item is now allocated using talloc_zero in the loop. I just think the other items including the SRV/TXT payload should be allocated using new_list as a context, that way you can just talloc_free(new_list). > > + ptr = ptr->next; > + old_list = old_list->next; > This is also bad, since ptr->next is not initialized. > For whatever reason I thought talloc_array was using talloc_zero under the hood. Using talloc_zero for every item separately now takes care of it. > Same goes for rewrite_talloc_txt_reply(). > Also fixed. >> [PATCH 2/2] Import ares 1.7.0 helpers >> Synchronizes the bundled helpers with the changes done during the c-ares >> 1.7.0 development in order for the SRV and TXT parsing routines to work >> also with pre-1.7.0 ares versions. > > Sorry, I didn't yet have time to review it, I will do it later (tomorrow > probably). The attached patch 0002 fixes the issue you outlined in the other reply to the thread. Jakub -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/ iEYEARECAAYFAksdUXQACgkQHsardTLnvCVifgCgnGX25X2yxF/FMLh9KtAiYnZB lTEAnRrWvivyOrCEOrsZsBFfdIZ/dDhy =Va/X -----END PGP SIGNATURE-----
>From 478cfade9f57ff0ee991a6eecff0ec5a7ced3bff Mon Sep 17 00:00:00 2001 From: Jakub Hrozek <jhro...@redhat.com> Date: Tue, 3 Nov 2009 16:24:25 +0100 Subject: [PATCH 1/3] Change ares usage to be c-ares 1.7.0 compatible * Rename structure accordingly to ares upstream * Use new ares parsing functions in the wrappers * fix tests for ares 1.7 --- server/resolv/async_resolv.c | 128 +++++++++++++++++++++--------------------- server/resolv/async_resolv.h | 6 +- server/tests/resolv-tests.c | 26 ++++----- 3 files changed, 77 insertions(+), 83 deletions(-) diff --git a/server/resolv/async_resolv.c b/server/resolv/async_resolv.c index 6ac5e41..51f981a 100644 --- a/server/resolv/async_resolv.c +++ b/server/resolv/async_resolv.c @@ -43,13 +43,13 @@ #include "util/util.h" #ifndef HAVE_ARES_PARSE_SRV -#define ares_parse_srv_reply(abuf, alen, srv_out, nsrvreply) \ - _ares_parse_srv_reply(abuf, alen, srv_out, nsrvreply) +#define ares_parse_srv_reply(abuf, alen, srv_out) \ + _ares_parse_srv_reply(abuf, alen, srv_out) #endif /* HAVE_ARES_PARSE_SRV */ #ifndef HAVE_ARES_PARSE_TXT -#define ares_parse_txt_reply(abuf, alen, txt_out, ntxtreply) \ - _ares_parse_txt_reply(abuf, alen, txt_out, ntxtreply) +#define ares_parse_txt_reply(abuf, alen, txt_out) \ + _ares_parse_txt_reply(abuf, alen, txt_out) #endif /* HAVE_ARES_PARSE_TXT */ struct fd_watch { @@ -442,40 +442,48 @@ ares_gethostbyname_wakeup(struct tevent_req *subreq) } /* - * A simple helper function that will take an array of struct srv_reply that + * A simple helper function that will take an array of struct ares_srv_reply that * was allocated by malloc() in c-ares and copies it using talloc. The old one * is freed and the talloc one is put into 'reply_list' instead. */ static int -rewrite_talloc_srv_reply(TALLOC_CTX *mem_ctx, struct srv_reply **reply_list, - int num_replies) +rewrite_talloc_srv_reply(TALLOC_CTX *mem_ctx, struct ares_srv_reply **reply_list) { - int i; - struct srv_reply *new_list; - struct srv_reply *old_list = *reply_list; + struct ares_srv_reply *ptr; + struct ares_srv_reply *new_list; + struct ares_srv_reply *old_list = *reply_list; - new_list = talloc_array(mem_ctx, struct srv_reply, num_replies); + new_list = talloc_zero(mem_ctx, struct ares_srv_reply); if (new_list == NULL) { return ENOMEM; } + ptr = new_list; + + /* Copy the linked list */ + while (old_list) { + if (!ptr) { + ptr = talloc_zero(new_list, struct ares_srv_reply); + if (ptr == NULL) { + talloc_free(new_list); + return ENOMEM; + } + } - /* Copy the new_list array. */ - for (i = 0; i < num_replies; i++) { - new_list[i].weight = old_list[i].weight; - new_list[i].priority = old_list[i].priority; - new_list[i].port = old_list[i].port; - new_list[i].host = talloc_strdup(new_list, old_list[i].host); - if (new_list[i].host == NULL) { + ptr->weight = old_list->weight; + ptr->priority = old_list->priority; + ptr->port = old_list->port; + ptr->host = talloc_strdup(new_list, old_list->host); + if (ptr->host == NULL) { talloc_free(new_list); return ENOMEM; } + + ptr = ptr->next; + old_list = old_list->next; } /* Free the old one (uses malloc). */ - for (i = 0; i < num_replies; i++) { - free(old_list[i].host); - } - free(old_list); + ares_free_data(reply_list); /* And now put our own new_list in place. */ *reply_list = new_list; @@ -493,8 +501,7 @@ struct getsrv_state { const char *query; /* parsed data returned by ares */ - struct srv_reply *reply_list; - int num_replies; + struct ares_srv_reply *reply_list; int status; int timeouts; }; @@ -522,7 +529,6 @@ resolv_getsrv_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, state->resolv_ctx = ctx; state->query = query; state->reply_list = NULL; - state->num_replies = 0; state->status = 0; state->timeouts = 0; @@ -543,8 +549,7 @@ resolv_getsrv_done(void *arg, int status, int timeouts, unsigned char *abuf, int struct tevent_req *req = talloc_get_type(arg, struct tevent_req); struct getsrv_state *state = tevent_req_data(req, struct getsrv_state); int ret; - int num_replies; - struct srv_reply *reply_list; + struct ares_srv_reply *reply_list; state->status = status; state->timeouts = timeouts; @@ -555,32 +560,29 @@ resolv_getsrv_done(void *arg, int status, int timeouts, unsigned char *abuf, int goto fail; } - ret = ares_parse_srv_reply(abuf, alen, &reply_list, &num_replies); + ret = ares_parse_srv_reply(abuf, alen, &reply_list); if (status != ARES_SUCCESS) { DEBUG(2, ("SRV record parsing failed: %d: %s\n", ret, ares_strerror(ret))); ret = return_code(ret); goto fail; } - ret = rewrite_talloc_srv_reply(req, &reply_list, num_replies); + ret = rewrite_talloc_srv_reply(req, &reply_list); if (ret != EOK) { goto fail; } state->reply_list = reply_list; - state->num_replies = num_replies; tevent_req_done(req); return; fail: state->reply_list = NULL; - state->num_replies = 0; tevent_req_error(req, ret); } int resolv_getsrv_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, int *status, - int *timeouts, struct srv_reply **reply_list, - int *num_replies) + int *timeouts, struct ares_srv_reply **reply_list) { struct getsrv_state *state = tevent_req_data(req, struct getsrv_state); @@ -590,8 +592,6 @@ resolv_getsrv_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, int *status, *timeouts = state->timeouts; if (reply_list) *reply_list = talloc_steal(mem_ctx, state->reply_list); - if (num_replies) - *num_replies = state->num_replies; TEVENT_REQ_RETURN_ON_ERROR(req); @@ -627,34 +627,40 @@ ares_getsrv_wakeup(struct tevent_req *subreq) * is freed and the talloc one is put into 'reply_list' instead. */ static int -rewrite_talloc_txt_reply(TALLOC_CTX *mem_ctx, struct txt_reply **reply_list, - int num_replies) +rewrite_talloc_txt_reply(TALLOC_CTX *mem_ctx, struct ares_txt_reply **reply_list) { - int i; - struct txt_reply *new_list; - struct txt_reply *old_list = *reply_list; + struct ares_txt_reply *ptr; + struct ares_txt_reply *new_list; + struct ares_txt_reply *old_list = *reply_list; - new_list = talloc_array(mem_ctx, struct txt_reply, num_replies); + new_list = talloc_zero(mem_ctx, struct ares_txt_reply); if (new_list == NULL) { return ENOMEM; } + ptr = new_list; - /* Copy the new_list array. */ - for (i = 0; i < num_replies; i++) { - new_list[i].length = old_list[i].length; - new_list[i].txt = talloc_memdup(new_list, old_list[i].txt, - old_list[i].length); - if (new_list[i].txt == NULL) { + /* Copy the linked list */ + while (old_list) { + if (!ptr) { + ptr = talloc_zero(new_list, struct ares_txt_reply); + if (ptr == NULL) { + return ENOMEM; + } + } + + ptr->length = old_list->length; + ptr->txt = talloc_memdup(new_list, old_list->txt, + old_list->length); + if (ptr->txt == NULL) { talloc_free(new_list); return ENOMEM; } - } - /* Free the old one (uses malloc). */ - for (i = 0; i < num_replies; i++) { - free(old_list[i].txt); + ptr = ptr->next; + old_list = old_list->next; } - free(old_list); + + ares_free_data(reply_list); /* And now put our own new_list in place. */ *reply_list = new_list; @@ -672,8 +678,7 @@ struct gettxt_state { const char *query; /* parsed data returned by ares */ - struct txt_reply *reply_list; - int num_replies; + struct ares_txt_reply *reply_list; int status; int timeouts; }; @@ -701,7 +706,6 @@ resolv_gettxt_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, state->resolv_ctx = ctx; state->query = query; state->reply_list = NULL; - state->num_replies = 0; state->status = 0; state->timeouts = 0; @@ -723,8 +727,7 @@ resolv_gettxt_done(void *arg, int status, int timeouts, unsigned char *abuf, int struct tevent_req *req = talloc_get_type(arg, struct tevent_req); struct gettxt_state *state = tevent_req_data(req, struct gettxt_state); int ret; - int num_replies; - struct txt_reply *reply_list; + struct ares_txt_reply *reply_list; state->status = status; state->timeouts = timeouts; @@ -734,32 +737,29 @@ resolv_gettxt_done(void *arg, int status, int timeouts, unsigned char *abuf, int goto fail; } - ret = ares_parse_txt_reply(abuf, alen, &reply_list, &num_replies); + ret = ares_parse_txt_reply(abuf, alen, &reply_list); if (status != ARES_SUCCESS) { DEBUG(2, ("TXT record parsing failed: %d: %s\n", ret, ares_strerror(ret))); ret = return_code(ret); goto fail; } - ret = rewrite_talloc_txt_reply(req, &reply_list, num_replies); + ret = rewrite_talloc_txt_reply(req, &reply_list); if (ret != EOK) { goto fail; } state->reply_list = reply_list; - state->num_replies = num_replies; tevent_req_done(req); return; fail: state->reply_list = NULL; - state->num_replies = 0; tevent_req_error(req, ret); } int resolv_gettxt_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, int *status, - int *timeouts, struct txt_reply **reply_list, - int *num_replies) + int *timeouts, struct ares_txt_reply **reply_list) { struct gettxt_state *state = tevent_req_data(req, struct gettxt_state); @@ -769,8 +769,6 @@ resolv_gettxt_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, int *status, *timeouts = state->timeouts; if (reply_list) *reply_list = talloc_steal(mem_ctx, state->reply_list); - if (num_replies) - *num_replies = state->num_replies; TEVENT_REQ_RETURN_ON_ERROR(req); diff --git a/server/resolv/async_resolv.h b/server/resolv/async_resolv.h index 702d4dd..9d080ec 100644 --- a/server/resolv/async_resolv.h +++ b/server/resolv/async_resolv.h @@ -77,8 +77,7 @@ int resolv_getsrv_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, int *status, int *timeouts, - struct srv_reply **reply_list, - int *num_replies); + struct ares_srv_reply **reply_list); /** Get TXT record **/ struct tevent_req *resolv_gettxt_send(TALLOC_CTX *mem_ctx, @@ -90,7 +89,6 @@ int resolv_gettxt_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, int *status, int *timeouts, - struct txt_reply **reply_list, - int *num_replies); + struct ares_txt_reply **reply_list); #endif /* __ASYNC_RESOLV_H__ */ diff --git a/server/tests/resolv-tests.c b/server/tests/resolv-tests.c index bf76849..d6b8c4f 100644 --- a/server/tests/resolv-tests.c +++ b/server/tests/resolv-tests.c @@ -253,15 +253,13 @@ END_TEST static void test_internet(struct tevent_req *req) { - int i; int recv_status; int status; struct resolv_test_ctx *test_ctx; void *tmp_ctx; struct hostent *hostent = NULL; - struct txt_reply *txt_replies = NULL; - struct srv_reply *srv_replies = NULL; - int count; + struct ares_txt_reply *txt_replies = NULL, *txtptr; + struct ares_srv_reply *srv_replies = NULL, *srvptr; test_ctx = tevent_req_callback_data(req, struct resolv_test_ctx); @@ -278,20 +276,20 @@ static void test_internet(struct tevent_req *req) break; case TESTING_TXT: recv_status = resolv_gettxt_recv(tmp_ctx, req, &status, NULL, - &txt_replies, &count); - test_ctx->error = (count == 0) ? ENOENT : EOK; - for (i = 0; i < count; i++) { - DEBUG(2, ("TXT Record: %s\n", txt_replies[i].txt)); + &txt_replies); + test_ctx->error = (txt_replies == NULL) ? ENOENT : EOK; + for (txtptr = txt_replies; txtptr != NULL; txtptr = txtptr->next) { + DEBUG(2, ("TXT Record: %s\n", txtptr->txt)); } break; case TESTING_SRV: recv_status = resolv_getsrv_recv(tmp_ctx, req, &status, NULL, - &srv_replies, &count); - test_ctx->error = (count == 0) ? ENOENT : EOK; - for (i = 0; i < count; i++) { - DEBUG(2, ("SRV Record: %d %d %d %s\n", srv_replies[i].weight, - srv_replies[i].priority, srv_replies[i].port, - srv_replies[i].host)); + &srv_replies); + test_ctx->error = (srv_replies == NULL) ? ENOENT : EOK; + for (srvptr = srv_replies; srvptr != NULL; srvptr = srvptr->next) { + DEBUG(2, ("SRV Record: %d %d %d %s\n", srvptr->weight, + srvptr->priority, srvptr->port, + srvptr->host)); } break; } -- 1.6.5.2
>From bc09339ff53de1b8cb54e356550ef9413db0f4e6 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek <jhro...@redhat.com> Date: Fri, 27 Nov 2009 09:39:41 +0100 Subject: [PATCH 2/3] Import ares 1.7.0 helpers --- server/Makefile.am | 11 ++- server/external/libcares.m4 | 21 +---- server/resolv/ares/ares_data.c | 140 +++++++++++++++++++++++++++++ server/resolv/ares/ares_data.h | 68 ++++++++++++++ server/resolv/ares/ares_parse_srv_reply.c | 88 ++++++++++-------- server/resolv/ares/ares_parse_srv_reply.h | 13 ++-- server/resolv/ares/ares_parse_txt_reply.c | 119 +++++++++++++++++-------- server/resolv/ares/ares_parse_txt_reply.h | 9 +- server/resolv/async_resolv.c | 11 ++- server/resolv/async_resolv.h | 10 +- 10 files changed, 374 insertions(+), 116 deletions(-) create mode 100644 server/resolv/ares/ares_data.c create mode 100644 server/resolv/ares/ares_data.h diff --git a/server/Makefile.am b/server/Makefile.am index c43eb47..3902da1 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -209,11 +209,11 @@ SSSD_TOOLS_OBJ = \ SSSD_RESOLV_OBJ = \ resolv/async_resolv.c -if BUILD_ARES_PARSE_SRV - SSSD_RESOLV_OBJ += resolv/ares/ares_parse_srv_reply.c -endif -if BUILD_ARES_PARSE_TXT - SSSD_RESOLV_OBJ += resolv/ares/ares_parse_txt_reply.c +if BUILD_ARES_DATA + SSSD_RESOLV_OBJ += \ + resolv/ares/ares_parse_srv_reply.c \ + resolv/ares/ares_parse_txt_reply.c \ + resolv/ares/ares_data.c endif SSSD_FAILOVER_OBJ = \ @@ -309,6 +309,7 @@ dist_noinst_HEADERS = \ resolv/async_resolv.h \ resolv/ares/ares_parse_srv_reply.h \ resolv/ares/ares_parse_txt_reply.h \ + resolv/ares/ares_data.h \ tests/common.h diff --git a/server/external/libcares.m4 b/server/external/libcares.m4 index 020a170..657deac 100644 --- a/server/external/libcares.m4 +++ b/server/external/libcares.m4 @@ -7,25 +7,14 @@ AC_CHECK_HEADERS(ares.h, [AC_MSG_ERROR([c-ares header files are not installed])] ) -dnl Check if this particular version of c-ares supports parsing of SRV records +dnl Check if this particular version of c-ares supports the generic ares_free_data function AC_CHECK_LIB([cares], - [ares_parse_srv_reply], - [AC_DEFINE([HAVE_ARES_PARSE_SRV], 1, [Does c-ares support srv parsing?]) + [ares_free_data], + [AC_DEFINE([HAVE_ARES_DATA], 1, [Does c-ares have ares_free_data()?]) ], [ - ares_build_srv=1 + ares_data=1 ] ) -dnl Check if this particular version of c-ares supports parsing of TXT records -AC_CHECK_LIB([cares], - [ares_parse_txt_reply], - [AC_DEFINE([HAVE_ARES_PARSE_TXT], 1, [Does c-ares support txt parsing?]) - ], - [ - ares_build_txt=1 - ] -) - -AM_CONDITIONAL(BUILD_ARES_PARSE_SRV, test x$ares_build_srv = x1) -AM_CONDITIONAL(BUILD_ARES_PARSE_TXT, test x$ares_build_txt = x1) +AM_CONDITIONAL(BUILD_ARES_DATA, test x$ares_data = x1) diff --git a/server/resolv/ares/ares_data.c b/server/resolv/ares/ares_data.c new file mode 100644 index 0000000..1cccaa5 --- /dev/null +++ b/server/resolv/ares/ares_data.c @@ -0,0 +1,140 @@ +/* $Id: ares_data.c,v 1.2 2009-11-20 09:06:33 yangtse Exp $ */ + +/* 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 <stddef.h> +#include <stdlib.h> + +#include "ares.h" +#include "ares_data.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: +** +** ares_parse_srv_reply() +** ares_parse_txt_reply() +*/ + +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/server/resolv/ares/ares_data.h b/server/resolv/ares/ares_data.h new file mode 100644 index 0000000..d360631 --- /dev/null +++ b/server/resolv/ares/ares_data.h @@ -0,0 +1,68 @@ +/* $Id: ares_data.h,v 1.2 2009-11-23 12:03:33 yangtse Exp $ */ + +/* 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. + */ + +#ifndef HAVE_ARES_DATA +#include "resolv/ares/ares_parse_txt_reply.h" +#include "resolv/ares/ares_parse_srv_reply.h" +#endif /* HAVE_ARES_DATA */ + +typedef enum { + ARES_DATATYPE_UNKNOWN = 1, /* unknown data type - introduced in 1.7.0 */ + ARES_DATATYPE_SRV_REPLY, /* struct ares_srv_reply - introduced in 1.7.0 */ + ARES_DATATYPE_TXT_REPLY, /* struct ares_txt_reply - introduced in 1.7.0 */ +#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_LAST /* not used - introduced in 1.7.0 */ +} 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); +void _ares_free_data(void *dataptr); + +ares_datatype ares_get_datatype(void * dataptr); diff --git a/server/resolv/ares/ares_parse_srv_reply.c b/server/resolv/ares/ares_parse_srv_reply.c index 9745fb0..086c4db 100644 --- a/server/resolv/ares/ares_parse_srv_reply.c +++ b/server/resolv/ares/ares_parse_srv_reply.c @@ -51,25 +51,24 @@ #include "ares.h" /* this drags in some private macros c-ares uses */ #include "ares_dns.h" +#include "ares_data.h" #include "ares_parse_srv_reply.h" int _ares_parse_srv_reply (const unsigned char *abuf, int alen, - struct srv_reply **srv_out, int *nsrvreply) + struct ares_srv_reply **srv_out) { - unsigned int qdcount, ancount; - const unsigned char *aptr; - int status, i, rr_type, rr_class, rr_len; + unsigned int qdcount, ancount, i; + const unsigned char *aptr, *vptr; + int status, rr_type, rr_class, rr_len; long len; char *hostname = NULL, *rr_name = NULL; - struct srv_reply *srv = NULL; + struct ares_srv_reply *srv_head = NULL; + struct ares_srv_reply *srv_last = NULL; + struct ares_srv_reply *srv_curr; /* Set *srv_out to NULL for all failure cases. */ - if (srv_out) - *srv_out = NULL; - /* Same with *nsrvreply. */ - if (nsrvreply) - *nsrvreply = 0; + *srv_out = NULL; /* Give up if abuf doesn't have room for a header. */ if (alen < HFIXEDSZ) @@ -96,14 +95,6 @@ int _ares_parse_srv_reply (const unsigned char *abuf, int alen, } aptr += len + QFIXEDSZ; - /* Allocate srv_reply array; ancount gives an upper bound */ - srv = malloc ((ancount) * sizeof (struct srv_reply)); - if (!srv) - { - free (hostname); - return ARES_ENOMEM; - } - /* Examine each answer resource record (RR) in turn. */ for (i = 0; i < (int) ancount; i++) { @@ -134,40 +125,59 @@ int _ares_parse_srv_reply (const unsigned char *abuf, int alen, break; } - srv[i].priority = ntohs (*((const uint16_t *)aptr)); - aptr += sizeof(uint16_t); - srv[i].weight = ntohs (*((const uint16_t *)aptr)); - aptr += sizeof(uint16_t); - srv[i].port = ntohs (*((const uint16_t *)aptr)); - aptr += sizeof(uint16_t); + /* Allocate storage for this SRV answer appending it to the list */ + srv_curr = _ares_malloc_data(ARES_DATATYPE_SRV_REPLY); + if (!srv_curr) + { + status = ARES_ENOMEM; + break; + } + if (srv_last) + { + srv_last->next = srv_curr; + } + else + { + srv_head = srv_curr; + } + srv_last = srv_curr; + + vptr = aptr; + srv_curr->priority = ntohs (*((const unsigned short *)vptr)); + vptr += sizeof(const unsigned short); + srv_curr->weight = ntohs (*((const unsigned short *)vptr)); + vptr += sizeof(const unsigned short); + srv_curr->port = ntohs (*((const unsigned short *)vptr)); + vptr += sizeof(const unsigned short); - status = ares_expand_name (aptr, abuf, alen, &srv[i].host, &len); + status = ares_expand_name (vptr, abuf, alen, &srv_curr->host, &len); if (status != ARES_SUCCESS) break; + } - /* Move on to the next record */ - aptr += len; + /* Don't lose memory in the next iteration */ + free(rr_name); + rr_name = NULL; - /* Don't lose memory in the next iteration */ - free (rr_name); - rr_name = NULL; - } + /* Move on to the next record */ + aptr += rr_len; } + if (hostname) + free (hostname); + if (rr_name) + free (rr_name); + /* clean up on error */ if (status != ARES_SUCCESS) { - free (srv); - free (hostname); - free (rr_name); + if (srv_head) + _ares_free_data (srv_head); return status; } /* everything looks fine, return the data */ - *srv_out = srv; - *nsrvreply = ancount; + *srv_out = srv_head; - free (hostname); - free (rr_name); - return status; + return ARES_SUCCESS; } diff --git a/server/resolv/ares/ares_parse_srv_reply.h b/server/resolv/ares/ares_parse_srv_reply.h index caf93cd..29c6e08 100644 --- a/server/resolv/ares/ares_parse_srv_reply.h +++ b/server/resolv/ares/ares_parse_srv_reply.h @@ -21,14 +21,15 @@ #ifndef __ARES_PARSE_SRV_REPLY_H__ #define __ARES_PARSE_SRV_REPLY_H__ -struct srv_reply { - u_int16_t weight; - u_int16_t priority; - u_int16_t port; - char *host; +struct ares_srv_reply { + struct ares_srv_reply *next; + char *host; + unsigned short priority; + unsigned short weight; + unsigned short port; }; int _ares_parse_srv_reply (const unsigned char *abuf, int alen, - struct srv_reply **srv_out, int *nsrvreply); + struct ares_srv_reply **srv_out); #endif /* __ARES_PARSE_SRV_REPLY_H__ */ diff --git a/server/resolv/ares/ares_parse_txt_reply.c b/server/resolv/ares/ares_parse_txt_reply.c index feb6af2..d710e8f 100644 --- a/server/resolv/ares/ares_parse_txt_reply.c +++ b/server/resolv/ares/ares_parse_txt_reply.c @@ -50,21 +50,26 @@ #include "ares.h" /* this drags in some private macros c-ares uses */ #include "ares_dns.h" +#include "ares_data.h" #include "ares_parse_txt_reply.h" -int _ares_parse_txt_reply(const unsigned char* abuf, int alen, - struct txt_reply **txt_out, int *ntxtreply) +int _ares_parse_txt_reply (const unsigned char *abuf, int alen, + struct ares_txt_reply **txt_out) { - unsigned int qdcount, ancount; + size_t substr_len, str_len; + unsigned int qdcount, ancount, i; const unsigned char *aptr; - int status, i, rr_type, rr_class, rr_len; + const unsigned char *strptr; + int status, rr_type, rr_class, rr_len; long len; char *hostname = NULL, *rr_name = NULL; - struct txt_reply *txt = NULL; + struct ares_txt_reply *txt_head = NULL; + struct ares_txt_reply *txt_last = NULL; + struct ares_txt_reply *txt_curr; - if (txt_out) - *txt_out = NULL; + /* Set *txt_out to NULL for all failure cases. */ + *txt_out = NULL; /* Give up if abuf doesn't have room for a header. */ if (alen < HFIXEDSZ) @@ -91,29 +96,21 @@ int _ares_parse_txt_reply(const unsigned char* abuf, int alen, } aptr += len + QFIXEDSZ; - /* Allocate txt_reply array; ancount gives an upper bound */ - txt = malloc ((ancount) * sizeof (struct txt_reply)); - if (!txt) - { - free (hostname); - return ARES_ENOMEM; - } - /* Examine each answer resource record (RR) in turn. */ for (i = 0; i < (int) ancount; i++) { /* Decode the RR up to the data field. */ status = ares_expand_name(aptr, abuf, alen, &rr_name, &len); if (status != ARES_SUCCESS) - { - break; - } + { + break; + } aptr += len; if (aptr + RRFIXEDSZ > abuf + alen) - { - status = ARES_EBADRESP; - break; - } + { + status = ARES_EBADRESP; + break; + } rr_type = DNS_RR_TYPE(aptr); rr_class = DNS_RR_CLASS(aptr); rr_len = DNS_RR_LEN(aptr); @@ -121,37 +118,87 @@ int _ares_parse_txt_reply(const unsigned char* abuf, int alen, /* Check if we are really looking at a TXT record */ if (rr_class == C_IN && rr_type == T_TXT) - { - /* Grab the TXT payload */ - txt[i].length = rr_len; - txt[i].txt = malloc(sizeof(unsigned char) * rr_len); - if (txt[i].txt == NULL) + { + /* Allocate storage for this TXT answer appending it to the list */ + txt_curr = _ares_malloc_data(ARES_DATATYPE_TXT_REPLY); + if (!txt_curr) { status = ARES_ENOMEM; break; } - memcpy((void *) txt[i].txt, aptr+1, sizeof(unsigned char) * rr_len); - /* Move on to the next record */ - aptr += rr_len; + if (txt_last) + { + txt_last->next = txt_curr; + } + else + { + txt_head = txt_curr; + } + txt_last = txt_curr; + + /* + * There may be multiple substrings in a single TXT record. Each + * substring may be up to 255 characters in length, with a + * "length byte" indicating the size of the substring payload. + * RDATA contains both the length-bytes and payloads of all + * substrings contained therein. + */ + + /* Compute total length to allow a single memory allocation */ + strptr = aptr; + while (strptr < (aptr + rr_len)) + { + substr_len = (unsigned char)*strptr; + txt_curr->length += substr_len; + strptr += substr_len + 1; + } + + /* Including null byte */ + txt_curr->txt = malloc (txt_curr->length + 1); + if (txt_curr->txt == NULL) + { + status = ARES_ENOMEM; + break; + } + + /* Step through the list of substrings, concatenating them */ + str_len = 0; + strptr = aptr; + while (strptr < (aptr + rr_len)) + { + substr_len = (unsigned char)*strptr; + strptr++; + memcpy ((char *) txt_curr->txt + str_len, strptr, substr_len); + str_len += substr_len; + strptr += substr_len; + } + /* Make sure we NULL-terminate */ + *((char *) txt_curr->txt + txt_curr->length) = '\0'; } /* Don't lose memory in the next iteration */ free(rr_name); rr_name = NULL; + + /* Move on to the next record */ + aptr += rr_len; } - free(hostname); - free(rr_name); + if (hostname) + free (hostname); + if (rr_name) + free (rr_name); /* clean up on error */ if (status != ARES_SUCCESS) { - free (txt); + if (txt_head) + _ares_free_data (txt_head); return status; } /* everything looks fine, return the data */ - *txt_out = txt; - *ntxtreply = ancount; - return 0; + *txt_out = txt_head; + + return ARES_SUCCESS; } diff --git a/server/resolv/ares/ares_parse_txt_reply.h b/server/resolv/ares/ares_parse_txt_reply.h index 9fd4278..216e2c0 100644 --- a/server/resolv/ares/ares_parse_txt_reply.h +++ b/server/resolv/ares/ares_parse_txt_reply.h @@ -21,12 +21,13 @@ #ifndef __ARES_PARSE_TXT_REPLY_H__ #define __ARES_PARSE_TXT_REPLY_H__ -struct txt_reply { - int length; /* length of the text */ - unsigned char *txt; /* may contain nulls */ +struct ares_txt_reply { + struct ares_txt_reply *next; + unsigned char *txt; + size_t length; /* length excludes null termination */ }; int _ares_parse_txt_reply(const unsigned char* abuf, int alen, - struct txt_reply **txt_out, int *ntxtreply); + struct ares_txt_reply **txt_out); #endif /* __ARES_PARSE_TXT_REPLY_H__ */ diff --git a/server/resolv/async_resolv.c b/server/resolv/async_resolv.c index 51f981a..1bbdf17 100644 --- a/server/resolv/async_resolv.c +++ b/server/resolv/async_resolv.c @@ -42,15 +42,16 @@ #include "util/dlinklist.h" #include "util/util.h" -#ifndef HAVE_ARES_PARSE_SRV +#ifndef HAVE_ARES_DATA #define ares_parse_srv_reply(abuf, alen, srv_out) \ _ares_parse_srv_reply(abuf, alen, srv_out) -#endif /* HAVE_ARES_PARSE_SRV */ - -#ifndef HAVE_ARES_PARSE_TXT #define ares_parse_txt_reply(abuf, alen, txt_out) \ _ares_parse_txt_reply(abuf, alen, txt_out) -#endif /* HAVE_ARES_PARSE_TXT */ +#define ares_free_data(dataptr) \ + _ares_free_data(dataptr) +#define ares_malloc_data(data) \ + _ares_malloc_data(data) +#endif /* HAVE_ARES_DATA */ struct fd_watch { struct fd_watch *prev; diff --git a/server/resolv/async_resolv.h b/server/resolv/async_resolv.h index 9d080ec..dab2fdf 100644 --- a/server/resolv/async_resolv.h +++ b/server/resolv/async_resolv.h @@ -29,13 +29,13 @@ #include <netdb.h> #include <ares.h> -#ifndef HAVE_ARES_PARSE_TXT -#include "resolv/ares/ares_parse_txt_reply.h" -#endif /* HAVE_ARES_PARSE_TXT */ +#include "config.h" -#ifndef HAVE_ARES_PARSE_SRV +#ifndef HAVE_ARES_DATA #include "resolv/ares/ares_parse_srv_reply.h" -#endif /* HAVE_ARES_PARSE_SRV */ +#include "resolv/ares/ares_parse_txt_reply.h" +#include "resolv/ares/ares_data.h" +#endif /* HAVE_ARES_DATA */ /* * An opaque structure which holds context for a module using the async -- 1.6.5.2
>From d2d677a1ff4f0212cfd956da4446b0e4f7db5905 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek <jhro...@redhat.com> Date: Mon, 7 Dec 2009 19:28:33 +0100 Subject: [PATCH 3/3] Don't build the SRV and TXT parsing code except for tests --- server/Makefile.am | 20 ++++++++++++-------- server/resolv/async_resolv.c | 6 ++++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/server/Makefile.am b/server/Makefile.am index 3902da1..ed6f0de 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -209,12 +209,6 @@ SSSD_TOOLS_OBJ = \ SSSD_RESOLV_OBJ = \ resolv/async_resolv.c -if BUILD_ARES_DATA - SSSD_RESOLV_OBJ += \ - resolv/ares/ares_parse_srv_reply.c \ - resolv/ares/ares_parse_txt_reply.c \ - resolv/ares/ares_data.c -endif SSSD_FAILOVER_OBJ = \ providers/fail_over.c \ @@ -478,14 +472,24 @@ files_tests_CFLAGS = \ files_tests_LDADD = \ $(FILES_TESTS_LIBS) +SSSD_RESOLV_TESTS_OBJ = \ + $(SSSD_RESOLV_OBJ) +if BUILD_ARES_DATA + SSSD_RESOLV_TESTS_OBJ += \ + resolv/ares/ares_parse_srv_reply.c \ + resolv/ares/ares_parse_txt_reply.c \ + resolv/ares/ares_data.c +endif + resolv_tests_SOURCES = \ tests/resolv-tests.c \ tests/common.c \ $(SSSD_UTIL_OBJ) \ - $(SSSD_RESOLV_OBJ) + $(SSSD_RESOLV_TESTS_OBJ) resolv_tests_CFLAGS = \ $(AM_CFLAGS) \ - $(CHECK_CFLAGS) + $(CHECK_CFLAGS) \ + -DBUILD_TXT_SRV resolv_tests_LDADD = \ $(SSSD_LIBS) \ $(CHECK_LIBS) \ diff --git a/server/resolv/async_resolv.c b/server/resolv/async_resolv.c index 1bbdf17..2a06a62 100644 --- a/server/resolv/async_resolv.c +++ b/server/resolv/async_resolv.c @@ -442,6 +442,11 @@ ares_gethostbyname_wakeup(struct tevent_req *subreq) state->family, resolv_gethostbyname_done, req); } +/* SRV and TXT parsing is not used anywhere in the code yet, so we disable it + * for now + */ +#ifdef BUILD_TXT_SRV + /* * A simple helper function that will take an array of struct ares_srv_reply that * was allocated by malloc() in c-ares and copies it using talloc. The old one @@ -799,3 +804,4 @@ ares_gettxt_wakeup(struct tevent_req *subreq) ns_c_in, ns_t_txt, resolv_gettxt_done, req); } +#endif -- 1.6.5.2
_______________________________________________ sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://fedorahosted.org/mailman/listinfo/sssd-devel