diff options
-rw-r--r-- | common/server-mainloop.c | 77 | ||||
-rw-r--r-- | plugin/Makefile.am | 2 | ||||
-rw-r--r-- | plugin/slapi-dnsnotify.c | 76 | ||||
-rw-r--r-- | tools/Makefile.am | 10 | ||||
-rw-r--r-- | tools/notify-dns-slaves.c (renamed from tools/notify-slaves.c) | 59 |
5 files changed, 132 insertions, 92 deletions
diff --git a/common/server-mainloop.c b/common/server-mainloop.c index fcd471d..1ba5085 100644 --- a/common/server-mainloop.c +++ b/common/server-mainloop.c @@ -45,6 +45,7 @@ typedef struct _socket_callback { int fd; server_socket_callback callback; void *arg; + int closed; struct _socket_callback *next; } socket_callback; @@ -54,6 +55,7 @@ typedef struct _timer_callback { struct timeval interval; server_timer_callback callback; void* arg; + int closed; struct _timer_callback *next; } timer_callback; @@ -166,35 +168,33 @@ add_timer (int ms, int oneshot, server_timer_callback callback, void *arg) return 0; } -static timer_callback* -remove_timer(timer_callback *timcb) +static void +remove_closed (void) { - timer_callback *cb; - timer_callback *next; - - if (!ctx.timers) - return NULL; - - /* First in list */; - if (ctx.timers == timcb) { - cb = ctx.timers; - ctx.timers = ctx.timers->next; - free (cb); - return ctx.timers; + timer_callback **tcb, *timcb; + socket_callback **scb, *sockcb; + + for (tcb = &ctx.timers; *tcb; ) { + timcb = *tcb; + if (timcb->closed) { + *tcb = timcb->next; + free (timcb); + continue; + } else { + tcb = &timcb->next; + } } - /* One ahead processing of rest */ - for (cb = ctx.timers; cb->next; cb = cb->next) { - if(cb->next == timcb) { - next = cb->next->next; - free (cb->next); - cb->next = next; - return cb->next; + for (scb = &ctx.callbacks; *scb; ) { + sockcb = *scb; + if (sockcb->closed) { + *scb = sockcb->next; + free (sockcb); + continue; + } else { + scb = &sockcb->next; } } - - /* Couldn't remove, return self */ - return timcb; } void @@ -248,7 +248,7 @@ server_run (void) struct timeval *timeout; struct timeval tv, current; timer_callback *timcb; - socket_callback *sockcb, *socknx; + socket_callback *sockcb; fd_set rfds, wfds; int r; @@ -268,9 +268,12 @@ server_run (void) return -1; /* Cycle through timers */ - for (timcb = ctx.timers; timcb; ) { + for (timcb = ctx.timers; timcb; timcb = timcb->next) { assert (timcb->callback); + if (timcb->closed) + continue; + /* Call any timers that have already passed */ if (timeval_compare (¤t, &timcb->at) >= 0) { @@ -287,7 +290,7 @@ server_run (void) /* Otherwise remove it. Either one shot, or returned 0 */ } else { - timcb = remove_timer (timcb); + timcb->closed = 1; continue; } } @@ -295,8 +298,6 @@ server_run (void) /* Get soonest timer */ if (!timeout || timeval_compare (&timcb->at, timeout) < 0) timeout = &timcb->at; - - timcb = timcb->next; } /* Convert to an offset */ @@ -309,6 +310,10 @@ server_run (void) if (ctx.stopped) continue; + remove_closed (); + if (!ctx.callbacks && !ctx.timers) + break; + /* fprintf(stderr, "selecting with timeout: "); timeval_dump(timeout); fprintf(stderr, "\n"); */ @@ -329,17 +334,16 @@ server_run (void) if(r == 0) continue; - for (sockcb = ctx.callbacks; sockcb; ) { + for (sockcb = ctx.callbacks; sockcb; sockcb = sockcb->next) { assert (sockcb->fd != -1); - socknx = sockcb->next; + if (sockcb->closed) + continue; /* Call any that are set */ if (FD_ISSET (sockcb->fd, &rfds)) (sockcb->callback) (sockcb->fd, SERVER_READ, sockcb->arg); if (FD_ISSET (sockcb->fd, &wfds)) (sockcb->callback) (sockcb->fd, SERVER_WRITE, sockcb->arg); - - sockcb = socknx; } } @@ -405,17 +409,14 @@ server_unwatch (int fd) /* First in list */; if (ctx.callbacks->fd == fd) { - cb = ctx.callbacks; - ctx.callbacks = cb->next; - free (cb); + ctx.callbacks->closed = 1; return; } /* One ahead processing of rest */ for (cb = ctx.callbacks; cb->next; cb = cb->next) { if (cb->next->fd == fd) { - cb->next = cb->next->next; - free (cb->next); + cb->next->closed = 1; return; } } diff --git a/plugin/Makefile.am b/plugin/Makefile.am index d1887a3..9b8f4de 100644 --- a/plugin/Makefile.am +++ b/plugin/Makefile.am @@ -2,7 +2,7 @@ INCLUDES = \ -I$(top_srcdir) \ -DSTRSET_CUSTMEM=1 \ - -DDNS_NOTIFY_PATH=\"$(bindir)/notify-slaves\" + -DDNS_NOTIFY_PATH=\"$(bindir)/notify-dns-slaves\" lib_LTLIBRARIES = slapi-dnsnotify.la diff --git a/plugin/slapi-dnsnotify.c b/plugin/slapi-dnsnotify.c index b871c86..329b913 100644 --- a/plugin/slapi-dnsnotify.c +++ b/plugin/slapi-dnsnotify.c @@ -190,13 +190,32 @@ load_soa_ns_attributes (const char *dn, char **soa_result, char ***ns_result) return 0; } +static void +kill_notify_process (void) +{ + int status; + + if (dnsnotify_pipe != -1) + close (dnsnotify_pipe); + dnsnotify_pipe = -1; + + if (dnsnotify_pid != -1) { + if (waitpid (dnsnotify_pid, &status, WNOHANG) == 0) { + /* We can play rough, because we know process can take it */ + if (kill (dnsnotify_pid, SIGKILL) >= 0) + waitpid (dnsnotify_pid, &status, 0); + } + dnsnotify_pid = -1; + } +} + static int fork_notify_process (void) { - pid_t pid; - int status; + int open_max, fd; int commpipe[2]; char *args[3]; + pid_t pid; if (pipe (commpipe) < 0) { log_plugin ("couldn't create communication pipe for child process: %s", strerror (errno)); @@ -221,18 +240,11 @@ fork_notify_process (void) /* close read end */ close (commpipe[0]); - /* hang onto write end */ - if (dnsnotify_pipe != -1) - close (dnsnotify_pipe); - dnsnotify_pipe = commpipe[1]; + /* Kill any previous process */ + kill_notify_process (); - if (dnsnotify_pid != -1) { - if (waitpid (dnsnotify_pid, &status, WNOHANG) == 0) { - /* We can play rough, because we know process can take it */ - if (kill (dnsnotify_pid, SIGKILL) >= 0) - waitpid (dnsnotify_pid, &status, 0); - } - } + /* hang onto write end, and new pid */ + dnsnotify_pipe = commpipe[1]; dnsnotify_pid = pid; return 0; @@ -245,6 +257,11 @@ fork_notify_process (void) if (dup2 (commpipe[0], 0) < 0) log_plugin ("couldn't setup stdin on notify child process: %s", strerror (errno)); + /* Close all other file descriptors */ + open_max = sysconf (_SC_OPEN_MAX); + for (fd = 3; fd < open_max; ++fd) + close (fd); + args[0] = DNS_NOTIFY_PATH; args[1] = "-s"; args[2] = NULL; @@ -285,7 +302,7 @@ prep_soa_domain (char *soa) /* Find the first space in the SOA and cut it off there */ while (soa[0] && isspace (soa[0])) ++soa; - at = strspn (soa, " \t\n\r\v"); + at = strcspn (soa, " \t\n\r\v"); if (at == 0) { log_plugin ("invalid SOA present"); return NULL; @@ -334,11 +351,11 @@ notify_dns_slaves (char *soa, char **ns) if (!n[0]) continue; - if (write_all (dnsnotify_pipe, "NOTIFY: ", 5) < 0 || + if (write_all (dnsnotify_pipe, "NOTIFY: ", 8) < 0 || write_all (dnsnotify_pipe, soa, strlen (soa)) < 0 || write_all (dnsnotify_pipe, " ", 1) < 0 || - write_all (dnsnotify_pipe, *ns, strlen (soa)) < 0 || - write_all (dnsnotify_pipe, "\n", 2) < 0) { + write_all (dnsnotify_pipe, *ns, strlen (*ns)) < 0 || + write_all (dnsnotify_pipe, "\n", 1) < 0) { if (errno == EPIPE) { complete = 0; break; @@ -363,6 +380,8 @@ slapi_dnsnotify_modify (Slapi_PBlock *pb) return_val_if_fail (pb, -1); + trace ("detect modify"); + /* Make sure it was successful, don't process errors */ rc = slapi_pblock_get (pb, SLAPI_RESULT_CODE, &code); return_val_if_fail (rc >= 0, -1); @@ -380,6 +399,7 @@ slapi_dnsnotify_modify (Slapi_PBlock *pb) for (m = mods; *m; ++m) { mod = *m; + trace (mod->mod_type); if (strcmp (mod->mod_type, dnsnotify_soa_attribute) == 0) { if (load_soa_ns_attributes (dn, &soa, &ns)) { notify_dns_slaves (soa, ns); @@ -432,8 +452,25 @@ static Slapi_PluginDesc plugin_description = { "Notify's DNS slaves when SOA change is made" /* plug-in description */ }; +static int +plugin_destroy (Slapi_PBlock *pb) +{ + if (dnsnotify_mutex) + slapi_lock_mutex (dnsnotify_mutex); + + kill_notify_process (); + + if (dnsnotify_mutex) { + slapi_unlock_mutex (dnsnotify_mutex); + slapi_destroy_mutex (dnsnotify_mutex); + dnsnotify_mutex = NULL; + } + + return 0; +} + int -plugin_init (Slapi_PBlock* pb) +plugin_init (Slapi_PBlock *pb) { char **argv = NULL; int argc = 0; @@ -464,7 +501,8 @@ plugin_init (Slapi_PBlock* pb) } if (slapi_pblock_set (pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03) != 0 || - slapi_pblock_set (pb, SLAPI_PLUGIN_DESCRIPTION, &plugin_description) != 0) { + slapi_pblock_set (pb, SLAPI_PLUGIN_DESCRIPTION, &plugin_description) != 0 || + slapi_pblock_set (pb, SLAPI_PLUGIN_DESTROY_FN, plugin_destroy)) { log_plugin ("error registring plugin"); return -1; } diff --git a/tools/Makefile.am b/tools/Makefile.am index 19bbc50..fe0ffc5 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -4,14 +4,14 @@ INCLUDES = \ $(PTHREAD_CFLAGS) bin_PROGRAMS = \ - notify-slaves + notify-dns-slaves -notify_slaves_SOURCES = \ - notify-slaves.c \ +notify_dns_slaves_SOURCES = \ + notify-dns-slaves.c \ ../common/async-resolver.c \ ../common/server-mainloop.c \ ../common/sock-any.c # TODO: Somehow PTHREAD_LIBS isn't setup on linux gcc -notify_slaves_LDFLAGS = -pthread -notify_slaves_LIBS = $(PTHREAD_LIBS)
\ No newline at end of file +notify_dns_slaves_LDFLAGS = -pthread +notify_dns_slaves_LIBS = $(PTHREAD_LIBS)
\ No newline at end of file diff --git a/tools/notify-slaves.c b/tools/notify-dns-slaves.c index ebd2262..96f2ea7 100644 --- a/tools/notify-slaves.c +++ b/tools/notify-dns-slaves.c @@ -105,13 +105,13 @@ static int the_socket6 = -1; static char stdin_buffer[LINE_LENGTH + 1]; static size_t stdin_offset = 0; -static int stdin_closed = 0; static int processing_active = 0; +static int input_complete = 0; static unsigned int unique_identifier = 1; static int is_helper = 0; -static int debug_level = LOG_WARNING; +static int debug_level = LOG_INFO; typedef struct _notification { struct _notification *next; @@ -164,9 +164,10 @@ vmessage(int level, int erno, const char* msg, va_list ap) } /* Either to syslog or stderr */ - if (is_helper && level < LOG_DEBUG) + if (is_helper && level != LOG_DEBUG) vsyslog (level, buf, ap); - vwarnx(buf, ap); + + vwarnx (buf, ap); } static void @@ -366,20 +367,18 @@ process_all_packets (uint64_t when, void *unused) } } - not = &(*not)->next; + not = ¬if->next; } /* Continue processing? */ if (the_notifications) return 1; - if (stdin_closed) { - debug ("processing done, and no more input, stopping"); + if (input_complete) server_stop (); - } else { - debug ("processing done for now"); - processing_active = 0; - } + + debug ("processing done"); + processing_active = 0; return 0; } @@ -418,6 +417,7 @@ address_resolved (int ecode, struct addrinfo *ai, void *arg) notif->server, gai_strerror (ecode)); *not = notif->next; free (notif); + break; /* A successful resolve */ } else { @@ -426,9 +426,8 @@ address_resolved (int ecode, struct addrinfo *ai, void *arg) SANY_LEN (notif->address) = ai->ai_addrlen; notif->resolved = 1; prepare_and_process (notif, server_get_time ()); + break; } - - break; } } @@ -641,27 +640,25 @@ stdin_callback (int fd, int type, void *arg) if (errno == EAGAIN || errno == EINTR) return; warningx ("couldn't read from stdin"); - server_unwatch (fd); - stdin_closed = 1; - return; + input_complete = 1; } else if (num == 0) { - stdin_closed = 1; - server_unwatch (fd); + debug ("input closed"); + input_complete = 1; + } else { + stdin_offset += num; } - stdin_offset += num; - - for (;;) { + do { line = strchr (stdin_buffer, '\n'); + if (!line && input_complete) + line = stdin_buffer + stdin_offset; + if (!line && stdin_offset >= LINE_LENGTH) { warningx ("input line too long"); line = stdin_buffer + LINE_LENGTH; } - if (!line && stdin_closed) - line = stdin_buffer + stdin_offset; - if (!line) /* Wait for more data */ break; @@ -672,8 +669,12 @@ stdin_callback (int fd, int type, void *arg) stdin_offset = LINE_LENGTH - num; memmove (stdin_buffer, stdin_buffer + num, stdin_offset); - if (stdin_closed) - break; + } while (!input_complete); + + if (input_complete) { + if (!the_notifications) + server_stop (); + server_unwatch (fd); } } @@ -785,14 +786,14 @@ main(int argc, char *argv[]) fatal (1, "couldn't initialize DNS resolver"); if (is_helper) { - stdin_closed = 0; - + openlog ("notify-dns-slaves", 0, LOG_DAEMON); + input_complete = 0; /* Watch stdin for data */ fcntl (0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NONBLOCK); if (server_watch (0, SERVER_READ, stdin_callback, NULL) < 0) fatal (1, "coludn't watch stdin for changes"); } else { - stdin_closed = 1; + input_complete = 1; str = argv[0]; for (i = 1; i < argc; ++i) process_notify (str, argv[i], 0); |