txt: introduce `ares_parse_txt_reply_ext`

Introduce `ares_txt_ext` structure with an extra `record_start`
field, which indicates a start of a new TXT record, thus allowing to
differentiate the chunks in the same record, from a chunks in a
different record.

Introduce a new API method: `ares_parse_txt_reply_ext` that works with
this kind of struct.
This commit is contained in:
Fedor Indutny 2014-03-28 00:14:59 +04:00 committed by David Drysdale
parent 0c4c1ca9bc
commit 53c2186e18
5 changed files with 99 additions and 19 deletions

15
ares.h
View File

@ -484,6 +484,17 @@ struct ares_txt_reply {
size_t length; /* length excludes null termination */
};
/* NOTE: This structure is a superset of ares_txt_reply
*/
struct ares_txt_ext {
struct ares_txt_ext *next;
unsigned char *txt;
size_t length;
/* 1 - if start of new record
* 0 - if a chunk in the same record */
unsigned char record_start;
};
struct ares_naptr_reply {
struct ares_naptr_reply *next;
unsigned char *flags;
@ -547,6 +558,10 @@ CARES_EXTERN int ares_parse_txt_reply(const unsigned char* abuf,
int alen,
struct ares_txt_reply** txt_out);
CARES_EXTERN int ares_parse_txt_reply_ext(const unsigned char* abuf,
int alen,
struct ares_txt_ext** txt_out);
CARES_EXTERN int ares_parse_naptr_reply(const unsigned char* abuf,
int alen,
struct ares_naptr_reply** naptr_out);

View File

@ -79,6 +79,7 @@ void ares_free_data(void *dataptr)
break;
case ARES_DATATYPE_TXT_REPLY:
case ARES_DATATYPE_TXT_EXT:
if (ptr->data.txt_reply.next)
ares_free_data(ptr->data.txt_reply.next);
@ -162,6 +163,10 @@ void *ares_malloc_data(ares_datatype type)
ptr->data.srv_reply.port = 0;
break;
case ARES_DATATYPE_TXT_EXT:
ptr->data.txt_ext.record_start = 0;
/* FALLTHROUGH */
case ARES_DATATYPE_TXT_REPLY:
ptr->data.txt_reply.next = NULL;
ptr->data.txt_reply.txt = NULL;

View File

@ -18,6 +18,7 @@ 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 */
ARES_DATATYPE_TXT_EXT, /* struct ares_txt_ext - introduced in 1.11.0 */
ARES_DATATYPE_ADDR_NODE, /* struct ares_addr_node - introduced in 1.7.1 */
ARES_DATATYPE_MX_REPLY, /* struct ares_mx_reply - introduced in 1.7.2 */
ARES_DATATYPE_NAPTR_REPLY,/* struct ares_naptr_reply - introduced in 1.7.6 */
@ -56,13 +57,14 @@ 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;
struct ares_addr_node addr_node;
struct ares_txt_reply txt_reply;
struct ares_txt_ext txt_ext;
struct ares_srv_reply srv_reply;
struct ares_addr_node addr_node;
struct ares_addr_port_node addr_port_node;
struct ares_mx_reply mx_reply;
struct ares_naptr_reply naptr_reply;
struct ares_soa_reply soa_reply;
struct ares_mx_reply mx_reply;
struct ares_naptr_reply naptr_reply;
struct ares_soa_reply soa_reply;
} data;
};

View File

