From 92c84d9594b4306a5808c1df4166cef8bd5ae7a9 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 12 Aug 2016 16:40:05 +0200 Subject: [PATCH 1/4] libreplace: Ask for eventfd(2) This will be used in tevent soon Signed-off-by: Volker Lendecke Reviewed-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 4771d0792e4343cc8631a36247a2f3c7c31d58b3) --- lib/replace/wscript | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/replace/wscript b/lib/replace/wscript index 145300d235c..1dfd90293ea 100644 --- a/lib/replace/wscript +++ b/lib/replace/wscript @@ -483,6 +483,9 @@ removeea setea if conf.CONFIG_SET('HAVE_PORT_CREATE') and conf.CONFIG_SET('HAVE_PORT_H'): conf.DEFINE('HAVE_SOLARIS_PORTS', 1) + if conf.CHECK_FUNCS('eventfd', headers='sys/eventfd.h'): + conf.DEFINE('HAVE_EVENTFD', 1) + conf.CHECK_HEADERS('poll.h') conf.CHECK_FUNCS('poll') -- 2.11.0 From 288fdc54121988105e28adeb35ef2bb6daa509f6 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 15 Aug 2016 10:33:09 +0200 Subject: [PATCH 2/4] tevent: Fix a typo Signed-off-by: Volker Lendecke Reviewed-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit c4ef0c8f3ecc4266fed3af8537ba2998730b3750) --- lib/tevent/tevent_threads.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c index 15882e4f40b..22b854c410f 100644 --- a/lib/tevent/tevent_threads.c +++ b/lib/tevent/tevent_threads.c @@ -108,7 +108,7 @@ static void schedule_immediate_functions(struct tevent_thread_proxy *tp) if (tp->tofree_im_list != NULL) { /* * Once the current immediate events - * are processed, we need to reshedule + * are processed, we need to reschedule * ourselves to free them. This works * as tevent_schedule_immediate() * always adds events to the *END* of -- 2.11.0 From 2988c42c7fb06dea5d952ec50be5e767b0e9efc0 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 29 Jul 2016 08:53:59 +0200 Subject: [PATCH 3/4] tevent: Move the async wakeup pipe to common Signalling the main event loop will also happen from threads soon, and that will use the same mechanism. This also keeps the pipe open after the last signal handler is removed. Threaded jobs will come and go very frequently, and always setting up and tearing down the pipe for each job will be expensive. Also, this is "just" two file descriptors, and with eventfd just one. Signed-off-by: Volker Lendecke Reviewed-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 8a9b8ac72461657a3a5de2fd5232eaa9861bf696) --- lib/tevent/ABI/tevent-0.9.29.sigs | 3 ++ lib/tevent/tevent.c | 87 +++++++++++++++++++++++++++++++++++++-- lib/tevent/tevent_internal.h | 4 ++ lib/tevent/tevent_poll.c | 5 +-- lib/tevent/tevent_signal.c | 60 ++++----------------------- 5 files changed, 99 insertions(+), 60 deletions(-) diff --git a/lib/tevent/ABI/tevent-0.9.29.sigs b/lib/tevent/ABI/tevent-0.9.29.sigs index 135775171ea..4b647419d08 100644 --- a/lib/tevent/ABI/tevent-0.9.29.sigs +++ b/lib/tevent/ABI/tevent-0.9.29.sigs @@ -28,10 +28,13 @@ tevent_common_fd_destructor: int (struct tevent_fd *) tevent_common_fd_get_flags: uint16_t (struct tevent_fd *) tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t) tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t) +tevent_common_have_events: bool (struct tevent_context *) tevent_common_loop_immediate: bool (struct tevent_context *) tevent_common_loop_timer_delay: struct timeval (struct tevent_context *) tevent_common_loop_wait: int (struct tevent_context *, const char *) tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *) +tevent_common_wakeup: int (struct tevent_context *) +tevent_common_wakeup_init: int (struct tevent_context *) tevent_context_init: struct tevent_context *(TALLOC_CTX *) tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *) tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *) diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c index 843cf0560f3..34cd402d5e4 100644 --- a/lib/tevent/tevent.c +++ b/lib/tevent/tevent.c @@ -620,6 +620,28 @@ done: return ret; } +bool tevent_common_have_events(struct tevent_context *ev) +{ + if (ev->fd_events != NULL) { + if (ev->fd_events != ev->pipe_fde) { + return true; + } + if (ev->fd_events->next != NULL) { + return true; + } + + /* + * At this point we just have the wakeup pipe event as + * the only fd_event. That one does not count as a + * regular event, so look at the other event types. + */ + } + + return ((ev->timer_events != NULL) || + (ev->immediate_events != NULL) || + (ev->signal_events != NULL)); +} + /* return on failure or (with 0) if all fd events are removed */ @@ -629,10 +651,7 @@ int tevent_common_loop_wait(struct tevent_context *ev, /* * loop as long as we have events pending */ - while (ev->fd_events || - ev->timer_events || - ev->immediate_events || - ev->signal_events) { + while (tevent_common_have_events(ev)) { int ret; ret = _tevent_loop_once(ev, location); if (ret != 0) { @@ -670,3 +689,63 @@ int tevent_re_initialise(struct tevent_context *ev) return ev->ops->context_init(ev); } + +static void wakeup_pipe_handler(struct tevent_context *ev, + struct tevent_fd *fde, + uint16_t flags, void *_private) +{ + ssize_t ret; + + char c[16]; + /* its non-blocking, doesn't matter if we read too much */ + do { + ret = read(fde->fd, c, sizeof(c)); + } while (ret == -1 && errno == EINTR); +} + +/* + * Initialize the wakeup pipe and pipe fde + */ + +int tevent_common_wakeup_init(struct tevent_context *ev) +{ + int ret; + + if (ev->pipe_fde != NULL) { + return 0; + } + + ret = pipe(ev->pipe_fds); + if (ret == -1) { + return errno; + } + ev_set_blocking(ev->pipe_fds[0], false); + ev_set_blocking(ev->pipe_fds[1], false); + + ev->pipe_fde = tevent_add_fd(ev, ev, ev->pipe_fds[0], + TEVENT_FD_READ, + wakeup_pipe_handler, NULL); + if (ev->pipe_fde == NULL) { + close(ev->pipe_fds[0]); + close(ev->pipe_fds[1]); + return ENOMEM; + } + + return 0; +} + +int tevent_common_wakeup(struct tevent_context *ev) +{ + ssize_t ret; + + if (ev->pipe_fds[1] == -1) { + return ENOTCONN; + } + + do { + char c = '\0'; + ret = write(ev->pipe_fds[1], &c, 1); + } while ((ret == -1) && (errno == EINTR)); + + return 0; +} diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h index 10cc4a47f83..83627705095 100644 --- a/lib/tevent/tevent_internal.h +++ b/lib/tevent/tevent_internal.h @@ -328,6 +328,10 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im, const char *location); bool tevent_common_loop_immediate(struct tevent_context *ev); +bool tevent_common_have_events(struct tevent_context *ev); +int tevent_common_wakeup_init(struct tevent_context *ev); +int tevent_common_wakeup(struct tevent_context *ev); + struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev, TALLOC_CTX *mem_ctx, int signum, diff --git a/lib/tevent/tevent_poll.c b/lib/tevent/tevent_poll.c index e1c305d20ea..3547e912b2c 100644 --- a/lib/tevent/tevent_poll.c +++ b/lib/tevent/tevent_poll.c @@ -667,10 +667,7 @@ static int poll_event_loop_wait(struct tevent_context *ev, /* * loop as long as we have events pending */ - while (ev->fd_events || - ev->timer_events || - ev->immediate_events || - ev->signal_events || + while (tevent_common_have_events(ev) || poll_ev->fresh || poll_ev->disabled) { int ret; diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c index 635a7a177aa..c85e1c528c4 100644 --- a/lib/tevent/tevent_signal.c +++ b/lib/tevent/tevent_signal.c @@ -95,7 +95,6 @@ static uint32_t tevent_sig_count(struct tevent_sigcounter s) */ static void tevent_common_signal_handler(int signum) { - char c = 0; struct tevent_common_signal_list *sl; struct tevent_context *ev = NULL; int saved_errno = errno; @@ -106,13 +105,8 @@ static void tevent_common_signal_handler(int signum) /* Write to each unique event context. */ for (sl = sig_state->sig_handlers[signum]; sl; sl = sl->next) { if (sl->se->event_ctx && sl->se->event_ctx != ev) { - ssize_t ret; - ev = sl->se->event_ctx; - /* doesn't matter if this pipe overflows */ - do { - ret = write(ev->pipe_fds[1], &c, 1); - } while (ret == -1 && errno == EINTR); + tevent_common_wakeup(ev); } } @@ -198,16 +192,6 @@ static int tevent_signal_destructor(struct tevent_signal *se) struct tevent_context *ev = se->event_ctx; DLIST_REMOVE(ev->signal_events, se); - - if (ev->signal_events == NULL && ev->pipe_fde != NULL) { - /* - * This was the last signal. Destroy the pipe. - */ - TALLOC_FREE(ev->pipe_fde); - - close(ev->pipe_fds[0]); - close(ev->pipe_fds[1]); - } } talloc_free(sl); @@ -233,21 +217,6 @@ static int tevent_signal_destructor(struct tevent_signal *se) } /* - this is part of the pipe hack needed to avoid the signal race condition -*/ -static void signal_pipe_handler(struct tevent_context *ev, struct tevent_fd *fde, - uint16_t flags, void *_private) -{ - ssize_t ret; - - char c[16]; - /* its non-blocking, doesn't matter if we read too much */ - do { - ret = read(fde->fd, c, sizeof(c)); - } while (ret == -1 && errno == EINTR); -} - -/* add a signal event return NULL on failure (memory allocation error) */ @@ -263,6 +232,13 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev, struct tevent_signal *se; struct tevent_common_signal_list *sl; sigset_t set, oldset; + int ret; + + ret = tevent_common_wakeup_init(ev); + if (ret != 0) { + errno = ret; + return NULL; + } if (signum >= TEVENT_NUM_SIGNALS) { errno = EINVAL; @@ -304,26 +280,6 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev, return NULL; } - /* we need to setup the pipe hack handler if not already - setup */ - if (ev->pipe_fde == NULL) { - if (pipe(ev->pipe_fds) == -1) { - talloc_free(se); - return NULL; - } - ev_set_blocking(ev->pipe_fds[0], false); - ev_set_blocking(ev->pipe_fds[1], false); - ev->pipe_fde = tevent_add_fd(ev, ev, ev->pipe_fds[0], - TEVENT_FD_READ, - signal_pipe_handler, NULL); - if (!ev->pipe_fde) { - close(ev->pipe_fds[0]); - close(ev->pipe_fds[1]); - talloc_free(se); - return NULL; - } - } - /* only install a signal handler if not already installed */ if (sig_state->sig_handlers[signum] == NULL) { struct sigaction act; -- 2.11.0 diff --git a/python/samba/tests/dns.py b/python/samba/tests/dns.py index 43eccddd957..9d040acdea4 100644 --- a/python/samba/tests/dns.py +++ b/python/samba/tests/dns.py @@ -937,6 +937,29 @@ class TestComplexQueries(DNSTest): self.assertEquals(response.answers[1].name, name2) self.assertEquals(response.answers[1].rdata, name0) + def test_cname_loop(self): + cname1 = "cnamelooptestrec." + self.get_dns_domain() + cname2 = "cnamelooptestrec2." + self.get_dns_domain() + cname3 = "cnamelooptestrec3." + self.get_dns_domain() + self.make_dns_update(cname1, cname2, dnsp.DNS_TYPE_CNAME) + self.make_dns_update(cname2, cname3, dnsp.DNS_TYPE_CNAME) + self.make_dns_update(cname3, cname1, dnsp.DNS_TYPE_CNAME) + + p = self.make_name_packet(dns.DNS_OPCODE_QUERY) + questions = [] + + q = self.make_name_question(cname1, + dns.DNS_QTYPE_A, + dns.DNS_QCLASS_IN) + questions.append(q) + self.finish_name_packet(p, questions) + + response = self.dns_transaction_udp(p) + + max_recursion_depth = 20 + self.assertEquals(len(response.answers), max_recursion_depth) + + class TestInvalidQueries(DNSTest): def test_one_a_query(self): diff --git a/selftest/knownfail.d/dns b/selftest/knownfail.d/dns index 6553c1fffe0..a22bcce6bf4 100644 --- a/selftest/knownfail.d/dns +++ b/selftest/knownfail.d/dns @@ -45,6 +45,11 @@ samba.tests.dns.__main__.TestSimpleQueries.test_one_SOA_query\(rodc:local\) samba.tests.dns.__main__.TestSimpleQueries.test_one_SOA_query\(vampire_dc:local\) samba.tests.dns.__main__.TestSimpleQueries.test_one_a_query\(vampire_dc:local\) samba.tests.dns.__main__.TestSimpleQueries.test_one_a_query_tcp\(vampire_dc:local\) +# +# rodc and vampire_dc require signed dns updates, so the test setup +# fails, but the test does run on fl2003dc +^samba.tests.dns.__main__.TestComplexQueries.test_cname_loop\(rodc:local\) +^samba.tests.dns.__main__.TestComplexQueries.test_cname_loop\(vampire_dc:local\) samba.tests.dns.__main__.TestSimpleQueries.test_one_mx_query\(vampire_dc:local\) samba.tests.dns.__main__.TestSimpleQueries.test_qtype_all_query\(vampire_dc:local\) samba.tests.dns.__main__.TestSimpleQueries.test_soa_hostname_query\(vampire_dc:local\) diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c index b8ecc2e7ac7..89199e16787 100644 --- a/source4/dns_server/dns_query.c +++ b/source4/dns_server/dns_query.c @@ -40,6 +40,7 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_DNS +#define MAX_Q_RECURSION_DEPTH 20 struct forwarder_string { const char *forwarder; @@ -470,6 +471,11 @@ static struct tevent_req *handle_dnsrpcrec_send( state->answers = answers; state->nsrecs = nsrecs; + if (talloc_array_length(*answers) >= MAX_Q_RECURSION_DEPTH) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } + resolve_cname = ((rec->wType == DNS_TYPE_CNAME) && ((question->question_type == DNS_QTYPE_A) || (question->question_type == DNS_QTYPE_AAAA)));