chiark / gitweb /
avoid crashes on log client teardown
authorRichard Kettlewell <rjk@greenend.org.uk>
Sun, 4 Nov 2007 11:16:14 +0000 (11:16 +0000)
committerRichard Kettlewell <rjk@greenend.org.uk>
Sun, 4 Nov 2007 11:16:14 +0000 (11:16 +0000)
lib/event.c
lib/eventlog.c
server/server.c

index bb9d4ea6b8d10603aadc5954e72d54ad00002bbf..9c48ed139607114aa9139267ff07490397c1194b 100644 (file)
@@ -978,6 +978,8 @@ ev_writer *ev_writer_new(ev_source *ev,
  * descriptor as and when it is writable.
  */
 struct sink *ev_writer_sink(ev_writer *w) {
  * descriptor as and when it is writable.
  */
 struct sink *ev_writer_sink(ev_writer *w) {
+  if(!w)
+    fatal(0, "ev_write_sink called with null writer");
   return &w->s;
 }
 
   return &w->s;
 }
 
index e652e2218c6a40ddfaa3581f92081f13e5a5802f..b9ae495e00f68985c93f32cf39678548516d7d37 100644 (file)
@@ -48,7 +48,7 @@ void eventlog_remove(struct eventlog_output *lo) {
 }
 
 static void veventlog(const char *keyword, const char *raw, va_list ap) {
 }
 
 static void veventlog(const char *keyword, const char *raw, va_list ap) {
-  struct eventlog_output *p;
+  struct eventlog_output *p, *pnext;
   struct dynstr d;
   const char *param;
 
   struct dynstr d;
   const char *param;
 
@@ -63,8 +63,12 @@ static void veventlog(const char *keyword, const char *raw, va_list ap) {
     dynstr_append_string(&d, raw);
   }
   dynstr_terminate(&d);
     dynstr_append_string(&d, raw);
   }
   dynstr_terminate(&d);
-  for(p = outputs; p; p = p->next)
+  for(p = outputs; p; p = pnext) {
+    /* We must be able to cope with eventlog_remove() being called from inside
+     * the callback */
+    pnext = p;
     p->fn(d.vec, p->user);
     p->fn(d.vec, p->user);
+  }
 }
 
 void eventlog_raw(const char *keyword, const char *raw, ...) {
 }
 
 void eventlog_raw(const char *keyword, const char *raw, ...) {
index 35f352d868b19cf76d3fb334d1b6e246fdef021b..1e4c6ca91930f9d8b1d4ac40849e7926828f236e 100644 (file)
@@ -142,7 +142,10 @@ static int reader_error(ev_source attribute((unused)) *ev,
 
   D(("server reader_error %d %d", fd, errno_value));
   error(errno, "S%x read error on socket", c->tag);
 
   D(("server reader_error %d %d", fd, errno_value));
   error(errno, "S%x read error on socket", c->tag);
-  ev_writer_cancel(c->w);
+  if(c->w) {
+    ev_writer_cancel(c->w);
+    c->w = 0;
+  }
   ev_report(ev);
   info("reader_error closing fd %d", fd); /* TODO */
   xclose(fd);
   ev_report(ev);
   info("reader_error closing fd %d", fd); /* TODO */
   xclose(fd);
@@ -732,8 +735,11 @@ static int logging_reader_callback(ev_source *ev,
 
   /* don't log to this conn any more */
   eventlog_remove(c->lo);
 
   /* don't log to this conn any more */
   eventlog_remove(c->lo);
-  /* terminate the log output */
-  sink_writes(ev_writer_sink(c->w), ".\n");
+  if(c->w) {
+    /* Terminate the log output, but only if the writer hasn't been killed off
+     * from a failure on some earlier write */
+    sink_writes(ev_writer_sink(c->w), ".\n");
+  }
   /* restore the reader callback */
   c->reader = reader_callback;
   /* ...and exit via it */
   /* restore the reader callback */
   c->reader = reader_callback;
   /* ...and exit via it */
@@ -743,6 +749,11 @@ static int logging_reader_callback(ev_source *ev,
 static void logclient(const char *msg, void *user) {
   struct conn *c = user;
 
 static void logclient(const char *msg, void *user) {
   struct conn *c = user;
 
+  if(!c->w || !c->r) {
+    /* This connection has gone up in smoke for some reason */
+    eventlog_remove(c->lo);
+    return;
+  }
   sink_printf(ev_writer_sink(c->w), "%"PRIxMAX" %s\n",
              (uintmax_t)time(0), msg);
 }
   sink_printf(ev_writer_sink(c->w), "%"PRIxMAX" %s\n",
              (uintmax_t)time(0), msg);
 }