summaryrefslogtreecommitdiff
path: root/contrib/unbound/util
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2016-09-04 12:17:57 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2016-09-04 12:17:57 +0000
commite2d1500434f5c64506dad196d921caee199cad1c (patch)
treecea39d51c3c88082749b235aed976fd9cd20ebbb /contrib/unbound/util
parenta4c138885ef0b9e48a510fa877830b91ab345917 (diff)
parenta6533d88996e7570cf04db0d99b6012d25a953d3 (diff)
downloadsrc-test2-e2d1500434f5c64506dad196d921caee199cad1c.tar.gz
src-test2-e2d1500434f5c64506dad196d921caee199cad1c.zip
Notes
Diffstat (limited to 'contrib/unbound/util')
-rw-r--r--contrib/unbound/util/config_file.c210
-rw-r--r--contrib/unbound/util/config_file.h84
-rw-r--r--contrib/unbound/util/configlexer.lex4
-rw-r--r--contrib/unbound/util/configparser.y59
-rw-r--r--contrib/unbound/util/data/dname.c18
-rw-r--r--contrib/unbound/util/data/msgencode.c22
-rw-r--r--contrib/unbound/util/data/msgparse.c60
-rw-r--r--contrib/unbound/util/data/msgparse.h28
-rw-r--r--contrib/unbound/util/data/msgreply.c154
-rw-r--r--contrib/unbound/util/data/msgreply.h52
-rw-r--r--contrib/unbound/util/fptr_wlist.c25
-rw-r--r--contrib/unbound/util/fptr_wlist.h2
-rw-r--r--contrib/unbound/util/iana_ports.inc7
-rw-r--r--contrib/unbound/util/module.h8
-rw-r--r--contrib/unbound/util/net_help.c6
-rw-r--r--contrib/unbound/util/netevent.c381
-rw-r--r--contrib/unbound/util/netevent.h18
-rw-r--r--contrib/unbound/util/tube.c12
-rw-r--r--contrib/unbound/util/tube.h3
-rw-r--r--contrib/unbound/util/ub_event.c448
-rw-r--r--contrib/unbound/util/ub_event.h127
-rw-r--r--contrib/unbound/util/ub_event_pluggable.c694
22 files changed, 2149 insertions, 273 deletions
diff --git a/contrib/unbound/util/config_file.c b/contrib/unbound/util/config_file.c
index 420dc717d207..2b79bd9a859a 100644
--- a/contrib/unbound/util/config_file.c
+++ b/contrib/unbound/util/config_file.c
@@ -163,6 +163,7 @@ config_create(void)
cfg->so_sndbuf = 0;
cfg->so_reuseport = 0;
cfg->ip_transparent = 0;
+ cfg->ip_freebind = 0;
cfg->num_ifs = 0;
cfg->ifs = NULL;
cfg->num_out_ifs = 0;
@@ -237,6 +238,7 @@ config_create(void)
if(!(cfg->dnstap_socket_path = strdup(DNSTAP_SOCKET_PATH)))
goto error_exit;
#endif
+ cfg->disable_dnssec_lame_check = 0;
cfg->ratelimit = 0;
cfg->ratelimit_slabs = 4;
cfg->ratelimit_size = 4*1024*1024;
@@ -393,6 +395,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_MEMSIZE("so-sndbuf:", so_sndbuf)
else S_YNO("so-reuseport:", so_reuseport)
else S_YNO("ip-transparent:", ip_transparent)
+ else S_YNO("ip-freebind:", ip_freebind)
else S_MEMSIZE("rrset-cache-size:", rrset_cache_size)
else S_POW2("rrset-cache-slabs:", rrset_cache_slabs)
else S_YNO("prefetch:", prefetch)
@@ -473,6 +476,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_STR("control-cert-file:", control_cert_file)
else S_STR("module-config:", module_conf)
else S_STR("python-script:", python_script)
+ else S_YNO("disable-dnssec-lame-check:", disable_dnssec_lame_check)
else if(strcmp(opt, "ratelimit:") == 0) {
IS_NUMBER_OR_ZERO; cfg->ratelimit = atoi(val);
infra_dp_ratelimit=cfg->ratelimit;
@@ -481,9 +485,11 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_POW2("ratelimit-slabs:", ratelimit_slabs)
else S_NUMBER_OR_ZERO("ratelimit-factor:", ratelimit_factor)
else S_YNO("qname-minimisation:", qname_minimisation)
+ else if(strcmp(opt, "define-tag:") ==0) {
+ return config_add_tag(cfg, val);
/* val_sig_skew_min and max are copied into val_env during init,
* so this does not update val_env with set_option */
- else if(strcmp(opt, "val-sig-skew-min:") == 0)
+ } else if(strcmp(opt, "val-sig-skew-min:") == 0)
{ IS_NUMBER_OR_ZERO; cfg->val_sig_skew_min = (int32_t)atoi(val); }
else if(strcmp(opt, "val-sig-skew-max:") == 0)
{ IS_NUMBER_OR_ZERO; cfg->val_sig_skew_max = (int32_t)atoi(val); }
@@ -504,7 +510,8 @@ int config_set_option(struct config_file* cfg, const char* opt,
* stub-zone, name, stub-addr, stub-host, stub-prime
* forward-first, stub-first,
* forward-zone, name, forward-addr, forward-host,
- * ratelimit-for-domain, ratelimit-below-domain */
+ * ratelimit-for-domain, ratelimit-below-domain,
+ * local-zone-tag */
return 0;
}
return 1;
@@ -628,9 +635,23 @@ config_collate_cat(struct config_strlist* list)
/** compare and print list option */
#define O_LS2(opt, name, lst) if(strcmp(opt, name)==0) { \
struct config_str2list* p = cfg->lst; \
- for(p = cfg->lst; p; p = p->next) \
- snprintf(buf, len, "%s %s\n", p->str, p->str2); \
+ for(p = cfg->lst; p; p = p->next) { \
+ snprintf(buf, len, "%s %s", p->str, p->str2); \
func(buf, arg); \
+ } \
+ }
+/** compare and print taglist option */
+#define O_LTG(opt, name, lst) if(strcmp(opt, name)==0) { \
+ char* tmpstr = NULL; \
+ struct config_strbytelist *p = cfg->lst; \
+ for(p = cfg->lst; p; p = p->next) {\
+ tmpstr = config_taglist2str(cfg, p->str2, p->str2len); \
+ if(tmpstr) {\
+ snprintf(buf, len, "%s %s", p->str, tmpstr); \
+ func(buf, arg); \
+ free(tmpstr); \
+ } \
+ } \
}
int
@@ -664,6 +685,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_MEM(opt, "so-sndbuf", so_sndbuf)
else O_YNO(opt, "so-reuseport", so_reuseport)
else O_YNO(opt, "ip-transparent", ip_transparent)
+ else O_YNO(opt, "ip-freebind", ip_freebind)
else O_MEM(opt, "rrset-cache-size", rrset_cache_size)
else O_DEC(opt, "rrset-cache-slabs", rrset_cache_slabs)
else O_YNO(opt, "prefetch-key", prefetch_key)
@@ -750,6 +772,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_YNO(opt, "insecure-lan-zones", insecure_lan_zones)
else O_DEC(opt, "max-udp-size", max_udp_size)
else O_STR(opt, "python-script", python_script)
+ else O_YNO(opt, "disable-dnssec-lame-check", disable_dnssec_lame_check)
else O_DEC(opt, "ratelimit", ratelimit)
else O_MEM(opt, "ratelimit-size", ratelimit_size)
else O_DEC(opt, "ratelimit-slabs", ratelimit_slabs)
@@ -759,6 +782,8 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_DEC(opt, "val-sig-skew-min", val_sig_skew_min)
else O_DEC(opt, "val-sig-skew-max", val_sig_skew_max)
else O_YNO(opt, "qname-minimisation", qname_minimisation)
+ else O_IFC(opt, "define-tag", num_tags, tagname)
+ else O_LTG(opt, "local-zone-tag", local_zone_tags)
/* not here:
* outgoing-permit, outgoing-avoid - have list of ports
* local-zone - zones and nodefault variables
@@ -931,6 +956,33 @@ config_delstubs(struct config_stub* p)
}
}
+/** delete string array */
+static void
+config_del_strarray(char** array, int num)
+{
+ int i;
+ if(!array)
+ return;
+ for(i=0; i<num; i++) {
+ free(array[i]);
+ }
+ free(array);
+}
+
+/** delete stringbytelist */
+static void
+config_del_strbytelist(struct config_strbytelist* p)
+{
+ struct config_strbytelist* np;
+ while(p) {
+ np = p->next;
+ free(p->str);
+ free(p->str2);
+ free(p);
+ p = np;
+ }
+}
+
void
config_delete(struct config_file* cfg)
{
@@ -943,18 +995,8 @@ config_delete(struct config_file* cfg)
free(cfg->target_fetch_policy);
free(cfg->ssl_service_key);
free(cfg->ssl_service_pem);
- if(cfg->ifs) {
- int i;
- for(i=0; i<cfg->num_ifs; i++)
- free(cfg->ifs[i]);
- free(cfg->ifs);
- }
- if(cfg->out_ifs) {
- int i;
- for(i=0; i<cfg->num_out_ifs; i++)
- free(cfg->out_ifs[i]);
- free(cfg->out_ifs);
- }
+ config_del_strarray(cfg->ifs, cfg->num_ifs);
+ config_del_strarray(cfg->out_ifs, cfg->num_out_ifs);
config_delstubs(cfg->stubs);
config_delstubs(cfg->forwards);
config_delstrlist(cfg->donotqueryaddrs);
@@ -978,6 +1020,8 @@ config_delete(struct config_file* cfg)
config_deldblstrlist(cfg->local_zones);
config_delstrlist(cfg->local_zones_nodefault);
config_delstrlist(cfg->local_data);
+ config_del_strarray(cfg->tagname, cfg->num_tags);
+ config_del_strbytelist(cfg->local_zone_tags);
config_delstrlist(cfg->control_ifs);
free(cfg->server_key_file);
free(cfg->server_cert_file);
@@ -1166,6 +1210,24 @@ cfg_str2list_insert(struct config_str2list** head, char* item, char* i2)
return 1;
}
+int
+cfg_strbytelist_insert(struct config_strbytelist** head, char* item,
+ uint8_t* i2, size_t i2len)
+{
+ struct config_strbytelist* s;
+ if(!item || !i2 || !head)
+ return 0;
+ s = (struct config_strbytelist*)calloc(1, sizeof(*s));
+ if(!s)
+ return 0;
+ s->str = item;
+ s->str2 = i2;
+ s->str2len = i2len;
+ s->next = *head;
+ *head = s;
+ return 1;
+}
+
time_t
cfg_convert_timeval(const char* str)
{
@@ -1270,6 +1332,122 @@ cfg_parse_memsize(const char* str, size_t* res)
return 1;
}
+int
+find_tag_id(struct config_file* cfg, const char* tag)
+{
+ int i;
+ for(i=0; i<cfg->num_tags; i++) {
+ if(strcmp(cfg->tagname[i], tag) == 0)
+ return i;
+ }
+ return -1;
+}
+
+int
+config_add_tag(struct config_file* cfg, const char* tag)
+{
+ char** newarray;
+ char* newtag;
+ if(find_tag_id(cfg, tag) != -1)
+ return 1; /* nothing to do */
+ newarray = (char**)malloc(sizeof(char*)*(cfg->num_tags+1));
+ if(!newarray)
+ return 0;
+ newtag = strdup(tag);
+ if(!newtag) {
+ free(newarray);
+ return 0;
+ }
+ if(cfg->tagname) {
+ memcpy(newarray, cfg->tagname, sizeof(char*)*cfg->num_tags);
+ free(cfg->tagname);
+ }
+ newarray[cfg->num_tags++] = newtag;
+ cfg->tagname = newarray;
+ return 1;
+}
+
+/** set a bit in a bit array */
+static void
+cfg_set_bit(uint8_t* bitlist, size_t len, int id)
+{
+ int pos = id/8;
+ log_assert((size_t)pos < len);
+ bitlist[pos] |= 1<<(id%8);
+}
+
+uint8_t* config_parse_taglist(struct config_file* cfg, char* str,
+ size_t* listlen)
+{
+ uint8_t* taglist = NULL;
+ size_t len = 0;
+ char* p, *s;
+
+ /* allocate */
+ if(cfg->num_tags == 0) {
+ log_err("parse taglist, but no tags defined");
+ return 0;
+ }
+ len = (size_t)(cfg->num_tags+7)/8;
+ taglist = calloc(1, len);
+ if(!taglist) {
+ log_err("out of memory");
+ return 0;
+ }
+
+ /* parse */
+ s = str;
+ while((p=strsep(&s, " \t\n")) != NULL) {
+ if(*p) {
+ int id = find_tag_id(cfg, p);
+ /* set this bit in the bitlist */
+ if(id == -1) {
+ log_err("unknown tag: %s", p);
+ free(taglist);
+ return 0;
+ }
+ cfg_set_bit(taglist, len, id);
+ }
+ }
+
+ *listlen = len;
+ return taglist;
+}
+
+char* config_taglist2str(struct config_file* cfg, uint8_t* taglist,
+ size_t taglen)
+{
+ char buf[10240];
+ size_t i, j, len = 0;
+ buf[0] = 0;
+ for(i=0; i<taglen; i++) {
+ if(taglist[i] == 0)
+ continue;
+ for(j=0; j<8; j++) {
+ if((taglist[i] & (1<<j)) != 0) {
+ size_t id = i*8 + j;
+ snprintf(buf+len, sizeof(buf)-len, "%s%s",
+ (len==0?"":" "), cfg->tagname[id]);
+ len += strlen(buf+len);
+ }
+ }
+ }
+ return strdup(buf);
+}
+
+int taglist_intersect(uint8_t* list1, size_t list1len, uint8_t* list2,
+ size_t list2len)
+{
+ size_t i;
+ if(!list1 || !list2)
+ return 0;
+ for(i=0; i<list1len && i<list2len; i++) {
+ if((list1[i] & list2[i]) != 0)
+ return 1;
+ }
+ return 0;
+}
+
void
config_apply(struct config_file* config)
{
diff --git a/contrib/unbound/util/config_file.h b/contrib/unbound/util/config_file.h
index ef823fb88d3a..a51cdb464c0c 100644
--- a/contrib/unbound/util/config_file.h
+++ b/contrib/unbound/util/config_file.h
@@ -44,6 +44,7 @@
struct config_stub;
struct config_strlist;
struct config_str2list;
+struct config_strbytelist;
struct module_qstate;
struct sock_list;
struct ub_packed_rrset_key;
@@ -142,6 +143,8 @@ struct config_file {
int so_reuseport;
/** IP_TRANSPARENT socket option requested on port 53 sockets */
int ip_transparent;
+ /** IP_FREEBIND socket option request on port 53 sockets */
+ int ip_freebind;
/** number of interfaces to open. If 0 default all interfaces. */
int num_ifs;
@@ -293,6 +296,12 @@ struct config_file {
int unblock_lan_zones;
/** insecure lan zones (don't validate AS112 zones) */
int insecure_lan_zones;
+ /** list of zonename, tagbitlist */
+ struct config_strbytelist* local_zone_tags;
+ /** tag list, array with tagname[i] is malloced string */
+ char** tagname;
+ /** number of items in the taglist */
+ int num_tags;
/** remote control section. enable toggle. */
int remote_control_enable;
@@ -358,6 +367,9 @@ struct config_file {
/** true to log dnstap FORWARDER_RESPONSE message events */
int dnstap_log_forwarder_response_messages;
+ /** true to disable DNSSEC lameness check in iterator */
+ int disable_dnssec_lame_check;
+
/** ratelimit 0 is off, otherwise qps (unless overridden) */
int ratelimit;
/** number of slabs for ratelimit cache */
@@ -421,6 +433,19 @@ struct config_str2list {
char* str2;
};
+/**
+ * List of string, bytestring for config options
+ */
+struct config_strbytelist {
+ /** next item in list */
+ struct config_strbytelist* next;
+ /** first string */
+ char* str;
+ /** second bytestring */
+ uint8_t* str2;
+ size_t str2len;
+};
+
/** List head for strlist processing, used for append operation. */
struct config_strlist_head {
/** first in list of text items */
@@ -560,6 +585,17 @@ int cfg_strlist_insert(struct config_strlist** head, char* item);
int cfg_str2list_insert(struct config_str2list** head, char* item, char* i2);
/**
+ * Insert string into strbytelist.
+ * @param head: pointer to str2list head variable.
+ * @param item: new item. malloced by caller. If NULL the insertion fails.
+ * @param i2: 2nd string, malloced by caller. If NULL the insertion fails.
+ * @param i2len: length of the i2 bytestring.
+ * @return: true on success.
+ */
+int cfg_strbytelist_insert(struct config_strbytelist** head, char* item,
+ uint8_t* i2, size_t i2len);
+
+/**
* Find stub in config list, also returns prevptr (for deletion).
* @param pp: call routine with pointer to a pointer to the start of the list,
* if the stub is found, on exit, the value contains a pointer to the
@@ -625,6 +661,54 @@ int cfg_count_numbers(const char* str);
int cfg_parse_memsize(const char* str, size_t* res);
/**
+ * Add a tag name to the config. It is added at the end with a new ID value.
+ * @param cfg: the config structure.
+ * @param tag: string (which is copied) with the name.
+ * @return: false on alloc failure.
+ */
+int config_add_tag(struct config_file* cfg, const char* tag);
+
+/**
+ * Find tag ID in the tag list.
+ * @param cfg: the config structure.
+ * @param tag: string with tag name to search for.
+ * @return: 0..(num_tags-1) with tag ID, or -1 if tagname is not found.
+ */
+int find_tag_id(struct config_file* cfg, const char* tag);
+
+/**
+ * parse taglist from string into bytestring with bitlist.
+ * @param cfg: the config structure (with tagnames)
+ * @param str: the string to parse. Parse puts 0 bytes in string.
+ * @param listlen: returns length of in bytes.
+ * @return malloced bytes with a bitlist of the tags. or NULL on parse error
+ * or malloc failure.
+ */
+uint8_t* config_parse_taglist(struct config_file* cfg, char* str,
+ size_t* listlen);
+
+/**
+ * convert tag bitlist to a malloced string with tag names. For debug output.
+ * @param cfg: the config structure (with tagnames)
+ * @param taglist: the tag bitlist.
+ * @param len: length of the tag bitlist.
+ * @return malloced string or NULL.
+ */
+char* config_taglist2str(struct config_file* cfg, uint8_t* taglist,
+ size_t len);
+
+/**
+ * see if two taglists intersect (have tags in common).
+ * @param list1: first tag bitlist.
+ * @param list1len: length in bytes of first list.
+ * @param list2: second tag bitlist.
+ * @param list2len: length in bytes of second list.
+ * @return true if there are tags in common, 0 if not.
+ */
+int taglist_intersect(uint8_t* list1, size_t list1len, uint8_t* list2,
+ size_t list2len);
+
+/**
* Parse local-zone directive into two strings and register it in the config.
* @param cfg: to put it in.
* @param val: argument strings to local-zone, "example.com nodefault".
diff --git a/contrib/unbound/util/configlexer.lex b/contrib/unbound/util/configlexer.lex
index ad49e37c51cb..852733b559be 100644
--- a/contrib/unbound/util/configlexer.lex
+++ b/contrib/unbound/util/configlexer.lex
@@ -236,6 +236,7 @@ so-rcvbuf{COLON} { YDVAR(1, VAR_SO_RCVBUF) }
so-sndbuf{COLON} { YDVAR(1, VAR_SO_SNDBUF) }
so-reuseport{COLON} { YDVAR(1, VAR_SO_REUSEPORT) }
ip-transparent{COLON} { YDVAR(1, VAR_IP_TRANSPARENT) }
+ip-freebind{COLON} { YDVAR(1, VAR_IP_FREEBIND) }
chroot{COLON} { YDVAR(1, VAR_CHROOT) }
username{COLON} { YDVAR(1, VAR_USERNAME) }
directory{COLON} { YDVAR(1, VAR_DIRECTORY) }
@@ -344,6 +345,8 @@ rrset-roundrobin{COLON} { YDVAR(1, VAR_RRSET_ROUNDROBIN) }
max-udp-size{COLON} { YDVAR(1, VAR_MAX_UDP_SIZE) }
dns64-prefix{COLON} { YDVAR(1, VAR_DNS64_PREFIX) }
dns64-synthall{COLON} { YDVAR(1, VAR_DNS64_SYNTHALL) }
+define-tag{COLON} { YDVAR(1, VAR_DEFINE_TAG) }
+local-zone-tag{COLON} { YDVAR(2, VAR_LOCAL_ZONE_TAG) }
dnstap{COLON} { YDVAR(0, VAR_DNSTAP) }
dnstap-enable{COLON} { YDVAR(1, VAR_DNSTAP_ENABLE) }
dnstap-socket-path{COLON} { YDVAR(1, VAR_DNSTAP_SOCKET_PATH) }
@@ -363,6 +366,7 @@ dnstap-log-forwarder-query-messages{COLON} {
YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES) }
dnstap-log-forwarder-response-messages{COLON} {
YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES) }
+disable-dnssec-lame-check{COLON} { YDVAR(1, VAR_DISABLE_DNSSEC_LAME_CHECK) }
ratelimit{COLON} { YDVAR(1, VAR_RATELIMIT) }
ratelimit-slabs{COLON} { YDVAR(1, VAR_RATELIMIT_SLABS) }
ratelimit-size{COLON} { YDVAR(1, VAR_RATELIMIT_SIZE) }
diff --git a/contrib/unbound/util/configparser.y b/contrib/unbound/util/configparser.y
index ea7acdb597ed..4ff18f0ce5c7 100644
--- a/contrib/unbound/util/configparser.y
+++ b/contrib/unbound/util/configparser.y
@@ -121,10 +121,11 @@ extern struct config_parser_state* cfg_parser;
%token VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES
%token VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES
%token VAR_HARDEN_ALGO_DOWNGRADE VAR_IP_TRANSPARENT
+%token VAR_DISABLE_DNSSEC_LAME_CHECK
%token VAR_RATELIMIT VAR_RATELIMIT_SLABS VAR_RATELIMIT_SIZE
%token VAR_RATELIMIT_FOR_DOMAIN VAR_RATELIMIT_BELOW_DOMAIN VAR_RATELIMIT_FACTOR
%token VAR_CAPS_WHITELIST VAR_CACHE_MAX_NEGATIVE_TTL VAR_PERMIT_SMALL_HOLDDOWN
-%token VAR_QNAME_MINIMISATION
+%token VAR_QNAME_MINIMISATION VAR_IP_FREEBIND VAR_DEFINE_TAG VAR_LOCAL_ZONE_TAG
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@@ -191,7 +192,9 @@ content_server: server_num_threads | server_verbosity | server_port |
server_ratelimit_size | server_ratelimit_for_domain |
server_ratelimit_below_domain | server_ratelimit_factor |
server_caps_whitelist | server_cache_max_negative_ttl |
- server_permit_small_holddown | server_qname_minimisation
+ server_permit_small_holddown | server_qname_minimisation |
+ server_ip_freebind | server_define_tag | server_local_zone_tag |
+ server_disable_dnssec_lame_check
;
stubstart: VAR_STUB_ZONE
{
@@ -662,6 +665,16 @@ server_ip_transparent: VAR_IP_TRANSPARENT STRING_ARG
free($2);
}
;
+server_ip_freebind: VAR_IP_FREEBIND STRING_ARG
+ {
+ OUTYY(("P(server_ip_freebind:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->ip_freebind =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
server_edns_buffer_size: VAR_EDNS_BUFFER_SIZE STRING_ARG
{
OUTYY(("P(server_edns_buffer_size:%s)\n", $2));
@@ -1286,6 +1299,39 @@ server_dns64_synthall: VAR_DNS64_SYNTHALL STRING_ARG
free($2);
}
;
+server_define_tag: VAR_DEFINE_TAG STRING_ARG
+ {
+ char* p, *s = $2;
+ OUTYY(("P(server_define_tag:%s)\n", $2));
+ while((p=strsep(&s, " \t\n")) != NULL) {
+ if(*p) {
+ if(!config_add_tag(cfg_parser->cfg, p))
+ yyerror("could not define-tag, "
+ "out of memory");
+ }
+ }
+ free($2);
+ }
+ ;
+server_local_zone_tag: VAR_LOCAL_ZONE_TAG STRING_ARG STRING_ARG
+ {
+ size_t len = 0;
+ uint8_t* bitlist = config_parse_taglist(cfg_parser->cfg, $3,
+ &len);
+ free($3);
+ OUTYY(("P(server_local_zone_tag:%s)\n", $2));
+ if(!bitlist)
+ yyerror("could not parse tags, (define-tag them first)");
+ if(bitlist) {
+ if(!cfg_strbytelist_insert(
+ &cfg_parser->cfg->local_zone_tags,
+ $2, bitlist, len)) {
+ yyerror("out of memory");
+ free($2);
+ }
+ }
+ }
+ ;
server_ratelimit: VAR_RATELIMIT STRING_ARG
{
OUTYY(("P(server_ratelimit:%s)\n", $2));
@@ -1643,6 +1689,15 @@ py_script: VAR_PYTHON_SCRIPT STRING_ARG
free(cfg_parser->cfg->python_script);
cfg_parser->cfg->python_script = $2;
}
+server_disable_dnssec_lame_check: VAR_DISABLE_DNSSEC_LAME_CHECK STRING_ARG
+ {
+ OUTYY(("P(disable_dnssec_lame_check:%s)\n", $2));
+ if (strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->disable_dnssec_lame_check =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
%%
/* parse helper routines could be here */
diff --git a/contrib/unbound/util/data/dname.c b/contrib/unbound/util/data/dname.c
index 79bf52ad4728..8fc475f7f3f1 100644
--- a/contrib/unbound/util/data/dname.c
+++ b/contrib/unbound/util/data/dname.c
@@ -256,11 +256,13 @@ dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2)
log_assert(len1 == len2 && len1 != 0);
/* compare labels */
while(len1--) {
- if(tolower((unsigned char)*d1++) != tolower((unsigned char)*d2++)) {
- if(tolower((unsigned char)d1[-1]) < tolower((unsigned char)d2[-1]))
+ if(tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) {
+ if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2))
return -1;
return 1;
}
+ d1++;
+ d2++;
}
len1 = *d1++;
len2 = *d2++;
@@ -281,8 +283,10 @@ dname_query_hash(uint8_t* dname, hashvalue_t h)
log_assert(lablen <= LDNS_MAX_LABELLEN);
labuf[0] = lablen;
i=0;
- while(lablen--)
- labuf[++i] = (uint8_t)tolower((unsigned char)*dname++);
+ while(lablen--) {
+ labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
+ dname++;
+ }
h = hashlittle(labuf, labuf[0] + 1, h);
lablen = *dname++;
}
@@ -309,8 +313,10 @@ dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_t h)
log_assert(lablen <= LDNS_MAX_LABELLEN);
labuf[0] = lablen;
i=0;
- while(lablen--)
- labuf[++i] = (uint8_t)tolower((unsigned char)*dname++);
+ while(lablen--) {
+ labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
+ dname++;
+ }
h = hashlittle(labuf, labuf[0] + 1, h);
lablen = *dname++;
}
diff --git a/contrib/unbound/util/data/msgencode.c b/contrib/unbound/util/data/msgencode.c
index 43464e9bbe0c..034bb24bd6e4 100644
--- a/contrib/unbound/util/data/msgencode.c
+++ b/contrib/unbound/util/data/msgencode.c
@@ -717,16 +717,23 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
uint16_t
calc_edns_field_size(struct edns_data* edns)
{
+ size_t rdatalen = 0;
+ struct edns_option* opt;
if(!edns || !edns->edns_present)
return 0;
- /* domain root '.' + type + class + ttl + rdatalen(=0) */
- return 1 + 2 + 2 + 4 + 2;
+ for(opt = edns->opt_list; opt; opt = opt->next) {
+ rdatalen += 4 + opt->opt_len;
+ }
+ /* domain root '.' + type + class + ttl + rdatalen */
+ return 1 + 2 + 2 + 4 + 2 + rdatalen;
}
void
attach_edns_record(sldns_buffer* pkt, struct edns_data* edns)
{
size_t len;
+ size_t rdatapos;
+ struct edns_option* opt;
if(!edns || !edns->edns_present)
return;
/* inc additional count */
@@ -742,7 +749,18 @@ attach_edns_record(sldns_buffer* pkt, struct edns_data* edns)
sldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */
sldns_buffer_write_u8(pkt, edns->edns_version);
sldns_buffer_write_u16(pkt, edns->bits);
+ rdatapos = sldns_buffer_position(pkt);
sldns_buffer_write_u16(pkt, 0); /* rdatalen */
+ /* write rdata */
+ for(opt=edns->opt_list; opt; opt=opt->next) {
+ sldns_buffer_write_u16(pkt, opt->opt_code);
+ sldns_buffer_write_u16(pkt, opt->opt_len);
+ if(opt->opt_len != 0)
+ sldns_buffer_write(pkt, opt->opt_data, opt->opt_len);
+ }
+ if(edns->opt_list)
+ sldns_buffer_write_u16_at(pkt, rdatapos,
+ sldns_buffer_position(pkt)-rdatapos-2);
sldns_buffer_flip(pkt);
}
diff --git a/contrib/unbound/util/data/msgparse.c b/contrib/unbound/util/data/msgparse.c
index 108c9dacb39b..1d565c1ea280 100644
--- a/contrib/unbound/util/data/msgparse.c
+++ b/contrib/unbound/util/data/msgparse.c
@@ -38,6 +38,7 @@
*/
#include "config.h"
#include "util/data/msgparse.h"
+#include "util/data/msgreply.h"
#include "util/data/dname.h"
#include "util/data/packed_rrset.h"
#include "util/storage/lookup3.h"
@@ -933,13 +934,41 @@ parse_packet(sldns_buffer* pkt, struct msg_parse* msg, struct regional* region)
return 0;
}
+/** parse EDNS options from EDNS wireformat rdata */
+static int
+parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len,
+ struct edns_data* edns, struct regional* region)
+{
+ /* while still more options, and have code+len to read */
+ /* ignores partial content (i.e. rdata len 3) */
+ while(rdata_len >= 4) {
+ uint16_t opt_code = sldns_read_uint16(rdata_ptr);
+ uint16_t opt_len = sldns_read_uint16(rdata_ptr+2);
+ rdata_ptr += 4;
+ rdata_len -= 4;
+ if(opt_len > rdata_len)
+ break; /* option code partial */
+ if(!edns_opt_append(edns, region, opt_code, opt_len,
+ rdata_ptr)) {
+ log_err("out of memory");
+ return 0;
+ }
+ rdata_ptr += opt_len;
+ rdata_len -= opt_len;
+ }
+ return 1;
+}
+
int
-parse_extract_edns(struct msg_parse* msg, struct edns_data* edns)
+parse_extract_edns(struct msg_parse* msg, struct edns_data* edns,
+ struct regional* region)
{
struct rrset_parse* rrset = msg->rrset_first;
struct rrset_parse* prev = 0;
struct rrset_parse* found = 0;
struct rrset_parse* found_prev = 0;
+ size_t rdata_len;
+ uint8_t* rdata_ptr;
/* since the class encodes the UDP size, we cannot use hash table to
* find the EDNS OPT record. Scan the packet. */
while(rrset) {
@@ -986,13 +1015,25 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns)
edns->edns_version = found->rr_last->ttl_data[1];
edns->bits = sldns_read_uint16(&found->rr_last->ttl_data[2]);
edns->udp_size = ntohs(found->rrset_class);
- /* ignore rdata and rrsigs */
+ edns->opt_list = NULL;
+
+ /* take the options */
+ rdata_len = found->rr_first->size;
+ rdata_ptr = found->rr_first->ttl_data+6;
+ if(!parse_edns_options(rdata_ptr, rdata_len, edns, region))
+ return 0;
+
+ /* ignore rrsigs */
+
return 0;
}
int
-parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns)
+parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns,
+ struct regional* region)
{
+ size_t rdata_len;
+ uint8_t* rdata_ptr;
log_assert(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) == 1);
log_assert(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) == 0);
log_assert(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) == 0);
@@ -1017,6 +1058,17 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns)
edns->ext_rcode = sldns_buffer_read_u8(pkt); /* ttl used for bits */
edns->edns_version = sldns_buffer_read_u8(pkt);
edns->bits = sldns_buffer_read_u16(pkt);
- /* ignore rdata and rrsigs */
+ edns->opt_list = NULL;
+
+ /* take the options */
+ rdata_len = sldns_buffer_read_u16(pkt);
+ if(sldns_buffer_remaining(pkt) < rdata_len)
+ return LDNS_RCODE_FORMERR;
+ rdata_ptr = sldns_buffer_current(pkt);
+ if(!parse_edns_options(rdata_ptr, rdata_len, edns, region))
+ return LDNS_RCODE_SERVFAIL;
+
+ /* ignore rrsigs */
+
return 0;
}
diff --git a/contrib/unbound/util/data/msgparse.h b/contrib/unbound/util/data/msgparse.h
index 44497c8ca381..cae988ff9950 100644
--- a/contrib/unbound/util/data/msgparse.h
+++ b/contrib/unbound/util/data/msgparse.h
@@ -69,6 +69,7 @@ struct sldns_buffer;
struct rrset_parse;
struct rr_parse;
struct regional;
+struct edns_option;
/** number of buckets in parse rrset hash table. Must be power of 2. */
#define PARSE_TABLE_SIZE 32
@@ -202,7 +203,8 @@ struct rr_parse {
/**
* EDNS data storage
- * EDNS rdata is ignored.
+ * rdata is parsed in a list (has accessor functions). allocated in a
+ * region.
*/
struct edns_data {
/** if EDNS OPT record was present */
@@ -215,6 +217,22 @@ struct edns_data {
uint16_t bits;
/** UDP reassembly size. */
uint16_t udp_size;
+ /** rdata element list, or NULL if none */
+ struct edns_option* opt_list;
+};
+
+/**
+ * EDNS option
+ */
+struct edns_option {
+ /** next item in list */
+ struct edns_option* next;
+ /** type of this edns option */
+ uint16_t opt_code;
+ /** length of this edns option (cannot exceed uint16 in encoding) */
+ size_t opt_len;
+ /** data of this edns option; allocated in region, or NULL if len=0 */
+ uint8_t* opt_data;
};
/**
@@ -249,10 +267,12 @@ int parse_packet(struct sldns_buffer* pkt, struct msg_parse* msg,
* @param msg: parsed message structure. Modified on exit, if EDNS was present
* it is removed from the additional section.
* @param edns: the edns data is stored here. Does not have to be initialised.
+ * @param region: region to alloc results in (edns option contents)
* @return: 0 on success. or an RCODE on an error.
* RCODE formerr if OPT in wrong section, and so on.
*/
-int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns);
+int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns,
+ struct regional* region);
/**
* If EDNS data follows a query section, extract it and initialize edns struct.
@@ -260,10 +280,12 @@ int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns);
* section. At end, right after EDNS data or no movement if failed.
* @param edns: the edns data allocated by the caller. Does not have to be
* initialised.
+ * @param region: region to alloc results in (edns option contents)
* @return: 0 on success, or an RCODE on error.
* RCODE formerr if OPT is badly formatted and so on.
*/
-int parse_edns_from_pkt(struct sldns_buffer* pkt, struct edns_data* edns);
+int parse_edns_from_pkt(struct sldns_buffer* pkt, struct edns_data* edns,
+ struct regional* region);
/**
* Calculate hash value for rrset in packet.
diff --git a/contrib/unbound/util/data/msgreply.c b/contrib/unbound/util/data/msgreply.c
index 06593ffe1b27..f8a24918dcad 100644
--- a/contrib/unbound/util/data/msgreply.c
+++ b/contrib/unbound/util/data/msgreply.c
@@ -461,7 +461,7 @@ int reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc,
if((ret = parse_packet(pkt, msg, region)) != 0) {
return ret;
}
- if((ret = parse_extract_edns(msg, edns)) != 0)
+ if((ret = parse_extract_edns(msg, edns, region)) != 0)
return ret;
/* parse OK, allocate return structures */
@@ -857,3 +857,155 @@ reply_all_rrsets_secure(struct reply_info* rep)
}
return 1;
}
+
+int edns_opt_append(struct edns_data* edns, struct regional* region,
+ uint16_t code, size_t len, uint8_t* data)
+{
+ struct edns_option** prevp;
+ struct edns_option* opt;
+
+ /* allocate new element */
+ opt = (struct edns_option*)regional_alloc(region, sizeof(*opt));
+ if(!opt)
+ return 0;
+ opt->next = NULL;
+ opt->opt_code = code;
+ opt->opt_len = len;
+ opt->opt_data = regional_alloc_init(region, data, len);
+ if(!opt->opt_data)
+ return 0;
+
+ /* append at end of list */
+ prevp = &edns->opt_list;
+ while(*prevp != NULL)
+ prevp = &((*prevp)->next);
+ *prevp = opt;
+ return 1;
+}
+
+int edns_opt_inplace_reply(struct edns_data* edns, struct regional* region)
+{
+ (void)region;
+ /* remove all edns options from the reply, because only the
+ * options that we understand should be in the reply
+ * (sec 6.1.2 RFC 6891) */
+ edns->opt_list = NULL;
+ return 1;
+}
+
+struct edns_option* edns_opt_copy_region(struct edns_option* list,
+ struct regional* region)
+{
+ struct edns_option* result = NULL, *cur = NULL, *s;
+ while(list) {
+ /* copy edns option structure */
+ s = regional_alloc_init(region, list, sizeof(*list));
+ if(!s) return NULL;
+ s->next = NULL;
+
+ /* copy option data */
+ if(s->opt_data) {
+ s->opt_data = regional_alloc_init(region, s->opt_data,
+ s->opt_len);
+ if(!s->opt_data)
+ return NULL;
+ }
+
+ /* link into list */
+ if(cur)
+ cur->next = s;
+ else result = s;
+ cur = s;
+
+ /* examine next element */
+ list = list->next;
+ }
+ return result;
+}
+
+int edns_opt_compare(struct edns_option* p, struct edns_option* q)
+{
+ if(!p && !q) return 0;
+ if(!p) return -1;
+ if(!q) return 1;
+ log_assert(p && q);
+ if(p->opt_code != q->opt_code)
+ return (int)q->opt_code - (int)p->opt_code;
+ if(p->opt_len != q->opt_len)
+ return (int)q->opt_len - (int)p->opt_len;
+ if(p->opt_len != 0)
+ return memcmp(p->opt_data, q->opt_data, p->opt_len);
+ return 0;
+}
+
+int edns_opt_list_compare(struct edns_option* p, struct edns_option* q)
+{
+ int r;
+ while(p && q) {
+ r = edns_opt_compare(p, q);
+ if(r != 0)
+ return r;
+ p = p->next;
+ q = q->next;
+ }
+ if(p || q) {
+ /* uneven length lists */
+ if(p) return 1;
+ if(q) return -1;
+ }
+ return 0;
+}
+
+void edns_opt_list_free(struct edns_option* list)
+{
+ struct edns_option* n;
+ while(list) {
+ free(list->opt_data);
+ n = list->next;
+ free(list);
+ list = n;
+ }
+}
+
+struct edns_option* edns_opt_copy_alloc(struct edns_option* list)
+{
+ struct edns_option* result = NULL, *cur = NULL, *s;
+ while(list) {
+ /* copy edns option structure */
+ s = memdup(list, sizeof(*list));
+ if(!s) {
+ edns_opt_list_free(result);
+ return NULL;
+ }
+ s->next = NULL;
+
+ /* copy option data */
+ if(s->opt_data) {
+ s->opt_data = memdup(s->opt_data, s->opt_len);
+ if(!s->opt_data) {
+ edns_opt_list_free(result);
+ return NULL;
+ }
+ }
+
+ /* link into list */
+ if(cur)
+ cur->next = s;
+ else result = s;
+ cur = s;
+
+ /* examine next element */
+ list = list->next;
+ }
+ return result;
+}
+
+struct edns_option* edns_opt_find(struct edns_option* list, uint16_t code)
+{
+ struct edns_option* p;
+ for(p=list; p; p=p->next) {
+ if(p->opt_code == code)
+ return p;
+ }
+ return NULL;
+}
diff --git a/contrib/unbound/util/data/msgreply.h b/contrib/unbound/util/data/msgreply.h
index 708897950089..b542b75e6970 100644
--- a/contrib/unbound/util/data/msgreply.h
+++ b/contrib/unbound/util/data/msgreply.h
@@ -437,4 +437,56 @@ void log_dns_msg(const char* str, struct query_info* qinfo,
void log_query_info(enum verbosity_value v, const char* str,
struct query_info* qinf);
+/**
+ * Append edns option to edns data structure
+ */
+int edns_opt_append(struct edns_data* edns, struct regional* region,
+ uint16_t code, size_t len, uint8_t* data);
+
+/**
+ * Find edns option in edns list
+ * @param list: list of edns options (eg. edns.opt_list)
+ * @param code: opt code to find.
+ * @return NULL or the edns_option element.
+ */
+struct edns_option* edns_opt_find(struct edns_option* list, uint16_t code);
+
+/**
+ * Transform edns data structure from query structure into reply structure.
+ * In place transform, for errors and cache replies.
+ * @param edns: on input contains the edns from the query. On output contains
+ * the edns for the answer. Add new options to the opt_list to put them
+ * in the answer (allocated in the region, with edns_opt_append).
+ * @param region: to allocate stuff in.
+ * @return false on failure (servfail to client, or for some error encodings,
+ * no EDNS options in the answer).
+ */
+int edns_opt_inplace_reply(struct edns_data* edns, struct regional* region);
+
+/**
+ * Copy edns option list allocated to the new region
+ */
+struct edns_option* edns_opt_copy_region(struct edns_option* list,
+ struct regional* region);
+
+/**
+ * Copy edns option list allocated with malloc
+ */
+struct edns_option* edns_opt_copy_alloc(struct edns_option* list);
+
+/**
+ * Free edns option list allocated with malloc
+ */
+void edns_opt_list_free(struct edns_option* list);
+
+/**
+ * Compare an edns option. (not entire list). Also compares contents.
+ */
+int edns_opt_compare(struct edns_option* p, struct edns_option* q);
+
+/**
+ * Compare edns option lists, also the order and contents of edns-options.
+ */
+int edns_opt_list_compare(struct edns_option* p, struct edns_option* q);
+
#endif /* UTIL_DATA_MSGREPLY_H */
diff --git a/contrib/unbound/util/fptr_wlist.c b/contrib/unbound/util/fptr_wlist.c
index 1397e9c1359d..80a23f20361b 100644
--- a/contrib/unbound/util/fptr_wlist.c
+++ b/contrib/unbound/util/fptr_wlist.c
@@ -78,6 +78,9 @@
#ifdef WITH_PYTHONMODULE
#include "pythonmod/pythonmod.h"
#endif
+#ifdef USE_CACHEDB
+#include "cachedb/cachedb.h"
+#endif
int
fptr_whitelist_comm_point(comm_point_callback_t *fptr)
@@ -264,8 +267,8 @@ int
fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
uint16_t flags, int dnssec, int want_dnssec, int nocaps,
- struct sockaddr_storage* addr, socklen_t addrlen,
- uint8_t* zone, size_t zonelen,
+ struct edns_option* opt_list, struct sockaddr_storage* addr,
+ socklen_t addrlen, uint8_t* zone, size_t zonelen,
struct module_qstate* q))
{
if(fptr == &worker_send_query) return 1;
@@ -315,6 +318,9 @@ fptr_whitelist_mod_init(int (*fptr)(struct module_env* env, int id))
#ifdef WITH_PYTHONMODULE
else if(fptr == &pythonmod_init) return 1;
#endif
+#ifdef USE_CACHEDB
+ else if(fptr == &cachedb_init) return 1;
+#endif
return 0;
}
@@ -327,6 +333,9 @@ fptr_whitelist_mod_deinit(void (*fptr)(struct module_env* env, int id))
#ifdef WITH_PYTHONMODULE
else if(fptr == &pythonmod_deinit) return 1;
#endif
+#ifdef USE_CACHEDB
+ else if(fptr == &cachedb_deinit) return 1;
+#endif
return 0;
}
@@ -340,6 +349,9 @@ fptr_whitelist_mod_operate(void (*fptr)(struct module_qstate* qstate,
#ifdef WITH_PYTHONMODULE
else if(fptr == &pythonmod_operate) return 1;
#endif
+#ifdef USE_CACHEDB
+ else if(fptr == &cachedb_operate) return 1;
+#endif
return 0;
}
@@ -353,6 +365,9 @@ fptr_whitelist_mod_inform_super(void (*fptr)(
#ifdef WITH_PYTHONMODULE
else if(fptr == &pythonmod_inform_super) return 1;
#endif
+#ifdef USE_CACHEDB
+ else if(fptr == &cachedb_inform_super) return 1;
+#endif
return 0;
}
@@ -366,6 +381,9 @@ fptr_whitelist_mod_clear(void (*fptr)(struct module_qstate* qstate,
#ifdef WITH_PYTHONMODULE
else if(fptr == &pythonmod_clear) return 1;
#endif
+#ifdef USE_CACHEDB
+ else if(fptr == &cachedb_clear) return 1;
+#endif
return 0;
}
@@ -378,6 +396,9 @@ fptr_whitelist_mod_get_mem(size_t (*fptr)(struct module_env* env, int id))
#ifdef WITH_PYTHONMODULE
else if(fptr == &pythonmod_get_mem) return 1;
#endif
+#ifdef USE_CACHEDB
+ else if(fptr == &cachedb_get_mem) return 1;
+#endif
return 0;
}
diff --git a/contrib/unbound/util/fptr_wlist.h b/contrib/unbound/util/fptr_wlist.h
index 10de5d816772..98ca21bb9671 100644
--- a/contrib/unbound/util/fptr_wlist.h
+++ b/contrib/unbound/util/fptr_wlist.h
@@ -212,7 +212,7 @@ int fptr_whitelist_hash_markdelfunc(lruhash_markdelfunc_t fptr);
int fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
uint16_t flags, int dnssec, int want_dnssec, int nocaps,
- struct sockaddr_storage* addr, socklen_t addrlen,
+ struct edns_option*, struct sockaddr_storage* addr, socklen_t addrlen,
uint8_t* zone, size_t zonelen,
struct module_qstate* q));
diff --git a/contrib/unbound/util/iana_ports.inc b/contrib/unbound/util/iana_ports.inc
index df5a560aff08..3856488ba347 100644
--- a/contrib/unbound/util/iana_ports.inc
+++ b/contrib/unbound/util/iana_ports.inc
@@ -3844,6 +3844,8 @@
4412,
4413,
4416,
+4418,
+4420,
4425,
4426,
4430,
@@ -3904,6 +3906,7 @@
4599,
4600,
4601,
+4621,
4658,
4659,
4660,
@@ -4222,6 +4225,7 @@
5436,
5437,
5443,
+5450,
5453,
5454,
5455,
@@ -4598,6 +4602,7 @@
7201,
7227,
7235,
+7244,
7262,
7272,
7273,
@@ -4651,6 +4656,7 @@
7570,
7574,
7588,
+7606,
7624,
7627,
7628,
@@ -5269,6 +5275,7 @@
23004,
23005,
23272,
+23294,
23333,
23400,
23401,
diff --git a/contrib/unbound/util/module.h b/contrib/unbound/util/module.h
index b9dde36e2f3c..c3ce8a40eda2 100644
--- a/contrib/unbound/util/module.h
+++ b/contrib/unbound/util/module.h
@@ -214,6 +214,8 @@ struct module_env {
* EDNS, the answer is likely to be useless for this domain.
* @param nocaps: do not use caps_for_id, use the qname as given.
* (ignored if caps_for_id is disabled).
+ * @param opt_list: set these EDNS options on the outgoing packet.
+ * or NULL if none (the list is deep-copied).
* @param addr: where to.
* @param addrlen: length of addr.
* @param zone: delegation point name.
@@ -226,9 +228,9 @@ struct module_env {
*/
struct outbound_entry* (*send_query)(uint8_t* qname, size_t qnamelen,
uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
- int want_dnssec, int nocaps, struct sockaddr_storage* addr,
- socklen_t addrlen, uint8_t* zone, size_t zonelen,
- struct module_qstate* q);
+ int want_dnssec, int nocaps, struct edns_option* opt_list,
+ struct sockaddr_storage* addr, socklen_t addrlen,
+ uint8_t* zone, size_t zonelen, struct module_qstate* q);
/**
* Detach-subqueries.
diff --git a/contrib/unbound/util/net_help.c b/contrib/unbound/util/net_help.c
index eb03cd0ae6d2..5d6c033d6597 100644
--- a/contrib/unbound/util/net_help.c
+++ b/contrib/unbound/util/net_help.c
@@ -783,7 +783,7 @@ void* outgoing_ssl_fd(void* sslctx, int fd)
#endif
}
-#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
+#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) && defined(CRYPTO_LOCK)
/** global lock list for openssl locks */
static lock_basic_t *ub_openssl_locks = NULL;
@@ -808,7 +808,7 @@ ub_crypto_lock_cb(int mode, int type, const char *ATTR_UNUSED(file),
int ub_openssl_lock_init(void)
{
-#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
+#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) && defined(CRYPTO_LOCK)
int i;
ub_openssl_locks = (lock_basic_t*)reallocarray(
NULL, (size_t)CRYPTO_num_locks(), sizeof(lock_basic_t));
@@ -825,7 +825,7 @@ int ub_openssl_lock_init(void)
void ub_openssl_lock_delete(void)
{
-#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
+#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) && defined(CRYPTO_LOCK)
int i;
if(!ub_openssl_locks)
return;
diff --git a/contrib/unbound/util/netevent.c b/contrib/unbound/util/netevent.c
index b827e6540b1f..bdb35739327b 100644
--- a/contrib/unbound/util/netevent.c
+++ b/contrib/unbound/util/netevent.c
@@ -40,6 +40,7 @@
*/
#include "config.h"
#include "util/netevent.h"
+#include "util/ub_event.h"
#include "util/log.h"
#include "util/net_help.h"
#include "util/fptr_wlist.h"
@@ -89,48 +90,29 @@
#define NUM_UDP_PER_SELECT 1
#endif
-/* We define libevent structures here to hide the libevent stuff. */
-
-#ifdef USE_MINI_EVENT
-# ifdef USE_WINSOCK
-# include "util/winsock_event.h"
-# else
-# include "util/mini_event.h"
-# endif /* USE_WINSOCK */
-#else /* USE_MINI_EVENT */
- /* we use libevent */
-# ifdef HAVE_EVENT_H
-# include <event.h>
-# else
-# include "event2/event.h"
-# include "event2/event_struct.h"
-# include "event2/event_compat.h"
-# endif
-#endif /* USE_MINI_EVENT */
-
/**
- * The internal event structure for keeping libevent info for the event.
+ * The internal event structure for keeping ub_event info for the event.
* Possibly other structures (list, tree) this is part of.
*/
struct internal_event {
/** the comm base */
struct comm_base* base;
- /** libevent event type, alloced here */
- struct event ev;
+ /** ub_event event type */
+ struct ub_event* ev;
};
/**
* Internal base structure, so that every thread has its own events.
*/
struct internal_base {
- /** libevent event_base type. */
- struct event_base* base;
+ /** ub_event event_base type. */
+ struct ub_event_base* base;
/** seconds time pointer points here */
time_t secs;
/** timeval with current time */
struct timeval now;
/** the event used for slow_accept timeouts */
- struct event slow_accept;
+ struct ub_event* slow_accept;
/** true if slow_accept is enabled */
int slow_accept_enabled;
};
@@ -139,10 +121,12 @@ struct internal_base {
* Internal timer structure, to store timer event in.
*/
struct internal_timer {
+ /** the super struct from which derived */
+ struct comm_timer super;
/** the comm base */
struct comm_base* base;
- /** libevent event type, alloced here */
- struct event ev;
+ /** ub_event event type */
+ struct ub_event* ev;
/** is timer enabled */
uint8_t enabled;
};
@@ -151,8 +135,8 @@ struct internal_timer {
* Internal signal structure, to store signal event in.
*/
struct internal_signal {
- /** libevent event type, alloced here */
- struct event ev;
+ /** ub_event event type */
+ struct ub_event* ev;
/** next in signal list */
struct internal_signal* next;
};
@@ -164,26 +148,13 @@ static struct comm_point* comm_point_create_tcp_handler(
/* -------- End of local definitions -------- */
-#ifdef USE_MINI_EVENT
-/** minievent updates the time when it blocks. */
-#define comm_base_now(x) /* nothing to do */
-#else /* !USE_MINI_EVENT */
-/** fillup the time values in the event base */
-static void
-comm_base_now(struct comm_base* b)
-{
- if(gettimeofday(&b->eb->now, NULL) < 0) {
- log_err("gettimeofday: %s", strerror(errno));
- }
- b->eb->secs = (time_t)b->eb->now.tv_sec;
-}
-#endif /* USE_MINI_EVENT */
-
struct comm_base*
comm_base_create(int sigs)
{
struct comm_base* b = (struct comm_base*)calloc(1,
sizeof(struct comm_base));
+ const char *evnm="event", *evsys="", *evmethod="";
+
if(!b)
return NULL;
b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base));
@@ -191,55 +162,20 @@ comm_base_create(int sigs)
free(b);
return NULL;
}
-#ifdef USE_MINI_EVENT
- (void)sigs;
- /* use mini event time-sharing feature */
- b->eb->base = event_init(&b->eb->secs, &b->eb->now);
-#else
-# if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)
- /* libev */
- if(sigs)
- b->eb->base=(struct event_base *)ev_default_loop(EVFLAG_AUTO);
- else
- b->eb->base=(struct event_base *)ev_loop_new(EVFLAG_AUTO);
-# else
- (void)sigs;
-# ifdef HAVE_EVENT_BASE_NEW
- b->eb->base = event_base_new();
-# else
- b->eb->base = event_init();
-# endif
-# endif
-#endif
+ b->eb->base = ub_default_event_base(sigs, &b->eb->secs, &b->eb->now);
if(!b->eb->base) {
free(b->eb);
free(b);
return NULL;
}
- comm_base_now(b);
- /* avoid event_get_method call which causes crashes even when
- * not printing, because its result is passed */
- verbose(VERB_ALGO,
-#if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)
- "libev"
-#elif defined(USE_MINI_EVENT)
- "event "
-#else
- "libevent "
-#endif
- "%s uses %s method.",
- event_get_version(),
-#ifdef HAVE_EVENT_BASE_GET_METHOD
- event_base_get_method(b->eb->base)
-#else
- "not_obtainable"
-#endif
- );
+ ub_comm_base_now(b);
+ ub_get_event_sys(b->eb->base, &evnm, &evsys, &evmethod);
+ verbose(VERB_ALGO, "%s %s user %s method.", evnm, evsys, evmethod);
return b;
}
struct comm_base*
-comm_base_create_event(struct event_base* base)
+comm_base_create_event(struct ub_event_base* base)
{
struct comm_base* b = (struct comm_base*)calloc(1,
sizeof(struct comm_base));
@@ -251,7 +187,7 @@ comm_base_create_event(struct event_base* base)
return NULL;
}
b->eb->base = base;
- comm_base_now(b);
+ ub_comm_base_now(b);
return b;
}
@@ -261,18 +197,12 @@ comm_base_delete(struct comm_base* b)
if(!b)
return;
if(b->eb->slow_accept_enabled) {
- if(event_del(&b->eb->slow_accept) != 0) {
+ if(ub_event_del(b->eb->slow_accept) != 0) {
log_err("could not event_del slow_accept");
}
+ ub_event_free(b->eb->slow_accept);
}
-#ifdef USE_MINI_EVENT
- event_base_free(b->eb->base);
-#elif defined(HAVE_EVENT_BASE_FREE) && defined(HAVE_EVENT_BASE_ONCE)
- /* only libevent 1.2+ has it, but in 1.2 it is broken -
- assertion fails on signal handling ev that is not deleted
- in libevent 1.3c (event_base_once appears) this is fixed. */
- event_base_free(b->eb->base);
-#endif /* HAVE_EVENT_BASE_FREE and HAVE_EVENT_BASE_ONCE */
+ ub_event_base_free(b->eb->base);
b->eb->base = NULL;
free(b->eb);
free(b);
@@ -284,9 +214,10 @@ comm_base_delete_no_base(struct comm_base* b)
if(!b)
return;
if(b->eb->slow_accept_enabled) {
- if(event_del(&b->eb->slow_accept) != 0) {
+ if(ub_event_del(b->eb->slow_accept) != 0) {
log_err("could not event_del slow_accept");
}
+ ub_event_free(b->eb->slow_accept);
}
b->eb->base = NULL;
free(b->eb);
@@ -304,8 +235,8 @@ void
comm_base_dispatch(struct comm_base* b)
{
int retval;
- retval = event_base_dispatch(b->eb->base);
- if(retval != 0) {
+ retval = ub_event_base_dispatch(b->eb->base);
+ if(retval < 0) {
fatal_exit("event_dispatch returned error %d, "
"errno is %s", retval, strerror(errno));
}
@@ -313,7 +244,7 @@ comm_base_dispatch(struct comm_base* b)
void comm_base_exit(struct comm_base* b)
{
- if(event_base_loopexit(b->eb->base, NULL) != 0) {
+ if(ub_event_base_loopexit(b->eb->base) != 0) {
log_err("Could not loopexit");
}
}
@@ -326,7 +257,7 @@ void comm_base_set_slow_accept_handlers(struct comm_base* b,
b->cb_arg = arg;
}
-struct event_base* comm_base_internal(struct comm_base* b)
+struct ub_event_base* comm_base_internal(struct comm_base* b)
{
return b->eb->base;
}
@@ -648,10 +579,10 @@ comm_point_udp_ancil_callback(int fd, short event, void* arg)
rep.c = (struct comm_point*)arg;
log_assert(rep.c->type == comm_udp);
- if(!(event&EV_READ))
+ if(!(event&UB_EV_READ))
return;
log_assert(rep.c && rep.c->buffer && rep.c->fd == fd);
- comm_base_now(rep.c->ev->base);
+ ub_comm_base_now(rep.c->ev->base);
for(i=0; i<NUM_UDP_PER_SELECT; i++) {
sldns_buffer_clear(rep.c->buffer);
rep.addrlen = (socklen_t)sizeof(rep.addr);
@@ -736,10 +667,10 @@ comm_point_udp_callback(int fd, short event, void* arg)
rep.c = (struct comm_point*)arg;
log_assert(rep.c->type == comm_udp);
- if(!(event&EV_READ))
+ if(!(event&UB_EV_READ))
return;
log_assert(rep.c && rep.c->buffer && rep.c->fd == fd);
- comm_base_now(rep.c->ev->base);
+ ub_comm_base_now(rep.c->ev->base);
for(i=0; i<NUM_UDP_PER_SELECT; i++) {
sldns_buffer_clear(rep.c->buffer);
rep.addrlen = (socklen_t)sizeof(rep.addr);
@@ -839,15 +770,16 @@ int comm_point_perform_accept(struct comm_point* c,
/* set timeout, no mallocs */
tv.tv_sec = NETEVENT_SLOW_ACCEPT_TIME/1000;
tv.tv_usec = NETEVENT_SLOW_ACCEPT_TIME%1000;
- event_set(&b->eb->slow_accept, -1, EV_TIMEOUT,
+ b->eb->slow_accept = ub_event_new(b->eb->base,
+ -1, UB_EV_TIMEOUT,
comm_base_handle_slow_accept, b);
- if(event_base_set(b->eb->base,
- &b->eb->slow_accept) != 0) {
+ if(b->eb->slow_accept == NULL) {
/* we do not want to log here, because
* that would spam the logfiles.
* error: "event_base_set failed." */
}
- if(event_add(&b->eb->slow_accept, &tv) != 0) {
+ else if(ub_event_add(b->eb->slow_accept, &tv)
+ != 0) {
/* we do not want to log here,
* error: "event_add failed." */
}
@@ -861,7 +793,7 @@ int comm_point_perform_accept(struct comm_point* c,
WSAGetLastError() == WSAECONNRESET)
return -1;
if(WSAGetLastError() == WSAEWOULDBLOCK) {
- winsock_tcp_wouldblock(&c->ev->ev, EV_READ);
+ ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
return -1;
}
log_err_addr("accept failed", wsa_strerror(WSAGetLastError()),
@@ -885,14 +817,14 @@ static long win_bio_cb(BIO *b, int oper, const char* ATTR_UNUSED(argp),
if( (oper == (BIO_CB_READ|BIO_CB_RETURN) && argl == 0) ||
(oper == (BIO_CB_GETS|BIO_CB_RETURN) && argl == 0)) {
if(WSAGetLastError() == WSAEWOULDBLOCK)
- winsock_tcp_wouldblock((struct event*)
- BIO_get_callback_arg(b), EV_READ);
+ ub_winsock_tcp_wouldblock((struct ub_event*)
+ BIO_get_callback_arg(b), UB_EV_READ);
}
if( (oper == (BIO_CB_WRITE|BIO_CB_RETURN) && argl == 0) ||
(oper == (BIO_CB_PUTS|BIO_CB_RETURN) && argl == 0)) {
if(WSAGetLastError() == WSAEWOULDBLOCK)
- winsock_tcp_wouldblock((struct event*)
- BIO_get_callback_arg(b), EV_WRITE);
+ ub_winsock_tcp_wouldblock((struct ub_event*)
+ BIO_get_callback_arg(b), UB_EV_WRITE);
}
/* return original return value */
return retvalue;
@@ -905,9 +837,9 @@ comm_point_tcp_win_bio_cb(struct comm_point* c, void* thessl)
SSL* ssl = (SSL*)thessl;
/* set them both just in case, but usually they are the same BIO */
BIO_set_callback(SSL_get_rbio(ssl), &win_bio_cb);
- BIO_set_callback_arg(SSL_get_rbio(ssl), (char*)&c->ev->ev);
+ BIO_set_callback_arg(SSL_get_rbio(ssl), (char*)c->ev->ev);
BIO_set_callback(SSL_get_wbio(ssl), &win_bio_cb);
- BIO_set_callback_arg(SSL_get_wbio(ssl), (char*)&c->ev->ev);
+ BIO_set_callback_arg(SSL_get_wbio(ssl), (char*)c->ev->ev);
}
#endif
@@ -917,11 +849,11 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg)
struct comm_point* c = (struct comm_point*)arg, *c_hdl;
int new_fd;
log_assert(c->type == comm_tcp_accept);
- if(!(event & EV_READ)) {
+ if(!(event & UB_EV_READ)) {
log_info("ignoring tcp accept event %d", (int)event);
return;
}
- comm_base_now(c->ev->base);
+ ub_comm_base_now(c->ev->base);
/* find free tcp handler. */
if(!c->tcp_free) {
log_warn("accepted too many tcp, connections full");
@@ -1297,7 +1229,8 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
if(WSAGetLastError() == WSAEINPROGRESS)
return 1;
if(WSAGetLastError() == WSAEWOULDBLOCK) {
- winsock_tcp_wouldblock(&c->ev->ev, EV_READ);
+ ub_winsock_tcp_wouldblock(c->ev->ev,
+ UB_EV_READ);
return 1;
}
log_err_addr("read (in tcp s)",
@@ -1342,7 +1275,7 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
if(WSAGetLastError() == WSAEINPROGRESS)
return 1;
if(WSAGetLastError() == WSAEWOULDBLOCK) {
- winsock_tcp_wouldblock(&c->ev->ev, EV_READ);
+ ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
return 1;
}
log_err_addr("read (in tcp r)",
@@ -1401,7 +1334,7 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
if(error == WSAEINPROGRESS)
return 1;
else if(error == WSAEWOULDBLOCK) {
- winsock_tcp_wouldblock(&c->ev->ev, EV_WRITE);
+ ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
return 1;
} else if(error != 0 && verbosity < 2)
return 0;
@@ -1451,7 +1384,8 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
if(WSAGetLastError() == WSAEINPROGRESS)
return 1;
if(WSAGetLastError() == WSAEWOULDBLOCK) {
- winsock_tcp_wouldblock(&c->ev->ev, EV_WRITE);
+ ub_winsock_tcp_wouldblock(c->ev->ev,
+ UB_EV_WRITE);
return 1;
}
log_err_addr("tcp send s",
@@ -1483,7 +1417,7 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
if(WSAGetLastError() == WSAEINPROGRESS)
return 1;
if(WSAGetLastError() == WSAEWOULDBLOCK) {
- winsock_tcp_wouldblock(&c->ev->ev, EV_WRITE);
+ ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
return 1;
}
log_err_addr("tcp send r", wsa_strerror(WSAGetLastError()),
@@ -1505,9 +1439,9 @@ comm_point_tcp_handle_callback(int fd, short event, void* arg)
{
struct comm_point* c = (struct comm_point*)arg;
log_assert(c->type == comm_tcp);
- comm_base_now(c->ev->base);
+ ub_comm_base_now(c->ev->base);
- if(event&EV_READ) {
+ if(event&UB_EV_READ) {
if(!comm_point_tcp_handle_read(fd, c, 0)) {
reclaim_tcp_handler(c);
if(!c->tcp_do_close) {
@@ -1519,7 +1453,7 @@ comm_point_tcp_handle_callback(int fd, short event, void* arg)
}
return;
}
- if(event&EV_WRITE) {
+ if(event&UB_EV_WRITE) {
if(!comm_point_tcp_handle_write(fd, c)) {
reclaim_tcp_handler(c);
if(!c->tcp_do_close) {
@@ -1531,7 +1465,7 @@ comm_point_tcp_handle_callback(int fd, short event, void* arg)
}
return;
}
- if(event&EV_TIMEOUT) {
+ if(event&UB_EV_TIMEOUT) {
verbose(VERB_QUERY, "tcp took too long, dropped");
reclaim_tcp_handler(c);
if(!c->tcp_do_close) {
@@ -1548,9 +1482,9 @@ void comm_point_local_handle_callback(int fd, short event, void* arg)
{
struct comm_point* c = (struct comm_point*)arg;
log_assert(c->type == comm_local);
- comm_base_now(c->ev->base);
+ ub_comm_base_now(c->ev->base);
- if(event&EV_READ) {
+ if(event&UB_EV_READ) {
if(!comm_point_tcp_handle_read(fd, c, 1)) {
fptr_ok(fptr_whitelist_comm_point(c->callback));
(void)(*c->callback)(c, c->cb_arg, NETEVENT_CLOSED,
@@ -1567,9 +1501,9 @@ void comm_point_raw_handle_callback(int ATTR_UNUSED(fd),
struct comm_point* c = (struct comm_point*)arg;
int err = NETEVENT_NOERROR;
log_assert(c->type == comm_raw);
- comm_base_now(c->ev->base);
+ ub_comm_base_now(c->ev->base);
- if(event&EV_TIMEOUT)
+ if(event&UB_EV_TIMEOUT)
err = NETEVENT_TIMEOUT;
fptr_ok(fptr_whitelist_comm_point_raw(c->callback));
(void)(*c->callback)(c, c->cb_arg, err, NULL);
@@ -1609,15 +1543,16 @@ comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer,
c->inuse = 0;
c->callback = callback;
c->cb_arg = callback_arg;
- evbits = EV_READ | EV_PERSIST;
- /* libevent stuff */
- event_set(&c->ev->ev, c->fd, evbits, comm_point_udp_callback, c);
- if(event_base_set(base->eb->base, &c->ev->ev) != 0) {
+ evbits = UB_EV_READ | UB_EV_PERSIST;
+ /* ub_event stuff */
+ c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
+ comm_point_udp_callback, c);
+ if(c->ev->ev == NULL) {
log_err("could not baseset udp event");
comm_point_delete(c);
return NULL;
}
- if(fd!=-1 && event_add(&c->ev->ev, c->timeout) != 0 ) {
+ if(fd!=-1 && ub_event_add(c->ev->ev, c->timeout) != 0 ) {
log_err("could not add udp event");
comm_point_delete(c);
return NULL;
@@ -1660,15 +1595,16 @@ comm_point_create_udp_ancil(struct comm_base *base, int fd,
c->tcp_check_nb_connect = 0;
c->callback = callback;
c->cb_arg = callback_arg;
- evbits = EV_READ | EV_PERSIST;
- /* libevent stuff */
- event_set(&c->ev->ev, c->fd, evbits, comm_point_udp_ancil_callback, c);
- if(event_base_set(base->eb->base, &c->ev->ev) != 0) {
+ evbits = UB_EV_READ | UB_EV_PERSIST;
+ /* ub_event stuff */
+ c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
+ comm_point_udp_ancil_callback, c);
+ if(c->ev->ev == NULL) {
log_err("could not baseset udp event");
comm_point_delete(c);
return NULL;
}
- if(fd!=-1 && event_add(&c->ev->ev, c->timeout) != 0 ) {
+ if(fd!=-1 && ub_event_add(c->ev->ev, c->timeout) != 0 ) {
log_err("could not add udp event");
comm_point_delete(c);
return NULL;
@@ -1725,10 +1661,11 @@ comm_point_create_tcp_handler(struct comm_base *base,
/* add to parent free list */
c->tcp_free = parent->tcp_free;
parent->tcp_free = c;
- /* libevent stuff */
- evbits = EV_PERSIST | EV_READ | EV_TIMEOUT;
- event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_handle_callback, c);
- if(event_base_set(base->eb->base, &c->ev->ev) != 0)
+ /* ub_event stuff */
+ evbits = UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT;
+ c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
+ comm_point_tcp_handle_callback, c);
+ if(c->ev->ev == NULL)
{
log_err("could not basetset tcphdl event");
parent->tcp_free = c->tcp_free;
@@ -1780,17 +1717,20 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize,
c->tcp_check_nb_connect = 0;
c->callback = NULL;
c->cb_arg = NULL;
- evbits = EV_READ | EV_PERSIST;
- /* libevent stuff */
- event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_accept_callback, c);
- if(event_base_set(base->eb->base, &c->ev->ev) != 0 ||
- event_add(&c->ev->ev, c->timeout) != 0 )
- {
+ evbits = UB_EV_READ | UB_EV_PERSIST;
+ /* ub_event stuff */
+ c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
+ comm_point_tcp_accept_callback, c);
+ if(c->ev->ev == NULL) {
+ log_err("could not baseset tcpacc event");
+ comm_point_delete(c);
+ return NULL;
+ }
+ if (ub_event_add(c->ev->ev, c->timeout) != 0) {
log_err("could not add tcpacc event");
comm_point_delete(c);
return NULL;
}
-
/* now prealloc the tcp handlers */
for(i=0; i<num; i++) {
c->tcp_handlers[i] = comm_point_create_tcp_handler(base,
@@ -1843,11 +1783,12 @@ comm_point_create_tcp_out(struct comm_base *base, size_t bufsize,
c->repinfo.c = c;
c->callback = callback;
c->cb_arg = callback_arg;
- evbits = EV_PERSIST | EV_WRITE;
- event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_handle_callback, c);
- if(event_base_set(base->eb->base, &c->ev->ev) != 0)
+ evbits = UB_EV_PERSIST | UB_EV_WRITE;
+ c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
+ comm_point_tcp_handle_callback, c);
+ if(c->ev->ev == NULL)
{
- log_err("could not basetset tcpout event");
+ log_err("could not baseset tcpout event");
sldns_buffer_free(c->buffer);
free(c->ev);
free(c);
@@ -1895,14 +1836,19 @@ comm_point_create_local(struct comm_base *base, int fd, size_t bufsize,
c->tcp_check_nb_connect = 0;
c->callback = callback;
c->cb_arg = callback_arg;
- /* libevent stuff */
- evbits = EV_PERSIST | EV_READ;
- event_set(&c->ev->ev, c->fd, evbits, comm_point_local_handle_callback,
- c);
- if(event_base_set(base->eb->base, &c->ev->ev) != 0 ||
- event_add(&c->ev->ev, c->timeout) != 0 )
- {
+ /* ub_event stuff */
+ evbits = UB_EV_PERSIST | UB_EV_READ;
+ c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
+ comm_point_local_handle_callback, c);
+ if(c->ev->ev == NULL) {
+ log_err("could not baseset localhdl event");
+ free(c->ev);
+ free(c);
+ return NULL;
+ }
+ if (ub_event_add(c->ev->ev, c->timeout) != 0) {
log_err("could not add localhdl event");
+ ub_event_free(c->ev->ev);
free(c->ev);
free(c);
return NULL;
@@ -1943,16 +1889,21 @@ comm_point_create_raw(struct comm_base* base, int fd, int writing,
c->tcp_check_nb_connect = 0;
c->callback = callback;
c->cb_arg = callback_arg;
- /* libevent stuff */
+ /* ub_event stuff */
if(writing)
- evbits = EV_PERSIST | EV_WRITE;
- else evbits = EV_PERSIST | EV_READ;
- event_set(&c->ev->ev, c->fd, evbits, comm_point_raw_handle_callback,
- c);
- if(event_base_set(base->eb->base, &c->ev->ev) != 0 ||
- event_add(&c->ev->ev, c->timeout) != 0 )
- {
+ evbits = UB_EV_PERSIST | UB_EV_WRITE;
+ else evbits = UB_EV_PERSIST | UB_EV_READ;
+ c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
+ comm_point_raw_handle_callback, c);
+ if(c->ev->ev == NULL) {
+ log_err("could not baseset rawhdl event");
+ free(c->ev);
+ free(c);
+ return NULL;
+ }
+ if (ub_event_add(c->ev->ev, c->timeout) != 0) {
log_err("could not add rawhdl event");
+ ub_event_free(c->ev->ev);
free(c->ev);
free(c);
return NULL;
@@ -1966,7 +1917,7 @@ comm_point_close(struct comm_point* c)
if(!c)
return;
if(c->fd != -1)
- if(event_del(&c->ev->ev) != 0) {
+ if(ub_event_del(c->ev->ev) != 0) {
log_err("could not event_del on close");
}
/* close fd after removing from event lists, or epoll.. is messed up */
@@ -2002,6 +1953,7 @@ comm_point_delete(struct comm_point* c)
free(c->timeout);
if(c->type == comm_tcp || c->type == comm_local)
sldns_buffer_free(c->buffer);
+ ub_event_free(c->ev->ev);
free(c->ev);
free(c);
}
@@ -2051,7 +2003,7 @@ void
comm_point_stop_listening(struct comm_point* c)
{
verbose(VERB_ALGO, "comm point stop listening %d", c->fd);
- if(event_del(&c->ev->ev) != 0) {
+ if(ub_event_del(c->ev->ev) != 0) {
log_err("event_del error to stoplisten");
}
}
@@ -2074,17 +2026,17 @@ comm_point_start_listening(struct comm_point* c, int newfd, int sec)
return;
}
}
- c->ev->ev.ev_events |= EV_TIMEOUT;
+ ub_event_add_bits(c->ev->ev, UB_EV_TIMEOUT);
#ifndef S_SPLINT_S /* splint fails on struct timeval. */
c->timeout->tv_sec = sec;
c->timeout->tv_usec = 0;
#endif /* S_SPLINT_S */
}
if(c->type == comm_tcp) {
- c->ev->ev.ev_events &= ~(EV_READ|EV_WRITE);
+ ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
if(c->tcp_is_reading)
- c->ev->ev.ev_events |= EV_READ;
- else c->ev->ev.ev_events |= EV_WRITE;
+ ub_event_add_bits(c->ev->ev, UB_EV_READ);
+ else ub_event_add_bits(c->ev->ev, UB_EV_WRITE);
}
if(newfd != -1) {
if(c->fd != -1) {
@@ -2095,9 +2047,9 @@ comm_point_start_listening(struct comm_point* c, int newfd, int sec)
#endif
}
c->fd = newfd;
- c->ev->ev.ev_fd = c->fd;
+ ub_event_set_fd(c->ev->ev, c->fd);
}
- if(event_add(&c->ev->ev, sec==0?NULL:c->timeout) != 0) {
+ if(ub_event_add(c->ev->ev, sec==0?NULL:c->timeout) != 0) {
log_err("event_add failed. in cpsl.");
}
}
@@ -2105,13 +2057,13 @@ comm_point_start_listening(struct comm_point* c, int newfd, int sec)
void comm_point_listen_for_rw(struct comm_point* c, int rd, int wr)
{
verbose(VERB_ALGO, "comm point listen_for_rw %d %d", c->fd, wr);
- if(event_del(&c->ev->ev) != 0) {
+ if(ub_event_del(c->ev->ev) != 0) {
log_err("event_del error to cplf");
}
- c->ev->ev.ev_events &= ~(EV_READ|EV_WRITE);
- if(rd) c->ev->ev.ev_events |= EV_READ;
- if(wr) c->ev->ev.ev_events |= EV_WRITE;
- if(event_add(&c->ev->ev, c->timeout) != 0) {
+ ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
+ if(rd) ub_event_add_bits(c->ev->ev, UB_EV_READ);
+ if(wr) ub_event_add_bits(c->ev->ev, UB_EV_WRITE);
+ if(ub_event_add(c->ev->ev, c->timeout) != 0) {
log_err("event_add failed. in cplf.");
}
}
@@ -2137,29 +2089,24 @@ size_t comm_point_get_mem(struct comm_point* c)
struct comm_timer*
comm_timer_create(struct comm_base* base, void (*cb)(void*), void* cb_arg)
{
- struct comm_timer *tm = (struct comm_timer*)calloc(1,
- sizeof(struct comm_timer));
- if(!tm)
- return NULL;
- tm->ev_timer = (struct internal_timer*)calloc(1,
+ struct internal_timer *tm = (struct internal_timer*)calloc(1,
sizeof(struct internal_timer));
- if(!tm->ev_timer) {
+ if(!tm) {
log_err("malloc failed");
- free(tm);
return NULL;
}
- tm->ev_timer->base = base;
- tm->callback = cb;
- tm->cb_arg = cb_arg;
- event_set(&tm->ev_timer->ev, -1, EV_TIMEOUT,
- comm_timer_callback, tm);
- if(event_base_set(base->eb->base, &tm->ev_timer->ev) != 0) {
+ tm->super.ev_timer = tm;
+ tm->base = base;
+ tm->super.callback = cb;
+ tm->super.cb_arg = cb_arg;
+ tm->ev = ub_event_new(base->eb->base, -1, UB_EV_TIMEOUT,
+ comm_timer_callback, &tm->super);
+ if(tm->ev == NULL) {
log_err("timer_create: event_base_set failed.");
- free(tm->ev_timer);
free(tm);
return NULL;
}
- return tm;
+ return &tm->super;
}
void
@@ -2167,7 +2114,7 @@ comm_timer_disable(struct comm_timer* timer)
{
if(!timer)
return;
- evtimer_del(&timer->ev_timer->ev);
+ ub_timer_del(timer->ev_timer->ev);
timer->ev_timer->enabled = 0;
}
@@ -2177,12 +2124,8 @@ comm_timer_set(struct comm_timer* timer, struct timeval* tv)
log_assert(tv);
if(timer->ev_timer->enabled)
comm_timer_disable(timer);
- event_set(&timer->ev_timer->ev, -1, EV_TIMEOUT,
- comm_timer_callback, timer);
- if(event_base_set(timer->ev_timer->base->eb->base,
- &timer->ev_timer->ev) != 0)
- log_err("comm_timer_set: set_base failed.");
- if(evtimer_add(&timer->ev_timer->ev, tv) != 0)
+ if(ub_timer_add(timer->ev_timer->ev, timer->ev_timer->base->eb->base,
+ comm_timer_callback, timer, tv) != 0)
log_err("comm_timer_set: evtimer_add failed.");
timer->ev_timer->enabled = 1;
}
@@ -2193,17 +2136,20 @@ comm_timer_delete(struct comm_timer* timer)
if(!timer)
return;
comm_timer_disable(timer);
+ /* Free the sub struct timer->ev_timer derived from the super struct timer.
+ * i.e. assert(timer == timer->ev_timer)
+ */
+ ub_event_free(timer->ev_timer->ev);
free(timer->ev_timer);
- free(timer);
}
void
comm_timer_callback(int ATTR_UNUSED(fd), short event, void* arg)
{
struct comm_timer* tm = (struct comm_timer*)arg;
- if(!(event&EV_TIMEOUT))
+ if(!(event&UB_EV_TIMEOUT))
return;
- comm_base_now(tm->ev_timer->base);
+ ub_comm_base_now(tm->ev_timer->base);
tm->ev_timer->enabled = 0;
fptr_ok(fptr_whitelist_comm_timer(tm->callback));
(*tm->callback)(tm->cb_arg);
@@ -2216,9 +2162,9 @@ comm_timer_is_set(struct comm_timer* timer)
}
size_t
-comm_timer_get_mem(struct comm_timer* timer)
+comm_timer_get_mem(struct comm_timer* ATTR_UNUSED(timer))
{
- return sizeof(*timer) + sizeof(struct internal_timer);
+ return sizeof(struct internal_timer);
}
struct comm_signal*
@@ -2242,9 +2188,9 @@ void
comm_signal_callback(int sig, short event, void* arg)
{
struct comm_signal* comsig = (struct comm_signal*)arg;
- if(!(event & EV_SIGNAL))
+ if(!(event & UB_EV_SIGNAL))
return;
- comm_base_now(comsig->base);
+ ub_comm_base_now(comsig->base);
fptr_ok(fptr_whitelist_comm_signal(comsig->callback));
(*comsig->callback)(sig, comsig->cb_arg);
}
@@ -2260,14 +2206,16 @@ comm_signal_bind(struct comm_signal* comsig, int sig)
}
log_assert(comsig);
/* add signal event */
- signal_set(&entry->ev, sig, comm_signal_callback, comsig);
- if(event_base_set(comsig->base->eb->base, &entry->ev) != 0) {
- log_err("Could not set signal base");
+ entry->ev = ub_signal_new(comsig->base->eb->base, sig,
+ comm_signal_callback, comsig);
+ if(entry->ev == NULL) {
+ log_err("Could not create signal event");
free(entry);
return 0;
}
- if(signal_add(&entry->ev, NULL) != 0) {
+ if(ub_signal_add(entry->ev, NULL) != 0) {
log_err("Could not add signal handler");
+ ub_event_free(entry->ev);
free(entry);
return 0;
}
@@ -2286,7 +2234,8 @@ comm_signal_delete(struct comm_signal* comsig)
p=comsig->ev_signal;
while(p) {
np = p->next;
- signal_del(&p->ev);
+ ub_signal_del(p->ev);
+ ub_event_free(p->ev);
free(p);
p = np;
}
diff --git a/contrib/unbound/util/netevent.h b/contrib/unbound/util/netevent.h
index 4b87cdba9e51..bdcddd848bd0 100644
--- a/contrib/unbound/util/netevent.h
+++ b/contrib/unbound/util/netevent.h
@@ -63,12 +63,12 @@
struct sldns_buffer;
struct comm_point;
struct comm_reply;
-struct event_base;
+struct ub_event_base;
/* internal event notification data storage structure. */
struct internal_event;
struct internal_base;
-struct internal_timer;
+struct internal_timer; /* A sub struct of the comm_timer super struct */
/** callback from communication point function type */
typedef int comm_point_callback_t(struct comm_point*, void*, int,
@@ -265,7 +265,7 @@ struct comm_point {
* Structure only for making timeout events.
*/
struct comm_timer {
- /** the internal event stuff */
+ /** the internal event stuff (derived) */
struct internal_timer* ev_timer;
/** callback function, takes user arg only */
@@ -301,12 +301,12 @@ struct comm_signal {
struct comm_base* comm_base_create(int sigs);
/**
- * Create comm base that uses the given event_base (underlying event
- * mechanism pointer).
- * @param base: underlying lib event base.
+ * Create comm base that uses the given ub_event_base (underlying pluggable
+ * event mechanism pointer).
+ * @param base: underlying pluggable event base.
* @return: the new comm base. NULL on error.
*/
-struct comm_base* comm_base_create_event(struct event_base* base);
+struct comm_base* comm_base_create_event(struct ub_event_base* base);
/**
* Delete comm base structure but not the underlying lib event base.
@@ -357,9 +357,9 @@ void comm_base_set_slow_accept_handlers(struct comm_base* b,
/**
* Access internal data structure (for util/tube.c on windows)
* @param b: comm base
- * @return event_base. Could be libevent, or internal event handler.
+ * @return ub_event_base.
*/
-struct event_base* comm_base_internal(struct comm_base* b);
+struct ub_event_base* comm_base_internal(struct comm_base* b);
/**
* Create an UDP comm point. Calls malloc.
diff --git a/contrib/unbound/util/tube.c b/contrib/unbound/util/tube.c
index 0535474386b5..e525f1ccd8aa 100644
--- a/contrib/unbound/util/tube.c
+++ b/contrib/unbound/util/tube.c
@@ -44,6 +44,7 @@
#include "util/net_help.h"
#include "util/netevent.h"
#include "util/fptr_wlist.h"
+#include "util/ub_event.h"
#ifndef USE_WINSOCK
/* on unix */
@@ -303,6 +304,8 @@ int tube_write_msg(struct tube* tube, uint8_t* buf, uint32_t len,
d = r;
while(d != (ssize_t)sizeof(len)) {
if((r=write(fd, ((char*)&len)+d, sizeof(len)-d)) == -1) {
+ if(errno == EAGAIN)
+ continue; /* temporarily unavail: try again*/
log_err("tube msg write failed: %s", strerror(errno));
(void)fd_set_nonblock(fd);
return 0;
@@ -312,6 +315,8 @@ int tube_write_msg(struct tube* tube, uint8_t* buf, uint32_t len,
d = 0;
while(d != (ssize_t)len) {
if((r=write(fd, buf+d, len-d)) == -1) {
+ if(errno == EAGAIN)
+ continue; /* temporarily unavail: try again*/
log_err("tube msg write failed: %s", strerror(errno));
(void)fd_set_nonblock(fd);
return 0;
@@ -537,7 +542,7 @@ void tube_close_write(struct tube* ATTR_UNUSED(tube))
void tube_remove_bg_listen(struct tube* tube)
{
verbose(VERB_ALGO, "tube remove_bg_listen");
- winsock_unregister_wsaevent(&tube->ev_listen);
+ ub_winsock_unregister_wsaevent(tube->ev_listen);
}
void tube_remove_bg_write(struct tube* tube)
@@ -668,8 +673,9 @@ int tube_setup_bg_listen(struct tube* tube, struct comm_base* base,
tube->listen_arg = arg;
if(!comm_base_internal(base))
return 1; /* ignore when no comm base - testing */
- return winsock_register_wsaevent(comm_base_internal(base),
- &tube->ev_listen, tube->event, &tube_handle_signal, tube);
+ tube->ev_listen = ub_winsock_register_wsaevent(
+ comm_base_internal(base), tube->event, &tube_handle_signal, tube);
+ return tube->ev_listen ? 1 : 0;
}
int tube_setup_bg_write(struct tube* ATTR_UNUSED(tube),
diff --git a/contrib/unbound/util/tube.h b/contrib/unbound/util/tube.h
index 6cc60502b34b..7971b776ae1f 100644
--- a/contrib/unbound/util/tube.h
+++ b/contrib/unbound/util/tube.h
@@ -48,7 +48,6 @@ struct tube;
struct tube_res_list;
#ifdef USE_WINSOCK
#include "util/locks.h"
-#include "util/winsock_event.h"
#endif
/**
@@ -99,7 +98,7 @@ struct tube {
/** the windows sockets event (signaled if items in pipe) */
WSAEVENT event;
/** winsock event storage when registered with event base */
- struct event ev_listen;
+ struct ub_event* ev_listen;
/** lock on the list of outstanding items */
lock_basic_t res_lock;
diff --git a/contrib/unbound/util/ub_event.c b/contrib/unbound/util/ub_event.c
new file mode 100644
index 000000000000..af2a18ea0fc8
--- /dev/null
+++ b/contrib/unbound/util/ub_event.c
@@ -0,0 +1,448 @@
+/*
+ * util/ub_event.c - directly call libevent (compatability) functions
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file contains and implementation for the indirection layer for pluggable
+ * events that transparently passes it either directly to libevent, or calls
+ * the libevent compatibility layer functions.
+ */
+#include "config.h"
+#include <sys/time.h>
+#include "util/ub_event.h"
+#include "util/log.h"
+#include "util/netevent.h"
+#include "util/tube.h"
+
+/* We define libevent structures here to hide the libevent stuff. */
+
+#ifdef USE_MINI_EVENT
+# ifdef USE_WINSOCK
+# include "util/winsock_event.h"
+# else
+# include "util/mini_event.h"
+# endif /* USE_WINSOCK */
+#else /* USE_MINI_EVENT */
+ /* we use libevent */
+# ifdef HAVE_EVENT_H
+# include <event.h>
+# else
+# include "event2/event.h"
+# include "event2/event_struct.h"
+# include "event2/event_compat.h"
+# endif
+#endif /* USE_MINI_EVENT */
+
+#if UB_EV_TIMEOUT != EV_TIMEOUT || UB_EV_READ != EV_READ || \
+ UB_EV_WRITE != EV_WRITE || UB_EV_SIGNAL != EV_SIGNAL || \
+ UB_EV_PERSIST != EV_PERSIST
+/* Only necessary for libev */
+# define NATIVE_BITS(b) ( \
+ (((b) & UB_EV_TIMEOUT) ? EV_TIMEOUT : 0) \
+ | (((b) & UB_EV_READ ) ? EV_READ : 0) \
+ | (((b) & UB_EV_WRITE ) ? EV_WRITE : 0) \
+ | (((b) & UB_EV_SIGNAL ) ? EV_SIGNAL : 0) \
+ | (((b) & UB_EV_PERSIST) ? EV_PERSIST : 0))
+
+# define UB_EV_BITS(b) ( \
+ (((b) & EV_TIMEOUT) ? UB_EV_TIMEOUT : 0) \
+ | (((b) & EV_READ ) ? UB_EV_READ : 0) \
+ | (((b) & EV_WRITE ) ? UB_EV_WRITE : 0) \
+ | (((b) & EV_SIGNAL ) ? UB_EV_SIGNAL : 0) \
+ | (((b) & EV_PERSIST) ? UB_EV_PERSIST : 0))
+
+# define UB_EV_BITS_CB(C) void my_ ## C (int fd, short bits, void *arg) \
+ { (C)(fd, UB_EV_BITS(bits), arg); }
+
+UB_EV_BITS_CB(comm_point_udp_callback);
+UB_EV_BITS_CB(comm_point_udp_ancil_callback)
+UB_EV_BITS_CB(comm_point_tcp_accept_callback)
+UB_EV_BITS_CB(comm_point_tcp_handle_callback)
+UB_EV_BITS_CB(comm_timer_callback)
+UB_EV_BITS_CB(comm_signal_callback)
+UB_EV_BITS_CB(comm_point_local_handle_callback)
+UB_EV_BITS_CB(comm_point_raw_handle_callback)
+UB_EV_BITS_CB(tube_handle_signal)
+UB_EV_BITS_CB(comm_base_handle_slow_accept)
+
+static void (*NATIVE_BITS_CB(void (*cb)(int, short, void*)))(int, short, void*)
+{
+ if(cb == comm_point_udp_callback)
+ return my_comm_point_udp_callback;
+ else if(cb == comm_point_udp_ancil_callback)
+ return my_comm_point_udp_ancil_callback;
+ else if(cb == comm_point_tcp_accept_callback)
+ return my_comm_point_tcp_accept_callback;
+ else if(cb == comm_point_tcp_handle_callback)
+ return my_comm_point_tcp_handle_callback;
+ else if(cb == comm_timer_callback)
+ return my_comm_timer_callback;
+ else if(cb == comm_signal_callback)
+ return my_comm_signal_callback;
+ else if(cb == comm_point_local_handle_callback)
+ return my_comm_point_local_handle_callback;
+ else if(cb == comm_point_raw_handle_callback)
+ return my_comm_point_raw_handle_callback;
+ else if(cb == tube_handle_signal)
+ return my_tube_handle_signal;
+ else if(cb == comm_base_handle_slow_accept)
+ return my_comm_base_handle_slow_accept;
+ else
+ return NULL;
+}
+#else
+# define NATIVE_BITS(b) (b)
+# define NATIVE_BITS_CB(c) (c)
+#endif
+
+#ifndef EVFLAG_AUTO
+#define EVFLAG_AUTO 0
+#endif
+
+#define AS_EVENT_BASE(x) \
+ (((union {struct ub_event_base* a; struct event_base* b;})x).b)
+#define AS_UB_EVENT_BASE(x) \
+ (((union {struct event_base* a; struct ub_event_base* b;})x).b)
+#define AS_EVENT(x) \
+ (((union {struct ub_event* a; struct event* b;})x).b)
+#define AS_UB_EVENT(x) \
+ (((union {struct event* a; struct ub_event* b;})x).b)
+
+const char* ub_event_get_version()
+{
+ return event_get_version();
+}
+
+#if (defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)) && defined(EVBACKEND_SELECT)
+static const char* ub_ev_backend2str(int b)
+{
+ switch(b) {
+ case EVBACKEND_SELECT: return "select";
+ case EVBACKEND_POLL: return "poll";
+ case EVBACKEND_EPOLL: return "epoll";
+ case EVBACKEND_KQUEUE: return "kqueue";
+ case EVBACKEND_DEVPOLL: return "devpoll";
+ case EVBACKEND_PORT: return "evport";
+ }
+ return "unknown";
+}
+#endif
+
+void
+ub_get_event_sys(struct ub_event_base* base, const char** n, const char** s,
+ const char** m)
+{
+#ifdef USE_WINSOCK
+ (void)base;
+ *n = "event";
+ *s = "winsock";
+ *m = "WSAWaitForMultipleEvents";
+#elif defined(USE_MINI_EVENT)
+ (void)base;
+ *n = "mini-event";
+ *s = "internal";
+ *m = "select";
+#else
+ struct event_base* b = AS_EVENT_BASE(base);
+ *s = event_get_version();
+# if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)
+ *n = "libev";
+ if (!b)
+ b = (struct event_base*)ev_default_loop(EVFLAG_AUTO);
+# ifdef EVBACKEND_SELECT
+ *m = ub_ev_backend2str(ev_backend((struct ev_loop*)b));
+# else
+ *m = "not obtainable";
+# endif
+# elif defined(HAVE_EVENT_BASE_GET_METHOD)
+ *n = "libevent";
+ if (!b)
+ b = event_base_new();
+ *m = event_base_get_method(b);
+# else
+ *n = "unknown";
+ *m = "not obtainable";
+ (void)b;
+# endif
+# ifdef HAVE_EVENT_BASE_FREE
+ if (b && b != AS_EVENT_BASE(base))
+ event_base_free(b);
+# endif
+#endif
+}
+
+struct ub_event_base*
+ub_default_event_base(int sigs, time_t* time_secs, struct timeval* time_tv)
+{
+ void* base;
+
+ (void)base;
+#ifdef USE_MINI_EVENT
+ (void)sigs;
+ /* use mini event time-sharing feature */
+ base = event_init(time_secs, time_tv);
+#else
+ (void)time_secs;
+ (void)time_tv;
+# if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)
+ /* libev */
+ if(sigs)
+ base = ev_default_loop(EVFLAG_AUTO);
+ else
+ base = ev_loop_new(EVFLAG_AUTO);
+# else
+ (void)sigs;
+# ifdef HAVE_EVENT_BASE_NEW
+ base = event_base_new();
+# else
+ base = event_init();
+# endif
+# endif
+#endif
+ return (struct ub_event_base*)base;
+}
+
+struct ub_event_base *
+ub_libevent_event_base(struct event_base* libevent_base)
+{
+#ifdef USE_MINI_EVENT
+ (void)libevent_base;
+ return NULL;
+#else
+ return AS_UB_EVENT_BASE(libevent_base);
+#endif
+}
+
+struct event_base *
+ub_libevent_get_event_base(struct ub_event_base* base)
+{
+#ifdef USE_MINI_EVENT
+ (void)base;
+ return NULL;
+#else
+ return AS_EVENT_BASE(base);
+#endif
+}
+
+void
+ub_event_base_free(struct ub_event_base* base)
+{
+#ifdef USE_MINI_EVENT
+ event_base_free(AS_EVENT_BASE(base));
+#elif defined(HAVE_EVENT_BASE_FREE) && defined(HAVE_EVENT_BASE_ONCE)
+ /* only libevent 1.2+ has it, but in 1.2 it is broken -
+ assertion fails on signal handling ev that is not deleted
+ in libevent 1.3c (event_base_once appears) this is fixed. */
+ event_base_free(AS_EVENT_BASE(base));
+#else
+ (void)base;
+#endif /* HAVE_EVENT_BASE_FREE and HAVE_EVENT_BASE_ONCE */
+}
+
+int
+ub_event_base_dispatch(struct ub_event_base* base)
+{
+ return event_base_dispatch(AS_EVENT_BASE(base));
+}
+
+int
+ub_event_base_loopexit(struct ub_event_base* base)
+{
+ return event_base_loopexit(AS_EVENT_BASE(base), NULL);
+}
+
+struct ub_event*
+ub_event_new(struct ub_event_base* base, int fd, short bits,
+ void (*cb)(int, short, void*), void* arg)
+{
+ struct event *ev = (struct event*)calloc(1, sizeof(struct event));
+
+ if (!ev)
+ return NULL;
+
+ event_set(ev, fd, NATIVE_BITS(bits), NATIVE_BITS_CB(cb), arg);
+ if (event_base_set(AS_EVENT_BASE(base), ev) != 0) {
+ free(ev);
+ return NULL;
+ }
+ return AS_UB_EVENT(ev);
+}
+
+struct ub_event*
+ub_signal_new(struct ub_event_base* base, int fd,
+ void (*cb)(int, short, void*), void* arg)
+{
+ struct event *ev = (struct event*)calloc(1, sizeof(struct event));
+
+ if (!ev)
+ return NULL;
+
+ signal_set(ev, fd, NATIVE_BITS_CB(cb), arg);
+ if (event_base_set(AS_EVENT_BASE(base), ev) != 0) {
+ free(ev);
+ return NULL;
+ }
+ return AS_UB_EVENT(ev);
+}
+
+struct ub_event*
+ub_winsock_register_wsaevent(struct ub_event_base* base, void* wsaevent,
+ void (*cb)(int, short, void*), void* arg)
+{
+#if defined(USE_MINI_EVENT) && defined(USE_WINSOCK)
+ struct event *ev = (struct event*)calloc(1, sizeof(struct event));
+
+ if (!ev)
+ return NULL;
+
+ if (winsock_register_wsaevent(AS_EVENT_BASE(base), ev, wsaevent, cb,
+ arg))
+ return AS_UB_EVENT(ev);
+ free(ev);
+ return NULL;
+#else
+ (void)base;
+ (void)wsaevent;
+ (void)cb;
+ (void)arg;
+ return NULL;
+#endif
+}
+
+void
+ub_event_add_bits(struct ub_event* ev, short bits)
+{
+ AS_EVENT(ev)->ev_events |= NATIVE_BITS(bits);
+}
+
+void
+ub_event_del_bits(struct ub_event* ev, short bits)
+{
+ AS_EVENT(ev)->ev_events &= ~NATIVE_BITS(bits);
+}
+
+void
+ub_event_set_fd(struct ub_event* ev, int fd)
+{
+ AS_EVENT(ev)->ev_fd = fd;
+}
+
+void
+ub_event_free(struct ub_event* ev)
+{
+ if (ev)
+ free(AS_EVENT(ev));
+}
+
+int
+ub_event_add(struct ub_event* ev, struct timeval* tv)
+{
+ return event_add(AS_EVENT(ev), tv);
+}
+
+int
+ub_event_del(struct ub_event* ev)
+{
+ return event_del(AS_EVENT(ev));
+}
+
+int
+ub_timer_add(struct ub_event* ev, struct ub_event_base* base,
+ void (*cb)(int, short, void*), void* arg, struct timeval* tv)
+{
+ event_set(AS_EVENT(ev), -1, EV_TIMEOUT, NATIVE_BITS_CB(cb), arg);
+ if (event_base_set(AS_EVENT_BASE(base), AS_EVENT(ev)) != 0)
+ return -1;
+ return evtimer_add(AS_EVENT(ev), tv);
+}
+
+int
+ub_timer_del(struct ub_event* ev)
+{
+ return evtimer_del(AS_EVENT(ev));
+}
+
+int
+ub_signal_add(struct ub_event* ev, struct timeval* tv)
+{
+ return signal_add(AS_EVENT(ev), tv);
+}
+
+int
+ub_signal_del(struct ub_event* ev)
+{
+ return signal_del(AS_EVENT(ev));
+}
+
+void
+ub_winsock_unregister_wsaevent(struct ub_event* ev)
+{
+#if defined(USE_MINI_EVENT) && defined(USE_WINSOCK)
+ winsock_unregister_wsaevent(AS_EVENT(ev));
+ free(AS_EVENT(ev));
+#else
+ (void)ev;
+#endif
+}
+
+void
+ub_winsock_tcp_wouldblock(struct ub_event* ev, int eventbits)
+{
+#if defined(USE_MINI_EVENT) && defined(USE_WINSOCK)
+ winsock_tcp_wouldblock(AS_EVENT(ev), NATIVE_BITS(eventbits));
+#else
+ (void)ev;
+ (void)eventbits;
+#endif
+}
+
+void ub_comm_base_now(struct comm_base* cb)
+{
+ #ifdef USE_MINI_EVENT
+/** minievent updates the time when it blocks. */
+ (void)cb; /* nothing to do */
+#else /* !USE_MINI_EVENT */
+/** fillup the time values in the event base */
+ time_t *tt;
+ struct timeval *tv;
+ comm_base_timept(cb, &tt, &tv);
+ if(gettimeofday(tv, NULL) < 0) {
+ log_err("gettimeofday: %s", strerror(errno));
+ }
+ *tt = tv->tv_sec;
+#endif /* USE_MINI_EVENT */
+}
+
diff --git a/contrib/unbound/util/ub_event.h b/contrib/unbound/util/ub_event.h
new file mode 100644
index 000000000000..9739e6d833ee
--- /dev/null
+++ b/contrib/unbound/util/ub_event.h
@@ -0,0 +1,127 @@
+/*
+ * util/ub_event.h - indirection layer for pluggable events
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file contains prototypes for event loop functions.
+ *
+ */
+
+#ifndef UB_EVENT_H
+#define UB_EVENT_H
+
+struct ub_event_base;
+struct ub_event;
+struct comm_base;
+struct event_base;
+
+/** event timeout */
+#define UB_EV_TIMEOUT 0x01
+/** event fd readable */
+#define UB_EV_READ 0x02
+/** event fd writable */
+#define UB_EV_WRITE 0x04
+/** event signal */
+#define UB_EV_SIGNAL 0x08
+/** event must persist */
+#define UB_EV_PERSIST 0x10
+
+/** Returns event-base type. Could be "mini-event", "winsock-event" for the
+ * daemon compile, and will be "pluggable-event<PACKAGE_VERSION>" for
+ * libunbound.
+ */
+const char* ub_event_get_version(void);
+/** Return the name, system and method for the pluggable event base */
+void ub_get_event_sys(struct ub_event_base*, const char** n, const char** s,
+ const char** m);
+/** Return a default event base. In the deamon thess will be the only event
+ * bases used.
+ */
+struct ub_event_base* ub_default_event_base(int, time_t*, struct timeval*);
+/** Return an ub_event_base constructed for the given libevent event base */
+struct ub_event_base* ub_libevent_event_base(struct event_base*);
+/** Return the libevent base underlying the given ub_event_base. Will return
+ * NULL when the ub_event_base does not have an underlying libevent event base
+ */
+struct event_base* ub_libevent_get_event_base(struct ub_event_base*);
+/** Free event base. Free events yourself */
+void ub_event_base_free(struct ub_event_base*);
+/** Run the event base */
+int ub_event_base_dispatch(struct ub_event_base*);
+/** exit that loop */
+int ub_event_base_loopexit(struct ub_event_base*);
+
+/** Create a new ub_event for the event base */
+struct ub_event* ub_event_new(struct ub_event_base*,
+ int fd, short bits, void (*cb)(int, short, void*), void* arg);
+/** Create a new ub_event signal for the event base */
+struct ub_event* ub_signal_new(struct ub_event_base*, int fd,
+ void (*cb)(int, short, void*), void* arg);
+/** Create a new ub_event associated with the wsaevent for the event base */
+struct ub_event* ub_winsock_register_wsaevent(struct ub_event_base*,
+ void* wsaevent, void (*cb)(int, short, void*), void* arg);
+
+/** Add event bits for this event to fire on */
+void ub_event_add_bits(struct ub_event*, short bits);
+ /** Configure the event so it will not longer fire on given bits */
+void ub_event_del_bits(struct ub_event*, short bits);
+/** Change or set the file descriptor on the event */
+void ub_event_set_fd(struct ub_event*, int fd);
+/** free the event */
+void ub_event_free(struct ub_event*);
+/** Activate the event. The given timeval is an timeout value. */
+int ub_event_add(struct ub_event*, struct timeval*);
+/** Deactivate the event */
+int ub_event_del(struct ub_event*);
+/** Reconfigure and activate a timeout event */
+int ub_timer_add(struct ub_event*, struct ub_event_base*,
+ void (*cb)(int, short, void*), void* arg, struct timeval*);
+/** Deactivate the timeout event */
+int ub_timer_del(struct ub_event*);
+/** Activate a signal event */
+int ub_signal_add(struct ub_event*, struct timeval*);
+/** Deactivate a signal event */
+int ub_signal_del(struct ub_event*);
+/** Free a with a wsaevent associated event */
+void ub_winsock_unregister_wsaevent(struct ub_event* ev);
+/** Signal the eventloop when a TCP windows socket will block on next read
+ * or write (given by the eventbits)
+ */
+void ub_winsock_tcp_wouldblock(struct ub_event*, int bits);
+/** Equip the comm_base with the current time */
+void ub_comm_base_now(struct comm_base* cb);
+
+#endif /* UB_EVENT_H */
diff --git a/contrib/unbound/util/ub_event_pluggable.c b/contrib/unbound/util/ub_event_pluggable.c
new file mode 100644
index 000000000000..5c517555e71b
--- /dev/null
+++ b/contrib/unbound/util/ub_event_pluggable.c
@@ -0,0 +1,694 @@
+/*
+ * util/ub_event_pluggable.c - call registered pluggable event functions
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file contains an implementation for the indirection layer for pluggable
+ * events that calls the registered pluggable event loop. It also defines a
+ * default pluggable event loop based on the default libevent (compatibility)
+ * functions.
+ */
+#include "config.h"
+#include <sys/time.h>
+#include "util/ub_event.h"
+#include "libunbound/unbound-event.h"
+#include "util/netevent.h"
+#include "util/log.h"
+#include "util/fptr_wlist.h"
+
+/* We define libevent structures here to hide the libevent stuff. */
+
+#ifdef USE_MINI_EVENT
+# ifdef USE_WINSOCK
+# include "util/winsock_event.h"
+# else
+# include "util/mini_event.h"
+# endif /* USE_WINSOCK */
+#else /* USE_MINI_EVENT */
+ /* we use libevent */
+# ifdef HAVE_EVENT_H
+# include <event.h>
+# else
+# include "event2/event.h"
+# include "event2/event_struct.h"
+# include "event2/event_compat.h"
+# endif
+#endif /* USE_MINI_EVENT */
+
+#if UB_EV_TIMEOUT != EV_TIMEOUT || UB_EV_READ != EV_READ || \
+ UB_EV_WRITE != EV_WRITE || UB_EV_SIGNAL != EV_SIGNAL || \
+ UB_EV_PERSIST != EV_PERSIST
+/* Only necessary for libev */
+# define NATIVE_BITS(b) ( \
+ (((b) & UB_EV_TIMEOUT) ? EV_TIMEOUT : 0) \
+ | (((b) & UB_EV_READ ) ? EV_READ : 0) \
+ | (((b) & UB_EV_WRITE ) ? EV_WRITE : 0) \
+ | (((b) & UB_EV_SIGNAL ) ? EV_SIGNAL : 0) \
+ | (((b) & UB_EV_PERSIST) ? EV_PERSIST : 0))
+
+# define UB_EV_BITS(b) ( \
+ (((b) & EV_TIMEOUT) ? UB_EV_TIMEOUT : 0) \
+ | (((b) & EV_READ ) ? UB_EV_READ : 0) \
+ | (((b) & EV_WRITE ) ? UB_EV_WRITE : 0) \
+ | (((b) & EV_SIGNAL ) ? UB_EV_SIGNAL : 0) \
+ | (((b) & EV_PERSIST) ? UB_EV_PERSIST : 0))
+
+# define UB_EV_BITS_CB(C) void my_ ## C (int fd, short bits, void *arg) \
+ { (C)(fd, UB_EV_BITS(bits), arg); }
+
+UB_EV_BITS_CB(comm_point_udp_callback);
+UB_EV_BITS_CB(comm_point_udp_ancil_callback)
+UB_EV_BITS_CB(comm_point_tcp_accept_callback)
+UB_EV_BITS_CB(comm_point_tcp_handle_callback)
+UB_EV_BITS_CB(comm_timer_callback)
+UB_EV_BITS_CB(comm_signal_callback)
+UB_EV_BITS_CB(comm_point_local_handle_callback)
+UB_EV_BITS_CB(comm_point_raw_handle_callback)
+UB_EV_BITS_CB(tube_handle_signal)
+UB_EV_BITS_CB(comm_base_handle_slow_accept)
+
+static void (*NATIVE_BITS_CB(void (*cb)(int, short, void*)))(int, short, void*)
+{
+ if(cb == comm_point_udp_callback)
+ return my_comm_point_udp_callback;
+ else if(cb == comm_point_udp_ancil_callback)
+ return my_comm_point_udp_ancil_callback;
+ else if(cb == comm_point_tcp_accept_callback)
+ return my_comm_point_tcp_accept_callback;
+ else if(cb == comm_point_tcp_handle_callback)
+ return my_comm_point_tcp_handle_callback;
+ else if(cb == comm_timer_callback)
+ return my_comm_timer_callback;
+ else if(cb == comm_signal_callback)
+ return my_comm_signal_callback;
+ else if(cb == comm_point_local_handle_callback)
+ return my_comm_point_local_handle_callback;
+ else if(cb == comm_point_raw_handle_callback)
+ return my_comm_point_raw_handle_callback;
+ else if(cb == tube_handle_signal)
+ return my_tube_handle_signal;
+ else if(cb == comm_base_handle_slow_accept)
+ return my_comm_base_handle_slow_accept;
+ else
+ return NULL;
+}
+#else
+# define NATIVE_BITS(b) (b)
+# define NATIVE_BITS_CB(c) (c)
+#endif
+
+#ifndef EVFLAG_AUTO
+#define EVFLAG_AUTO 0
+#endif
+
+struct my_event_base {
+ struct ub_event_base super;
+ struct event_base* base;
+};
+
+struct my_event {
+ struct ub_event super;
+ struct event ev;
+};
+
+#define AS_MY_EVENT_BASE(x) \
+ (((union {struct ub_event_base* a; struct my_event_base* b;})x).b)
+#define AS_MY_EVENT(x) \
+ (((union {struct ub_event* a; struct my_event* b;})x).b)
+
+const char* ub_event_get_version()
+{
+ return "pluggable-event"PACKAGE_VERSION;
+}
+
+static void
+my_event_add_bits(struct ub_event* ev, short bits)
+{
+ AS_MY_EVENT(ev)->ev.ev_events |= NATIVE_BITS(bits);
+}
+
+static void
+my_event_del_bits(struct ub_event* ev, short bits)
+{
+ AS_MY_EVENT(ev)->ev.ev_events &= ~NATIVE_BITS(bits);
+}
+
+static void
+my_event_set_fd(struct ub_event* ev, int fd)
+{
+ AS_MY_EVENT(ev)->ev.ev_fd = fd;
+}
+
+static void
+my_event_free(struct ub_event* ev)
+{
+ free(AS_MY_EVENT(ev));
+}
+
+static int
+my_event_add(struct ub_event* ev, struct timeval* tv)
+{
+ return event_add(&AS_MY_EVENT(ev)->ev, tv);
+}
+
+static int
+my_event_del(struct ub_event* ev)
+{
+ return event_del(&AS_MY_EVENT(ev)->ev);
+}
+
+static int
+my_timer_add(struct ub_event* ev, struct ub_event_base* base,
+ void (*cb)(int, short, void*), void* arg, struct timeval* tv)
+{
+ event_set(&AS_MY_EVENT(ev)->ev, -1, EV_TIMEOUT,NATIVE_BITS_CB(cb),arg);
+ if (event_base_set(AS_MY_EVENT_BASE(base)->base, &AS_MY_EVENT(ev)->ev)
+ != 0)
+ return -1;
+ return evtimer_add(&AS_MY_EVENT(ev)->ev, tv);
+}
+
+static int
+my_timer_del(struct ub_event* ev)
+{
+ return evtimer_del(&AS_MY_EVENT(ev)->ev);
+}
+
+static int
+my_signal_add(struct ub_event* ev, struct timeval* tv)
+{
+ return signal_add(&AS_MY_EVENT(ev)->ev, tv);
+}
+
+static int
+my_signal_del(struct ub_event* ev)
+{
+ return signal_del(&AS_MY_EVENT(ev)->ev);
+}
+
+static void
+my_winsock_unregister_wsaevent(struct ub_event* ev)
+{
+#if defined(USE_MINI_EVENT) && defined(USE_WINSOCK)
+ winsock_unregister_wsaevent(&AS_MY_EVENT(ev)->ev);
+ free(AS_MY_EVENT(ev));
+#else
+ (void)ev;
+#endif
+}
+
+static void
+my_winsock_tcp_wouldblock(struct ub_event* ev, int eventbits)
+{
+#if defined(USE_MINI_EVENT) && defined(USE_WINSOCK)
+ winsock_tcp_wouldblock(&AS_MY_EVENT(ev)->ev, NATIVE_BITS(eventbits));
+#else
+ (void)ev;
+ (void)eventbits;
+#endif
+}
+
+static struct ub_event_vmt default_event_vmt = {
+ my_event_add_bits, my_event_del_bits, my_event_set_fd,
+ my_event_free, my_event_add, my_event_del,
+ my_timer_add, my_timer_del, my_signal_add, my_signal_del,
+ my_winsock_unregister_wsaevent, my_winsock_tcp_wouldblock
+};
+
+static void
+my_event_base_free(struct ub_event_base* base)
+{
+#ifdef USE_MINI_EVENT
+ event_base_free(AS_MY_EVENT_BASE(base)->base);
+#elif defined(HAVE_EVENT_BASE_FREE) && defined(HAVE_EVENT_BASE_ONCE)
+ /* only libevent 1.2+ has it, but in 1.2 it is broken -
+ assertion fails on signal handling ev that is not deleted
+ in libevent 1.3c (event_base_once appears) this is fixed. */
+ event_base_free(AS_MY_EVENT_BASE(base)->base);
+#endif /* HAVE_EVENT_BASE_FREE and HAVE_EVENT_BASE_ONCE */
+ free(AS_MY_EVENT_BASE(base));
+}
+
+static int
+my_event_base_dispatch(struct ub_event_base* base)
+{
+ return event_base_dispatch(AS_MY_EVENT_BASE(base)->base);
+}
+
+static int
+my_event_base_loopexit(struct ub_event_base* base, struct timeval* tv)
+{
+ return event_base_loopexit(AS_MY_EVENT_BASE(base)->base, tv);
+}
+
+static struct ub_event*
+my_event_new(struct ub_event_base* base, int fd, short bits,
+ void (*cb)(int, short, void*), void* arg)
+{
+ struct my_event *my_ev = (struct my_event*)calloc(1,
+ sizeof(struct my_event));
+
+ if (!my_ev)
+ return NULL;
+
+ event_set(&my_ev->ev, fd, NATIVE_BITS(bits), NATIVE_BITS_CB(cb), arg);
+ if (event_base_set(AS_MY_EVENT_BASE(base)->base, &my_ev->ev) != 0) {
+ free(my_ev);
+ return NULL;
+ }
+ my_ev->super.magic = UB_EVENT_MAGIC;
+ my_ev->super.vmt = &default_event_vmt;
+ return &my_ev->super;
+}
+
+static struct ub_event*
+my_signal_new(struct ub_event_base* base, int fd,
+ void (*cb)(int, short, void*), void* arg)
+{
+ struct my_event *my_ev = (struct my_event*)calloc(1,
+ sizeof(struct my_event));
+
+ if (!my_ev)
+ return NULL;
+
+ signal_set(&my_ev->ev, fd, NATIVE_BITS_CB(cb), arg);
+ if (event_base_set(AS_MY_EVENT_BASE(base)->base, &my_ev->ev) != 0) {
+ free(my_ev);
+ return NULL;
+ }
+ my_ev->super.magic = UB_EVENT_MAGIC;
+ my_ev->super.vmt = &default_event_vmt;
+ return &my_ev->super;
+}
+
+static struct ub_event*
+my_winsock_register_wsaevent(struct ub_event_base* base, void* wsaevent,
+ void (*cb)(int, short, void*), void* arg)
+{
+#if defined(USE_MINI_EVENT) && defined(USE_WINSOCK)
+ struct my_event *my_ev = (struct my_event*)calloc(1,
+ sizeof(struct my_event));
+
+ if (!my_ev)
+ return NULL;
+
+ if (!winsock_register_wsaevent(AS_MY_EVENT_BASE(base)->base,
+ &my_ev->ev, wsaevent, cb, arg)) {
+ free(my_ev);
+ return NULL;
+
+ }
+ my_ev->super.magic = UB_EVENT_MAGIC;
+ my_ev->super.vmt = &default_event_vmt;
+ return &my_ev->super;
+#else
+ (void)base;
+ (void)wsaevent;
+ (void)cb;
+ (void)arg;
+ return NULL;
+#endif
+}
+
+static struct ub_event_base_vmt default_event_base_vmt = {
+ my_event_base_free, my_event_base_dispatch,
+ my_event_base_loopexit, my_event_new, my_signal_new,
+ my_winsock_register_wsaevent
+};
+
+struct ub_event_base*
+ub_default_event_base(int sigs, time_t* time_secs, struct timeval* time_tv)
+{
+ struct my_event_base* my_base = (struct my_event_base*)calloc(1,
+ sizeof(struct my_event_base));
+
+ if (!my_base)
+ return NULL;
+
+#ifdef USE_MINI_EVENT
+ (void)sigs;
+ /* use mini event time-sharing feature */
+ my_base->base = event_init(time_secs, time_tv);
+#else
+ (void)time_secs;
+ (void)time_tv;
+# if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)
+ /* libev */
+ if(sigs)
+ my_base->base = (struct event_base*)ev_default_loop(EVFLAG_AUTO);
+ else
+ my_base->base = (struct event_base*)ev_loop_new(EVFLAG_AUTO);
+# else
+ (void)sigs;
+# ifdef HAVE_EVENT_BASE_NEW
+ my_base->base = event_base_new();
+# else
+ my_base->base = event_init();
+# endif
+# endif
+#endif
+ if (!my_base->base) {
+ free(my_base);
+ return NULL;
+ }
+ my_base->super.magic = UB_EVENT_MAGIC;
+ my_base->super.vmt = &default_event_base_vmt;
+ return &my_base->super;
+}
+
+struct ub_event_base*
+ub_libevent_event_base(struct event_base* base)
+{
+#ifdef USE_MINI_EVENT
+ (void)base;
+ return NULL;
+#else
+ struct my_event_base* my_base = (struct my_event_base*)calloc(1,
+ sizeof(struct my_event_base));
+
+ if (!my_base)
+ return NULL;
+ my_base->super.magic = UB_EVENT_MAGIC;
+ my_base->super.vmt = &default_event_base_vmt;
+ my_base->base = base;
+ return &my_base->super;
+#endif
+}
+
+struct event_base*
+ub_libevent_get_event_base(struct ub_event_base* base)
+{
+#ifndef USE_MINI_EVENT
+ if (base->vmt == &default_event_base_vmt)
+ return AS_MY_EVENT_BASE(base)->base;
+#else
+ (void)base;
+#endif
+ return NULL;
+}
+
+#if (defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)) && defined(EVBACKEND_SELECT)
+static const char* ub_ev_backend2str_pluggable(int b)
+{
+ switch(b) {
+ case EVBACKEND_SELECT: return "select";
+ case EVBACKEND_POLL: return "poll";
+ case EVBACKEND_EPOLL: return "epoll";
+ case EVBACKEND_KQUEUE: return "kqueue";
+ case EVBACKEND_DEVPOLL: return "devpoll";
+ case EVBACKEND_PORT: return "evport";
+ }
+ return "unknown";
+}
+#endif
+
+void
+ub_get_event_sys(struct ub_event_base* ub_base, const char** n, const char** s,
+ const char** m)
+{
+#ifdef USE_WINSOCK
+ (void)ub_base;
+ *n = "pluggable-event";
+ *s = "winsock";
+ *m = "WSAWaitForMultipleEvents";
+#elif defined(USE_MINI_EVENT)
+ (void)ub_base;
+ *n = "pluggable-event";
+ *s = "internal";
+ *m = "select";
+#else
+ struct event_base* b = ub_libevent_get_event_base(ub_base);
+ /* This function is only called from comm_base_create, so
+ * ub_base is guaranteed to exist and to be the default
+ * event base.
+ */
+ assert(b);
+ *n = "pluggable-event";
+ *s = event_get_version();
+# if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)
+ *n = "pluggable-libev";
+# ifdef EVBACKEND_SELECT
+ *m = ub_ev_backend2str_pluggable(ev_backend((struct ev_loop*)b));
+# else
+ *m = "not obtainable";
+# endif
+# elif defined(HAVE_EVENT_BASE_GET_METHOD)
+ *n = "pluggable-libevent";
+ *m = event_base_get_method(b);
+# else
+ *m = "not obtainable";
+# endif
+#endif
+}
+
+void
+ub_event_base_free(struct ub_event_base* base)
+{
+ if (base && base->magic == UB_EVENT_MAGIC) {
+ fptr_ok(base->vmt != &default_event_base_vmt ||
+ base->vmt->free == my_event_base_free);
+ (*base->vmt->free)(base);
+ }
+}
+
+int
+ub_event_base_dispatch(struct ub_event_base* base)
+{
+ if (base->magic == UB_EVENT_MAGIC) {
+ fptr_ok(base->vmt != &default_event_base_vmt ||
+ base->vmt->dispatch == my_event_base_dispatch);
+ return (*base->vmt->dispatch)(base);
+ }
+ return -1;
+}
+
+int
+ub_event_base_loopexit(struct ub_event_base* base)
+{
+ if (base->magic == UB_EVENT_MAGIC) {
+ fptr_ok(base->vmt != &default_event_base_vmt ||
+ base->vmt->loopexit == my_event_base_loopexit);
+ return (*base->vmt->loopexit)(base, NULL);
+ }
+ return -1;
+}
+
+struct ub_event*
+ub_event_new(struct ub_event_base* base, int fd, short bits,
+ void (*cb)(int, short, void*), void* arg)
+{
+ if (base->magic == UB_EVENT_MAGIC) {
+ fptr_ok(base->vmt != &default_event_base_vmt ||
+ base->vmt->new_event == my_event_new);
+ return (*base->vmt->new_event)(base, fd, bits, cb, arg);
+ }
+ return NULL;
+}
+
+struct ub_event*
+ub_signal_new(struct ub_event_base* base, int fd,
+ void (*cb)(int, short, void*), void* arg)
+{
+ if (base->magic == UB_EVENT_MAGIC) {
+ fptr_ok(base->vmt != &default_event_base_vmt ||
+ base->vmt->new_signal == my_signal_new);
+ return (*base->vmt->new_signal)(base, fd, cb, arg);
+ }
+ return NULL;
+}
+
+struct ub_event*
+ub_winsock_register_wsaevent(struct ub_event_base* base, void* wsaevent,
+ void (*cb)(int, short, void*), void* arg)
+{
+ if (base->magic == UB_EVENT_MAGIC) {
+ fptr_ok(base->vmt != &default_event_base_vmt ||
+ base->vmt->winsock_register_wsaevent ==
+ my_winsock_register_wsaevent);
+ return (*base->vmt->winsock_register_wsaevent)(base, wsaevent, cb, arg);
+ }
+ return NULL;
+}
+
+void
+ub_event_add_bits(struct ub_event* ev, short bits)
+{
+ if (ev->magic == UB_EVENT_MAGIC) {
+ fptr_ok(ev->vmt != &default_event_vmt ||
+ ev->vmt->add_bits == my_event_add_bits);
+ (*ev->vmt->add_bits)(ev, bits);
+ }
+}
+
+void
+ub_event_del_bits(struct ub_event* ev, short bits)
+{
+ if (ev->magic == UB_EVENT_MAGIC) {
+ fptr_ok(ev->vmt != &default_event_vmt ||
+ ev->vmt->del_bits == my_event_del_bits);
+ (*ev->vmt->del_bits)(ev, bits);
+ }
+}
+
+void
+ub_event_set_fd(struct ub_event* ev, int fd)
+{
+ if (ev->magic == UB_EVENT_MAGIC) {
+ fptr_ok(ev->vmt != &default_event_vmt ||
+ ev->vmt->set_fd == my_event_set_fd);
+ (*ev->vmt->set_fd)(ev, fd);
+ }
+}
+
+void
+ub_event_free(struct ub_event* ev)
+{
+ if (ev && ev->magic == UB_EVENT_MAGIC) {
+ fptr_ok(ev->vmt != &default_event_vmt ||
+ ev->vmt->free == my_event_free);
+ (*ev->vmt->free)(ev);
+ }
+}
+
+int
+ub_event_add(struct ub_event* ev, struct timeval* tv)
+{
+ if (ev->magic == UB_EVENT_MAGIC) {
+ fptr_ok(ev->vmt != &default_event_vmt ||
+ ev->vmt->add == my_event_add);
+ return (*ev->vmt->add)(ev, tv);
+ }
+ return -1;
+}
+
+int
+ub_event_del(struct ub_event* ev)
+{
+ if (ev->magic == UB_EVENT_MAGIC) {
+ fptr_ok(ev->vmt != &default_event_vmt ||
+ ev->vmt->del == my_event_del);
+ return (*ev->vmt->del)(ev);
+ }
+ return -1;
+}
+
+int
+ub_timer_add(struct ub_event* ev, struct ub_event_base* base,
+ void (*cb)(int, short, void*), void* arg, struct timeval* tv)
+{
+ if (ev->magic == UB_EVENT_MAGIC) {
+ fptr_ok(ev->vmt != &default_event_vmt ||
+ ev->vmt->add_timer == my_timer_add);
+ return (*ev->vmt->add_timer)(ev, base, cb, arg, tv);
+ }
+ return -1;
+}
+
+int
+ub_timer_del(struct ub_event* ev)
+{
+ if (ev->magic == UB_EVENT_MAGIC) {
+ fptr_ok(ev->vmt != &default_event_vmt ||
+ ev->vmt->del_timer == my_timer_del);
+ return (*ev->vmt->del_timer)(ev);
+ }
+ return -1;
+}
+
+int
+ub_signal_add(struct ub_event* ev, struct timeval* tv)
+{
+ if (ev->magic == UB_EVENT_MAGIC) {
+ fptr_ok(ev->vmt != &default_event_vmt ||
+ ev->vmt->add_signal == my_signal_add);
+ return (*ev->vmt->add_signal)(ev, tv);
+ }
+ return -1;
+}
+
+int
+ub_signal_del(struct ub_event* ev)
+{
+ if (ev->magic == UB_EVENT_MAGIC) {
+ fptr_ok(ev->vmt != &default_event_vmt ||
+ ev->vmt->del_signal == my_signal_del);
+ return (*ev->vmt->del_signal)(ev);
+ }
+ return -1;
+}
+
+void
+ub_winsock_unregister_wsaevent(struct ub_event* ev)
+{
+ if (ev->magic == UB_EVENT_MAGIC) {
+ fptr_ok(ev->vmt != &default_event_vmt ||
+ ev->vmt->winsock_unregister_wsaevent ==
+ my_winsock_unregister_wsaevent);
+ (*ev->vmt->winsock_unregister_wsaevent)(ev);
+ }
+}
+
+void
+ub_winsock_tcp_wouldblock(struct ub_event* ev, int eventbits)
+{
+ if (ev->magic == UB_EVENT_MAGIC) {
+ fptr_ok(ev->vmt != &default_event_vmt ||
+ ev->vmt->winsock_tcp_wouldblock ==
+ my_winsock_tcp_wouldblock);
+ (*ev->vmt->winsock_tcp_wouldblock)(ev, eventbits);
+ }
+}
+
+void ub_comm_base_now(struct comm_base* cb)
+{
+ time_t *tt;
+ struct timeval *tv;
+
+#ifdef USE_MINI_EVENT
+/** minievent updates the time when it blocks. */
+ if (comm_base_internal(cb)->magic == UB_EVENT_MAGIC &&
+ comm_base_internal(cb)->vmt == &default_event_base_vmt)
+ return; /* Actually using mini event, so do not set time */
+#endif /* USE_MINI_EVENT */
+
+/** fillup the time values in the event base */
+ comm_base_timept(cb, &tt, &tv);
+ if(gettimeofday(tv, NULL) < 0) {
+ log_err("gettimeofday: %s", strerror(errno));
+ }
+ *tt = tv->tv_sec;
+}
+