@ -22,13 +22,16 @@ ares_parse_txt_reply \- Parse a reply to a DNS query of type TXT
.PP
.B int ares_parse_txt_reply(const unsigned char* \fIabuf\fP, int \fIalen\fP,
.B struct ares_txt_reply **\fItxt_out\fP);
.PP
.B int ares_parse_txt_reply_ext(const unsigned char* \fIabuf\fP, int \fIalen\fP,
.B struct ares_txt_ext **\fItxt_out\fP);
.fi
.SH DESCRIPTION
The
.B ares_parse_txt_reply
.BR "ares_parse_txt_reply" " (" "ares_parse_txt_reply_ext" ")"
function parses the response to a query of type TXT into a
linked list (one element per sub-string) of
.I struct ares_txt_reply
.IR "struct ares_txt_reply" " (" "struct ares_txt_ext" ")"
The parameters
.I abuf
and
@ -55,8 +58,44 @@ struct ares_txt_reply {
.fi
.in
.PP
The structure
.I ares_txt_ext
contains the following fields:
.sp
.in +4n
.nf
struct ares_txt_ext {
struct ares_txt_ext *next;
unsigned int length;
unsigned char *txt;
unsigned char record_start;
};
.fi
.in
.PP
The
.I record_start
field in
.I struct ares_txt_ext
is 1 if this structure is a start of a TXT record, and 0 if the structure is a
continuation of a previous record. The linked list of the
.I struct ares_txt_ext
will have at least one item with
.I record_start
equal to 1, and may have some items with
.I record_start
equal to 0 between them.
.PP
These sequences of
.I struct ares_txt_ext
(starting from the item with
.I record_start
equal to 1, and ending right before the record start item) may be treated as
either components of a single TXT record or as a multi-parted TXT record,
depending on particular use case.
.PP
.SH RETURN VALUES
.B ares_parse_txt_reply
.BR "ares_parse_txt_reply" " (" "ares_parse_txt_reply_ext" ")"
can return any of the following values:
.TP 15
.B ARES_SUCCESS
@ -77,4 +116,5 @@ This function was first introduced in c-ares version 1.7.0.
.BR ares_free_data (3)
.SH AUTHOR
Written by Jakub Hrozek <jhrozek@redhat.com>, on behalf of Red Hat, Inc http://www.redhat.com
.PP
Amended by Fedor Indutny <fedor@indutny.com>, on behalf of PayPal, Inc https://www.paypal.com

View File

@ -44,9 +44,9 @@
#include "ares_data.h"
#include "ares_private.h"
int
ares_parse_txt_reply (const unsigned char *abuf, int alen,
struct ares_txt_reply **txt_out)
static int
ares__parse_txt_reply (const unsigned char *abuf, int alen,
int ex, void **txt_out)
{
size_t substr_len;
unsigned int qdcount, ancount, i;
@ -55,9 +55,9 @@ ares_parse_txt_reply (const unsigned char *abuf, int alen,
int status, rr_type, rr_class, rr_len;
long len;
char *hostname = NULL, *rr_name = NULL;
struct ares_txt_reply *txt_head = NULL;
struct ares_txt_reply *txt_last = NULL;
struct ares_txt_reply *txt_curr;
struct ares_txt_ext *txt_head = NULL;
struct ares_txt_ext *txt_last = NULL;
struct ares_txt_ext *txt_curr;
/* Set *txt_out to NULL for all failure cases. */
*txt_out = NULL;
@ -133,10 +133,9 @@ ares_parse_txt_reply (const unsigned char *abuf, int alen,
break;
}
++strptr;
/* Allocate storage for this TXT answer appending it to the list */
txt_curr = ares_malloc_data(ARES_DATATYPE_TXT_REPLY);
txt_curr = ares_malloc_data(ex ? ARES_DATATYPE_TXT_EXT :
ARES_DATATYPE_TXT_REPLY);
if (!txt_curr)
{
status = ARES_ENOMEM;
@ -152,6 +151,8 @@ ares_parse_txt_reply (const unsigned char *abuf, int alen,
}
txt_last = txt_curr;
if (ex)
txt_curr->record_start = (strptr == aptr);
txt_curr->length = substr_len;
txt_curr->txt = ares_malloc (substr_len + 1/* Including null byte */);
if (txt_curr->txt == NULL)
@ -159,6 +160,8 @@ ares_parse_txt_reply (const unsigned char *abuf, int alen,
status = ARES_ENOMEM;
break;
}
++strptr;
memcpy ((char *) txt_curr->txt, strptr, substr_len);
/* Make sure we NULL-terminate */
@ -200,3 +203,18 @@ ares_parse_txt_reply (const unsigned char *abuf, int alen,
return ARES_SUCCESS;
}
int
ares_parse_txt_reply (const unsigned char *abuf, int alen,
struct ares_txt_reply **txt_out)
{
return ares__parse_txt_reply(abuf, alen, 0, (void **) txt_out);
}
int
ares_parse_txt_reply_ext (const unsigned char *abuf, int alen,
struct ares_txt_ext **txt_out)
{
return ares__parse_txt_reply(abuf, alen, 1, (void **) txt_out);
}