summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/Makefile.am11
-rw-r--r--server/external/libcares.m421
-rw-r--r--server/resolv/ares/ares_data.c140
-rw-r--r--server/resolv/ares/ares_data.h68
-rw-r--r--server/resolv/ares/ares_parse_srv_reply.c88
-rw-r--r--server/resolv/ares/ares_parse_srv_reply.h13
-rw-r--r--server/resolv/ares/ares_parse_txt_reply.c119
-rw-r--r--server/resolv/ares/ares_parse_txt_reply.h9
-rw-r--r--server/resolv/async_resolv.c11
-rw-r--r--server/resolv/async_resolv.h10
10 files changed, 374 insertions, 116 deletions
diff --git a/server/Makefile.am b/server/Makefile.am
index fdaefea2a..9814d4f64 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -211,11 +211,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 = \
@@ -311,6 +311,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 020a1708d..657deac59 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 000000000..1cccaa55c
--- /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 000000000..d3606314e
--- /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 9745fb07a..086c4dba0 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 caf93cd2b..29c6e08d1 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 feb6af23d..d710e8f98 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 9fd42787e..216e2c0d1 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 be2107a22..afad4107b 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 9d080ec69..dab2fdfc4 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