CHROMIUM: Initial work eventizing tlsdated

tlsdated provides the daemonized integration of tlsdate and the host
system -- resumable time, DBus announcements, time-sync events, and so
on.

At present, it provides only netlink based wakeups and limited
time synchronization.  On Chromium OS, proxy support and network
changes are integrated through external shell scripts monitoring
DBus.  These scripts lack the robustness required for a production
grade time synchronization system.

This change is manyfold:
- Convert tlsdated "wakeup" input into events
- Convert tlsdate execution and status collection into a event-friendly technique
- Integrate libevent into the tlsdated design
- Integrate support for platform specific wake up events
- Integrate support for dynamic proxy resolution on each tlsdate call
- Integrate CrOS wakeup events: proxy changes, default network service change, power state/resume, etc
- Integrate time continuity checking using MONOTONIC clocks versus REALTIME for all wake events
- Integrate DBus support directly into the event loop to allow for message sending
  and signal receipt (e.g., dbus_announce)
- Addition of DOT file for laying out event flows
- Split off time setting to a privileged helper by having tlsdate pass back time_t
- Added configure support for --enable-cros and libevent2 checking
- Support dynamic proxy resolution for multiple sources
- Fixed a NULL deref in source traversal
- Added "sync type" and priority
- Added DBus interface for SetTime, CanSetTime, LastSyncInfo methods.
- Added "sync source" to the TimeUpdated signal
- Updated existing unittests
- Add seccomp filter for priv'd time setter
- Added dynamic proxy per source so we can add a final source with no proxy.
- Style consistency: "find ./ -name '*.[ch]' -exec astyle --style=gnu -xd \{\} \;"
  Followed by the same with sed -i -e 's/) )/))/g'
- Added DBus policy and interface files and a new dbus-client-group configure argument.

Design: https://docs.google.com/a/google.com/document/d/1U1y7KBMo-BgWPspzoyeO5gSmU6dMwEJBc2HNNkGMJzY/view

- Outstanding work: new unit and integration tests

BUG=chromium:271644
TEST=manually tested on x86_64, arm, and x86-32.
     end-to-end autotest: https://chromium-review.googlesource.com/#/c/169141/
     fixed up existing autotests: https://chromium-review.googlesource.com/174782

Change-Id: I0d24951182a768532d6d04eea2224ac70cf04052
Reviewed-on: https://chromium-review.googlesource.com/169131
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
Tested-by: Will Drewry <wad@chromium.org>
Commit-Queue: Will Drewry <wad@chromium.org>
diff --git a/Makefile.am b/Makefile.am
index 9f18106..d5abfc0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -44,6 +44,7 @@
 	@rm config/missing
 	@rm configure
 	@rmdir config
+	@rm dbus/org.torproject.tlsdate.conf
 	@rm m4/libtool.m4
 	@rm m4/ltoptions.m4
 	@rm m4/ltsugar.m4
@@ -67,7 +68,6 @@
 man_MANS+= man/tlsdate-helper.1
 man_MANS+= man/tlsdate-routeup.1
 man_MANS+= man/tlsdated.conf.5
-man_MANS+= man/tlsdate-dbus-announce.1
 EXTRA_DIST+= $(man_MANS)
 
 .PHONY: debian_orig git-tag git-push git-tag-debian deb really-clean valgrind_test
diff --git a/configure.ac b/configure.ac
index 8e4074d..1b1cb57 100644
--- a/configure.ac
+++ b/configure.ac
@@ -27,7 +27,7 @@
 COMPILE_DATE=`date +%s`
 AC_SUBST([COMPILE_DATE])
 AC_DEFINE_UNQUOTED([RECENT_COMPILE_DATE],
-                   [(uint32_t) ${COMPILE_DATE}],
+                   [${COMPILE_DATE}L],
                    [Time in seconds since the Disco epoch at build time])
 
 dnl Build up the directory we will use to install certs
@@ -59,8 +59,13 @@
 AC_CHECK_HEADERS([time.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
 AC_CHECK_HEADERS([unistd.h], ,[AC_MSG_ERROR([Required headers missing; compilation will not succeed])])
 
-AC_CHECK_FUNCS([setresuid])
-AC_CHECK_FUNCS([gettimeofday])
+AC_CHECK_FUNCS_ONCE(m4_flatten([
+    gettimeofday
+    prctl
+    preadv
+    pwritev
+    setresuid
+]))
 
 AC_MSG_CHECKING([user/group to drop privs to])
 
@@ -71,6 +76,7 @@
         [""|yes|no], [UNPRIV_USER="nobody"],
         [*], [UNPRIV_USER=$with_unpriv_user])
 AC_DEFINE_UNQUOTED([UNPRIV_USER], ["${UNPRIV_USER}"], [Unprivileged user])
+AC_SUBST([UNPRIV_USER])
 
 AC_ARG_WITH([unpriv-group],
             [AS_HELP_STRING([--with-unpriv-group=<group>],
@@ -82,6 +88,17 @@
 
 AC_MSG_RESULT(${UNPRIV_USER}:${UNPRIV_GROUP})
 
+AC_MSG_CHECKING([group to allow DBus calls from])
+AC_ARG_WITH([dbus-client-group],
+            [AS_HELP_STRING([--with-dbus-client-group=<group>],
+                [Allow dbus method calls from group @<:@default: root@:>@])])
+AS_CASE([$with_dbus_client_group],
+        [""|yes|no], [DBUS_CLIENT_GROUP="root"],
+        [*], [DBUS_CLIENT_GROUP=$with_dbus_client_group])
+AC_DEFINE_UNQUOTED([DBUS_CLIENT_GROUP], ["${DBUS_CLIENT_GROUP}"], [DBus client group])
+AC_MSG_RESULT(${DBUS_CLIENT_GROUP})
+AC_SUBST([DBUS_CLIENT_GROUP])
+
 dnl Check for clock_gettime.  Some systems put it into -lc, while
 dnl others use -lrt.  Try the first and fallback to the latter.
 RT_LIB=
@@ -90,36 +107,100 @@
                             [AC_MSG_ERROR([Your system lacks clock_gettime])])])
 AC_SUBST(RT_LIB)
 
+PKG_CHECK_MODULES([LIBEVENT], [libevent >= 2.0])
+
+have_dbus=false
 AC_ARG_ENABLE([dbus],
               [AS_HELP_STRING([--disable-dbus],
                               [Disable automatically dbus support])])
 AS_IF([test "x$enable_dbus" = xyes], [
     PKG_CHECK_MODULES([DBUS], [dbus-1], [
-            AC_DEFINE([HAVE_DBUS], [1], [Enable dbus support])
-            AC_MSG_CHECKING([user/group to use for dbus])
-            AC_ARG_WITH([dbus-user],
-                        [AS_HELP_STRING([--with-dbus-user=<user>],
-                                        [User to send dbus signals from @<:@default: nobody@:>@])])
-            AS_CASE([$with_dbus_user],
-                    [""|yes|no], [DBUS_USER="nobody"],
-                    [*], [DBUS_USER=$with_dbus_user])
-            AC_ARG_WITH([dbus-group],
-                        [AS_HELP_STRING([--with-dbus-group=<group>],
-                                        [Group to send dbus signals from @<:@default: nogroup@:>@])])
-            AS_CASE([$with_dbus_group],
-                    [""|yes|no], [DBUS_GROUP="nogroup"],
-                    [*], [DBUS_GROUP=$with_dbus_group])
-            AC_MSG_RESULT(${DBUS_USER}:${DBUS_GROUP})
-            AC_DEFINE_UNQUOTED([DBUS_USER], ["${DBUS_USER}"], [DBus user])
-            AC_DEFINE_UNQUOTED([DBUS_GROUP], ["${DBUS_GROUP}"], [DBus group])
+            have_dbus=true
+            AC_DEFINE([HAVE_DBUS], [1], [dbus enabled])
         ], [
             AS_IF([test "x$enable_dbus" = xyes],
                   [AC_MSG_ERROR([dbus requested but not found])])
         ])
     ])
+AM_CONDITIONAL([HAVE_DBUS], ${have_dbus})
 
 AC_SUBST(DBUS_CFLAGS)
 AC_SUBST(DBUS_LIBS)
+AC_SUBST(LIBEVENT_CFLAGS)
+AC_SUBST(LIBEVENT_LIBS)
+
+have_seccomp_filter=false
+AC_ARG_ENABLE([seccomp_filter],
+              [AS_HELP_STRING([--enable-seccomp-filter],
+                              [Require seccomp filter])])
+
+AC_MSG_CHECKING([kernel for seccomp_filter support])
+AS_IF([test "x$enable_seccomp_filter" = xyes], [
+    dnl Force seccomp filter use
+    have_seccomp_filter=true
+    AC_MSG_RESULT([forced])
+  ], [
+  dnl Detect seccomp filter support.
+  AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+      #include <errno.h>
+      #include <linux/audit.h>
+      #include <linux/filter.h>
+      #include <stdlib.h>
+      #include <sys/prctl.h>
+      #include "src/seccomp-compat.h"
+    ]],
+    [[ errno = 0;
+       if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
+         exit(1);
+       prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, 0, 0);
+       exit(errno == EFAULT ? 0 : 1); ]])],
+    [ AC_MSG_RESULT([yes])
+      have_seccomp_filter=true
+    ], [
+      AC_MSG_RESULT([no])
+    ],
+    [ AC_MSG_RESULT([cross-compiling, assuming yes])
+      have_seccomp_filter=true
+    ]
+  )
+])
+
+AS_IF([${have_seccomp_filter}], [
+    AC_DEFINE([HAVE_SECCOMP_FILTER], [1], [Enable seccomp filter])
+  ])
+AM_CONDITIONAL([HAVE_SECCOMP_FILTER], ${have_seccomp_filter})
+
+
+
+have_seccomp_debug=false
+AC_ARG_ENABLE([seccomp_debugging],
+              [AS_HELP_STRING([--enable-seccomp-debugging],
+                [Enable seccomp filter debugging])])
+AS_IF([test "x$enable_seccomp_debugging" = xyes], [
+    AC_DEFINE([SECCOMP_FILTER_DEBUG], [1], [Enable seccomp filter debugging])
+    have_seccomp_debug=true
+  ])
+AM_CONDITIONAL([SECCOMP_FILTER_DEBUG], ${have_seccomp_debug})
+
+
+AC_MSG_CHECKING([for CrOS-specific platform wake event support])
+AC_ARG_ENABLE([cros],
+              [AS_HELP_STRING([--disable-cros],
+                              [Disable CrOS platform support])])
+
+AS_IF([test "x$enable_cros" = xyes -a "x$enable_dbus" != xyes ], [
+    AC_MSG_ERROR([--enable-dbus is required for --enable-cros])
+  ])
+
+have_cros=false
+AS_IF([test "x$enable_cros" = xyes], [
+    have_cros=true
+    AC_DEFINE([HAVE_CROS], [1], [Enable CrOS support])
+    AC_MSG_RESULT([yes])
+  ], [
+    AC_MSG_RESULT([no])
+  ])
+AM_CONDITIONAL([HAVE_CROS], ${have_cros})
 
 dnl Debug and hardening flags all in one shot
 dnl Always do this at the end, otherwise you end up filtering system/other libraries
@@ -154,5 +235,6 @@
                               [Enable gcov/lcov compile time options])],
               [AX_APPEND_COMPILE_FLAGS([-ftest-coverage -fprofile-arcs])])
 
+AC_CONFIG_FILES([dbus/org.torproject.tlsdate.conf])
 AC_CONFIG_FILES([Makefile])
 AC_OUTPUT
diff --git a/dbus/org.torproject.tlsdate.conf.in b/dbus/org.torproject.tlsdate.conf.in
new file mode 100644
index 0000000..80c83c1
--- /dev/null
+++ b/dbus/org.torproject.tlsdate.conf.in
@@ -0,0 +1,31 @@
+<!DOCTYPE busconfig PUBLIC
+          "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+          "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+
+  <!-- Only certain user can own the tlsdated service -->
+  <policy user="@UNPRIV_USER@">
+    <allow own="org.torproject.tlsdate"/>
+  </policy>
+
+  <!-- Allow anyone in the given group to invoke methods -->
+  <policy group="@DBUS_CLIENT_GROUP@">
+    <allow send_destination="org.torproject.tlsdate"
+           send_interface="org.torproject.tlsdate"
+           send_member="LastSyncInfo"/>
+    <allow send_destination="org.torproject.tlsdate"
+           send_interface="org.torproject.tlsdate"
+           send_member="SetTime"/>
+    <allow send_destination="org.torproject.tlsdate"
+           send_interface="org.torproject.tlsdate"
+           send_member="CanSetTime"/>
+  </policy>
+
+  <!-- Disallow anyone to invoke methods on tlsdated interface -->
+  <policy context="default">
+    <deny send_interface="org.torproject.tlsdate" />
+    <allow send_destination="org.torproject.tlsdate"
+           send_interface="org.torproject.tlsdate"
+           send_member="LastSyncInfo"/>
+  </policy>
+</busconfig>
diff --git a/dbus/org.torproject.tlsdate.service b/dbus/org.torproject.tlsdate.service
new file mode 100644
index 0000000..36ee56d
--- /dev/null
+++ b/dbus/org.torproject.tlsdate.service
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.torproject.tlsdate
+Exec=/usr/bin/tlsdated
diff --git a/dbus/org.torproject.tlsdate.xml b/dbus/org.torproject.tlsdate.xml
new file mode 100644
index 0000000..2023494
--- /dev/null
+++ b/dbus/org.torproject.tlsdate.xml
@@ -0,0 +1,42 @@
+<!DOCTYPE node PUBLIC
+"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
+
+  <interface name="org.torproject.tlsdate">
+    <method name="SetTime">
+      <arg name="time" direction="in" type="x">
+        <doc:doc><doc:summary>The requested time to set the system clock to. It may be tested
+        with:
+        dbus-send --print-reply --system --dest=org.torproject.tlsdate --type=method_call \
+                 /org/torproject/tlsdate org.torproject.tlsdate.SetTime int64:12345678
+        </doc:summary></doc:doc>
+      </arg>
+      <arg name="code" direction="out" type="u">
+        <doc:doc><doc:summary>Returns success or failure via an enum:
+          OK:0, Bad value:1, Not allowed:2, Bad call format:3
+        </doc:summary></doc:doc>
+      </arg>
+    </method>
+    <method name="CanSetTime">
+      <arg name="code" direction="out" type="b">
+        <doc:doc><doc:summary>Returns TRUE is SetTime is allowed.
+        </doc:summary></doc:doc>
+      </arg>
+    </method>
+    <method name="LastSyncInfo">
+      <arg name="network_synchronized" direction="out" type="b">
+        <doc:doc><doc:summary>Whether the time is rooted in a network synchronization source since
+                              fallback to "system-clock" happens at steady state intervals.
+        </doc:summary></doc:doc>
+      </arg>
+      <arg name="source" direction="out" type="s">
+        <doc:doc><doc:summary>Name of the last source</doc:summary></doc:doc>
+      </arg>
+      <arg name="time" direction="out" type="x">
+        <doc:doc><doc:summary>Last sync time</doc:summary></doc:doc>
+      </arg>
+    </method>
+
+  </interface>
+</node>
diff --git a/events.dot b/events.dot
new file mode 100644
index 0000000..658240b
--- /dev/null
+++ b/events.dot
@@ -0,0 +1,58 @@
+/* This DOT file represents the logical interaction between
+ * the events in the system and the "state" of tlsdated.
+ */
+digraph tlsdated {
+  graph[compound=true];
+
+  node[style=filled,color=lightblue];
+
+  subgraph cluster_states {
+    state_label[shape=box,style=dashed,label="States"];
+    sleep -> wake;
+    wake -> sync;
+    sync -> save;
+    save -> sleep;
+    wake -> terminate;
+    sync -> terminate;
+    save -> terminate;
+  }
+
+  subgraph cluster_wake {
+    color=purple;
+    style=filled;
+    wake_label[shape=box,style=dashed,label="Wake Events"];
+    periodic_local_clock_check -> wake;
+    periodic_network_sync -> wake;
+    random_sigterm -> wake;
+    random_route_change -> wake;
+  }
+
+  subgraph cluster_dbus {
+    dbus_label[shape=box,style=dashed,label="DBus Events"];
+    dbus-> cros_shill_manager_change -> wake;
+    dbus-> cros_shill_service_change -> wake;
+    dbus -> cros_proxy_resolved -> {proxy_ok, proxy_failed};
+    dbus -> cros_user_set_time -> save;
+            cros_user_set_time -> sync [style=dotted];
+    get_proxy -> cros_resolve_proxy -> dbus;
+    announce -> dbus;
+  }
+
+  subgraph cluster_sync {
+    sync_label[shape=box,style=dashed,label="Network Sync"];
+    sync -> get_proxy -> {proxy_ok, proxy_failed, proxy_timed_out} -> tlsdate;
+    tlsdate -> tlsdate_ok -> save;
+    tlsdate -> tlsdate_fail;
+    tlsdate_fail -> tlsdate [label="retry",style=dotted];
+    tlsdate_fail -> terminate;
+  };
+
+  subgraph cluster_save {
+    save_label[shape=box,style=dashed,label="Save to the system"];
+    save -> { synchronize_rtc, synchronize_kernel, synchronize_disk } -> { save_ok, save_fail, save_bad_time };
+    save_ok -> announce -> sleep;
+    save_fail -> terminate;
+    save_bad_time -> sleep;
+  }
+}
+
diff --git a/man/tlsdate-dbus-announce.1 b/man/tlsdate-dbus-announce.1
deleted file mode 100644
index 92f4947..0000000
--- a/man/tlsdate-dbus-announce.1
+++ /dev/null
@@ -1,24 +0,0 @@
-.\" Process this file with
-.\" groff -man -Tascii foo.1
-.\"
-.TH TLSDATE-DBUS-ANNOUNCE 1 "JANUARY 2013" Linux "User Manuals"
-.SH NAME
-tlsdate-dbus-announce \- secure parasitic rdate replacement dbus announcer
-.SH SYNOPSIS
-.B tlsdate-dbus-announce
-.SH DESCRIPTION
-.B tlsdate-dbus-announce
-is a tool for use with tlsdated. It is automatically launched by tlsdated to
-announce that the system time has changed.
-.SH BUGS
-It's likely! Let us know by contacting jacob@appelbaum.net
-
-Note that
-.B tlsdate(1)
-is still in Alpha, and may not work as expected.
-.SH AUTHOR
-Jacob Appelbaum <jacob at appelbaum dot net>
-.SH "SEE ALSO"
-.B tlsdated(1),
-.B tlsdate-helper(1)
-.B tlsdate-routeup(1)
diff --git a/src/Makefile.am b/src/Makefile.am
index ec4c676..348fe88 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,14 +9,26 @@
 proxy_bio_unittest_SOURCES = proxy-bio.c proxy-bio-unittest.c test-bio.c util.c
 proxy_bio_unittest_LDADD = -lssl -lcrypto
 tlsdate_routeup_SOURCES = routeup.c util.c
-tlsdate_routeup_CFLAGS = $(AM_CFLAGS) -DROUTEUP_MAIN
+tlsdate_routeup_CPPFLAGS = -DROUTEUP_MAIN
 tlsdate_SOURCES = tlsdate.c
 tlsdate_helper_SOURCES = proxy-bio.c util.c tlsdate-helper.c
 tlsdate_helper_LDADD = -lssl -lcrypto -lrt \
                        $(top_builddir)/src/compat/libtlsdate_compat.la
-tlsdated_SOURCES = routeup.c tlsdated.c util.c
-tlsdated_CFLAGS = $(AM_CFLAGS) -DTLSDATED_MAIN
-tlsdated_unittest_SOURCES = routeup.c tlsdated-unittest.c util.c
+tlsdated_SOURCES = routeup.c tlsdate-monitor.c tlsdated.c util.c \
+                   tlsdate-setter.c \
+                   events/check_continuity.c events/kickoff_time_sync.c \
+                   events/route_up.c events/run_tlsdate.c events/sigterm.c \
+                   events/save.c events/time_set.c events/tlsdate_status.c \
+                   events/sigchld.c
+if HAVE_SECCOMP_FILTER
+tlsdated_SOURCES += seccomp.c
+endif
+if HAVE_DBUS
+tlsdated_SOURCES += dbus.c
+endif
+tlsdated_CPPFLAGS = -DTLSDATED_MAIN
+
+tlsdated_unittest_SOURCES = $(tlsdated_SOURCES) tlsdated-unittest.c
 
 TESTS = proxy_bio_unittest tlsdated_unittest
 
diff --git a/src/compat/clock-linux.c b/src/compat/clock-linux.c
index dcfbd01..34534ba 100644
--- a/src/compat/clock-linux.c
+++ b/src/compat/clock-linux.c
@@ -20,12 +20,11 @@
  * @param time where the current time is stored
  * @return clock_gettime syscall return value
  */
-int clock_get_real_time_linux(struct tlsdate_time *time)
+int clock_get_real_time_linux (struct tlsdate_time *time)
 {
   /* Safety net */
-  assert(time);
-
-  return clock_gettime(CLOCK_REALTIME, &time->tp);
+  assert (time);
+  return clock_gettime (CLOCK_REALTIME, &time->tp);
 }
 
 /**
@@ -34,12 +33,11 @@
  * @param time where the current time to set is stored
  * @return clock_settime syscall return value
  */
-int clock_set_real_time_linux(const struct tlsdate_time *time)
+int clock_set_real_time_linux (const struct tlsdate_time *time)
 {
   /* Safety net */
-  assert(time);
-
-  return clock_settime(CLOCK_REALTIME, &time->tp);
+  assert (time);
+  return clock_settime (CLOCK_REALTIME, &time->tp);
 }
 
 /**
@@ -48,12 +46,11 @@
  * @param sec is the seconds
  * @param nsec is the nanoseconds
  */
-void clock_init_time_linux(struct tlsdate_time *time, time_t sec,
-                           long nsec)
+void clock_init_time_linux (struct tlsdate_time *time, time_t sec,
+                            long nsec)
 {
   /* Safety net */
-  assert(time);
-
+  assert (time);
   time->tp.tv_sec = sec;
   time->tp.tv_nsec = nsec;
 }
diff --git a/src/compat/clock.h b/src/compat/clock.h
index 27f3c26..2ea0cd4 100644
--- a/src/compat/clock.h
+++ b/src/compat/clock.h
@@ -14,18 +14,19 @@
 #  include <time.h>
 #endif
 
-struct tlsdate_time {
-    struct timespec tp;
+struct tlsdate_time
+{
+  struct timespec tp;
 };
 
-extern int clock_get_real_time_linux(struct tlsdate_time *time);
+extern int clock_get_real_time_linux (struct tlsdate_time *time);
 #define clock_get_real_time(time) clock_get_real_time_linux(time)
 
-extern int clock_set_real_time_linux(const struct tlsdate_time *time);
+extern int clock_set_real_time_linux (const struct tlsdate_time *time);
 #define clock_set_real_time(time) clock_set_real_time_linux(time)
 
-extern void clock_init_time_linux(struct tlsdate_time *time, time_t sec,
-                                  long nsec);
+extern void clock_init_time_linux (struct tlsdate_time *time, time_t sec,
+                                   long nsec);
 #define clock_init_time(time, sec, nsec) \
         clock_init_time_linux(time, sec, nsec)
 
@@ -37,20 +38,21 @@
 
 #elif _WIN32
 
-struct tlsdate_time {
-    /* TODO: Fix Windows support */
+struct tlsdate_time
+{
+  /* TODO: Fix Windows support */
 };
 
 TLSDATE_API
-int clock_get_real_time_win(struct tlsdate_time *time);
+int clock_get_real_time_win (struct tlsdate_time *time);
 #define clock_get_real_time(time) clock_get_real_time_win(time)
 
-extern int clock_set_real_time_win(const struct tlsdate_time *time);
+extern int clock_set_real_time_win (const struct tlsdate_time *time);
 #define clock_set_real_time(time) clock_set_real_time_win(time)
 
 TLSDATE_API
-void clock_init_time_win(struct tlsdate_time *time, time_t sec,
-                                long nsec);
+void clock_init_time_win (struct tlsdate_time *time, time_t sec,
+                          long nsec);
 #define clock_init_time(time, sec, nsec) \
         clock_init_time_win(time, sec, nsec)
 
diff --git a/src/conf-unittest.c b/src/conf-unittest.c
index eac3fb6..450b2fb 100644
--- a/src/conf-unittest.c
+++ b/src/conf-unittest.c
@@ -13,67 +13,73 @@
 #include "src/conf.h"
 #include "src/test_harness.h"
 
-FILE *fopenstr(const char *str) {
+FILE *fopenstr (const char *str)
+{
   /* strlen(str) instead of strlen(str) + 1 because files shouldn't appear
    * null-terminated. Cast away constness because we're in read mode, but the
    * fmemopen prototype has no way to express that. */
-  return fmemopen((char *)str, strlen(str), "r");
+  return fmemopen ( (char *) str, strlen (str), "r");
 }
 
-TEST(parse_empty) {
+TEST (parse_empty)
+{
   /* can't do a truly empty file - fmemopen() combusts */
-  FILE *f = fopenstr("\n");
-  ASSERT_NE(NULL, f);
-  struct conf_entry *e = conf_parse(f);
-  EXPECT_NULL(e);
-  conf_free(e);
+  FILE *f = fopenstr ("\n");
+  ASSERT_NE (NULL, f);
+  struct conf_entry *e = conf_parse (f);
+  EXPECT_NULL (e);
+  conf_free (e);
 }
 
-TEST(parse_basic) {
-  FILE *f = fopenstr("foo bar\nbaz quxx\n");
-  ASSERT_NE(NULL, f);
-  struct conf_entry *e = conf_parse(f);
-  ASSERT_NE(NULL, e);
-  EXPECT_STREQ(e->key, "foo");
-  EXPECT_STREQ(e->value, "bar");
-  ASSERT_NE(NULL, e->next);
-  EXPECT_STREQ(e->next->key, "baz");
-  EXPECT_STREQ(e->next->value, "quxx");
-  ASSERT_NULL(e->next->next);
-  conf_free(e);
+TEST (parse_basic)
+{
+  FILE *f = fopenstr ("foo bar\nbaz quxx\n");
+  ASSERT_NE (NULL, f);
+  struct conf_entry *e = conf_parse (f);
+  ASSERT_NE (NULL, e);
+  EXPECT_STREQ (e->key, "foo");
+  EXPECT_STREQ (e->value, "bar");
+  ASSERT_NE (NULL, e->next);
+  EXPECT_STREQ (e->next->key, "baz");
+  EXPECT_STREQ (e->next->value, "quxx");
+  ASSERT_NULL (e->next->next);
+  conf_free (e);
 }
 
-TEST(parse_novalue) {
-  FILE *f = fopenstr("abcdef\n");
-  ASSERT_NE(NULL, f);
-  struct conf_entry *e = conf_parse(f);
-  ASSERT_NE(NULL, e);
-  EXPECT_STREQ(e->key, "abcdef");
-  EXPECT_NULL(e->value);
-  EXPECT_NULL(e->next);
-  conf_free(e);
+TEST (parse_novalue)
+{
+  FILE *f = fopenstr ("abcdef\n");
+  ASSERT_NE (NULL, f);
+  struct conf_entry *e = conf_parse (f);
+  ASSERT_NE (NULL, e);
+  EXPECT_STREQ (e->key, "abcdef");
+  EXPECT_NULL (e->value);
+  EXPECT_NULL (e->next);
+  conf_free (e);
 }
 
-TEST(parse_whitespace) {
-  FILE *f = fopenstr("         fribble		  grotz  \n");
-  ASSERT_NE(NULL, f);
-  struct conf_entry *e = conf_parse(f);
-  ASSERT_NE(NULL, e);
-  EXPECT_STREQ(e->key, "fribble");
-  EXPECT_STREQ(e->value, "grotz  ");
-  EXPECT_NULL(e->next);
-  conf_free(e);
+TEST (parse_whitespace)
+{
+  FILE *f = fopenstr ("         fribble		  grotz  \n");
+  ASSERT_NE (NULL, f);
+  struct conf_entry *e = conf_parse (f);
+  ASSERT_NE (NULL, e);
+  EXPECT_STREQ (e->key, "fribble");
+  EXPECT_STREQ (e->value, "grotz  ");
+  EXPECT_NULL (e->next);
+  conf_free (e);
 }
 
-TEST(parse_comment) {
-  FILE *f = fopenstr("#foo bar\nbaz quxx\n");
-  ASSERT_NE(NULL, f);
-  struct conf_entry *e = conf_parse(f);
-  ASSERT_NE(NULL, e);
-  EXPECT_STREQ(e->key, "baz");
-  EXPECT_STREQ(e->value, "quxx");
-  EXPECT_NULL(e->next);
-  conf_free(e);
+TEST (parse_comment)
+{
+  FILE *f = fopenstr ("#foo bar\nbaz quxx\n");
+  ASSERT_NE (NULL, f);
+  struct conf_entry *e = conf_parse (f);
+  ASSERT_NE (NULL, e);
+  EXPECT_STREQ (e->key, "baz");
+  EXPECT_STREQ (e->value, "quxx");
+  EXPECT_NULL (e->next);
+  conf_free (e);
 }
 
 TEST_HARNESS_MAIN
diff --git a/src/conf.c b/src/conf.c
index ee7a9b8..0d0800d 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -8,79 +8,83 @@
 
 #include "src/conf.h"
 
-void strip_newlines(char *line)
+void strip_newlines (char *line)
 {
-  *strchrnul(line, '\n') = '\0';
-  *strchrnul(line, '\r') = '\0';
+  *strchrnul (line, '\n') = '\0';
+  *strchrnul (line, '\r') = '\0';
 }
 
-char *eat_whitespace(char *line)
+char *eat_whitespace (char *line)
 {
-  while (isspace(*line))
+  while (isspace (*line))
     line++;
   return line;
 }
 
-int is_ignored_line(char *line)
+int is_ignored_line (char *line)
 {
   return !*line || *line == '#';
 }
 
-struct conf_entry *conf_parse(FILE *f)
+struct conf_entry *conf_parse (FILE *f)
 {
   struct conf_entry *head = NULL;
   struct conf_entry *tail = NULL;
   char buf[CONF_MAX_LINE];
 
-  while (fgets(buf, sizeof(buf), f)) {
-    struct conf_entry *e;
-    char *start = buf;
-    char *key;
-    char *val;
-
-    strip_newlines(start);
-    start = eat_whitespace(start);
-    if (is_ignored_line(start))
-      continue;
-
-    key = strtok(start, " \t");
-    val = strtok(NULL, "");
-    if (val)
-      val = eat_whitespace(val);
-    e = malloc(sizeof *e);
-    if (!e)
-      goto fail;
-    e->next = NULL;
-    e->key = strdup(key);
-    e->value = val ? strdup(val) : NULL;
-    if (!e->key || (val && !e->value)) {
-      free(e->key);
-      free(e->value);
-      goto fail;
+  while (fgets (buf, sizeof (buf), f))
+    {
+      struct conf_entry *e;
+      char *start = buf;
+      char *key;
+      char *val;
+      strip_newlines (start);
+      start = eat_whitespace (start);
+      if (is_ignored_line (start))
+        continue;
+      key = strtok (start, " \t");
+      val = strtok (NULL, "");
+      if (val)
+        val = eat_whitespace (val);
+      e = malloc (sizeof *e);
+      if (!e)
+        goto fail;
+      e->next = NULL;
+      e->key = strdup (key);
+      e->value = val ? strdup (val) : NULL;
+      if (!e->key || (val && !e->value))
+        {
+          free (e->key);
+          free (e->value);
+          goto fail;
+        }
+      if (!head)
+        {
+          head = e;
+          tail = e;
+        }
+      else
+        {
+          tail->next = e;
+          tail = e;
+        }
     }
-    if (!head) {
-      head = e;
-      tail = e;
-    } else {
-      tail->next = e;
-      tail = e;
-    }
-  }
 
   return head;
 fail:
-  conf_free(head);
+  conf_free (head);
   return NULL;
 }
 
-void conf_free(struct conf_entry *e)
+void conf_free (struct conf_entry *e)
 {
   struct conf_entry *n;
-  while (e) {
-    n = e->next;
-    free(e->key);
-    free(e->value);
-    free(e);
-    e = n;
-  }
+  while (e)
+    {
+      n = e->next;
+      free (e->key);
+      free (e->value);
+      free (e);
+      e = n;
+    }
 }
diff --git a/src/conf.h b/src/conf.h
index d64120d..d01290b 100644
--- a/src/conf.h
+++ b/src/conf.h
@@ -7,13 +7,14 @@
 
 #define CONF_MAX_LINE 16384
 
-struct conf_entry {
-	struct conf_entry *next;
-	char *key;
-	char *value;
+struct conf_entry
+{
+  struct conf_entry *next;
+  char *key;
+  char *value;
 };
 
-struct conf_entry *conf_parse(FILE *f);
-void conf_free(struct conf_entry *e);
+struct conf_entry *conf_parse (FILE *f);
+void conf_free (struct conf_entry *e);
 
 #endif /* !CONF_H */
diff --git a/src/dbus.c b/src/dbus.c
new file mode 100644
index 0000000..81bda4b
--- /dev/null
+++ b/src/dbus.c
@@ -0,0 +1,573 @@
+/*
+ * dbus.c - event loop dbus integration
+ * Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "config.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <dbus/dbus.h>
+#include <event2/event.h>
+#include "src/dbus.h"
+#include "src/tlsdate.h"
+#include "src/util.h"
+
+/* Pointers are needed so that we don't have to deal with array-to-pointer
+ * weirdness with DBus argument passing.
+ */
+static const char kServiceInterfaceData[] = "org.torproject.tlsdate";
+static const char *kServiceInterface = kServiceInterfaceData;
+static const char kServicePathData[] = "/org/torproject/tlsdate";
+static const char *kServicePath = kServicePathData;
+static const char kServiceSetTimeData[] = "SetTime";
+static const char *kServiceSetTime = kServiceSetTimeData;
+static const char kServiceCanSetTimeData[] = "CanSetTime";
+static const char *kServiceCanSetTime = kServiceCanSetTimeData;
+static const char kServiceLastSyncInfoData[] = "LastSyncInfo";
+static const char *kServiceLastSyncInfo = kServiceLastSyncInfoData;
+
+static const char kTimeUpdatedData[] = "TimeUpdated";
+static const char *kTimeUpdated = kTimeUpdatedData;
+
+static
+short
+dbus_to_event (unsigned int flags)
+{
+  short events = 0;
+  if (flags & DBUS_WATCH_READABLE)
+    events |= EV_READ;
+  if (flags & DBUS_WATCH_WRITABLE)
+    events |= EV_WRITE;
+  return events;
+}
+
+static
+unsigned int
+event_to_dbus (short events)
+{
+  unsigned int flags = 0;
+  if (events & EV_READ)
+    flags |= DBUS_WATCH_READABLE;
+  if (events & EV_WRITE)
+    flags |= DBUS_WATCH_WRITABLE;
+  return flags;
+}
+
+static
+void
+watch_handler (evutil_socket_t fd, short what, void *arg)
+{
+  DBusWatch *watch = arg;
+  struct dbus_event_data *data = dbus_watch_get_data (watch);
+  unsigned int flags = event_to_dbus (what);
+  dbus_connection_ref (data->state->conn);
+  while (!dbus_watch_handle (watch, flags))
+    {
+      info ("dbus_watch_handle waiting for memory . . .");
+      /* TODO(wad) this seems like a bad idea. */
+      sleep (1);
+    }
+  while (dbus_connection_dispatch (data->state->conn) ==
+         DBUS_DISPATCH_DATA_REMAINS);
+  dbus_connection_unref (data->state->conn);
+}
+
+static
+dbus_bool_t
+add_watch (DBusWatch *watch, void *user_data)
+{
+  struct state *tlsdate_state = user_data;
+  struct dbus_state *state = tlsdate_state->dbus;
+  struct dbus_event_data *data;
+  /* Don't add anything if it isn't active. */
+  data = dbus_malloc0 (sizeof (struct dbus_event_data));
+  if (!data)
+    return FALSE;
+  data->state = state;
+  data->event = event_new (tlsdate_state->base,
+                           dbus_watch_get_unix_fd (watch),
+                           EV_PERSIST|dbus_to_event (dbus_watch_get_flags (watch)),
+                           watch_handler,
+                           watch);
+  if (!data->event)
+    {
+      dbus_free (data);
+      return FALSE;
+    }
+  event_priority_set (data->event, PRI_WAKE);
+
+  dbus_watch_set_data (watch, data, dbus_free);
+  if (!dbus_watch_get_enabled (watch))
+    return TRUE;
+  /* Only add the event if it is enabled. */
+  if (event_add (data->event, NULL))
+    {
+      error ("Could not add a new watch!");
+      event_free (data->event);
+      dbus_free (data);
+      return FALSE;
+    }
+  return TRUE;
+}
+
+static
+void
+remove_watch (DBusWatch *watch, void *user_data)
+{
+  struct dbus_event_data *data = dbus_watch_get_data (watch);
+  /* TODO(wad) should this just be in a free_function? */
+  if (data && data->event)
+    {
+      event_del (data->event);
+      event_free (data->event);
+    }
+}
+
+static
+void
+toggle_watch (DBusWatch *watch, void *user_data)
+{
+  struct dbus_event_data *data = dbus_watch_get_data (watch);
+  if (!data || !data->event)  /* should not be possible */
+    return;
+  /* If the event is pending, then we have to remove it to
+   * disable it or remove it before re-enabling it.
+   */
+  if (event_pending (data->event,
+                     dbus_to_event (dbus_watch_get_flags (watch)), NULL))
+    event_del (data->event);
+  if (dbus_watch_get_enabled (watch))
+    {
+      event_add (data->event, NULL);
+    }
+}
+
+static
+void
+timeout_handler (evutil_socket_t fd, short what, void *arg)
+{
+  DBusTimeout *t = arg;
+  struct dbus_event_data *data = dbus_timeout_get_data (t);
+  dbus_connection_ref (data->state->conn);
+  dbus_timeout_handle (t);
+  dbus_connection_unref (data->state->conn);
+}
+
+static
+dbus_bool_t
+add_timeout (DBusTimeout *t, void *user_data)
+{
+  struct state *tlsdate_state = user_data;
+  struct dbus_state *state = tlsdate_state->dbus;
+  struct dbus_event_data *data;
+  int ms = dbus_timeout_get_interval (t);
+  struct timeval interval;
+  data = dbus_malloc0 (sizeof (struct dbus_event_data));
+  if (!data)
+    return FALSE;
+  interval.tv_sec = ms / 1000;
+  interval.tv_usec = (ms % 1000) * 1000;
+  data->state = state;
+  data->event = event_new (tlsdate_state->base,
+                           -1,
+                           EV_TIMEOUT|EV_PERSIST,
+                           timeout_handler,
+                           t);
+  if (!data->event)
+    {
+      dbus_free (data);
+      return FALSE;
+    }
+  event_priority_set (data->event, PRI_WAKE);
+  dbus_timeout_set_data (t, data, dbus_free);
+  /* Only add it to the queue if it is enabled. */
+  if (!dbus_timeout_get_enabled (t))
+    return TRUE;
+  if (event_add (data->event, &interval))
+    {
+      error ("Could not add a new timeout!");
+      event_free (data->event);
+      dbus_free (data);
+      return FALSE;
+    }
+  return TRUE;
+}
+
+static
+void
+remove_timeout (DBusTimeout *t, void *user_data)
+{
+  struct dbus_event_data *data = dbus_timeout_get_data (t);
+  if (data && data->event)
+    {
+      event_del (data->event);
+      event_free (data->event);
+    }
+}
+
+static
+void
+toggle_timeout (DBusTimeout *t, void *user_data)
+{
+  struct dbus_event_data *data = dbus_timeout_get_data (t);
+  int ms = dbus_timeout_get_interval (t);
+  struct timeval interval;
+  /* If the event is pending, then we have to remove it to
+   * disable it or remove it before re-enabling it.
+   */
+  if (evtimer_pending (data->event, NULL))
+    event_del (data->event);
+  if (dbus_timeout_get_enabled (t))
+    {
+      interval.tv_sec = ms / 1000;
+      interval.tv_usec = (ms % 1000) * 1000;
+      event_add (data->event, &interval);
+    }
+}
+
+#ifdef TLSDATED_MAIN
+void
+dbus_announce (struct state *global_state)
+{
+  struct dbus_state *state = global_state->dbus;
+  DBusConnection *conn = state->conn;
+  DBusMessage *msg;
+  uint32_t ignored;
+  const char *sync_type = sync_type_str (global_state->last_sync_type);
+  msg = dbus_message_new_signal (kServicePath, kServiceInterface, kTimeUpdated);
+  if (!msg)
+    {
+      error ("[dbus] could not allocate new announce signal");
+      return;
+    }
+  if (!dbus_message_append_args (msg,
+                                 DBUS_TYPE_STRING, &sync_type,
+                                 DBUS_TYPE_INVALID))
+    {
+      error ("[dbus] could not allocate new announce args");
+      return;
+    }
+  if (!dbus_connection_send (conn, msg, &ignored))
+    {
+      error ("[dbus] could not send announce signal");
+      return;
+    }
+}
+#endif
+
+static
+DBusHandlerResult
+send_time_reply (DBusConnection *connection,
+                 DBusMessage *message,
+                 dbus_uint32_t code)
+{
+   DBusMessage *reply;
+   DBusMessageIter args;
+   dbus_uint32_t serial = dbus_message_get_serial (message);
+
+   reply = dbus_message_new_method_return (message);
+   if (!reply)
+     {
+       error ("[dbus] no memory to reply to SetTime");
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+     }
+
+  if (!dbus_message_set_reply_serial (reply, serial))
+    {
+      error ("[dbus] no memory to set serial for reply to SetTime");
+      dbus_message_unref (reply);
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+  dbus_message_iter_init_append (reply, &args);
+  if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_UINT32, &code))
+    {
+      error ("[dbus] no memory to add reply args to SetTime");
+      dbus_message_unref (reply);
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+  if (!dbus_connection_send (connection, reply, &serial))
+   {
+      error ("[dbus] unable to send SetTime reply");
+      dbus_message_unref (reply);
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+   }
+  dbus_connection_flush (connection);
+  dbus_message_unref (reply);
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static
+DBusHandlerResult
+send_can_reply (DBusConnection *connection,
+                DBusMessage *message,
+                dbus_bool_t allowed)
+{
+  DBusMessage *reply;
+  DBusMessageIter args;
+  dbus_uint32_t serial = dbus_message_get_serial (message);
+
+  reply = dbus_message_new_method_return (message);
+  if (!reply)
+    {
+      error ("[dbus] no memory to reply to CanSetTime");
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+  if (!dbus_message_set_reply_serial (reply, serial))
+    {
+      error ("[dbus] no memory to set serial for reply to CanSetTime");
+      dbus_message_unref (reply);
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+  dbus_message_iter_init_append (reply, &args);
+  if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_BOOLEAN, &allowed))
+    {
+      error ("[dbus] no memory to add reply args to CanSetTime");
+      dbus_message_unref (reply);
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+  if (!dbus_connection_send (connection, reply, &serial))
+   {
+      error ("[dbus] unable to send CanSetTime reply");
+      dbus_message_unref (reply);
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+   }
+  dbus_connection_flush (connection);
+  dbus_message_unref (reply);
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+/* Returns 0 if time cannot be set, and 1 otherwise. */
+static
+int
+can_set_time (struct state *state)
+{
+  time_t delta = state->clock_delta;
+  /* Force a synchronization check. */
+  if (check_continuity (&delta) > 0)
+    {
+      info ("[event:%s] clock delta desync detected (%ld != %ld)",
+            __func__, state->clock_delta, delta);
+      delta = state->clock_delta = 0;
+      invalidate_time (state);
+    }
+  /* Only use the time if we're not synchronized. */
+  return !state->clock_delta;
+}
+
+static
+DBusHandlerResult
+handle_set_time (DBusConnection *connection,
+                 DBusMessage *message,
+                 struct state *state)
+{
+  DBusMessageIter iter;
+  DBusError error;
+  dbus_int64_t requested_time = 0;
+  debug ("[event:%s]: fired", __func__);
+  dbus_error_init (&error);
+
+  /* Expects DBUS_TYPE_INT64:<time_t> */
+  if (!dbus_message_iter_init (message, &iter))
+    return send_time_reply (connection, message, SET_TIME_BAD_CALL);
+  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INT64)
+    return send_time_reply (connection, message, SET_TIME_BAD_CALL);
+  dbus_message_iter_get_basic (&iter, &requested_time);
+  if (!is_sane_time ((time_t) requested_time))
+    {
+      error ("event:%s] invalid time from user: %ld", __func__,
+             (time_t) requested_time);
+      return send_time_reply (connection, message, SET_TIME_INVALID);
+    }
+  if (!can_set_time (state))
+    {
+      info ("[event:%s]: time is already synchronized.", __func__);
+      return send_time_reply (connection, message, SET_TIME_NOT_ALLOWED);
+    }
+
+  state->last_time = requested_time;
+  state->last_sync_type = SYNC_TYPE_PLATFORM;
+  trigger_event (state, E_SAVE, -1);
+  /* Kick off a network sync for good measure. */
+  action_kickoff_time_sync (-1, EV_TIMEOUT, state);
+
+  return send_time_reply (connection, message, SET_TIME_OK);
+}
+
+static
+DBusHandlerResult
+handle_can_set_time (DBusConnection *connection,
+                     DBusMessage *message,
+                     struct state *state)
+{
+  debug ("[event:%s]: fired", __func__);
+  return send_can_reply (connection, message, can_set_time (state));
+}
+
+static
+DBusHandlerResult
+handle_last_sync_info (DBusConnection *connection,
+                       DBusMessage *message,
+                       struct state *state)
+{
+  DBusMessage *reply;
+  DBusMessageIter args;
+  dbus_uint32_t serial = dbus_message_get_serial (message);
+  dbus_bool_t net_synced = !!state->clock_delta;
+  const char *sync = sync_type_str (state->last_sync_type);
+  int64_t t = state->last_time;
+
+  debug ("[dbus]: handler fired");
+  reply = dbus_message_new_method_return (message);
+  if (!reply)
+    {
+      error ("[dbus] no memory to reply to LastSyncInfo");
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+  if (!dbus_message_set_reply_serial (reply, serial))
+    {
+     error ("[dbus] no memory to set serial for reply to LastSyncInfo");
+     dbus_message_unref (reply);
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+  dbus_message_iter_init_append (reply, &args);
+  if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_BOOLEAN, &net_synced))
+    {
+      error ("[dbus] no memory to add reply args to LastSyncInfo");
+      dbus_message_unref (reply);
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+  if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &sync))
+    {
+      error ("[dbus] no memory to add reply args to LastSyncInfo");
+      dbus_message_unref (reply);
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+  if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_INT64, &t))
+    {
+      error ("[dbus] no memory to add reply args to LastSyncInfo");
+      dbus_message_unref (reply);
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+  if (!dbus_connection_send (connection, reply, &serial))
+   {
+      error ("[dbus] unable to send LastSyncInfo reply");
+      dbus_message_unref (reply);
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+   }
+  dbus_connection_flush (connection);
+  dbus_message_unref (reply);
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static
+void
+unregister_service (DBusConnection *conn, void *data)
+{
+  info ("dbus service has been unregistered");
+}
+
+static
+DBusHandlerResult
+service_dispatch (DBusConnection *conn, DBusMessage *msg, void *data)
+{
+  struct state *state = data;
+  const char *interface;
+  const char *method;
+
+  debug ("[dbus] service dispatcher called");
+  if (dbus_message_get_type (msg) != DBUS_MESSAGE_TYPE_METHOD_CALL)
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+  interface = dbus_message_get_interface (msg);
+  method = dbus_message_get_member (msg);
+  if (!interface || !method)
+    {
+      debug ("[dbus] service request fired with bogus data");
+      /* Consume it */
+      return DBUS_HANDLER_RESULT_HANDLED;
+    }
+  if (strcmp (interface, kServiceInterface))
+    {
+      debug ("[dbus] invalid interface supplied");
+      return DBUS_HANDLER_RESULT_HANDLED;
+    }
+  if (!strcmp (method, kServiceSetTime))
+    return handle_set_time (conn, msg, state);
+  else if (!strcmp (method, kServiceCanSetTime))
+    return handle_can_set_time (conn, msg, state);
+  else if (!strcmp (method, kServiceLastSyncInfo))
+    return handle_last_sync_info (conn, msg, state);
+  debug ("[dbus] invalid method supplied");
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusObjectPathVTable service_vtable = {
+    .unregister_function = unregister_service,
+    .message_function = service_dispatch,
+};
+
+int
+init_dbus (struct state *tlsdate_state)
+{
+  DBusError error;
+  dbus_error_init (&error);
+  struct dbus_state *state = calloc (1, sizeof (struct dbus_state));
+  if (!state)
+    return 1;
+  tlsdate_state->dbus = state;
+  state->conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
+  if (state->conn == NULL || dbus_error_is_set (&error))
+    {
+      error ("[dbus] error when connecting to the bus: %s",
+             error.message);
+      goto err;
+    }
+  if (!dbus_connection_set_timeout_functions (state->conn, add_timeout,
+      remove_timeout, toggle_timeout, tlsdate_state, dbus_free))
+    {
+      error ("[dbus] dbus_connection_set_timeout_functions failed");
+      /* TODO(wad) disconnect from DBus */
+      goto err;
+    }
+  if (!dbus_connection_set_watch_functions (state->conn, add_watch,
+      remove_watch, toggle_watch, tlsdate_state, dbus_free))
+    {
+      error ("[dbus] dbus_connection_set_watch_functions failed");
+      goto err;
+    }
+  if (!dbus_bus_request_name (state->conn, kServiceInterface, 0, &error) ||
+      dbus_error_is_set (&error))
+    {
+      error ("[dbus] failed to get name: %s", error.message);
+      goto err;
+    }
+
+  /* Setup the vtable for dispatching incoming messages. */
+  if (dbus_connection_register_object_path (
+          state->conn, kServicePath, &service_vtable, tlsdate_state) == FALSE)
+    {
+      error ("[dbus] failed to register object path: %s", kServicePath);
+      goto err;
+    }
+
+  debug ("[dbus] initialized");
+  return 0;
+err:
+  tlsdate_state->dbus = NULL;
+  free (state);
+  return 1;
+}
diff --git a/src/dbus.h b/src/dbus.h
new file mode 100644
index 0000000..b166a7d
--- /dev/null
+++ b/src/dbus.h
@@ -0,0 +1,53 @@
+/*
+ * dbus.h - event loop dbus integration
+ * Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef DBUS_H_
+#define DBUS_H_
+
+#include "config.h"
+
+#ifdef HAVE_DBUS
+#include <dbus/dbus.h>
+
+#define SET_TIME_OK 0
+#define SET_TIME_INVALID 1
+#define SET_TIME_NOT_ALLOWED 2
+#define SET_TIME_BAD_CALL 3
+
+struct state;
+int init_dbus (struct state *state);
+
+struct dbus_state
+{
+  DBusConnection *conn;
+};
+
+struct dbus_event_data
+{
+  struct dbus_state *state;
+  struct event *event;
+};
+
+#ifdef TLSDATED_MAIN
+void dbus_announce (struct state *);
+#else
+static inline void dbus_announce (struct state *global_state)
+{
+}
+#endif
+
+#else  /* !HAVE_DBUS */
+struct state;
+static inline int init_dbus (struct state *state)
+{
+  return 0;
+}
+static inline void dbus_announce (struct state *global_state)
+{
+}
+#endif
+
+#endif  /* DBUS_H_ */
diff --git a/src/events/check_continuity.c b/src/events/check_continuity.c
new file mode 100644
index 0000000..a19a278
--- /dev/null
+++ b/src/events/check_continuity.c
@@ -0,0 +1,68 @@
+/*
+ * check_continuity.c - periodically check local clock deltas
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <time.h>
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/tlsdate.h"
+#include "src/util.h"
+
+
+/* Returns < 0 on error,
+ *           0 on sync'd,
+ * and     > 0 on desync'd.
+ * Old delta is in |delta|. |delta| is overwritten
+ * if >= 0 is returned.
+ *
+ * Desynchronization between MONOTONIC_RAW and REALTIME
+ * will occur any time a system suspends and the real-time
+ * clock is not maintained.
+ */
+int
+check_continuity (time_t *delta)
+{
+  time_t new_delta;
+  struct timespec monotonic, real;
+  if (clock_gettime (CLOCK_REALTIME, &real) < 0)
+    return -1;
+  if (clock_gettime (CLOCK_MONOTONIC_RAW, &monotonic) < 0)
+    return -1;
+  new_delta = real.tv_sec - monotonic.tv_sec;
+  if (*delta)
+    {
+      if (new_delta < *delta - 10 || new_delta > *delta + 10)
+        {
+          *delta = new_delta;
+          return  1;
+        }
+    }
+  /* First delta after de-sync. */
+  *delta = new_delta;
+  return 0;
+}
+
+/* Sets up a wake event just in case there has not been a wake event
+ * recently enough to catch clock desynchronization.  This does not
+ * invalidate the time like the action_invalidate_time event.
+ */
+int setup_event_timer_continuity (struct state *state)
+{
+  struct event *event;
+  struct timeval interval = { state->opts.continuity_interval, 0 };
+  event = event_new (state->base, -1, EV_TIMEOUT|EV_PERSIST,
+                     action_kickoff_time_sync, state);
+  if (!event)
+    {
+      error ("Failed to create interval event");
+      return 1;
+    }
+  event_priority_set (event, PRI_WAKE);
+  return event_add (event, &interval);
+}
diff --git a/src/events/kickoff_time_sync.c b/src/events/kickoff_time_sync.c
new file mode 100644
index 0000000..d56a967
--- /dev/null
+++ b/src/events/kickoff_time_sync.c
@@ -0,0 +1,140 @@
+/*
+ * kickoff_time_sync.c - network time synchronization
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <openssl/rand.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/util.h"
+#include "src/tlsdate.h"
+
+int
+add_jitter (int base, int jitter)
+{
+  int n = 0;
+  if (!jitter)
+    return base;
+  if (RAND_bytes ( (unsigned char *) &n, sizeof (n)) != 1)
+    fatal ("RAND_bytes() failed");
+  return base + (abs (n) % (2 * jitter)) - jitter;
+}
+
+void
+invalidate_time (struct state *state)
+{
+  state->last_sync_type = SYNC_TYPE_RTC;
+  state->last_time = time (NULL);
+  /* Note(!) this does not invalidate the clock_delta implicitly.
+   * This allows forced invalidation to not lose synchronization
+   * data.
+   */
+}
+
+void
+action_invalidate_time (evutil_socket_t fd, short what, void *arg)
+{
+  struct state *state = arg;
+  debug ("[event:%s] fired", __func__);
+  /* If time is already invalid and being acquired, do nothing. */
+  if (state->last_sync_type == SYNC_TYPE_RTC &&
+      event_pending (state->events[E_TLSDATE], EV_TIMEOUT, NULL))
+    return;
+  /* Time out our trust in network synchronization but don't persist
+   * the change to disk or notify the system.  Let a network sync
+   * failure or success do that.
+   */
+  invalidate_time (state);
+  /* Then trigger a network sync if possible. */
+  action_kickoff_time_sync (-1, EV_TIMEOUT, arg);
+}
+
+int
+setup_event_timer_sync (struct state *state)
+{
+  int wait_time = add_jitter (state->opts.steady_state_interval,
+                              state->opts.jitter);
+  struct timeval interval = { wait_time, 0 };
+  state->events[E_STEADYSTATE] = event_new (state->base, -1,
+                                 EV_TIMEOUT|EV_PERSIST,
+                                 action_invalidate_time, state);
+  if (!state->events[E_STEADYSTATE])
+    {
+      error ("Failed to create interval event");
+      return 1;
+    }
+  event_priority_set (state->events[E_STEADYSTATE], PRI_ANY);
+  return event_add (state->events[E_STEADYSTATE], &interval);
+}
+
+/* Begins a network synchronization attempt.  If the local clocks
+ * are synchronized, then make sure that the _current_ synchronization
+ * source is set to the real-time clock and note that the clock_delta
+ * is unreliable.  If the clock was in sync and the last synchronization
+ * source was the network, then this action does nothing.
+ *
+ * In the case of desynchronization, the clock_delta value is used as a
+ * guard to indicate that even if the synchronization source isn't the
+ * network, the source is still tracking the clock delta that was
+ * established from a network source.
+ * TODO(wad) Change the name of clock_delta to indicate that it is the local
+ *           clock delta after the last network sync.
+ */
+void action_kickoff_time_sync (evutil_socket_t fd, short what, void *arg)
+{
+  struct state *state = arg;
+  debug ("[event:%s] fired", __func__);
+  time_t delta = state->clock_delta;
+  if (check_continuity (&delta) > 0)
+    {
+      info ("[event:%s] clock delta desync detected (%d != %d)", __func__,
+            state->clock_delta, delta);
+      /* Forget the old delta until we have time again. */
+      state->clock_delta = 0;
+      invalidate_time (state);
+      /* Don't bother saving here */
+    }
+  if (state->last_sync_type == SYNC_TYPE_NET)
+    {
+      debug ("[event:%s] time in sync. skipping", __func__);
+      return;
+    }
+  /* Keep parity with run_tlsdate: for every wake, allow it to retry again. */
+  if (state->tries > 0)
+    {
+      state->tries -= 1;
+      /* Don't bother re-triggering tlsdate */
+      debug ("[event:%s] called while tries are in progress", __func__);
+      return;
+    }
+  /* Don't over-schedule if the first attempt hasn't fired. If a wake event
+   * impacts the result of a proxy resolution, then the updated value can be
+   * acquired on the next run. If the wake comes in after E_TLSDATE is
+   * serviced, then the tries count will be decremented.
+   */
+  if (event_pending (state->events[E_TLSDATE], EV_TIMEOUT, NULL))
+    {
+      debug ("[event:%s] called while tlsdate is pending", __func__);
+      return;
+    }
+  if (!state->events[E_RESOLVER])
+    {
+      trigger_event (state, E_TLSDATE, 0);
+      return;
+    }
+  /* If the resolver relies on an external response, then make sure that a
+   * tlsdate event is waiting in the wings if the resolver is too slow.  Even
+   * if this fires, it won't stop eventual handling of the resolver since it
+   * doesn't event_del() E_RESOLVER.
+   */
+  trigger_event (state, E_TLSDATE, RESOLVER_TIMEOUT);
+  trigger_event (state, E_RESOLVER, 0);
+}
diff --git a/src/events/route_up.c b/src/events/route_up.c
new file mode 100644
index 0000000..280467d
--- /dev/null
+++ b/src/events/route_up.c
@@ -0,0 +1,94 @@
+/*
+ * route_up.c - wake events for route changes
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/routeup.h"
+#include "src/tlsdate.h"
+#include "src/util.h"
+
+void action_stdin_wakeup (evutil_socket_t fd, short what, void *arg)
+{
+  struct state *state = arg;
+  char buf[1];
+  debug ("[event:%s] fired", __func__);
+  if (what != EV_READ)
+    return;
+  if (IGNORE_EINTR (read (fd, buf, sizeof (buf))) != sizeof (buf))
+    {
+      error ("[event:%s] unregistering stdin handler - it's broken!",
+             __func__);
+      event_del (state->events[E_ROUTEUP]);
+      return;
+    }
+  action_kickoff_time_sync (-1, EV_TIMEOUT, arg);
+}
+
+
+void action_netlink_ready (evutil_socket_t fd, short what, void *arg)
+{
+  struct routeup routeup_cfg;
+  debug ("[event:%s] fired", __func__);
+  routeup_cfg.netlinkfd = fd;
+  if (what & EV_READ)
+    {
+      if (routeup_process (&routeup_cfg) == 0)
+        {
+          debug ("[event:%s] routes changed", __func__);
+          /* Fire off a proxy resolution attempt and a new sync request */
+          action_kickoff_time_sync (-1, EV_TIMEOUT, arg);
+        }
+    }
+}
+
+int setup_event_route_up (struct state *state)
+{
+  event_callback_fn handler;
+  int fd = -1;
+  struct routeup routeup_cfg;
+  if (state->opts.should_netlink)
+    {
+      if (routeup_setup (&routeup_cfg))
+        {
+          error ("routeup_setup() failed");
+          return 1;
+        }
+      fd = routeup_cfg.netlinkfd;
+      handler = action_netlink_ready;
+    }
+  else      /* Listen for cues from stdin */
+    {
+      fd = STDIN_FILENO;
+      if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
+        {
+          perror ("stdin fcntl(O_NONBLOCK) failed");
+          return 1;
+        }
+      handler = action_stdin_wakeup;
+    }
+  state->events[E_ROUTEUP] = event_new (state->base, fd,
+                                        EV_READ|EV_PERSIST, handler, state);
+  if (!state->events[E_ROUTEUP])
+    {
+      if (state->opts.should_netlink)
+        {
+          routeup_teardown (&routeup_cfg);
+        }
+      return 1;
+    }
+  event_priority_set (state->events[E_ROUTEUP], PRI_WAKE);
+  event_add (state->events[E_ROUTEUP], NULL);
+  return 0;
+}
diff --git a/src/events/run_tlsdate.c b/src/events/run_tlsdate.c
new file mode 100644
index 0000000..c36da16
--- /dev/null
+++ b/src/events/run_tlsdate.c
@@ -0,0 +1,76 @@
+/*
+ * run_tlsdate.c - events for running tlsdate
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/dbus.h"
+#include "src/util.h"
+#include "src/tlsdate.h"
+
+/* TODO(wad) split out backoff logic to make this testable */
+void action_run_tlsdate (evutil_socket_t fd, short what, void *arg)
+{
+  struct state *state = arg;
+  debug ("[event:%s] fired", __func__);
+  if (state->last_sync_type == SYNC_TYPE_NET)
+    {
+      info ("[event:%s] called, but network time isn't needed");
+      return;
+    }
+  state->resolving = 0;
+  if (state->running)
+    {
+      /* It's possible that a network or proxy change occurred during a call. If
+       * the call succeeded, it doesn't matter.  If the call fails, reissuing
+       * the attempt with the new configuration has a chance of succeeding.  To
+       * avoid missing a retry, we decrement the try count and reset the
+       * backoff.
+       */
+      if (state->tries > 0)
+        {
+          state->tries--;
+          /* TODO(wad) Make a shorter retry constant for this. */
+          state->backoff = state->opts.wait_between_tries;
+        }
+      info ("[event:%s] requested re-run of tlsdate while tlsdate is running",
+            __func__);
+      return;
+    }
+  /* Enforce maximum retries here instead of in sigchld.c */
+  if (state->tries < state->opts.max_tries)
+    {
+      state->tries++;
+    }
+  else
+    {
+      state->tries = 0;
+      state->backoff = state->opts.wait_between_tries;
+      error ("[event:%s] tlsdate tried and failed to get the time", __func__);
+      return;
+    }
+  state->running = 1;
+  info ("[event:%s] attempt %d backoff %d", __func__,
+        state->tries, state->backoff);
+  /* Setup a timeout before killing tlsdate */
+  trigger_event (state, E_TLSDATE_TIMEOUT,
+                 state->opts.subprocess_wait_between_tries);
+  /* Add the response listener event */
+  trigger_event (state, E_TLSDATE_STATUS, -1);
+  /* Fire off the child process now! */
+  if (tlsdate (state))
+    {
+      /* TODO(wad) Should this be fatal? */
+      error ("[event:%s] tlsdate failed to launch!", __func__);
+      state->running = 0;
+      state->tries = 0;
+      event_del (state->events[E_TLSDATE_TIMEOUT]);
+      return;
+    }
+}
diff --git a/src/events/save.c b/src/events/save.c
new file mode 100644
index 0000000..3b3b889
--- /dev/null
+++ b/src/events/save.c
@@ -0,0 +1,62 @@
+/*
+ * save.c - send new time to the time setter
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/util.h"
+#include "src/tlsdate.h"
+
+void action_sync_and_save (evutil_socket_t fd, short what, void *arg)
+{
+  struct state *state = arg;
+  time_t t = state->last_time;
+  ssize_t bytes;
+  debug ("[event:%s] fired", __func__);
+  /* For all non-net sources, don't write to disk by
+   * flagging the time negative.  We don't use negative
+   * times and this won't effect shutdown (0) writes.
+   */
+  if (state->last_sync_type != SYNC_TYPE_NET)
+    t = -t;
+  if (what & EV_READ)
+    {
+      /* EPIPE/EBADF notification */
+      error ("[event:%s] time setter is gone!", __func__);
+      /* SIGCHLD will handle teardown. */
+      return;
+    }
+  bytes = IGNORE_EINTR (write (fd, &t, sizeof (t)));
+  if (bytes == -1)
+    {
+      if (errno == EPIPE)
+        {
+          error ("[event:%s] time setter is gone! (EPIPE)", __func__);
+          return;
+        }
+      if (errno == EAGAIN)
+        return; /* Get notified again. */
+      error ("[event:%s] Unexpected errno %d", __func__, errno);
+    }
+  if (bytes != sizeof (t))
+    pfatal ("[event:%s] unexpected write to time setter (%d)",
+            __func__, bytes);
+  /* If we're going down and we wrote the time, send a shutdown message. */
+  if (state->exitting && t)
+    {
+      state->last_time = 0;
+      action_sync_and_save (fd, what, arg);
+    }
+  return;
+}
diff --git a/src/events/sigchld.c b/src/events/sigchld.c
new file mode 100644
index 0000000..e164f2e
--- /dev/null
+++ b/src/events/sigchld.c
@@ -0,0 +1,140 @@
+/*
+ * sigchld.c - event for SIGCHLD
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <event2/event.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+#include "src/conf.h"
+#include "src/util.h"
+#include "src/tlsdate.h"
+
+/* Returns 1 if a death was handled, otherwise 0. */
+int
+handle_child_death (struct state *state)
+{
+  siginfo_t info;
+  int ret;
+  info.si_pid = 0;
+  ret = waitid (P_ALL, -1, &info, WEXITED|WNOHANG);
+  if (ret == -1)
+    {
+      if (errno == ECHILD)
+        return 0;
+      perror ("[event:%s] waitid() failed after SIGCHLD", __func__);
+      return 0;
+    }
+  if (info.si_pid == 0)
+    {
+      return 0;
+    }
+  if (info.si_pid == state->setter_pid)
+    {
+      report_setter_error (&info);
+      event_base_loopbreak (state->base);
+      return 1;
+    }
+  if (info.si_pid != state->tlsdate_pid)
+    {
+      error ("[event:%s] SIGCHLD for an unknown process -- "
+             "pid:%d uid:%d status:%d code:%d", __func__,
+             info.si_pid, info.si_uid, info.si_status, info.si_code);
+      return 1;
+    }
+  info ("[event:%s] tlsdate reaped => "
+        "pid:%d uid:%d status:%d code:%d", __func__,
+        info.si_pid, info.si_uid, info.si_status, info.si_code);
+
+  /* If it was still active, remove it. */
+  event_del (state->events[E_TLSDATE_TIMEOUT]);
+  state->running = 0;
+  state->tlsdate_pid = 0;
+  /* Clean exit - don't rerun! */
+  if (info.si_status == 0)
+    return 1;
+  /* Rerun a failed tlsdate */
+  if (state->backoff < MAX_SANE_BACKOFF)
+    state->backoff *= 2;
+  /* If there is no resolver, call tlsdate directly. */
+  if (!state->events[E_RESOLVER])
+    {
+      trigger_event (state, E_TLSDATE, state->backoff);
+      return 1;
+    }
+  /* Run tlsdate even if the resolver doesn't come back. */
+  trigger_event (state, E_TLSDATE, RESOLVER_TIMEOUT + state->backoff);
+  /* Schedule the resolver.  This is always done after tlsdate in case there
+   * is no resolver.
+   */
+  trigger_event (state, E_RESOLVER, state->backoff);
+  return 1;
+}
+
+/* Returns 1 if a death was handled, otherwise 0. */
+int
+handle_child_stop (struct state *state)
+{
+  /* Handle unexpected external interactions */
+  siginfo_t info;
+  int ret;
+  info.si_pid = 0;
+  ret = waitid (P_ALL, -1, &info, WSTOPPED|WCONTINUED|WNOHANG);
+  if (ret == -1)
+    {
+      if (errno == ECHILD)
+        return 0;
+      perror ("[event:%s] waitid() failed after SIGCHLD", __func__);
+      return 0;
+    }
+  if (info.si_pid == 0)
+    return 0;
+  info ("[event:%s] a child has been STOPPED or CONTINUED. Killing it.",
+         __func__);
+  /* Kill it then catch the next SIGCHLD. */
+  if (kill (info.si_pid, SIGKILL))
+    {
+      if (errno == EPERM)
+        fatal ("[event:%s] cannot terminate STOPPED privileged child",
+               __func__);
+      if (errno == ESRCH)
+        info ("[event:%s] child gone before we could kill it",
+              __func__);
+    }
+  return 1;
+}
+
+void
+action_sigchld (evutil_socket_t fd, short what, void *arg)
+{
+  struct state *state = arg;
+  debug ("[event:%s] a child process has SIGCHLD'd!", __func__);
+  /* Process SIGCHLDs in two steps: death and stopped until all
+   * pending children are sorted.
+   */
+  if (!handle_child_death (state) && !handle_child_stop (state))
+    info ("[event:%s] SIGCHLD fired but no children ready!", __func__);
+  while (handle_child_death (state) || handle_child_stop (state));
+}
+
+int
+setup_sigchld_event (struct state *state, int persist)
+{
+  state->events[E_SIGCHLD] = event_new (state->base, SIGCHLD,
+                                        EV_SIGNAL| (persist ? EV_PERSIST : 0),
+                                        action_sigchld, state);
+  if (!state->events[E_SIGCHLD])
+    return 1;
+  /* Make sure this is lower than SAVE so we get any error
+   * messages back from the time setter.
+   */
+  event_priority_set (state->events[E_SIGCHLD], PRI_NET);
+  event_add (state->events[E_SIGCHLD], NULL);
+  return 0;
+}
diff --git a/src/events/sigterm.c b/src/events/sigterm.c
new file mode 100644
index 0000000..0143d6f
--- /dev/null
+++ b/src/events/sigterm.c
@@ -0,0 +1,33 @@
+/*
+ * sigterm.c - handler for SIGTERM
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <sys/time.h>
+
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/util.h"
+#include "src/tlsdate.h"
+
+/* On sigterm, grab the system clock and write it before terminating */
+void action_sigterm (evutil_socket_t fd, short what, void *arg)
+{
+  struct state *state = arg;
+  struct timeval tv;
+  info ("[event:%s] starting graceful shutdown . . .", __func__);
+  state->exitting = 1;
+  if (gettimeofday (&tv, NULL))
+    {
+      pfatal ("[event:%s] couldn't gettimeofday to exit gracefully", __func__);
+    }
+  /* Don't change the last sync_type */
+  state->last_time = tv.tv_sec;
+  /* Immediately save and exit. */
+  trigger_event (state, E_SAVE, -1);
+}
diff --git a/src/events/time_set.c b/src/events/time_set.c
new file mode 100644
index 0000000..9b3c7f3
--- /dev/null
+++ b/src/events/time_set.c
@@ -0,0 +1,173 @@
+/*
+ * time_set.c - time setting functions
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/dbus.h"
+#include "src/tlsdate.h"
+#include "src/util.h"
+
+void
+handle_time_setter (struct state *state, int status)
+{
+  switch (status)
+    {
+    case SETTER_BAD_TIME:
+      info ("[event:%s] time setter received bad time", __func__);
+      /* This is the leaf node. Failure means that our source
+       * tried to walk back in time.
+       */
+      state->last_sync_type = SYNC_TYPE_RTC;
+      state->last_time = time (NULL);
+      break;
+    case SETTER_TIME_SET:
+      info ("[event:%s] time set from the %s (%ld)",
+            __func__, sync_type_str (state->last_sync_type), state->last_time);
+      if (state->last_sync_type == SYNC_TYPE_NET)
+        {
+          /* Update the delta so it doesn't fire again immediately. */
+          state->clock_delta = 0;
+          check_continuity (&state->clock_delta);
+          /* Reset the sources list! */
+          state->opts.cur_source = NULL;
+        }
+      /* Share our success. */
+      dbus_announce (state);
+      break;
+    case SETTER_NO_SBOX:
+      error ("[event:%s] time setter failed to sandbox", __func__);
+      break;
+    case SETTER_EXIT:
+      error ("[event:%s] time setter exited gracefully", __func__);
+      break;
+    case SETTER_SET_ERR:
+      error ("[event:%s] time setter could not settimeofday()", __func__);
+      break;
+    case SETTER_NO_RTC:
+      error ("[event:%s] time setter could sync rtc", __func__);
+      break;
+    case SETTER_NO_SAVE:
+      error ("[event:%s] time setter could not open save file", __func__);
+      break;
+    case SETTER_READ_ERR:
+      error ("[event:%s] time setter could not read time", __func__);
+      break;
+    default:
+      error ("[event:%s] received bogus status from time setter: %d",
+             __func__, status);
+      exit (status);
+    }
+}
+
+void
+action_time_set (evutil_socket_t fd, short what, void *arg)
+{
+  struct state *state = arg;
+  int status = -1;
+  ssize_t bytes = 0;
+  debug ("[event:%s] fired", __func__);
+  bytes = IGNORE_EINTR (read (fd, &status, sizeof (status)));
+  if (bytes == -1 && errno == EAGAIN)
+    return;  /* Catch next wake up */
+  /* Catch the rest of the errnos and any truncation. */
+  if (bytes != sizeof (status))
+    {
+      /* Truncation of an int over a pipe shouldn't happen except in
+       * terminal cases.
+       */
+      perror ("[event:%s] time setter pipe truncated! (%d)", __func__,
+              bytes);
+      /* Let SIGCHLD do the teardown. */
+      close (fd);
+      return;
+    }
+  handle_time_setter (state, status);
+}
+
+int
+setup_time_setter (struct state *state)
+{
+  struct event *event;
+  int to_fds[2];
+  int from_fds[2];
+  if (pipe (to_fds) < 0)
+    {
+      perror ("pipe failed");
+      return 1;
+    }
+  if (pipe (from_fds) < 0)
+    {
+      perror ("pipe failed");
+      close (to_fds[0]);
+      close (to_fds[1]);
+      return 1;
+    }
+  /* The fd that tlsdated will write to */
+  state->setter_save_fd = to_fds[1];
+  state->setter_notify_fd = from_fds[0];
+  /* Make the notifications fd non-blocking. */
+  if (fcntl (from_fds[0], F_SETFL, O_NONBLOCK) < 0)
+    {
+      perror ("notifier_fd fcntl(O_NONBLOCK) failed");
+      goto close_and_fail;
+    }
+  /* Make writes non-blocking */
+  if (fcntl (to_fds[1], F_SETFL, O_NONBLOCK) < 0)
+    {
+      perror ("save_fd fcntl(O_NONBLOCK) failed");
+      goto close_and_fail;
+    }
+  event = event_new (state->base, from_fds[0], EV_READ|EV_PERSIST,
+                     action_time_set, state);
+  if (!event)
+    {
+      error ("Failed to allocate tlsdate setter event");
+      goto close_and_fail;
+    }
+  event_priority_set (event, PRI_NET);
+  event_add (event, NULL);
+  /* fork */
+  state->setter_pid = fork();
+  if (state->setter_pid < 0)
+    {
+      perror ("fork()ing the time setter failed");
+      goto close_and_fail;
+    }
+  if (state->setter_pid == 0)
+    {
+      close (to_fds[1]);
+      close (from_fds[0]);
+      time_setter_coprocess (to_fds[0], from_fds[1], state);
+      _exit (1);
+    }
+  close (from_fds[1]);
+  close (to_fds[0]);
+  return 0;
+
+close_and_fail:
+  close (to_fds[0]);
+  close (to_fds[1]);
+  close (from_fds[0]);
+  close (from_fds[1]);
+  return 1;
+}
diff --git a/src/events/tlsdate_status.c b/src/events/tlsdate_status.c
new file mode 100644
index 0000000..caa71fd
--- /dev/null
+++ b/src/events/tlsdate_status.c
@@ -0,0 +1,146 @@
+/*
+ * tlsdate_status.c - handles tlsdate-monitor responses
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/util.h"
+#include "src/tlsdate.h"
+
+/* Returns < 0 on error, > 0 on eagain, and 0 on success */
+int
+read_tlsdate_response (int fd, time_t *t)
+{
+  /* TLS passes time as a 32-bit value. */
+  uint32_t server_time;
+  ssize_t ret = IGNORE_EINTR (read (fd, &server_time, sizeof (server_time)));
+  if (ret == -1 && errno == EAGAIN)
+    {
+      /* Full response isn't ready yet. */
+      return 1;
+    }
+  if (ret != sizeof (server_time))
+    {
+      /* End of pipe (0) or truncated: death probable. */
+      error ("[event:(%s)] invalid time read from tlsdate (ret:%zd).",
+             __func__, ret);
+      return -1;
+    }
+  /* uint32_t moves to signed long so there is room for silliness. */
+  *t = server_time;
+  return 0;
+}
+
+void
+action_tlsdate_timeout (evutil_socket_t fd, short what, void *arg)
+{
+  struct state *state = arg;
+  info ("[event:%s] tlsdate timed out", __func__);
+  /* Force kill it and let action_sigchld rerun. */
+  if (state->tlsdate_pid)
+    kill (state->tlsdate_pid, SIGKILL);
+}
+
+void
+action_tlsdate_status (evutil_socket_t fd, short what, void *arg)
+{
+  struct state *state = arg;
+  time_t t = 0;
+  int ret = read_tlsdate_response (fd, &t);
+  debug ("[event:%s] fired", __func__);
+  if (ret < 0)
+    {
+      trigger_event (state, E_TLSDATE_TIMEOUT, 0);
+      return;
+    }
+  if (ret)
+    {
+      /* EAGAIN'd: wait for the rest. */
+      trigger_event (state, E_TLSDATE_STATUS, -1);
+      return;
+    }
+  if (is_sane_time (t))
+    {
+      /* Note that last_time is from an online source */
+      state->last_sync_type = SYNC_TYPE_NET;
+      state->last_time = t;
+      trigger_event (state, E_SAVE, -1);
+    }
+  else
+    {
+      error ("[event:%s] invalid time received from tlsdate: %ld",
+             __func__, t);
+    }
+  /* Restore the backoff and tries count on success, insane or not.
+   * On failure, the event handler does it.
+   */
+  state->tries = 0;
+  state->backoff = state->opts.wait_between_tries;
+  return;
+}
+
+/* Returns 0 on success and populates |fds| */
+int
+new_tlsdate_monitor_pipe (int fds[2])
+{
+  if (pipe (fds) < 0)
+    {
+      perror ("pipe failed");
+      return -1;
+    }
+  /* TODO(wad): CLOEXEC, Don't leak these into tlsdate proper. */
+  return 0;
+}
+
+/* Create a fd pair that the tlsdate runner will communicate over */
+int
+setup_tlsdate_status (struct state *state)
+{
+  int fds[2];
+  /* One pair of pipes are reused along with the event. */
+  if (new_tlsdate_monitor_pipe (fds))
+    {
+      return -1;
+    }
+  /* The fd that the monitor process will write to */
+  state->tlsdate_monitor_fd = fds[1];
+  /* Make the reader fd non-blocking and not leak into tlsdate. */
+  if (fcntl (fds[0], F_SETFL, O_NONBLOCK|O_CLOEXEC) < 0)
+    {
+      perror ("pipe[0] fcntl(O_NONBLOCK) failed");
+      return 1;
+    }
+  state->events[E_TLSDATE_STATUS] = event_new (state->base, fds[0],
+                                    EV_READ,
+                                    action_tlsdate_status, state);
+  if (!state->events[E_TLSDATE_STATUS])
+    {
+      error ("Failed to allocate tlsdate status event");
+      return 1;
+    }
+  event_priority_set (state->events[E_TLSDATE_STATUS], PRI_NET);
+  state->events[E_TLSDATE_TIMEOUT] = event_new (state->base, -1,
+                                     EV_TIMEOUT,
+                                     action_tlsdate_timeout, state);
+  if (!state->events[E_TLSDATE_TIMEOUT])
+    {
+      error ("Failed to allocate tlsdate timeout event");
+      return 1;
+    }
+  event_priority_set (state->events[E_TLSDATE_TIMEOUT], PRI_SAVE);
+  return 0;
+}
diff --git a/src/include.am b/src/include.am
index 93b4b76..f3a6bcd 100644
--- a/src/include.am
+++ b/src/include.am
@@ -7,14 +7,13 @@
 bin_PROGRAMS+= src/tlsdate
 bin_PROGRAMS+= src/tlsdate-helper
 bin_PROGRAMS+= src/tlsdated
-bin_PROGRAMS+= src/tlsdate-dbus-announce
 
 src_conf_unittest_SOURCES = src/conf.c
 src_conf_unittest_SOURCES+= src/conf-unittest.c
 check_PROGRAMS+= src/conf_unittest
 noinst_PROGRAMS+= src/conf_unittest
 
-src_tlsdate_routeup_CFLAGS = -DROUTEUP_MAIN
+src_tlsdate_routeup_CPPFLAGS = -DROUTEUP_MAIN
 src_tlsdate_routeup_SOURCES = src/routeup.c
 src_tlsdate_routeup_SOURCES+= src/util.c
 
@@ -26,22 +25,46 @@
 src_tlsdate_helper_SOURCES+= src/proxy-bio.c
 src_tlsdate_helper_SOURCES+= src/util.c
 
-src_tlsdated_CFLAGS = -DTLSDATED_MAIN
-src_tlsdated_LDADD = -lcrypto
+src_tlsdated_CFLAGS = $(DBUS_CFLAGS) $(LIBEVENT_CFLAGS)
+src_tlsdated_CPPFLAGS = -DTLSDATED_MAIN -DWITH_EVENTS
+if SECCOMP_FILTER_DEBUG
+src_tlsdated_CPPFLAGS += -DSECCOMP_FILTER_DEBUG=1
+endif
+src_tlsdated_LDADD = -lcrypto $(RT_LIB) $(DBUS_LIBS) $(LIBEVENT_LIBS)
 src_tlsdated_SOURCES = src/conf.c
 src_tlsdated_SOURCES+= src/routeup.c
+if HAVE_DBUS
+src_tlsdated_SOURCES+= src/dbus.c
+endif
+if HAVE_CROS
+src_tlsdated_SOURCES+= src/platform-cros.c
+endif
+if HAVE_SECCOMP_FILTER
+src_tlsdated_SOURCES+= src/seccomp.c
+endif
+src_tlsdated_SOURCES+= src/tlsdate-monitor.c
+src_tlsdated_SOURCES+= src/tlsdate-setter.c
 src_tlsdated_SOURCES+= src/tlsdated.c
 src_tlsdated_SOURCES+= src/util.c
+src_tlsdated_SOURCES+= src/events/check_continuity.c
+src_tlsdated_SOURCES+= src/events/kickoff_time_sync.c
+src_tlsdated_SOURCES+= src/events/route_up.c
+src_tlsdated_SOURCES+= src/events/run_tlsdate.c
+src_tlsdated_SOURCES+= src/events/sigterm.c
+src_tlsdated_SOURCES+= src/events/sigchld.c
+src_tlsdated_SOURCES+= src/events/save.c
+src_tlsdated_SOURCES+= src/events/time_set.c
+src_tlsdated_SOURCES+= src/events/tlsdate_status.c
 
-src_tlsdate_dbus_announce_CFLAGS = @DBUS_CFLAGS@
-src_tlsdate_dbus_announce_LDADD = @DBUS_LIBS@
-src_tlsdate_dbus_announce_SOURCES = src/tlsdate-dbus-announce.c
+src_tlsdated_unittest_CFLAGS = $(DBUS_CFLAGS) $(LIBEVENT_CFLAGS)
+src_tlsdated_unittest_CPPFLAGS = -DWITH_EVENTS
+if SECCOMP_FILTER_DEBUG
+src_tlsdated_unittest_CPPFLAGS += -DSECCOMP_FILTER_DEBUG=1
+endif
+src_tlsdated_unittest_LDADD = -lcrypto $(RT_LIB) $(DBUS_LIBS) $(LIBEVENT_LIBS)
+src_tlsdated_unittest_SOURCES = src/tlsdated-unittest.c
+src_tlsdated_unittest_SOURCES+= $(src_tlsdated_SOURCES)
 
-src_tlsdated_unittest_LDADD = -lcrypto
-src_tlsdated_unittest_SOURCES = src/routeup.c
-src_tlsdated_unittest_SOURCES+= src/tlsdated-unittest.c
-src_tlsdated_unittest_SOURCES+= src/util.c
-src_tlsdated_unittest_SOURCES+= src/tlsdated.c
 check_PROGRAMS+= src/tlsdated_unittest
 noinst_PROGRAMS+= src/tlsdated_unittest
 
@@ -57,11 +80,15 @@
 noinst_HEADERS+= src/routeup.h
 noinst_HEADERS+= src/test_harness.h
 noinst_HEADERS+= src/tlsdate-helper.h
+noinst_HEADERS+= src/seccomp.h
+noinst_HEADERS+= src/seccomp-compat.h
 noinst_HEADERS+= src/tlsdate.h
 noinst_HEADERS+= src/util.h
 noinst_HEADERS+= src/visibility.h
 noinst_HEADERS+= src/proxy-bio.h
 noinst_HEADERS+= src/test-bio.h
 noinst_HEADERS+= src/conf.h
+noinst_HEADERS+= src/dbus.h
+noinst_HEADERS+= src/platform.h
 
-check_PROGRAMS+= src/test/proxy-override src/test/rotate src/test/sleep-wrap
+check_PROGRAMS+= src/test/proxy-override src/test/check-host-1 src/test/check-host-2 src/test/sleep-wrap
diff --git a/src/platform-cros.c b/src/platform-cros.c
new file mode 100644
index 0000000..27fb86e
--- /dev/null
+++ b/src/platform-cros.c
@@ -0,0 +1,622 @@
+/*
+ * platform-cros.c - CrOS platform DBus integration
+ * Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "config.h"
+
+#include <ctype.h>
+#include <dbus/dbus.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+
+#include <event2/event.h>
+
+#include "src/dbus.h"
+#include "src/platform.h"
+#include "src/tlsdate.h"
+#include "src/util.h"
+
+static const char kMatchFormatData[] = "interface='%s',member='%s',arg0='%s'";
+static const char *kMatchFormat = kMatchFormatData;
+static const char kMatchNoArgFormatData[] = "interface='%s',member='%s'";
+static const char *kMatchNoArgFormat = kMatchNoArgFormatData;
+
+static const char kLibCrosDestData[] = "org.chromium.LibCrosService";
+static const char *kLibCrosDest = kLibCrosDestData;
+static const char kLibCrosInterfaceData[] = "org.chromium.LibCrosServiceInterface";
+static const char *kLibCrosInterface = kLibCrosInterfaceData;
+static const char kLibCrosPathData[] = "/org/chromium/LibCrosService";
+static const char *kLibCrosPath = kLibCrosPathData;
+static const char kResolveNetworkProxyData[] = "ResolveNetworkProxy";
+static const char *kResolveNetworkProxy = kResolveNetworkProxyData;
+
+static const char kDBusInterfaceData[] = "org.freedesktop.DBus";
+static const char *kDBusInterface = kDBusInterfaceData;
+static const char kNameOwnerChangedData[] = "NameOwnerChanged";
+static const char *kNameOwnerChanged = kNameOwnerChangedData;
+static const char kNameAcquiredData[] = "NameAcquired";
+static const char *kNameAcquired = kNameAcquiredData;
+
+static const char kManagerInterfaceData[] = "org.chromium.flimflam.Manager";
+static const char *kManagerInterface = kManagerInterfaceData;
+
+static const char kServiceInterfaceData[] = "org.chromium.flimflam.Service";
+static const char *kServiceInterface = kServiceInterfaceData;
+static const char kMemberData[] = "PropertyChanged";
+static const char *kMember = kMemberData;
+
+static const char kProxyConfigData[] = "ProxyConfig";
+static const char *kProxyConfig = kProxyConfigData;
+static const char kDefaultServiceData[] = "DefaultService";
+static const char *kDefaultService = kDefaultServiceData;
+
+static const char kResolveInterfaceData[] = "org.torproject.tlsdate.Resolver";
+static const char *kResolveInterface = kResolveInterfaceData;
+static const char kResolveMemberData[] = "ProxyChange";
+static const char *kResolveMember = kResolveMemberData;
+
+/* TODO(wad) Integrate with cros_system_api/dbus/service_constants.h */
+static const char kPowerManagerInterfaceData[] = "org.chromium.PowerManager";
+static const char *kPowerManagerInterface = kPowerManagerInterfaceData;
+static const char kPowerStateChangedData[] = "PowerStateChanged";
+static const char *kPowerStateChanged = kPowerStateChangedData;
+static const char kPowerStateArgData[] = "on";
+static const char *kPowerStateArg = kPowerStateArgData;
+
+static const char kErrorServiceUnknownData[] = "org.freedesktop.DBus.Error.ServiceUnknown";
+static const char *kErrorServiceUnknown = kErrorServiceUnknownData;
+
+struct platform_state
+{
+  struct event_base *base;
+  struct state *state;
+  DBusMessage **resolve_msg;
+  int resolve_msg_count;
+  uint32_t resolve_network_proxy_serial;
+};
+
+static
+bool
+get_valid_hostport (const char *hostport, char *out, size_t len)
+{
+  bool host = true;
+  const char *end = hostport + strlen (hostport);
+  const char *c;
+  *out = '\0';
+  /* Hosts begin with alphanumeric only. */
+  if (!isalnum (*hostport))
+    {
+      info ("Host does not start with alnum");
+      return false;
+    }
+  *out++ = *hostport;
+  for (c = hostport + 1;  c < end && len > 0; ++c, ++out, --len)
+    {
+      *out = *c;
+      if (host)
+        {
+          if (isalnum (*c) || *c == '-' || *c == '.')
+            {
+              continue;
+            }
+          if (*c == ':')
+            {
+              host = false;
+              continue;
+            }
+        }
+      else
+        {
+          if (isdigit (*c))
+            continue;
+        }
+      *out = '\0';
+      return false;
+    }
+  *out = '\0';
+  return true;
+}
+
+/* Convert PAC return format to tlsdated url format */
+/* TODO(wad) support multiple proxies when Chromium does:
+ * PROXY x.x.x.x:yyyy; PROXY z.z.z.z:aaaaa
+ */
+static
+void
+canonicalize_pac (const char *pac_fmt, char *proxy_url, size_t len)
+{
+  size_t type_len;
+  size_t copied = 0;
+  const char *space;
+  /* host[255]:port[6]\0 */
+  char hostport[6 + 255 + 2];
+  proxy_url[0] = '\0';
+  if (len < 1)
+    return;
+  if (!strcmp (pac_fmt, "DIRECT"))
+    {
+      return;
+    }
+  /* Find type */
+  space = strchr (pac_fmt, ' ');
+  if (!space)
+    return;
+  type_len = space - pac_fmt;
+  if (!get_valid_hostport (space + 1, hostport, sizeof (hostport)))
+    {
+      error ("invalid host:port: %s", space + 1);
+      return;
+    }
+  proxy_url[0] = '\0';
+  if (!strncmp (pac_fmt, "PROXY", type_len))
+    {
+      copied = snprintf (proxy_url, len, "http://%s", hostport);
+    }
+  else if (!strncmp (pac_fmt, "SOCKS", type_len))
+    {
+      copied = snprintf (proxy_url, len, "socks4://%s", hostport);
+    }
+  else if (!strncmp (pac_fmt, "SOCKS5", type_len))
+    {
+      copied = snprintf (proxy_url, len, "socks5://%s", hostport);
+    }
+  else if (!strncmp (pac_fmt, "HTTPS", type_len))
+    {
+      copied = snprintf (proxy_url, len, "https://%s", hostport);
+    }
+  else
+    {
+      error ("pac_fmt unmatched: '%s' %zu", pac_fmt, type_len);
+    }
+  if (copied >= len)
+    {
+      error ("canonicalize_pac: truncation '%s'", proxy_url);
+      proxy_url[0] = '\0';
+      return;
+    }
+}
+
+static
+DBusHandlerResult
+handle_service_change (DBusConnection *connection,
+                       DBusMessage *message,
+                       struct platform_state *ctx)
+{
+  DBusMessageIter iter, subiter;
+  DBusError error;
+  const char *pname;
+  const char *pval;
+  const char *service;
+  dbus_error_init (&error);
+  debug ("[event:cros:%s]: fired", __func__);
+  /* TODO(wad) Track the current DefaultService only fire when it changes */
+  service = dbus_message_get_path (message);
+  if (!service)
+    return DBUS_HANDLER_RESULT_HANDLED;
+  /* Shill emits string:ProxyConfig variant string:"..." */
+  if (!dbus_message_iter_init (message, &iter))
+    return DBUS_HANDLER_RESULT_HANDLED;
+  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
+    return DBUS_HANDLER_RESULT_HANDLED;
+  dbus_message_iter_get_basic (&iter, &pname);
+  /* Make sure we are only firing on a ProxyConfig property change. */
+  if (strcmp (pname, kProxyConfig))
+    return DBUS_HANDLER_RESULT_HANDLED;
+  if (!dbus_message_iter_next (&iter))
+    return DBUS_HANDLER_RESULT_HANDLED;
+  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
+    return DBUS_HANDLER_RESULT_HANDLED;
+  dbus_message_iter_recurse (&iter, &subiter);
+  if (dbus_message_iter_get_arg_type (&subiter) != DBUS_TYPE_STRING)
+    return DBUS_HANDLER_RESULT_HANDLED;
+  dbus_message_iter_get_basic (&subiter, &pval);
+  /* Right now, nothing is done with the Shill proxy value because
+   * Chromium handles .pac resolution.  This may be more useful for
+   * ignoring incomplete proxy values sent while a user is typing.
+   */
+  action_kickoff_time_sync (-1, EV_TIMEOUT, ctx->state);
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static
+DBusHandlerResult
+handle_manager_change (DBusConnection *connection,
+                       DBusMessage *message,
+                       struct platform_state *ctx)
+{
+  DBusMessageIter iter, subiter;
+  DBusError error;
+  const char *pname;
+  const char *pval;
+  debug ("[event:cros:%s]: fired", __func__);
+  dbus_error_init (&error);
+  if (!dbus_message_iter_init (message, &iter))
+    return DBUS_HANDLER_RESULT_HANDLED;
+  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
+    return DBUS_HANDLER_RESULT_HANDLED;
+  dbus_message_iter_get_basic (&iter, &pname);
+  /* Make sure we caught the right property. */
+  if (strcmp (pname, kDefaultService))
+    return DBUS_HANDLER_RESULT_HANDLED;
+  if (!dbus_message_iter_next (&iter))
+    return DBUS_HANDLER_RESULT_HANDLED;
+  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
+    return DBUS_HANDLER_RESULT_HANDLED;
+  dbus_message_iter_recurse (&iter, &subiter);
+  if (dbus_message_iter_get_arg_type (&subiter) != DBUS_TYPE_OBJECT_PATH)
+    return DBUS_HANDLER_RESULT_HANDLED;
+  dbus_message_iter_get_basic (&subiter, &pval);
+  /* TODO(wad) Filter on the currently active service in pval. */
+  debug ("[event:cros:%s] service change on path %s",
+         __func__, pval);
+  action_kickoff_time_sync (-1, EV_TIMEOUT, ctx->state);
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static
+DBusHandlerResult
+handle_power_state_change (DBusConnection *connection,
+                           DBusMessage *message,
+                           struct platform_state *ctx)
+{
+  DBusMessageIter iter;
+  DBusError error;
+  const char *pname;
+  debug ("[event:cros:%s]: fired", __func__);
+  dbus_error_init (&error);
+  if (!dbus_message_iter_init (message, &iter))
+    return DBUS_HANDLER_RESULT_HANDLED;
+  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
+    return DBUS_HANDLER_RESULT_HANDLED;
+  dbus_message_iter_get_basic (&iter, &pname);
+  /* Coming back from resume, trigger a continuity and time
+   * check just in case none of the other events happen.
+   */
+  if (!strcmp (pname, kPowerStateArg))
+    action_kickoff_time_sync (-1, EV_TIMEOUT, ctx->state);
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static
+DBusHandlerResult
+handle_proxy_change (DBusConnection *connection,
+                     DBusMessage *message,
+                     struct platform_state *ctx)
+{
+  DBusMessageIter iter;
+  DBusError error;
+  const char *pname;
+  const char *pval;
+  char time_host[MAX_PROXY_URL];
+  int url_len = 0;
+  struct source *src = ctx->state->opts.sources;
+  debug ("[event:cros:%s]: fired", __func__);
+  if (ctx->state->opts.cur_source && ctx->state->opts.cur_source->next)
+    src = ctx->state->opts.cur_source->next;
+  if (!ctx->state->resolving)
+    {
+      info ("[event:cros:%s] Unexpected ResolveNetworkProxy signal seen",
+            __func__);
+      return DBUS_HANDLER_RESULT_HANDLED;
+    }
+  dbus_error_init (&error);
+  /* Shill emits string:ProxyConfig variant string:"..." */
+  if (!dbus_message_iter_init (message, &iter))
+    return DBUS_HANDLER_RESULT_HANDLED;
+  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
+    return DBUS_HANDLER_RESULT_HANDLED;
+  dbus_message_iter_get_basic (&iter, &pname);
+  /* Make sure this was the resolution we asked for */
+  url_len = snprintf (time_host, sizeof (time_host), "https://%s:%s",
+                      src->host, src->port);
+  if (url_len >= sizeof (time_host))
+    {
+      error ("[event:cros:%s]: current source url is too long",
+             __func__);
+    }
+  if (strcmp (pname, time_host))
+    {
+      error ("[event:cros:%s]: resolved host mismatch: %s v %s",
+             __func__, pname, time_host);
+      return DBUS_HANDLER_RESULT_HANDLED;
+    }
+  if (!dbus_message_iter_next (&iter))
+    return DBUS_HANDLER_RESULT_HANDLED;
+  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
+    return DBUS_HANDLER_RESULT_HANDLED;
+  dbus_message_iter_get_basic (&iter, &pval);
+  ctx->state->resolving = 0;
+  canonicalize_pac (pval, ctx->state->dynamic_proxy, sizeof (ctx->state->dynamic_proxy));
+  trigger_event (ctx->state, E_TLSDATE, 1);
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static
+DBusHandlerResult
+handle_dbus_change (DBusConnection *connection,
+                    DBusMessage *message,
+                    struct platform_state *ctx)
+{
+  DBusMessageIter iter;
+  DBusError error;
+  const char *pname;
+  debug ("[event:cros:%s]: fired", __func__);
+  dbus_error_init (&error);
+  if (!dbus_message_iter_init (message, &iter))
+    return DBUS_HANDLER_RESULT_HANDLED;
+  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
+    return DBUS_HANDLER_RESULT_HANDLED;
+  dbus_message_iter_get_basic (&iter, &pname);
+  /* Make sure we caught the right property. */
+  if (strcmp (pname, kLibCrosDest))
+    return DBUS_HANDLER_RESULT_HANDLED;
+  action_kickoff_time_sync (-1, EV_TIMEOUT, ctx->state);
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static
+void
+action_resolve_proxy (evutil_socket_t fd, short what, void *arg)
+{
+  struct platform_state *ctx = arg;
+  struct dbus_state *dbus_state = ctx->state->dbus;
+  DBusConnection *conn = dbus_state->conn;
+  struct source *src = ctx->state->opts.sources;
+  debug ("[event:%s] fired", __func__);
+  /* Emulate tlsdate-monitor.c:build_argv and choose the next source */
+  if (ctx->state->opts.cur_source && ctx->state->opts.cur_source->next)
+    src = ctx->state->opts.cur_source->next;
+  if (ctx->state->resolving || ctx->resolve_network_proxy_serial)
+    {
+      /* Note, this is not the same as the response signal. It just avoids
+       * multiple requests in a single dispatch window.
+       */
+      info ("[event:%s] no resolve_proxy sent; pending method_reply",
+            __func__);
+      return;
+    }
+  ctx->state->dynamic_proxy[0] = '\0';
+  if (ctx->resolve_msg[src->id] == NULL)
+    {
+      info ("[event:%s] no dynamic proxy for %s:%s", __func__,
+            src->host, src->port);
+      trigger_event (ctx->state, E_TLSDATE, 1);
+      return;
+    }
+  info ("[event:%s] resolving proxy for %s:%s", __func__,
+        src->host, src->port);
+  ctx->state->resolving = 1;
+  if (!dbus_connection_send (conn,
+                             ctx->resolve_msg[src->id],
+                             &ctx->resolve_network_proxy_serial))
+    {
+      error ("[event:%s] cannot send ResolveNetworkProxy query!", __func__);
+      return;
+    }
+}
+
+static
+DBusHandlerResult
+dbus_filter (DBusConnection *connection, DBusMessage *message, void *data)
+{
+  struct platform_state *state = data;
+  /* Terminate gracefully if DBus goes away. */
+  if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected"))
+    {
+      error ("[cros] DBus system bus has become inaccessible. Terminating.");
+      /* Trigger a graceful teardown. */
+      kill (getpid(), SIGINT);
+      return DBUS_HANDLER_RESULT_HANDLED;
+    }
+  /* Hand it over to the service dispatcher. */
+  if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL)
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+  /* Handle explicitly defined signals only. */
+  if (dbus_message_is_signal (message, kDBusInterface, kNameAcquired))
+    {
+      info ("[cros] DBus name acquired successfully");
+      return DBUS_HANDLER_RESULT_HANDLED;
+    }
+  if (dbus_message_is_signal (message, kServiceInterface, kMember))
+    return handle_service_change (connection, message, state);
+  if (dbus_message_is_signal (message, kManagerInterface, kMember))
+    return handle_manager_change (connection, message, state);
+  if (dbus_message_is_signal (message, kResolveInterface, kResolveMember))
+    return handle_proxy_change (connection, message, state);
+  if (dbus_message_is_signal (message, kDBusInterface, kNameOwnerChanged))
+    return handle_dbus_change (connection, message, state);
+  if (dbus_message_is_signal (message, kPowerManagerInterface, kPowerStateChanged))
+    return handle_power_state_change (connection, message, state);
+  if (dbus_message_is_error (message, kErrorServiceUnknown))
+    {
+      info ("[cros] org.chromium.LibCrosService.ResolveNetworkProxy is missing");
+      info ("[cros] skipping proxy resolution for now");
+      /* Fire off tlsdate rather than letting it fail silently. */
+      state->resolve_network_proxy_serial = 0;
+      state->state->resolving = 0;
+      trigger_event (state->state, E_TLSDATE, 1);
+      return DBUS_HANDLER_RESULT_HANDLED;
+    }
+  /* Indicates a successful resolve request was issued. */
+  if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
+    {
+      uint32_t serial = dbus_message_get_reply_serial (message);
+      if (serial == state->resolve_network_proxy_serial)
+        {
+          state->resolve_network_proxy_serial = 0;
+          return DBUS_HANDLER_RESULT_HANDLED;
+        }
+      info ("[cros] unknown DBus METHOD_RETURN seen: %u", serial);
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+  debug ("[cros] unknown message received: "
+         "type=%s dest=%s interface=%s member=%s path=%s sig=%s error_name=%s",
+         dbus_message_type_to_string (dbus_message_get_type (message)),
+         dbus_message_get_destination (message),
+         dbus_message_get_interface (message),
+         dbus_message_get_member (message),
+         dbus_message_get_path (message),
+         dbus_message_get_signature (message),
+         dbus_message_get_error_name (message));
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+int
+add_match (DBusConnection *conn, const char *interface, const char *member,
+           const char *arg0)
+{
+  char match[1024];
+  DBusError error;
+  int len;
+  dbus_error_init (&error);
+  if (arg0)
+    {
+      len = snprintf (match, sizeof (match), kMatchFormat,
+                      interface, member, arg0);
+    }
+  else
+    {
+      len = snprintf (match, sizeof (match), kMatchNoArgFormat,
+                      interface, member);
+    }
+  if (len >= sizeof (match) || len < 0)
+    {
+      error ("[dbus] match truncated for '%s,%s'", interface, member);
+      return 1;
+    }
+  dbus_bus_add_match (conn, match, &error);
+  if (dbus_error_is_set (&error))
+    {
+      error ("[dbus] failed to add_match for '%s,%s'; error: %s, %s",
+             interface, member, error.name, error.message);
+      dbus_error_free (&error);
+      return 1;
+    }
+  return 0;
+}
+
+DBusMessage *
+new_resolver_message(const struct source *src)
+{
+  char time_host[MAX_PROXY_URL];
+  void *time_host_ptr = &time_host;
+  int url_len;
+  DBusMessage *res;
+  DBusMessageIter args;
+  if (!src->proxy || strcmp (src->proxy, "dynamic"))
+    {
+      return NULL;
+    }
+  res = dbus_message_new_method_call (kLibCrosDest, kLibCrosPath,
+                                      kLibCrosInterface, kResolveNetworkProxy);
+  if (!res)
+    {
+      error ("[cros] could not setup dynamic proxy for source %d", src->id);
+      return NULL;
+    }
+  /* Build the time_host */
+  url_len = snprintf (time_host, sizeof (time_host), "https://%s:%s",
+                      src->host, src->port);
+  if (url_len >= sizeof (time_host))
+    {
+      fatal ("[cros] source %d url is too long! (%d)", src->id, url_len);
+    }
+  /* Finish the message */
+  dbus_message_iter_init_append (res, &args);
+  if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &time_host_ptr) ||
+      !dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &kResolveInterface) ||
+      !dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &kResolveMember))
+    {
+      fatal ("[cros could not append arguments for resolver message");
+    }
+  return res;
+}
+
+int
+platform_init_cros (struct state *state)
+{
+  /* Watch for per-service ProxyConfig property changes */
+  struct event_base *base = state->base;
+  struct dbus_state *dbus_state = state->dbus;
+  struct source *src = NULL;
+  int sources = 0;
+  DBusConnection *conn = dbus_state->conn;
+  DBusError error;
+  struct platform_state *platform_state =
+      calloc (1, sizeof (struct platform_state));
+  if (!platform_state)
+    {
+      error ("[cros] could not allocate platform_state");
+      return -1;
+    }
+  /* TODO(wad) Follow up with dbus_error_free() where needed. */
+  dbus_error_init (&error);
+  /* Add watches for: proxy changes, default service changes, proxy resolution,
+   * LibCrosService ownership, and power state changes.
+   */
+  if (add_match (conn, kServiceInterface, kMember, kProxyConfig) ||
+      add_match (conn, kManagerInterface, kMember, kDefaultService) ||
+      add_match (conn, kResolveInterface, kResolveMember, NULL) ||
+      add_match (conn, kDBusInterface, kNameOwnerChanged, kLibCrosDest) ||
+      add_match (conn, kPowerManagerInterface, kPowerStateChanged, kPowerStateArg))
+    return 1;
+
+  /* Allocate one per source */
+  for (src = state->opts.sources; src; src = src->next, ++sources);
+  platform_state->resolve_msg_count = sources;
+  platform_state->resolve_msg = calloc (sources, sizeof (DBusMessage *));
+  if (!platform_state->resolve_msg)
+    {
+      error ("[cros] cannot allocate resolver messages");
+      free (platform_state);
+      return -1;
+    }
+  for (src = state->opts.sources; src; src = src->next)
+    {
+      if (src->id >= sources)
+        fatal ("Source ID is greater than available sources!");
+      platform_state->resolve_msg[src->id] = new_resolver_message (src);
+      if (platform_state->resolve_msg[src->id])
+        src->proxy = state->dynamic_proxy;
+    }
+  state->dynamic_proxy[0] = '\0';
+  if (state->opts.proxy && !strcmp (state->opts.proxy, "dynamic"))
+    {
+      info ("[cros] default dynamic proxy support");
+      state->opts.proxy = state->dynamic_proxy;
+    }
+  platform_state->base = base;
+  platform_state->state = state;
+  /* Add the dynamic resolver if tlsdate doesn't already have one. */
+  if (!state->events[E_RESOLVER])
+    {
+      state->events[E_RESOLVER] = event_new (base, -1, EV_TIMEOUT,
+                                             action_resolve_proxy,
+                                             platform_state);
+      if (!state->events[E_RESOLVER])
+        /* Let's not clean up DBus. */
+        fatal ("Could not allocated resolver event");
+      /* Wake up as a NET event since it'll self-block until DBus has a chance
+       * to send it.
+       */
+      event_priority_set (state->events[E_RESOLVER], PRI_NET);
+    }
+  /* Each platform can attach their own filter, but the filter func needs to be
+   * willing to DBUS_HANDLER_RESULT_NOT_YET_HANDLED on unexpected events.
+   */
+  /* TODO(wad) add the clean up function as the callback. */
+  if (!dbus_connection_add_filter (conn,
+                                   dbus_filter, platform_state, NULL))
+    {
+      error ("Failed to register signal handler callback");
+      return 1;
+    }
+  return 0;
+}
diff --git a/src/platform.h b/src/platform.h
new file mode 100644
index 0000000..f17efa2
--- /dev/null
+++ b/src/platform.h
@@ -0,0 +1,21 @@
+/*
+ * platform.h - platform handlers for event loops
+ * Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef PLATFORM_H_
+#define PLATFORM_H_
+#include "config.h"
+
+struct state;
+
+#ifdef HAVE_CROS
+int platform_init_cros (struct state *state);
+#else
+static inline int platform_init_cros (struct state *state)
+{
+  return 0;
+}
+#endif  /* HAVE_CROS */
+#endif  /* PLATFORM_H_ */
diff --git a/src/proxy-bio-unittest.c b/src/proxy-bio-unittest.c
index ec562fc..f01ba02 100644
--- a/src/proxy-bio-unittest.c
+++ b/src/proxy-bio-unittest.c
@@ -12,85 +12,93 @@
 #include "src/test_harness.h"
 #include "src/tlsdate.h"
 
-FIXTURE(test_bio) {
+FIXTURE (test_bio)
+{
   BIO *test;
 };
 
-FIXTURE_SETUP(test_bio) {
+FIXTURE_SETUP (test_bio)
+{
   self->test = BIO_new_test();
-  ASSERT_NE(NULL, self->test);
+  ASSERT_NE (NULL, self->test);
 }
 
-FIXTURE_TEARDOWN(test_bio) {
-  BIO_free(self->test);
+FIXTURE_TEARDOWN (test_bio)
+{
+  BIO_free (self->test);
 }
 
-BIO *proxy_bio(BIO *test, const char *type)
+BIO *proxy_bio (BIO *test, const char *type)
 {
   BIO *proxy = BIO_new_proxy();
-  BIO_proxy_set_type(proxy, type);
-  BIO_proxy_set_host(proxy, kTestHost);
-  BIO_proxy_set_port(proxy, TEST_PORT);
-  BIO_push(proxy, test);
+  BIO_proxy_set_type (proxy, type);
+  BIO_proxy_set_host (proxy, kTestHost);
+  BIO_proxy_set_port (proxy, TEST_PORT);
+  BIO_push (proxy, test);
   return proxy;
 }
 
-int need_out_bytes(BIO *test, const unsigned char *out, size_t sz)
+int need_out_bytes (BIO *test, const unsigned char *out, size_t sz)
 {
-  unsigned char *buf = malloc(sz);
+  unsigned char *buf = malloc (sz);
   size_t i;
   int result;
   if (!buf)
     return 1;
-  if (BIO_test_output_left(test) <  sz) {
-    fprintf(TH_LOG_STREAM, "not enough output: %d < %d\n",
-            (int)BIO_test_output_left(test), (int)sz);
-    free(buf);
-    return 2;
-  }
-  if (BIO_test_get_output(test, buf, sz) != sz) {
-    free(buf);
-    return 3;
-  }
-  if (memcmp(buf, out, sz)) {
-    for (i = 0; i < sz; i++) {
-      if (buf[i] != out[i])
-        fprintf(TH_LOG_STREAM,
-                "mismatch %d %02x %02x\n", (int)i,
-                buf[i], out[i]);
+  if (BIO_test_output_left (test) <  sz)
+    {
+      fprintf (TH_LOG_STREAM, "not enough output: %d < %d\n",
+               (int) BIO_test_output_left (test), (int) sz);
+      free (buf);
+      return 2;
     }
-  }
-  result = memcmp(buf, out, sz);
-  free(buf);
+  if (BIO_test_get_output (test, buf, sz) != sz)
+    {
+      free (buf);
+      return 3;
+    }
+  if (memcmp (buf, out, sz))
+    {
+      for (i = 0; i < sz; i++)
+        {
+          if (buf[i] != out[i])
+            fprintf (TH_LOG_STREAM,
+                     "mismatch %d %02x %02x\n", (int) i,
+                     buf[i], out[i]);
+        }
+    }
+  result = memcmp (buf, out, sz);
+  free (buf);
   return result;
 }
 
-int need_out_byte(BIO *test, unsigned char out)
+int need_out_byte (BIO *test, unsigned char out)
 {
   unsigned char c;
-  if (BIO_test_output_left(test) < 1)
+  if (BIO_test_output_left (test) < 1)
     return 1;
-  if (BIO_test_get_output(test, &c, 1) != 1)
+  if (BIO_test_get_output (test, &c, 1) != 1)
     return 2;
   return c != out;
 }
 
-int get_bytes(BIO *test, unsigned char *buf, size_t sz)
+int get_bytes (BIO *test, unsigned char *buf, size_t sz)
 {
-  return BIO_test_get_output(test, buf, sz);
+  return BIO_test_get_output (test, buf, sz);
 }
 
-void put_bytes(BIO *test, const unsigned char *buf, size_t sz)
+void put_bytes (BIO *test, const unsigned char *buf, size_t sz)
 {
-  BIO_test_add_input(test, buf, sz);
+  BIO_test_add_input (test, buf, sz);
 }
 
-void put_byte(BIO *test, char c)
+void put_byte (BIO *test, char c)
 {
-  BIO_test_add_input(test, (unsigned char *)&c, 1);
+  BIO_test_add_input (test, (unsigned char *) &c, 1);
 }
 
-unsigned const char kSocks4ARequest[] = {
+unsigned const char kSocks4ARequest[] =
+{
   0x04, /* socks4 */
   0x01, /* tcp stream */
   (TEST_PORT & 0xff00) >> 8,
@@ -100,56 +108,62 @@
   TEST_HOST, 0x00 /* null-terminated host */
 };
 
-TEST_F(test_bio, socks4a_success)
+TEST_F (test_bio, socks4a_success)
 {
   unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
-  unsigned const char kReply[] = {
+  unsigned const char kReply[] =
+  {
     0x00, /* null byte */
     0x5a, /* success */
     (TEST_PORT & 0xff00) >> 8,  /* port high */
     TEST_PORT & 0xff, /* port low */
     0x00, 0x00, 0x00, 0x00  /* bogus IP */
   };
-  BIO *proxy = proxy_bio(self->test, "socks4a");
-  put_bytes(self->test, kReply, sizeof(kReply));
-  EXPECT_EQ(4, BIO_write(proxy, kTestInput, sizeof(kTestInput)));
-  EXPECT_EQ(0, need_out_bytes(self->test, kSocks4ARequest,
-                              sizeof(kSocks4ARequest)));
-  EXPECT_EQ(0, need_out_bytes(self->test, kTestInput,
-                              sizeof(kTestInput)));
-  EXPECT_EQ(0, BIO_test_output_left(self->test));
+  BIO *proxy = proxy_bio (self->test, "socks4a");
+  put_bytes (self->test, kReply, sizeof (kReply));
+  EXPECT_EQ (4, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
+  EXPECT_EQ (0, need_out_bytes (self->test, kSocks4ARequest,
+                                sizeof (kSocks4ARequest)));
+  EXPECT_EQ (0, need_out_bytes (self->test, kTestInput,
+                                sizeof (kTestInput)));
+  EXPECT_EQ (0, BIO_test_output_left (self->test));
 }
 
-TEST_F(test_bio, socks4a_fail) {
+TEST_F (test_bio, socks4a_fail)
+{
   unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
-  unsigned const char kReply[] = {
+  unsigned const char kReply[] =
+  {
     0x00, /* null byte */
     0x5b, /* fail */
     (TEST_PORT & 0xff00) >> 8,  /* port high */
     TEST_PORT & 0xff, /* port low */
     0x00, 0x00, 0x00, 0x00  /* bogus IP */
   };
-  BIO *proxy = proxy_bio(self->test, "socks4a");
-  put_bytes(self->test, kReply, sizeof(kReply));
-  EXPECT_EQ(0, BIO_write(proxy, kTestInput, sizeof(kTestInput)));
-  EXPECT_EQ(0, need_out_bytes(self->test, kSocks4ARequest,
-                              sizeof(kSocks4ARequest)));
+  BIO *proxy = proxy_bio (self->test, "socks4a");
+  put_bytes (self->test, kReply, sizeof (kReply));
+  EXPECT_EQ (0, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
+  EXPECT_EQ (0, need_out_bytes (self->test, kSocks4ARequest,
+                                sizeof (kSocks4ARequest)));
   /* We shouldn't have written any payload */
-  EXPECT_EQ(0, BIO_test_output_left(self->test));
+  EXPECT_EQ (0, BIO_test_output_left (self->test));
 }
 
-unsigned const char kSocks5AuthRequest[] = {
+unsigned const char kSocks5AuthRequest[] =
+{
   0x05, /* socks5 */
   0x01, /* one auth method */
   0x00  /* no auth */
 };
 
-unsigned const char kSocks5AuthReply[] = {
+unsigned const char kSocks5AuthReply[] =
+{
   0x05, /* socks5 */
   0x00, /* no auth */
 };
 
-unsigned const char kSocks5ConnectRequest[] = {
+unsigned const char kSocks5ConnectRequest[] =
+{
   0x05, /* socks5 */
   0x01, /* tcp stream */
   0x00, /* reserved 0x00 */
@@ -160,7 +174,8 @@
   TEST_PORT & 0xff
 };
 
-unsigned const char kSocks5ConnectReply[] = {
+unsigned const char kSocks5ConnectReply[] =
+{
   0x05, /* socks5 */
   0x00, /* success */
   0x00, /* reserved 0x00 */
@@ -171,41 +186,43 @@
   TEST_PORT & 0xff
 };
 
-TEST_F(test_bio, socks5_success)
+TEST_F (test_bio, socks5_success)
 {
   unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
-  BIO *proxy = proxy_bio(self->test, "socks5");
-  put_bytes(self->test, kSocks5AuthReply, sizeof(kSocks5AuthReply));
-  put_bytes(self->test, kSocks5ConnectReply, sizeof(kSocks5ConnectReply));
-  EXPECT_EQ(4, BIO_write(proxy, kTestInput, sizeof(kTestInput)));
-  EXPECT_EQ(0, need_out_bytes(self->test, kSocks5AuthRequest,
-                              sizeof(kSocks5AuthRequest)));
-  EXPECT_EQ(0, need_out_bytes(self->test, kSocks5ConnectRequest,
-                              sizeof(kSocks5ConnectRequest)));
-  EXPECT_EQ(0, need_out_bytes(self->test, kTestInput,
-                              sizeof(kTestInput)));
-  EXPECT_EQ(0, BIO_test_output_left(self->test));
+  BIO *proxy = proxy_bio (self->test, "socks5");
+  put_bytes (self->test, kSocks5AuthReply, sizeof (kSocks5AuthReply));
+  put_bytes (self->test, kSocks5ConnectReply, sizeof (kSocks5ConnectReply));
+  EXPECT_EQ (4, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
+  EXPECT_EQ (0, need_out_bytes (self->test, kSocks5AuthRequest,
+                                sizeof (kSocks5AuthRequest)));
+  EXPECT_EQ (0, need_out_bytes (self->test, kSocks5ConnectRequest,
+                                sizeof (kSocks5ConnectRequest)));
+  EXPECT_EQ (0, need_out_bytes (self->test, kTestInput,
+                                sizeof (kTestInput)));
+  EXPECT_EQ (0, BIO_test_output_left (self->test));
 }
 
-TEST_F(test_bio, socks5_auth_fail)
+TEST_F (test_bio, socks5_auth_fail)
 {
   unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
-  unsigned const char kAuthFail[] = {
+  unsigned const char kAuthFail[] =
+  {
     0x05,
     0xff,
   };
-  BIO *proxy = proxy_bio(self->test, "socks5");
-  put_bytes(self->test, kAuthFail, sizeof(kAuthFail));
-  EXPECT_EQ(0, BIO_write(proxy, kTestInput, sizeof(kTestInput)));
-  EXPECT_EQ(0, need_out_bytes(self->test, kSocks5AuthRequest,
-                              sizeof(kSocks5AuthRequest)));
-  EXPECT_EQ(0, BIO_test_output_left(self->test));
+  BIO *proxy = proxy_bio (self->test, "socks5");
+  put_bytes (self->test, kAuthFail, sizeof (kAuthFail));
+  EXPECT_EQ (0, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
+  EXPECT_EQ (0, need_out_bytes (self->test, kSocks5AuthRequest,
+                                sizeof (kSocks5AuthRequest)));
+  EXPECT_EQ (0, BIO_test_output_left (self->test));
 }
 
-TEST_F(test_bio, socks5_connect_fail)
+TEST_F (test_bio, socks5_connect_fail)
 {
   unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
-  unsigned const char kConnectFail[] = {
+  unsigned const char kConnectFail[] =
+  {
     0x05,
     0x01,
     0x00,
@@ -215,59 +232,59 @@
     (TEST_PORT & 0xff00) >> 8,
     TEST_PORT & 0xff
   };
-  BIO *proxy = proxy_bio(self->test, "socks5");
-  put_bytes(self->test, kSocks5AuthReply, sizeof(kSocks5AuthReply));
-  put_bytes(self->test, kConnectFail, sizeof(kConnectFail));
-  EXPECT_EQ(0, BIO_write(proxy, kTestInput, sizeof(kTestInput)));
-  EXPECT_EQ(0, need_out_bytes(self->test, kSocks5AuthRequest,
-                              sizeof(kSocks5AuthRequest)));
-  EXPECT_EQ(0, need_out_bytes(self->test, kSocks5ConnectRequest,
-                              sizeof(kSocks5ConnectRequest)));
-  EXPECT_EQ(0, BIO_test_output_left(self->test));
+  BIO *proxy = proxy_bio (self->test, "socks5");
+  put_bytes (self->test, kSocks5AuthReply, sizeof (kSocks5AuthReply));
+  put_bytes (self->test, kConnectFail, sizeof (kConnectFail));
+  EXPECT_EQ (0, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
+  EXPECT_EQ (0, need_out_bytes (self->test, kSocks5AuthRequest,
+                                sizeof (kSocks5AuthRequest)));
+  EXPECT_EQ (0, need_out_bytes (self->test, kSocks5ConnectRequest,
+                                sizeof (kSocks5ConnectRequest)));
+  EXPECT_EQ (0, BIO_test_output_left (self->test));
 }
 
-TEST_F(test_bio, http_success)
+TEST_F (test_bio, http_success)
 {
   unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
-  BIO *proxy = proxy_bio(self->test, "http");
+  BIO *proxy = proxy_bio (self->test, "http");
   char kConnectRequest[1024];
   char kConnectResponse[] = "HTTP/1.0 200 OK\r\n"
-                                     "Uninteresting-Header: foobar\r\n"
-                                     "Another-Header: lol\r\n"
-                                     "\r\n";
-  snprintf(kConnectRequest, sizeof(kConnectRequest),
-           "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n\r\n",
-           kTestHost, TEST_PORT, kTestHost, TEST_PORT);
-  put_bytes(self->test, (unsigned char *)kConnectResponse,
-            strlen(kConnectResponse));
-  EXPECT_EQ(4, BIO_write(proxy, kTestInput, sizeof(kTestInput)));
-  EXPECT_EQ(0, need_out_bytes(self->test,
-                              (unsigned char *)kConnectRequest,
-                              strlen(kConnectRequest)));
-  EXPECT_EQ(0, need_out_bytes(self->test, kTestInput,
-                              sizeof(kTestInput)));
-  EXPECT_EQ(0, BIO_test_output_left(self->test));
+                            "Uninteresting-Header: foobar\r\n"
+                            "Another-Header: lol\r\n"
+                            "\r\n";
+  snprintf (kConnectRequest, sizeof (kConnectRequest),
+            "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n\r\n",
+            kTestHost, TEST_PORT, kTestHost, TEST_PORT);
+  put_bytes (self->test, (unsigned char *) kConnectResponse,
+             strlen (kConnectResponse));
+  EXPECT_EQ (4, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
+  EXPECT_EQ (0, need_out_bytes (self->test,
+                                (unsigned char *) kConnectRequest,
+                                strlen (kConnectRequest)));
+  EXPECT_EQ (0, need_out_bytes (self->test, kTestInput,
+                                sizeof (kTestInput)));
+  EXPECT_EQ (0, BIO_test_output_left (self->test));
 }
 
-TEST_F(test_bio, http_error)
+TEST_F (test_bio, http_error)
 {
   unsigned const char kTestInput[] = { 0xde, 0xad, 0xbe, 0xef };
-  BIO *proxy = proxy_bio(self->test, "http");
+  BIO *proxy = proxy_bio (self->test, "http");
   char kConnectRequest[1024];
   char kConnectResponse[] = "HTTP/1.0 403 NO U\r\n"
                             "Uninteresting-Header: foobar\r\n"
                             "Another-Header: lol\r\n"
                             "\r\n";
-  snprintf(kConnectRequest, sizeof(kConnectRequest),
-           "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n\r\n",
-           kTestHost, TEST_PORT, kTestHost, TEST_PORT);
-  put_bytes(self->test, (unsigned char *)kConnectResponse,
-            strlen(kConnectResponse));
-  EXPECT_EQ(0, BIO_write(proxy, kTestInput, sizeof(kTestInput)));
-  EXPECT_EQ(0, need_out_bytes(self->test,
-                              (unsigned char *)kConnectRequest,
-                              strlen(kConnectRequest)));
-  EXPECT_EQ(0, BIO_test_output_left(self->test));
+  snprintf (kConnectRequest, sizeof (kConnectRequest),
+            "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n\r\n",
+            kTestHost, TEST_PORT, kTestHost, TEST_PORT);
+  put_bytes (self->test, (unsigned char *) kConnectResponse,
+             strlen (kConnectResponse));
+  EXPECT_EQ (0, BIO_write (proxy, kTestInput, sizeof (kTestInput)));
+  EXPECT_EQ (0, need_out_bytes (self->test,
+                                (unsigned char *) kConnectRequest,
+                                strlen (kConnectRequest)));
+  EXPECT_EQ (0, BIO_test_output_left (self->test));
 }
 
 TEST_HARNESS_MAIN
diff --git a/src/proxy-bio.c b/src/proxy-bio.c
index fa72e8f..006e9b4 100644
--- a/src/proxy-bio.c
+++ b/src/proxy-bio.c
@@ -30,20 +30,21 @@
 
 #include "src/proxy-bio.h"
 
-struct proxy_ctx {
+struct proxy_ctx
+{
   char *host;
   uint16_t port;
   int connected;
-  int (*connect)(BIO *b);
+  int (*connect) (BIO *b);
 };
 
-int socks4a_connect(BIO *b);
-int socks5_connect(BIO *b);
-int http_connect(BIO *b);
+int socks4a_connect (BIO *b);
+int socks5_connect (BIO *b);
+int http_connect (BIO *b);
 
-int proxy_new(BIO *b)
+int proxy_new (BIO *b)
 {
-  struct proxy_ctx *ctx = malloc(sizeof *ctx);
+  struct proxy_ctx *ctx = malloc (sizeof *ctx);
   if (!ctx)
     return 0;
   ctx->connected = 0;
@@ -56,30 +57,28 @@
   return 1;
 }
 
-int proxy_free(BIO *b)
+int proxy_free (BIO *b)
 {
   struct proxy_ctx *c;
   if (!b || !b->ptr)
     return 1;
   c = b->ptr;
   if (c->host)
-    free(c->host);
+    free (c->host);
   c->host = NULL;
   b->ptr = NULL;
-  free(c);
+  free (c);
   return 1;
 }
 
-int socks4a_connect(BIO *b)
+int socks4a_connect (BIO *b)
 {
   struct proxy_ctx *ctx = b->ptr;
   int r;
   unsigned char buf[NI_MAXHOST + 16];
-  uint16_t port_n = htons(ctx->port);
+  uint16_t port_n = htons (ctx->port);
   size_t sz = 0;
-
-  verb("V: proxy4: connecting %s:%d\n", ctx->host, ctx->port);
-
+  verb ("V: proxy4: connecting %s:%d\n", ctx->host, ctx->port);
   /*
    * Packet layout:
    * 1b: Version (must be 0x04)
@@ -92,52 +91,44 @@
   buf[0] = 0x04;
   buf[1] = 0x01;
   sz += 2;
-
-  memcpy(buf + 2, &port_n, sizeof(port_n));
-  sz += sizeof(port_n);
-
+  memcpy (buf + 2, &port_n, sizeof (port_n));
+  sz += sizeof (port_n);
   buf[4] = 0x00;
   buf[5] = 0x00;
   buf[6] = 0x00;
   buf[7] = 0x01;
   sz += 4;
-
   buf[8] = 0x00;
   sz += 1;
-
-  memcpy(buf + sz, ctx->host, strlen(ctx->host) + 1);
-  sz += strlen(ctx->host) + 1;
-
-  r = BIO_write(b->next_bio, buf, sz);
+  memcpy (buf + sz, ctx->host, strlen (ctx->host) + 1);
+  sz += strlen (ctx->host) + 1;
+  r = BIO_write (b->next_bio, buf, sz);
   if (r != sz)
     return 0;
-
   /* server reply: 1 + 1 + 2 + 4 */
-  r = BIO_read(b->next_bio, buf, 8);
+  r = BIO_read (b->next_bio, buf, 8);
   if (r != 8)
     return 0;
-  if (buf[1] == 0x5a) {
-    verb("V: proxy4: connected\n");
-    ctx->connected = 1;
-    return 1;
-  }
+  if (buf[1] == 0x5a)
+    {
+      verb ("V: proxy4: connected\n");
+      ctx->connected = 1;
+      return 1;
+    }
   return 0;
 }
 
-int socks5_connect(BIO *b)
+int socks5_connect (BIO *b)
 {
   unsigned char buf[NI_MAXHOST + 16];
   int r;
   struct proxy_ctx *ctx = b->ptr;
-  uint16_t port_n = htons(ctx->port);
+  uint16_t port_n = htons (ctx->port);
   size_t sz = 0;
-
   /* the length for SOCKS addresses is only one byte. */
-  if (strnlen(ctx->host, UINT8_MAX + 1) == UINT8_MAX + 1)
+  if (strnlen (ctx->host, UINT8_MAX + 1) == UINT8_MAX + 1)
     return 0;
-
-  verb("V: proxy5: connecting %s:%d\n", ctx->host, ctx->port);
-
+  verb ("V: proxy5: connecting %s:%d\n", ctx->host, ctx->port);
   /*
    * Hello packet layout:
    * 1b: Version
@@ -150,20 +141,17 @@
   buf[0] = 0x05;
   buf[1] = 0x01;
   buf[2] = 0x00;
-
-  r = BIO_write(b->next_bio, buf, 3);
+  r = BIO_write (b->next_bio, buf, 3);
   if (r != 3)
     return 0;
-
-  r = BIO_read(b->next_bio, buf, 2);
+  r = BIO_read (b->next_bio, buf, 2);
   if (r != 2)
     return 0;
-
-  if (buf[0] != 0x05 || buf[1] != 0x00) {
-    verb("V: proxy5: auth error %02x %02x\n", buf[0], buf[1]);
-    return 0;
-  }
-
+  if (buf[0] != 0x05 || buf[1] != 0x00)
+    {
+      verb ("V: proxy5: auth error %02x %02x\n", buf[0], buf[1]);
+      return 0;
+    }
   /*
    * Connect packet layout:
    * 1b: version
@@ -177,17 +165,15 @@
   buf[1] = 0x01;
   buf[2] = 0x00;
   buf[3] = 0x03;
-  buf[4] = strlen(ctx->host);
+  buf[4] = strlen (ctx->host);
   sz += 5;
-  memcpy(buf + 5, ctx->host, strlen(ctx->host));
-  sz += strlen(ctx->host);
-  memcpy(buf + sz, &port_n, sizeof(port_n));
-  sz += sizeof(port_n);
-
-  r = BIO_write(b->next_bio, buf, sz);
+  memcpy (buf + 5, ctx->host, strlen (ctx->host));
+  sz += strlen (ctx->host);
+  memcpy (buf + sz, &port_n, sizeof (port_n));
+  sz += sizeof (port_n);
+  r = BIO_write (b->next_bio, buf, sz);
   if (r != sz)
     return 0;
-
   /*
    * Server's response:
    * 1b: version
@@ -197,187 +183,183 @@
    * nb: addr len (1b) + addr bytes, no null termination
    * 2b: port, network byte order
    */
-
   /* grab up through the addr type */
-  r = BIO_read(b->next_bio, buf, 4);
+  r = BIO_read (b->next_bio, buf, 4);
   if (r != 4)
     return 0;
-
-  if (buf[0] != 0x05 || buf[1] != 0x00) {
-    verb("V: proxy5: connect error %02x %02x\n", buf[0], buf[1]);
-    return 0;
-  }
-
-  if (buf[3] == 0x03) {
-    unsigned int len;
-    r = BIO_read(b->next_bio, buf + 4, 1);
-    if (r != 1)
+  if (buf[0] != 0x05 || buf[1] != 0x00)
+    {
+      verb ("V: proxy5: connect error %02x %02x\n", buf[0], buf[1]);
       return 0;
-    /* host (buf[4] bytes) + port (2 bytes) */
-    len = buf[4] + 2;
-    while (len) {
-      r = BIO_read(b->next_bio, buf + 5, min(len, sizeof(buf)));
-      if (r <= 0)
-        return 0;
-      len -= min(len, r);
     }
-  } else if (buf[3] == 0x01) {
-    /* 4 bytes ipv4 addr, 2 bytes port */
-    r = BIO_read(b->next_bio, buf + 4, 6);
-    if (r != 6)
-      return 0;
-  }
-
-  verb("V: proxy5: connected\n");
+  if (buf[3] == 0x03)
+    {
+      unsigned int len;
+      r = BIO_read (b->next_bio, buf + 4, 1);
+      if (r != 1)
+        return 0;
+      /* host (buf[4] bytes) + port (2 bytes) */
+      len = buf[4] + 2;
+      while (len)
+        {
+          r = BIO_read (b->next_bio, buf + 5, min (len, sizeof (buf)));
+          if (r <= 0)
+            return 0;
+          len -= min (len, r);
+        }
+    }
+  else if (buf[3] == 0x01)
+    {
+      /* 4 bytes ipv4 addr, 2 bytes port */
+      r = BIO_read (b->next_bio, buf + 4, 6);
+      if (r != 6)
+        return 0;
+    }
+  verb ("V: proxy5: connected\n");
   ctx->connected = 1;
   return 1;
 }
 
 /* SSL socket BIOs don't support BIO_gets, so... */
-int sock_gets(BIO *b, char *buf, size_t sz)
+int sock_gets (BIO *b, char *buf, size_t sz)
 {
   char c;
-  while (BIO_read(b, &c, 1) > 0 && sz > 1) {
-    *buf++ = c;
-    sz--;
-    if (c == '\n') {
-      *buf = '\0';
-      return 0;
+  while (BIO_read (b, &c, 1) > 0 && sz > 1)
+    {
+      *buf++ = c;
+      sz--;
+      if (c == '\n')
+        {
+          *buf = '\0';
+          return 0;
+        }
     }
-  }
   return 1;
 }
 
-int http_connect(BIO *b)
+int http_connect (BIO *b)
 {
   int r;
   struct proxy_ctx *ctx = b->ptr;
   char buf[4096];
   int retcode;
-
-  snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.1\r\n",
-           ctx->host, ctx->port);
-  r = BIO_write(b->next_bio, buf, strlen(buf));
-  if (r != strlen(buf))
+  snprintf (buf, sizeof (buf), "CONNECT %s:%d HTTP/1.1\r\n",
+            ctx->host, ctx->port);
+  r = BIO_write (b->next_bio, buf, strlen (buf));
+  if (r != strlen (buf))
     return 0;
   /* required by RFC 2616 14.23 */
-  snprintf(buf, sizeof(buf), "Host: %s:%d\r\n", ctx->host, ctx->port);
-  r = BIO_write(b->next_bio, buf, strlen(buf));
-  if (r != strlen(buf))
+  snprintf (buf, sizeof (buf), "Host: %s:%d\r\n", ctx->host, ctx->port);
+  r = BIO_write (b->next_bio, buf, strlen (buf));
+  if (r != strlen (buf))
     return 0;
-  strcpy(buf, "\r\n");
-  r = BIO_write(b->next_bio, buf, strlen(buf));
-  if (r != strlen(buf))
+  strcpy (buf, "\r\n");
+  r = BIO_write (b->next_bio, buf, strlen (buf));
+  if (r != strlen (buf))
     return 0;
-
-  r = sock_gets(b->next_bio, buf, sizeof(buf));
+  r = sock_gets (b->next_bio, buf, sizeof (buf));
   if (r)
     return 0;
   /* use %*s to ignore the version */
-  if (sscanf(buf, "HTTP/%*s %d", &retcode) != 1)
+  if (sscanf (buf, "HTTP/%*s %d", &retcode) != 1)
     return 0;
-
   if (retcode < 200 || retcode > 299)
     return 0;
-  while (!(r = sock_gets(b->next_bio, buf, sizeof(buf)))) {
-    if (!strcmp(buf, "\r\n")) {
-      /* Done with the header */
-      ctx->connected = 1;
-      return 1;
+  while (! (r = sock_gets (b->next_bio, buf, sizeof (buf))))
+    {
+      if (!strcmp (buf, "\r\n"))
+        {
+          /* Done with the header */
+          ctx->connected = 1;
+          return 1;
+        }
     }
-  }
   return 0;
 }
 
-int proxy_write(BIO *b, const char *buf, int sz)
+int proxy_write (BIO *b, const char *buf, int sz)
 {
   int r;
   struct proxy_ctx *ctx = b->ptr;
-
-  assert(buf);
-
+  assert (buf);
   if (sz <= 0)
     return 0;
-
   if (!b->next_bio)
     return 0;
-
-  if (!ctx->connected) {
-    assert(ctx->connect);
-    if (!ctx->connect(b))
-      return 0;
-  }
-
-  r = BIO_write(b->next_bio, buf, sz);
-  BIO_clear_retry_flags(b);
-  BIO_copy_next_retry(b);
+  if (!ctx->connected)
+    {
+      assert (ctx->connect);
+      if (!ctx->connect (b))
+        return 0;
+    }
+  r = BIO_write (b->next_bio, buf, sz);
+  BIO_clear_retry_flags (b);
+  BIO_copy_next_retry (b);
   return r;
 }
 
-int proxy_read(BIO *b, char *buf, int sz)
+int proxy_read (BIO *b, char *buf, int sz)
 {
   int r;
   struct proxy_ctx *ctx = b->ptr;
-
-  assert(buf);
-
+  assert (buf);
   if (!b->next_bio)
     return 0;
-
-  if (!ctx->connected) {
-    assert(ctx->connect);
-    if (!ctx->connect(b))
-      return 0;
-  }
-
-  r = BIO_read(b->next_bio, buf, sz);
-  BIO_clear_retry_flags(b);
-  BIO_copy_next_retry(b);
+  if (!ctx->connected)
+    {
+      assert (ctx->connect);
+      if (!ctx->connect (b))
+        return 0;
+    }
+  r = BIO_read (b->next_bio, buf, sz);
+  BIO_clear_retry_flags (b);
+  BIO_copy_next_retry (b);
   return r;
 }
 
-long proxy_ctrl(BIO *b, int cmd, long num, void *ptr)
+long proxy_ctrl (BIO *b, int cmd, long num, void *ptr)
 {
   long ret;
   struct proxy_ctx *ctx;
   if (!b->next_bio)
     return 0;
   ctx = b->ptr;
-  assert(ctx);
-
-  switch (cmd) {
-  case BIO_C_DO_STATE_MACHINE:
-    BIO_clear_retry_flags(b);
-    ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
-    BIO_copy_next_retry(b);
-    break;
-  case BIO_CTRL_DUP:
-    ret = 0;
-    break;
-  default:
-    ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
-  }
+  assert (ctx);
+  switch (cmd)
+    {
+    case BIO_C_DO_STATE_MACHINE:
+      BIO_clear_retry_flags (b);
+      ret = BIO_ctrl (b->next_bio, cmd, num, ptr);
+      BIO_copy_next_retry (b);
+      break;
+    case BIO_CTRL_DUP:
+      ret = 0;
+      break;
+    default:
+      ret = BIO_ctrl (b->next_bio, cmd, num, ptr);
+    }
   return ret;
 }
 
-int proxy_gets(BIO *b, char *buf, int size)
+int proxy_gets (BIO *b, char *buf, int size)
 {
-  return BIO_gets(b->next_bio, buf, size);
+  return BIO_gets (b->next_bio, buf, size);
 }
 
-int proxy_puts(BIO *b, const char *str)
+int proxy_puts (BIO *b, const char *str)
 {
-  return BIO_puts(b->next_bio, str);
+  return BIO_puts (b->next_bio, str);
 }
 
-long proxy_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
+long proxy_callback_ctrl (BIO *b, int cmd, bio_info_cb *fp)
 {
   if (!b->next_bio)
     return 0;
-  return BIO_callback_ctrl(b->next_bio, cmd, fp);
+  return BIO_callback_ctrl (b->next_bio, cmd, fp);
 }
 
-BIO_METHOD proxy_methods = {
+BIO_METHOD proxy_methods =
+{
   BIO_TYPE_MEM,
   "proxy",
   proxy_write,
@@ -399,33 +381,33 @@
 
 BIO API *BIO_new_proxy()
 {
-  return BIO_new(BIO_f_proxy());
+  return BIO_new (BIO_f_proxy());
 }
 
-int API BIO_proxy_set_type(BIO *b, const char *type)
+int API BIO_proxy_set_type (BIO *b, const char *type)
 {
   struct proxy_ctx *ctx = b->ptr;
-  if (!strcmp(type, "socks5"))
+  if (!strcmp (type, "socks5"))
     ctx->connect = socks5_connect;
-  else if (!strcmp(type, "socks4a"))
+  else if (!strcmp (type, "socks4a"))
     ctx->connect = socks4a_connect;
-  else if (!strcmp(type, "http"))
+  else if (!strcmp (type, "http"))
     ctx->connect = http_connect;
   else
     return 1;
   return 0;
 }
 
-int API BIO_proxy_set_host(BIO *b, const char *host)
+int API BIO_proxy_set_host (BIO *b, const char *host)
 {
   struct proxy_ctx *ctx = b->ptr;
-  if (strnlen(host, NI_MAXHOST) == NI_MAXHOST)
+  if (strnlen (host, NI_MAXHOST) == NI_MAXHOST)
     return 1;
-  ctx->host = strdup(host);
+  ctx->host = strdup (host);
   return 0;
 }
 
-void API BIO_proxy_set_port(BIO *b, uint16_t port)
+void API BIO_proxy_set_port (BIO *b, uint16_t port)
 {
   struct proxy_ctx *ctx = b->ptr;
   ctx->port = port;
diff --git a/src/proxy-bio.h b/src/proxy-bio.h
index d8f8458..099daef 100644
--- a/src/proxy-bio.h
+++ b/src/proxy-bio.h
@@ -18,8 +18,8 @@
 BIO *BIO_new_proxy();
 
 /* These do not take ownership of their string arguments. */
-int BIO_proxy_set_type(BIO *b, const char *type);
-int BIO_proxy_set_host(BIO *b, const char *host);
-void BIO_proxy_set_port(BIO *b, uint16_t port);
+int BIO_proxy_set_type (BIO *b, const char *type);
+int BIO_proxy_set_host (BIO *b, const char *host);
+void BIO_proxy_set_port (BIO *b, uint16_t port);
 
 #endif /* !PROXY_BIO_H */
diff --git a/src/routeup.c b/src/routeup.c
index 4bc212e..3edc63a 100644
--- a/src/routeup.c
+++ b/src/routeup.c
@@ -36,11 +36,9 @@
 routeup_setup (struct routeup *rtc)
 {
   struct sockaddr_nl sa;
-
   memset (&sa, 0, sizeof (sa));
   sa.nl_family = AF_NETLINK;
   sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE;
-
   rtc->netlinkfd = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
   if (rtc->netlinkfd < 0)
     {
@@ -63,58 +61,71 @@
 }
 
 /*
- * Handle a single netlink message. Block until we get a route status
- * change message. Returns 0 if there was a route status change, 1 if there was
- * a timeout, and -1 if there was a read error.
+ * Handle a single netlink message.
+ * Returns 0 if there was a route status change, 1 if there
+ * were no valid nlmsghdrs, and -1 if there was a read error.
+ */
+int API
+routeup_process (struct routeup *rtc)
+{
+  char buf[4096];
+  ssize_t sz;
+  struct nlmsghdr *nh;
+  if ( (sz = read (rtc->netlinkfd, buf, sizeof (buf))) < 0)
+    return -1;
+  for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, sz);
+       nh = NLMSG_NEXT (nh, sz))
+    {
+      /*
+       * Unpack the netlink message into a bunch of... well...
+       * netlink messages. The terminology is overloaded. Walk
+       * through the message until we find a header of type
+       * NLMSG_DONE.
+       */
+      if (nh->nlmsg_type == NLMSG_DONE)
+        break;
+      if (nh->nlmsg_type != RTM_NEWROUTE)
+        continue;
+      /*
+       * Clear out the socket so we don't keep old messages
+       * queued up and eventually overflow the receive buffer.
+       */
+      while (read (rtc->netlinkfd, buf, sizeof (buf)) > 0)
+        /* loop through receive queue */;
+      if (errno != EAGAIN) return -1;
+      return 0;
+    }
+  return 1;
+}
+
+
+/*
+ * Blocks until we get a route status change message then calls
+ * route_process().  Returns 0 if there was a route state change, 1 if there
+ * was a timeout, and -1 if there was a read error.
  */
 int API
 routeup_once (struct routeup *rtc, unsigned int timeout)
 {
-  char buf[4096];
-  ssize_t sz;
+  int ret;
   struct timeval remaining;
   struct timeval *rp = timeout ? &remaining : NULL;
   fd_set fds;
-
   remaining.tv_sec = timeout;
   remaining.tv_usec = 0;
-
   FD_ZERO (&fds);
   FD_SET (rtc->netlinkfd, &fds);
-
   while (select (rtc->netlinkfd + 1, &fds, NULL, NULL, rp) >= 0)
     {
       FD_ZERO (&fds);
       FD_SET (rtc->netlinkfd, &fds);
       if (timeout && !remaining.tv_sec && !remaining.tv_usec)
-  return 1;
-      if ((sz = read (rtc->netlinkfd, buf, sizeof (buf))) < 0)
-  return -1;
-      struct nlmsghdr *nh;
-      for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, sz);
-     nh = NLMSG_NEXT (nh, sz))
-  {
-    /*
-     * Unpack the netlink message into a bunch of... well...
-     * netlink messages. The terminology is overloaded. Walk
-     * through the message until we find a header of type
-     * NLMSG_DONE.
-     */
-    if (nh->nlmsg_type == NLMSG_DONE)
-      break;
-    if (nh->nlmsg_type != RTM_NEWROUTE)
-      continue;
-    /*
-     * Clear out the socket so we don't keep old messages
-     * queued up and eventually overflow the receive buffer.
-     */
-    while (read (rtc->netlinkfd, buf, sizeof(buf)) > 0)
-      /* loop through receive queue */;
-    if (errno != EAGAIN) return -1;
-    return 0;
-  }
+        return 1;
+      ret = routeup_process (rtc);
+      if (ret == 1)
+        continue;
+      return ret;
     }
-
   return -1;
 }
 
diff --git a/src/routeup.h b/src/routeup.h
index 8f5bb50..3dc9595 100644
--- a/src/routeup.h
+++ b/src/routeup.h
@@ -13,12 +13,14 @@
 #ifndef ROUTEUP_H
 #define ROUTEUP_H
 
-struct routeup {
+struct routeup
+{
   int netlinkfd;  /* AF_NETLINK event socket */
 };
 
-int routeup_setup(struct routeup *ifc);
-int routeup_once(struct routeup *ifc, unsigned int timeout);
-void routeup_teardown(struct routeup *ifc);
+int routeup_setup (struct routeup *ifc);
+int routeup_once (struct routeup *ifc, unsigned int timeout);
+int routeup_process (struct routeup *rtc);
+void routeup_teardown (struct routeup *ifc);
 
 #endif /* !ROUTEUP_H */
diff --git a/src/seccomp-compat.h b/src/seccomp-compat.h
new file mode 100644
index 0000000..9f1da87
--- /dev/null
+++ b/src/seccomp-compat.h
@@ -0,0 +1,32 @@
+/*
+ * seccomp-compat.h - seccomp defines for bad headers
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef SECCOMP_COMPAT_H
+#define SECCOMP_COMPAT_H
+
+#include <stdint.h>
+
+#ifndef PR_SET_NO_NEW_PRIVS
+#  define PR_SET_NO_NEW_PRIVS 38
+#endif
+
+#ifndef SECCOMP_MODE_FILTER
+#define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */
+#define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */
+#define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */
+#define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */
+#define SECCOMP_RET_ERRNO 0x00050000U /* returns an errno */
+
+struct seccomp_data
+{
+  int nr;
+  uint32_t arch;
+  uint64_t instruction_pointer;
+  uint64_t args[6];
+};
+#endif  /* !SECCOMP_MODE_FILTER */
+
+#endif
diff --git a/src/seccomp.c b/src/seccomp.c
new file mode 100644
index 0000000..bc25e4c
--- /dev/null
+++ b/src/seccomp.c
@@ -0,0 +1,103 @@
+/*
+ * seccomp.c - seccomp utility functions
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <asm/unistd.h>
+#include <elf.h>
+#include <errno.h>
+#include <sys/prctl.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include <linux/audit.h>
+#include <linux/filter.h>
+
+#include "src/seccomp.h"
+
+/* Linux seccomp_filter sandbox */
+#define SECCOMP_FILTER_FAIL SECCOMP_RET_KILL
+
+/* Use a signal handler to emit violations when debugging */
+#ifdef SECCOMP_FILTER_DEBUG
+# undef SECCOMP_FILTER_FAIL
+# define SECCOMP_FILTER_FAIL SECCOMP_RET_TRAP
+#endif /* SANDBOX_SECCOMP_FILTER_DEBUG */
+
+/* Simple helpers to avoid manual errors (but larger BPF programs). */
+#define SC_DENY(_nr, _errno) \
+  BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 1), \
+  BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO|(_errno))
+#define SC_ALLOW(_nr) \
+  BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 1), \
+  BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
+
+#if defined(__i386__)
+#  define SECCOMP_AUDIT_ARCH AUDIT_ARCH_I386
+#elif defined(__x86_64__)
+#  define SECCOMP_AUDIT_ARCH AUDIT_ARCH_X86_64
+#elif defined(__arm__)
+# ifndef EM_ARM
+#   define EM_ARM 40
+# endif
+#  define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARM
+#else
+#  error "Platform does not support seccomp filter yet"
+#endif
+
+/* Returns 0 if the the sandbox is enabled using
+ * the time setter policy.
+ */
+int
+enable_setter_seccomp (void)
+{
+  static const struct sock_filter insns[] =
+  {
+    /* Ensure the syscall arch convention is as expected. */
+    BPF_STMT (BPF_LD+BPF_W+BPF_ABS,
+    offsetof (struct seccomp_data, arch)),
+    BPF_JUMP (BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_AUDIT_ARCH, 1, 0),
+    BPF_STMT (BPF_RET+BPF_K, SECCOMP_FILTER_FAIL),
+    /* Load the syscall number for checking. */
+    BPF_STMT (BPF_LD+BPF_W+BPF_ABS,
+    offsetof (struct seccomp_data, nr)),
+
+    SC_DENY (open, EINVAL),
+    SC_DENY (fcntl, EINVAL),
+    SC_DENY (fstat, EINVAL),
+#ifdef __NR_mmap
+    SC_DENY (mmap, EINVAL),
+#endif
+#ifdef __NR_mmap2
+    SC_DENY (mmap2, EINVAL),
+#endif
+
+    SC_ALLOW (lseek),
+    SC_ALLOW (close),
+    SC_ALLOW (munmap),
+
+    SC_ALLOW (settimeofday),
+    SC_ALLOW (read),
+    SC_ALLOW (write),
+    SC_ALLOW (pwritev),
+    SC_ALLOW (ioctl), /* TODO(wad) filter for fd and RTC_SET_TIME */
+    SC_ALLOW (restart_syscall),
+    SC_ALLOW (exit_group),
+    SC_ALLOW (exit),
+    BPF_STMT (BPF_RET+BPF_K, SECCOMP_FILTER_FAIL),
+  };
+  static const struct sock_fprog prog =
+  {
+    .len = (unsigned short) (sizeof (insns) /sizeof (insns[0])),
+    .filter = (struct sock_filter *) insns,
+  };
+  return (prctl (PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) ||
+          prctl (PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog));
+}
diff --git a/src/seccomp.h b/src/seccomp.h
new file mode 100644
index 0000000..5f4a5f3
--- /dev/null
+++ b/src/seccomp.h
@@ -0,0 +1,24 @@
+/*
+ * seccomp.h - seccomp functions
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef SECCOMP_H
+#define SECCOMP_H
+
+#include "config.h"
+
+#include "src/seccomp-compat.h"
+
+#ifdef HAVE_SECCOMP_FILTER
+int enable_setter_seccomp (void);
+#else  /* HAVE_SECCOMP_FILTER */
+static
+inline int enable_setter_seccomp (void)
+{
+  return 0;
+}
+#endif  /* !HAVE_SECCOMP_FILTER */
+
+#endif
diff --git a/src/test-bio.c b/src/test-bio.c
index bd2a333..43b717b 100644
--- a/src/test-bio.c
+++ b/src/test-bio.c
@@ -22,7 +22,8 @@
 
 static const unsigned int kMagic = 0x5f8d3f15;
 
-struct test_ctx {
+struct test_ctx
+{
   unsigned int magic;
   unsigned char *out;
   size_t outsz;
@@ -30,37 +31,37 @@
   size_t insz;
 };
 
-static struct test_ctx *bio_ctx(BIO *b)
+static struct test_ctx *bio_ctx (BIO *b)
 {
   struct test_ctx *ctx = b->ptr;
-  assert(ctx->magic == kMagic);
+  assert (ctx->magic == kMagic);
   return ctx;
 }
 
-static size_t buf_drain(unsigned char **buf, size_t *bufsz,
-                        unsigned char *out, size_t outsz)
+static size_t buf_drain (unsigned char **buf, size_t *bufsz,
+                         unsigned char *out, size_t outsz)
 {
   if (*bufsz < outsz)
     outsz = *bufsz;
-  memcpy(out, *buf, outsz);
+  memcpy (out, *buf, outsz);
   if (*bufsz > outsz)
-    memmove(*buf, *buf + outsz, *bufsz - outsz);
+    memmove (*buf, *buf + outsz, *bufsz - outsz);
   *bufsz -= outsz;
-  *buf = realloc(*buf, *bufsz);
+  *buf = realloc (*buf, *bufsz);
   return outsz;
 }
 
-static void buf_fill(unsigned char **buf, size_t *bufsz,
-                     const unsigned char *in, size_t insz)
+static void buf_fill (unsigned char **buf, size_t *bufsz,
+                      const unsigned char *in, size_t insz)
 {
-  *buf = realloc(*buf, *bufsz + insz);
-  memcpy(*buf + *bufsz, in, insz);
+  *buf = realloc (*buf, *bufsz + insz);
+  memcpy (*buf + *bufsz, in, insz);
   *bufsz += insz;
 }
 
-int test_new(BIO *b)
+int test_new (BIO *b)
 {
-  struct test_ctx *ctx = malloc(sizeof *ctx);
+  struct test_ctx *ctx = malloc (sizeof *ctx);
   if (!ctx)
     return 0;
   ctx->magic = kMagic;
@@ -74,49 +75,46 @@
   return 1;
 }
 
-int test_free(BIO *b)
+int test_free (BIO *b)
 {
   struct test_ctx *ctx;
   if (!b || !b->ptr)
     return 1;
-  ctx = bio_ctx(b);
-  free(ctx->in);
-  free(ctx->out);
+  ctx = bio_ctx (b);
+  free (ctx->in);
+  free (ctx->out);
   return 1;
 }
 
-int test_write(BIO *b, const char *buf, int sz)
+int test_write (BIO *b, const char *buf, int sz)
 {
-  struct test_ctx *ctx = bio_ctx(b);
-
+  struct test_ctx *ctx = bio_ctx (b);
   if (sz <= 0)
     return 0;
-
-  buf_fill(&ctx->out, &ctx->outsz, (unsigned char *)buf, sz);
+  buf_fill (&ctx->out, &ctx->outsz, (unsigned char *) buf, sz);
   return sz;
 }
 
-int test_read(BIO *b, char *buf, int sz)
+int test_read (BIO *b, char *buf, int sz)
 {
-  struct test_ctx *ctx = bio_ctx(b);
-
+  struct test_ctx *ctx = bio_ctx (b);
   if (sz <= 0)
     return 0;
-
-  return buf_drain(&ctx->in, &ctx->insz, (unsigned char *)buf, sz);
+  return buf_drain (&ctx->in, &ctx->insz, (unsigned char *) buf, sz);
 }
 
-long test_ctrl(BIO *b, int cmd, long num, void *ptr)
+long test_ctrl (BIO *b, int cmd, long num, void *ptr)
 {
   return 0;
 }
 
-long test_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
+long test_callback_ctrl (BIO *b, int cmd, bio_info_cb *fp)
 {
   return 0;
 }
 
-BIO_METHOD test_methods = {
+BIO_METHOD test_methods =
+{
   BIO_TYPE_SOCKET,
   "test",
   test_write,
@@ -136,22 +134,22 @@
 
 BIO API *BIO_new_test()
 {
-  return BIO_new(BIO_s_test());
+  return BIO_new (BIO_s_test());
 }
 
-size_t API BIO_test_output_left(BIO *b)
+size_t API BIO_test_output_left (BIO *b)
 {
-  return bio_ctx(b)->outsz;
+  return bio_ctx (b)->outsz;
 }
 
-size_t API BIO_test_get_output(BIO *b, unsigned char *buf, size_t bufsz)
+size_t API BIO_test_get_output (BIO *b, unsigned char *buf, size_t bufsz)
 {
-  struct test_ctx *c = bio_ctx(b);
-  return buf_drain(&c->out, &c->outsz, buf, bufsz);
+  struct test_ctx *c = bio_ctx (b);
+  return buf_drain (&c->out, &c->outsz, buf, bufsz);
 }
 
-void API BIO_test_add_input(BIO *b, const unsigned char *buf, size_t bufsz)
+void API BIO_test_add_input (BIO *b, const unsigned char *buf, size_t bufsz)
 {
-  struct test_ctx *c = bio_ctx(b);
-  return buf_fill(&c->in, &c->insz, buf, bufsz);
+  struct test_ctx *c = bio_ctx (b);
+  return buf_fill (&c->in, &c->insz, buf, bufsz);
 }
diff --git a/src/test-bio.h b/src/test-bio.h
index 0b7d752..dcf1721 100644
--- a/src/test-bio.h
+++ b/src/test-bio.h
@@ -13,8 +13,8 @@
 
 BIO *BIO_new_test();
 
-size_t BIO_test_output_left(BIO *b);
-size_t BIO_test_get_output(BIO *b, unsigned char *buf, size_t bufsz);
-void BIO_test_add_input(BIO *b, const unsigned char *buf, size_t bufsz);
+size_t BIO_test_output_left (BIO *b);
+size_t BIO_test_get_output (BIO *b, unsigned char *buf, size_t bufsz);
+void BIO_test_add_input (BIO *b, const unsigned char *buf, size_t bufsz);
 
 #endif /* !TEST_BIO_H */
diff --git a/src/test/check-host-1.c b/src/test/check-host-1.c
new file mode 100644
index 0000000..33f745a
--- /dev/null
+++ b/src/test/check-host-1.c
@@ -0,0 +1,27 @@
+/* test returns a "sane" time if the host, port, and proxy
+ * are passed in properly on the commandline.  The test
+ * is invoked by tlsdated instead of tlsdate.
+ * This expects host1, port1, proxy1.
+ *
+ * Paired with check-host-2.c, it allows for source rotation
+ * testing.
+ */
+#include "config.h"
+
+#include <string.h>
+#include <stdio.h>
+
+int main (int argc, char *argv[])
+{
+  unsigned int t = RECENT_COMPILE_DATE + 1;
+  if (argc < 7)
+    return 3;
+  if (!strcmp (argv[2], "host1")
+      && !strcmp (argv[4], "port1")
+      && !strcmp (argv[6], "proxy1"))
+    {
+      fwrite (&t, sizeof (t), 1, stdout);
+      return 0;
+    }
+  return 1;
+}
diff --git a/src/test/check-host-2.c b/src/test/check-host-2.c
new file mode 100644
index 0000000..869a865
--- /dev/null
+++ b/src/test/check-host-2.c
@@ -0,0 +1,26 @@
+/* test returns a "sane" time if the host, port, and proxy
+ * are passed in properly on the commandline.  The test
+ * is invoked by tlsdated instead of tlsdate.
+ * This expects host2, port2, proxy2.
+ *
+ * Paired with check-host-2.c, it allows for source rotation
+ * testing.
+ */
+#include "config.h"
+#include <string.h>
+#include <stdio.h>
+
+int main (int argc, char *argv[])
+{
+  unsigned int t = RECENT_COMPILE_DATE + 1;
+  if (argc < 7)
+    return 3;
+  if (!strcmp (argv[2], "host2")
+      && !strcmp (argv[4], "port2")
+      && !strcmp (argv[6], "proxy2"))
+    {
+      fwrite (&t, sizeof (t), 1, stdout);
+      return 0;
+    }
+  return 1;
+}
diff --git a/src/test/proxy-override.c b/src/test/proxy-override.c
index 3e2c372..39abdc6 100644
--- a/src/test/proxy-override.c
+++ b/src/test/proxy-override.c
@@ -1,14 +1,32 @@
-#include <string.h>
+/* This test is called in lieu of tlsdate by tlsdated
+ * and it returns a timestamp that matches the proxy
+ * ordering - global, dynamic, etc.
+ * For use, see tlsdated-unittests.c
+ */
+#include "config.h"
 
-int main(int argc, char *argv[])
+#include <string.h>
+#include <stdio.h>
+
+int main (int argc, char *argv[])
 {
+  /* Unsigned int to match what tlsdate -Vraw returns, not time_t */
+  /* TODO(wad) move tlsdated -Vraw to emitting time_t */
+  unsigned int t = RECENT_COMPILE_DATE + 1;
   int saw_good_proxy = 0;
-  while (argc--) {
-    if (!strcmp(argv[0], "socks5://good.proxy"))
-      saw_good_proxy = 1;
-    if (!strcmp(argv[0], "socks5://bad.proxy"))
-      return 2;
-    argv++;
-  }
-  return !saw_good_proxy;
+  while (argc--)
+    {
+      if (!strcmp (argv[0], "socks5://good.proxy"))
+        saw_good_proxy = 1;
+      if (!strcmp (argv[0], "socks5://bad.proxy"))
+        {
+          t = RECENT_COMPILE_DATE + 3;
+          break;
+        }
+      argv++;
+    }
+  if (saw_good_proxy)
+    t = RECENT_COMPILE_DATE + 2;
+  fwrite (&t, sizeof (t), 1, stdout);
+  return 0;
 }
diff --git a/src/test/rotate.c b/src/test/rotate.c
deleted file mode 100644
index 4d3aad4..0000000
--- a/src/test/rotate.c
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <string.h>
-
-int main(int argc, char *argv[])
-{
-  if (argc < 7)
-    return 3;
-  if (   !strcmp(argv[2], "host1")
-      && !strcmp(argv[4], "port1")
-      && !strcmp(argv[6], "proxy1"))
-    return 1;
-  if (   !strcmp(argv[2], "host2")
-      && !strcmp(argv[4], "port2")
-      && !strcmp(argv[6], "proxy2"))
-    return 2;
-  return 4;
-}
diff --git a/src/test/sleep-wrap.c b/src/test/sleep-wrap.c
index 7989ca7..d45d92f 100644
--- a/src/test/sleep-wrap.c
+++ b/src/test/sleep-wrap.c
@@ -1,10 +1,20 @@
+/* Test invoked by tlsdated instead of tlsdate to
+ * show allow arbitrary delays before returning a
+ * "sane" time. This makes for easy timeout testing.
+ */
+#include "config.h"
+
+#include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
-int main(int argc, char *argv[])
+int main (int argc, char *argv[])
 {
+  /* Unsigned int to match what tlsdate -Vraw returns, not time_t */
+  unsigned int t = RECENT_COMPILE_DATE + 1;
   if (argc < 2)
     return 1;
-  sleep(atoi(argv[1]));
+  sleep (atoi (argv[1]));
+  fwrite (&t, sizeof (t), 1, stdout);
   return 0;
 }
diff --git a/src/test_harness.h b/src/test_harness.h
index a9e5fa5..3fd118a 100644
--- a/src/test_harness.h
+++ b/src/test_harness.h
@@ -357,9 +357,10 @@
 } while (0); OPTIONAL_HANDLER(_assert)
 
 /* Contains all the information for test execution and status checking. */
-struct __test_metadata {
+struct __test_metadata
+{
   const char *name;
-  void (*fn)(struct __test_metadata *);
+  void (*fn) (struct __test_metadata *);
   int passed;
   int trigger; /* extra handler after the evaluation */
   struct __test_metadata *prev, *next;
@@ -370,70 +371,80 @@
 static unsigned int __test_count = 0;
 static unsigned int __fixture_count = 0;
 
-static inline void __register_test(struct __test_metadata *t) {
+static inline void __register_test (struct __test_metadata *t)
+{
   __test_count++;
   /* Circular linked list where only prev is circular. */
-  if (__test_list == NULL) {
-    __test_list = t;
-    t->next = NULL;
-    t->prev = t;
-    return;
-  }
+  if (__test_list == NULL)
+    {
+      __test_list = t;
+      t->next = NULL;
+      t->prev = t;
+      return;
+    }
   t->next = NULL;
   t->prev = __test_list->prev;
   t->prev->next = t;
   __test_list->prev = t;
 }
 
-static inline int __bail(int for_realz) {
+static inline int __bail (int for_realz)
+{
   if (for_realz)
     abort();
   return 0;
 }
 
-static int test_harness_run(int __attribute__((unused)) argc,
-                            char __attribute__((unused)) **argv) {
+static int test_harness_run (int __attribute__ ( (unused)) argc,
+                             char __attribute__ ( (unused)) **argv)
+{
   struct __test_metadata *t;
   int ret = 0;
   unsigned int count = 0;
-
   /* TODO(wad) add optional arguments similar to gtest. */
-  printf("[==========] Running %u tests from %u test cases.\n",
+  printf ("[==========] Running %u tests from %u test cases.\n",
           __test_count, __fixture_count + 1);
-  for (t = __test_list; t; t = t->next) {
-    pid_t child_pid;
-    int status;
-    count++;
-    t->passed = 1;
-    t->trigger = 0;
-    printf("[ RUN      ] %s\n", t->name);
-    child_pid = fork();
-    if (child_pid < 0) {
-      printf("ERROR SPAWNING TEST CHILD\n");
-      t->passed = 0;
-    } else if (child_pid == 0) {
-      t->fn(t);
-      _exit(t->passed);
-    } else {
-      /* TODO(wad) add timeout support. */
-      waitpid(child_pid, &status, 0);
-      if (WIFEXITED(status))
-        t->passed = WEXITSTATUS(status);
-      if (WIFSIGNALED(status)) {
-        t->passed = 0;
-        fprintf(TH_LOG_STREAM,
-                "%s: Test terminated unexpectedly by signal %d\n",
-               t->name,
-               WTERMSIG(status));
-      }
+  for (t = __test_list; t; t = t->next)
+    {
+      pid_t child_pid;
+      int status;
+      count++;
+      t->passed = 1;
+      t->trigger = 0;
+      printf ("[ RUN      ] %s\n", t->name);
+      child_pid = fork();
+      if (child_pid < 0)
+        {
+          printf ("ERROR SPAWNING TEST CHILD\n");
+          t->passed = 0;
+        }
+      else if (child_pid == 0)
+        {
+          t->fn (t);
+          _exit (t->passed);
+        }
+      else
+        {
+          /* TODO(wad) add timeout support. */
+          waitpid (child_pid, &status, 0);
+          if (WIFEXITED (status))
+            t->passed = WEXITSTATUS (status);
+          if (WIFSIGNALED (status))
+            {
+              t->passed = 0;
+              fprintf (TH_LOG_STREAM,
+                       "%s: Test terminated unexpectedly by signal %d\n",
+                       t->name,
+                       WTERMSIG (status));
+            }
+        }
+      printf ("[     %4s ] %s\n", (t->passed ? "OK" : "FAIL"), t->name);
+      if (!t->passed)
+        ret = 1;
     }
-    printf("[     %4s ] %s\n", (t->passed ? "OK" : "FAIL"), t->name);
-    if (!t->passed)
-      ret = 1;
-  }
   /* TODO(wad) organize by fixtures since ordering is not guaranteed now. */
-  printf("[==========] %u tests ran.\n", count);
-  printf("[  %s  ]\n", (ret ? "FAILED" : "PASSED"));
+  printf ("[==========] %u tests ran.\n", count);
+  printf ("[  %s  ]\n", (ret ? "FAILED" : "PASSED"));
   return ret;
 }
 
diff --git a/src/tlsdate-dbus-announce.c b/src/tlsdate-dbus-announce.c
deleted file mode 100644
index fc474fe..0000000
--- a/src/tlsdate-dbus-announce.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * tlsdate-dbus-announce.c - announce date change on dbus
- * Copyright (c) 2012 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "config.h"
-
-#ifdef HAVE_DBUS
-#include <dbus/dbus.h>
-#include <stdint.h>
-
-int main(void)
-{
-  DBusConnection *conn = NULL;
-  DBusMessage *msg = NULL;
-  DBusError error;
-  uint32_t ignored;
-
-  dbus_error_init(&error);
-  conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
-  if (!conn)
-    return 1;
-  if (dbus_bus_request_name(conn, "org.torproject.tlsdate", 0, &error) < 0)
-    return 1;
-  msg = dbus_message_new_signal("/org/torproject/tlsdate", "org.torproject.tlsdate", "TimeUpdated");
-  if (!msg)
-    return 1;
-  if (!dbus_connection_send(conn, msg, &ignored))
-    return 1;
-  dbus_connection_flush(conn);
-  dbus_message_unref(msg);
-  return 0;
-}
-#else
-int main(void)
-{
-  return 2;
-}
-#endif
diff --git a/src/tlsdate-helper.c b/src/tlsdate-helper.c
index 4cf0068..02dac7a 100644
--- a/src/tlsdate-helper.c
+++ b/src/tlsdate-helper.c
@@ -82,68 +82,64 @@
 #include "src/compat/clock.h"
 
 static void
-validate_proxy_scheme(const char *scheme)
+validate_proxy_scheme (const char *scheme)
 {
-  if (!strcmp(scheme, "http"))
+  if (!strcmp (scheme, "http"))
     return;
-  if (!strcmp(scheme, "socks4"))
+  if (!strcmp (scheme, "socks4"))
     return;
-  if (!strcmp(scheme, "socks5"))
+  if (!strcmp (scheme, "socks5"))
     return;
-  die("invalid proxy scheme\n");
+  die ("invalid proxy scheme\n");
 }
 
 static void
-validate_proxy_host(const char *host)
+validate_proxy_host (const char *host)
 {
   const char *kValid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                        "abcdefghijklmnopqrstuvwxyz"
                        "0123456789"
                        ".-";
-  if (strspn(host, kValid) != strlen(host))
-    die("invalid char in host\n");
+  if (strspn (host, kValid) != strlen (host))
+    die ("invalid char in host\n");
 }
 
 static void
-validate_proxy_port(const char *port)
+validate_proxy_port (const char *port)
 {
   while (*port)
-    if (!isdigit(*port++))
-      die("invalid char in port\n");
+    if (!isdigit (*port++))
+      die ("invalid char in port\n");
 }
 
 static void
-parse_proxy_uri(char *proxy, char **scheme, char **host, char **port)
+parse_proxy_uri (char *proxy, char **scheme, char **host, char **port)
 {
   /* Expecting a URI, so: <scheme> '://' <host> ':' <port> */
   *scheme = proxy;
-  proxy = strstr(proxy, "://");
+  proxy = strstr (proxy, "://");
   if (!proxy)
-    die("malformed proxy URI\n");
+    die ("malformed proxy URI\n");
   *proxy = '\0'; /* terminate scheme string */
-  proxy += strlen("://");
-
+  proxy += strlen ("://");
   *host = proxy;
-  proxy = strchr(proxy, ':');
+  proxy = strchr (proxy, ':');
   if (!proxy)
-    die("malformed proxy URI\n");
+    die ("malformed proxy URI\n");
   *proxy++ = '\0';
-
   *port = proxy;
-
-  validate_proxy_scheme(*scheme);
-  validate_proxy_host(*host);
-  validate_proxy_port(*port);
+  validate_proxy_scheme (*scheme);
+  validate_proxy_host (*host);
+  validate_proxy_port (*port);
 }
 
 static void
-setup_proxy(BIO *ssl)
+setup_proxy (BIO *ssl)
 {
   BIO *bio;
   char *scheme;
   char *proxy_host;
   char *proxy_port;
-
   if (!proxy)
     return;
   /*
@@ -153,28 +149,27 @@
    * target) and swap out the connect BIO's target host and port so it'll
    * connect to the proxy instead.
    */
-  parse_proxy_uri(proxy, &scheme, &proxy_host, &proxy_port);
+  parse_proxy_uri (proxy, &scheme, &proxy_host, &proxy_port);
   bio = BIO_new_proxy();
-  BIO_proxy_set_type(bio, scheme);
-  BIO_proxy_set_host(bio, host);
-  BIO_proxy_set_port(bio, atoi(port));
+  BIO_proxy_set_type (bio, scheme);
+  BIO_proxy_set_host (bio, host);
+  BIO_proxy_set_port (bio, atoi (port));
   host = proxy_host;
   port = proxy_port;
-  BIO_push(ssl, bio);
+  BIO_push (ssl, bio);
 }
 
 static BIO *
-make_ssl_bio(SSL_CTX *ctx)
+make_ssl_bio (SSL_CTX *ctx)
 {
   BIO *con = NULL;
   BIO *ssl = NULL;
-
-  if (!(con = BIO_new(BIO_s_connect())))
-    die("BIO_s_connect failed\n");
-  if (!(ssl = BIO_new_ssl(ctx, 1)))
-    die("BIO_new_ssl failed\n");
-  setup_proxy(ssl);
-  BIO_push(ssl, con);
+  if (! (con = BIO_new (BIO_s_connect())))
+    die ("BIO_s_connect failed\n");
+  if (! (ssl = BIO_new_ssl (ctx, 1)))
+    die ("BIO_new_ssl failed\n");
+  setup_proxy (ssl);
+  BIO_push (ssl, con);
   return ssl;
 }
 
@@ -183,14 +178,11 @@
 xmalloc (size_t size)
 {
   void *ptr;
-
   if (0 == size)
-    die("xmalloc: zero size\n");
-
-  ptr = malloc(size);
+    die ("xmalloc: zero size\n");
+  ptr = malloc (size);
   if (NULL == ptr)
-    die("xmalloc: out of memory (allocating %zu bytes)\n", size);
-
+    die ("xmalloc: out of memory (allocating %zu bytes)\n", size);
   return ptr;
 }
 
@@ -200,9 +192,8 @@
 xfree (void *ptr)
 {
   if (NULL == ptr)
-    die("xfree: NULL pointer given as argument\n");
-
-  free(ptr);
+    die ("xfree: NULL pointer given as argument\n");
+  free (ptr);
 }
 
 
@@ -211,33 +202,35 @@
 {
   if (where == SSL_CB_CONNECT_LOOP &&
       (ssl->state == SSL3_ST_CR_SRVR_HELLO_A || ssl->state == SSL3_ST_CR_SRVR_HELLO_B))
-  {
-    // XXX TODO: If we want to trust the remote system for time,
-    // can we just read that time out of the remote system and if the
-    // cert verifies, decide that the time is reasonable?
-    // Such a process seems to indicate that a once valid cert would be
-    // forever valid - we stopgap that by ensuring it isn't less than
-    // the latest compiled_time and isn't above max_reasonable_time...
-    // XXX TODO: Solve eternal question about the Chicken and the Egg...
-    uint32_t compiled_time = RECENT_COMPILE_DATE;
-    uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
-    uint32_t server_time;
-    verb("V: freezing time for x509 verification\n");
-    memcpy(&server_time, ssl->s3->server_random, sizeof(uint32_t));
-    if (compiled_time < ntohl(server_time)
-        &&
-        ntohl(server_time) < max_reasonable_time)
     {
-      verb("V: remote peer provided: %d, preferred over compile time: %d\n",
-            ntohl(server_time), compiled_time);
-      verb("V: freezing time with X509_VERIFY_PARAM_set_time\n");
-      X509_VERIFY_PARAM_set_time(ssl->ctx->cert_store->param,
-                                 (time_t) ntohl(server_time) + 86400);
-    } else {
-      die("V: the remote server is a false ticker! server: %d compile: %d\n",
-           ntohl(server_time), compiled_time);
+      // XXX TODO: If we want to trust the remote system for time,
+      // can we just read that time out of the remote system and if the
+      // cert verifies, decide that the time is reasonable?
+      // Such a process seems to indicate that a once valid cert would be
+      // forever valid - we stopgap that by ensuring it isn't less than
+      // the latest compiled_time and isn't above max_reasonable_time...
+      // XXX TODO: Solve eternal question about the Chicken and the Egg...
+      uint32_t compiled_time = RECENT_COMPILE_DATE;
+      uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
+      uint32_t server_time;
+      verb ("V: freezing time for x509 verification\n");
+      memcpy (&server_time, ssl->s3->server_random, sizeof (uint32_t));
+      if (compiled_time < ntohl (server_time)
+          &&
+          ntohl (server_time) < max_reasonable_time)
+        {
+          verb ("V: remote peer provided: %d, preferred over compile time: %d\n",
+                ntohl (server_time), compiled_time);
+          verb ("V: freezing time with X509_VERIFY_PARAM_set_time\n");
+          X509_VERIFY_PARAM_set_time (ssl->ctx->cert_store->param,
+                                      (time_t) ntohl (server_time) + 86400);
+        }
+      else
+        {
+          die ("V: the remote server is a false ticker! server: %d compile: %d\n",
+               ntohl (server_time), compiled_time);
+        }
     }
-  }
 }
 
 uint32_t
@@ -248,83 +241,83 @@
    */
   uint32_t key_bits;
   switch (public_key->type)
-  {
+    {
     case EVP_PKEY_RSA:
-      verb("V: key type: EVP_PKEY_RSA\n");
-      key_bits = BN_num_bits(public_key->pkey.rsa->n);
+      verb ("V: key type: EVP_PKEY_RSA\n");
+      key_bits = BN_num_bits (public_key->pkey.rsa->n);
       break;
     case EVP_PKEY_RSA2:
-      verb("V: key type: EVP_PKEY_RSA2\n");
-      key_bits = BN_num_bits(public_key->pkey.rsa->n);
+      verb ("V: key type: EVP_PKEY_RSA2\n");
+      key_bits = BN_num_bits (public_key->pkey.rsa->n);
       break;
     case EVP_PKEY_DSA:
-      verb("V: key type: EVP_PKEY_DSA\n");
-      key_bits = BN_num_bits(public_key->pkey.dsa->p);
+      verb ("V: key type: EVP_PKEY_DSA\n");
+      key_bits = BN_num_bits (public_key->pkey.dsa->p);
       break;
     case EVP_PKEY_DSA1:
-      verb("V: key type: EVP_PKEY_DSA1\n");
-      key_bits = BN_num_bits(public_key->pkey.dsa->p);
+      verb ("V: key type: EVP_PKEY_DSA1\n");
+      key_bits = BN_num_bits (public_key->pkey.dsa->p);
       break;
     case EVP_PKEY_DSA2:
-      verb("V: key type: EVP_PKEY_DSA2\n");
-      key_bits = BN_num_bits(public_key->pkey.dsa->p);
+      verb ("V: key type: EVP_PKEY_DSA2\n");
+      key_bits = BN_num_bits (public_key->pkey.dsa->p);
       break;
     case EVP_PKEY_DSA3:
-      verb("V: key type: EVP_PKEY_DSA3\n");
-      key_bits = BN_num_bits(public_key->pkey.dsa->p);
+      verb ("V: key type: EVP_PKEY_DSA3\n");
+      key_bits = BN_num_bits (public_key->pkey.dsa->p);
       break;
     case EVP_PKEY_DSA4:
-      verb("V: key type: EVP_PKEY_DSA4\n");
-      key_bits = BN_num_bits(public_key->pkey.dsa->p);
+      verb ("V: key type: EVP_PKEY_DSA4\n");
+      key_bits = BN_num_bits (public_key->pkey.dsa->p);
       break;
     case EVP_PKEY_DH:
-      verb("V: key type: EVP_PKEY_DH\n");
-      key_bits = BN_num_bits(public_key->pkey.dh->pub_key);
+      verb ("V: key type: EVP_PKEY_DH\n");
+      key_bits = BN_num_bits (public_key->pkey.dh->pub_key);
       break;
     case EVP_PKEY_EC:
-      verb("V: key type: EVP_PKEY_EC\n");
-      key_bits = EVP_PKEY_bits(public_key);
+      verb ("V: key type: EVP_PKEY_EC\n");
+      key_bits = EVP_PKEY_bits (public_key);
       break;
-    // Should we also care about EVP_PKEY_HMAC and EVP_PKEY_CMAC?
+      // Should we also care about EVP_PKEY_HMAC and EVP_PKEY_CMAC?
     default:
       key_bits = 0;
       die ("unknown public key type\n");
       break;
-  }
+    }
   verb ("V: keybits: %d\n", key_bits);
   return key_bits;
 }
 
 uint32_t
-dns_label_count(char *label, char *delim)
+dns_label_count (char *label, char *delim)
 {
   char *label_tmp;
   char *saveptr;
   char *saveptr_tmp;
   uint32_t label_count;
-
-  label_tmp = strdup(label);
+  label_tmp = strdup (label);
   label_count = 0;
   saveptr = NULL;
   saveptr_tmp = NULL;
-  saveptr = strtok_r(label_tmp, delim, &saveptr);
+  saveptr = strtok_r (label_tmp, delim, &saveptr);
   if (NULL != saveptr)
-  {
-    // Did we find our first label?
-    if (saveptr[0] != delim[0])
     {
-      label_count++;
-      verb ("V: label found; total label count: %d\n", label_count);
+      // Did we find our first label?
+      if (saveptr[0] != delim[0])
+        {
+          label_count++;
+          verb ("V: label found; total label count: %d\n", label_count);
+        }
+      do
+        {
+          // Find all subsequent labels
+          label_count++;
+          saveptr_tmp = strtok_r (NULL, delim, &saveptr);
+          verb ("V: label found; total label count: %d\n", label_count);
+        }
+      while (NULL != saveptr_tmp);
     }
-    do
-    {
-      // Find all subsequent labels
-      label_count++;
-      saveptr_tmp = strtok_r(NULL, delim, &saveptr);
-      verb ("V: label found; total label count: %d\n", label_count);
-    } while (NULL != saveptr_tmp);
-  }
-  free(label_tmp);
+  free (label_tmp);
   return label_count;
 }
 
@@ -335,7 +328,7 @@
 // Do allow *.example.com
 uint32_t
 check_wildcard_match_rfc2595 (const char *orig_hostname,
-                      const char *orig_cert_wild_card)
+                              const char *orig_cert_wild_card)
 {
   char *hostname;
   char *hostname_to_free;
@@ -348,96 +341,105 @@
   uint32_t ok;
   uint32_t wildcard_encountered;
   uint32_t label_count;
-
   // First we copy the original strings
-  hostname = strndup(orig_hostname, strlen(orig_hostname));
-  cert_wild_card = strndup(orig_cert_wild_card, strlen(orig_cert_wild_card));
+  hostname = strndup (orig_hostname, strlen (orig_hostname));
+  cert_wild_card = strndup (orig_cert_wild_card, strlen (orig_cert_wild_card));
   hostname_to_free = hostname;
   cert_wild_card_to_free = cert_wild_card;
-  delim = strdup(".");
-  wildchar = strdup("*");
-
+  delim = strdup (".");
+  wildchar = strdup ("*");
   verb ("V: Inspecting '%s' for possible wildcard match against '%s'\n",
-         hostname, cert_wild_card);
-
+        hostname, cert_wild_card);
   // By default we have not processed any labels
-  label_count = dns_label_count(cert_wild_card, delim);
-
+  label_count = dns_label_count (cert_wild_card, delim);
   // By default we have no match
   ok = 0;
   wildcard_encountered = 0;
   // First - do we have labels? If not, we refuse to even try to match
-  if ((NULL != strpbrk(cert_wild_card, delim)) &&
-      (NULL != strpbrk(hostname, delim)) &&
-      (label_count <= ((uint32_t)RFC2595_MIN_LABEL_COUNT)))
-  {
-    if (wildchar[0] == cert_wild_card[0])
+  if ( (NULL != strpbrk (cert_wild_card, delim)) &&
+       (NULL != strpbrk (hostname, delim)) &&
+       (label_count <= ( (uint32_t) RFC2595_MIN_LABEL_COUNT)))
     {
-      verb ("V: Found wildcard in at start of provided certificate name\n");
-      do
-      {
-        // Skip over the bytes between the first char and until the next label
-        wildcard_label = strsep(&cert_wild_card, delim);
-        expected_label = strsep(&hostname, delim);
-        if (NULL != wildcard_label &&
-            NULL != expected_label &&
-            NULL != hostname &&
-            NULL != cert_wild_card)
+      if (wildchar[0] == cert_wild_card[0])
         {
-          // Now we only consider this wildcard valid if the rest of the
-          // hostnames match verbatim
-          verb ("V: Attempting match of '%s' against '%s'\n",
-                 expected_label, wildcard_label);
-          // This is the case where we have a label that begins with wildcard
-          // Furthermore, we only allow this for the first label
-          if (wildcard_label[0] == wildchar[0] &&
-              0 == wildcard_encountered && 0 == ok)
-          {
-            verb ("V: Forced match of '%s' against '%s'\n", expected_label, wildcard_label);
-            wildcard_encountered = 1;
-          } else {
-            verb ("V: Attempting match of '%s' against '%s'\n",
-                   hostname, cert_wild_card);
-            if (0 == strcasecmp (expected_label, wildcard_label) &&
-                label_count >= ((uint32_t)RFC2595_MIN_LABEL_COUNT))
+          verb ("V: Found wildcard in at start of provided certificate name\n");
+          do
             {
-              ok = 1;
-              verb ("V: remaining labels match!\n");
-              break;
-            } else {
-              ok = 0;
-              verb ("V: remaining labels do not match!\n");
-              break;
+              // Skip over the bytes between the first char and until the next label
+              wildcard_label = strsep (&cert_wild_card, delim);
+              expected_label = strsep (&hostname, delim);
+              if (NULL != wildcard_label &&
+                  NULL != expected_label &&
+                  NULL != hostname &&
+                  NULL != cert_wild_card)
+                {
+                  // Now we only consider this wildcard valid if the rest of the
+                  // hostnames match verbatim
+                  verb ("V: Attempting match of '%s' against '%s'\n",
+                        expected_label, wildcard_label);
+                  // This is the case where we have a label that begins with wildcard
+                  // Furthermore, we only allow this for the first label
+                  if (wildcard_label[0] == wildchar[0] &&
+                      0 == wildcard_encountered && 0 == ok)
+                    {
+                      verb ("V: Forced match of '%s' against '%s'\n", expected_label, wildcard_label);
+                      wildcard_encountered = 1;
+                    }
+                  else
+                    {
+                      verb ("V: Attempting match of '%s' against '%s'\n",
+                            hostname, cert_wild_card);
+                      if (0 == strcasecmp (expected_label, wildcard_label) &&
+                          label_count >= ( (uint32_t) RFC2595_MIN_LABEL_COUNT))
+                        {
+                          ok = 1;
+                          verb ("V: remaining labels match!\n");
+                          break;
+                        }
+                      else
+                        {
+                          ok = 0;
+                          verb ("V: remaining labels do not match!\n");
+                          break;
+                        }
+                    }
+                }
+              else
+                {
+                  // We hit this case when we have a mismatched number of labels
+                  verb ("V: NULL label; no wildcard here\n");
+                  break;
+                }
             }
-          }
-        } else {
-          // We hit this case when we have a mismatched number of labels
-          verb("V: NULL label; no wildcard here\n");
-          break;
+          while (0 != wildcard_encountered && label_count <= RFC2595_MIN_LABEL_COUNT);
         }
-      } while (0 != wildcard_encountered && label_count <= RFC2595_MIN_LABEL_COUNT);
-    } else {
-      verb ("V: Not a RFC 2595 wildcard\n");
+      else
+        {
+          verb ("V: Not a RFC 2595 wildcard\n");
+        }
     }
-  } else {
-    verb ("V: Not a valid wildcard certificate\n");
-    ok = 0;
-  }
+  else
+    {
+      verb ("V: Not a valid wildcard certificate\n");
+      ok = 0;
+    }
   // Free our copies
-  free(wildchar);
-  free(delim);
-  free(hostname_to_free);
-  free(cert_wild_card_to_free);
+  free (wildchar);
+  free (delim);
+  free (hostname_to_free);
+  free (cert_wild_card_to_free);
   if (wildcard_encountered & ok && label_count >= RFC2595_MIN_LABEL_COUNT)
-  {
-    verb ("V: wildcard match of %s against %s\n",
-          orig_hostname, orig_cert_wild_card);
-    return (wildcard_encountered & ok);
-  } else {
-    verb ("V: wildcard match failure of %s against %s\n",
-          orig_hostname, orig_cert_wild_card);
-    return 0;
-  }
+    {
+      verb ("V: wildcard match of %s against %s\n",
+            orig_hostname, orig_cert_wild_card);
+      return (wildcard_encountered & ok);
+    }
+  else
+    {
+      verb ("V: wildcard match failure of %s against %s\n",
+            orig_hostname, orig_cert_wild_card);
+      return 0;
+    }
 }
 
 /**
@@ -451,37 +453,33 @@
   char *cn_buf;
   X509 *certificate;
   X509_NAME *xname;
-
-  cn_buf = xmalloc(TLSDATE_HOST_NAME_MAX + 1);
-
-  certificate = SSL_get_peer_certificate(ssl);
+  cn_buf = xmalloc (TLSDATE_HOST_NAME_MAX + 1);
+  certificate = SSL_get_peer_certificate (ssl);
   if (NULL == certificate)
-  {
-    die ("Unable to extract certificate\n");
-  }
-
-  memset(cn_buf, '\0', (TLSDATE_HOST_NAME_MAX + 1));
-  xname = X509_get_subject_name(certificate);
-  ret = X509_NAME_get_text_by_NID(xname, NID_commonName,
-                                  cn_buf, TLSDATE_HOST_NAME_MAX);
-
-  if (-1 == ret && ret != strlen(hostname))
-  {
-    die ("Unable to extract commonName\n");
-  }
-  if (strcasecmp(cn_buf, hostname))
-  {
-    verb ("V: commonName mismatch! Expected: %s - received: %s\n",
-          hostname, cn_buf);
-  } else {
-    verb ("V: commonName matched: %s\n", cn_buf);
-    ok = 1;
-  }
-
-  X509_NAME_free(xname);
-  X509_free(certificate);
-  xfree(cn_buf);
-
+    {
+      die ("Unable to extract certificate\n");
+    }
+  memset (cn_buf, '\0', (TLSDATE_HOST_NAME_MAX + 1));
+  xname = X509_get_subject_name (certificate);
+  ret = X509_NAME_get_text_by_NID (xname, NID_commonName,
+                                   cn_buf, TLSDATE_HOST_NAME_MAX);
+  if (-1 == ret && ret != strlen (hostname))
+    {
+      die ("Unable to extract commonName\n");
+    }
+  if (strcasecmp (cn_buf, hostname))
+    {
+      verb ("V: commonName mismatch! Expected: %s - received: %s\n",
+            hostname, cn_buf);
+    }
+  else
+    {
+      verb ("V: commonName matched: %s\n", cn_buf);
+      ok = 1;
+    }
+  X509_NAME_free (xname);
+  X509_free (certificate);
+  xfree (cn_buf);
   return ok;
 }
 
@@ -494,93 +492,91 @@
   X509 *cert;
   int extcount, ok = 0;
   /* What an OpenSSL mess ... */
-  if (NULL == (cert = SSL_get_peer_certificate(ssl)))
-  {
-    die ("Getting certificate failed\n");
-  }
-
-  if ((extcount = X509_get_ext_count(cert)) > 0)
-  {
-    int i;
-    for (i = 0; i < extcount; ++i)
+  if (NULL == (cert = SSL_get_peer_certificate (ssl)))
     {
-      const char *extstr;
-      X509_EXTENSION *ext;
-      ext = X509_get_ext(cert, i);
-      extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
-
-      if (!strcmp(extstr, "subjectAltName"))
-      {
-
-        int j;
-        void *extvalstr;
-        const unsigned char *tmp;
-
-        STACK_OF(CONF_VALUE) *val;
-        CONF_VALUE *nval;
-#if OPENSSL_VERSION_NUMBER >= 0x10000000L
-        const
-#endif
-        X509V3_EXT_METHOD *method;
-
-        if (!(method = X509V3_EXT_get(ext)))
+      die ("Getting certificate failed\n");
+    }
+  if ( (extcount = X509_get_ext_count (cert)) > 0)
+    {
+      int i;
+      for (i = 0; i < extcount; ++i)
         {
-          break;
-        }
-
-        tmp = ext->value->data;
-        if (method->it)
-        {
-          extvalstr = ASN1_item_d2i(NULL, &tmp, ext->value->length,
-                                    ASN1_ITEM_ptr(method->it));
-        } else {
-          extvalstr = method->d2i(NULL, &tmp, ext->value->length);
-        }
-
-        if (!extvalstr)
-        {
-          break;
-        }
-
-        if (method->i2v)
-        {
-          val = method->i2v(method, extvalstr, NULL);
-          for (j = 0; j < sk_CONF_VALUE_num(val); ++j)
-          {
-            nval = sk_CONF_VALUE_value(val, j);
-            if ((!strcasecmp(nval->name, "DNS") &&
-                !strcasecmp(nval->value, hostname) ) ||
-                (!strcasecmp(nval->name, "iPAddress") &&
-                !strcasecmp(nval->value, hostname)))
+          const char *extstr;
+          X509_EXTENSION *ext;
+          ext = X509_get_ext (cert, i);
+          extstr = OBJ_nid2sn (OBJ_obj2nid (X509_EXTENSION_get_object (ext)));
+          if (!strcmp (extstr, "subjectAltName"))
             {
-              verb ("V: subjectAltName matched: %s, type: %s\n", nval->value, nval->name); // We matched this; so it's safe to print
-              ok = 1;
+              int j;
+              void *extvalstr;
+              const unsigned char *tmp;
+              STACK_OF (CONF_VALUE) *val;
+              CONF_VALUE *nval;
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+              const
+#endif
+              X509V3_EXT_METHOD *method;
+              if (! (method = X509V3_EXT_get (ext)))
+                {
+                  break;
+                }
+              tmp = ext->value->data;
+              if (method->it)
+                {
+                  extvalstr = ASN1_item_d2i (NULL, &tmp, ext->value->length,
+                                             ASN1_ITEM_ptr (method->it));
+                }
+              else
+                {
+                  extvalstr = method->d2i (NULL, &tmp, ext->value->length);
+                }
+              if (!extvalstr)
+                {
+                  break;
+                }
+              if (method->i2v)
+                {
+                  val = method->i2v (method, extvalstr, NULL);
+                  for (j = 0; j < sk_CONF_VALUE_num (val); ++j)
+                    {
+                      nval = sk_CONF_VALUE_value (val, j);
+                      if ( (!strcasecmp (nval->name, "DNS") &&
+                            !strcasecmp (nval->value, hostname)) ||
+                           (!strcasecmp (nval->name, "iPAddress") &&
+                            !strcasecmp (nval->value, hostname)))
+                        {
+                          verb ("V: subjectAltName matched: %s, type: %s\n", nval->value, nval->name); // We matched this; so it's safe to print
+                          ok = 1;
+                          break;
+                        }
+                      // Attempt to match subjectAltName DNS names
+                      if (!strcasecmp (nval->name, "DNS"))
+                        {
+                          ok = check_wildcard_match_rfc2595 (hostname, nval->value);
+                          if (ok)
+                            {
+                              break;
+                            }
+                        }
+                      verb ("V: subjectAltName found but not matched: %s, type: %s\n", nval->value, nval->name); // XXX: Clean this string!
+                    }
+                }
+            }
+          else
+            {
+              verb ("V: found non subjectAltName extension\n");
+            }
+          if (ok)
+            {
               break;
             }
-            // Attempt to match subjectAltName DNS names
-            if (!strcasecmp(nval->name, "DNS"))
-            {
-              ok = check_wildcard_match_rfc2595(hostname, nval->value);
-              if (ok)
-              {
-                break;
-              }
-            }
-            verb ("V: subjectAltName found but not matched: %s, type: %s\n", nval->value, nval->name); // XXX: Clean this string!
-          }
         }
-      } else {
-        verb ("V: found non subjectAltName extension\n");
-      }
-      if (ok)
-      {
-        break;
-      }
     }
-  } else {
-    verb ("V: no X509_EXTENSION field(s) found\n");
-  }
-  X509_free(cert);
+  else
+    {
+      verb ("V: no X509_EXTENSION field(s) found\n");
+    }
+  X509_free (cert);
   return ok;
 }
 
@@ -589,14 +585,16 @@
 {
   uint32_t ret;
   ret = 0;
-  ret = check_cn(ssl, hostname);
-  ret += check_san(ssl, hostname);
+  ret = check_cn (ssl, hostname);
+  ret += check_san (ssl, hostname);
   if (0 != ret && 0 < ret)
-  {
-    verb ("V: hostname verification passed\n");
-  } else {
-    die ("hostname verification failed for host %s!\n", host);
-  }
+    {
+      verb ("V: hostname verification passed\n");
+    }
+  else
+    {
+      die ("hostname verification failed for host %s!\n", host);
+    }
   return ret;
 }
 
@@ -605,27 +603,26 @@
 {
   long ssl_verify_result;
   X509 *certificate;
-
-  certificate = SSL_get_peer_certificate(ssl);
+  certificate = SSL_get_peer_certificate (ssl);
   if (NULL == certificate)
-  {
-    die ("Getting certificate failed\n");
-  }
+    {
+      die ("Getting certificate failed\n");
+    }
   // In theory, we verify that the cert is valid
-  ssl_verify_result = SSL_get_verify_result(ssl);
+  ssl_verify_result = SSL_get_verify_result (ssl);
   switch (ssl_verify_result)
-  {
-  case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
-  case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
-    die ("certificate is self signed\n");
-  case X509_V_OK:
-    verb ("V: certificate verification passed\n");
-    break;
-  default:
-    die ("certification verification error: %ld\n",
-         ssl_verify_result);
-  }
- return 0;
+    {
+    case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+    case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+      die ("certificate is self signed\n");
+    case X509_V_OK:
+      verb ("V: certificate verification passed\n");
+      break;
+    default:
+      die ("certification verification error: %ld\n",
+           ssl_verify_result);
+    }
+  return 0;
 }
 
 void
@@ -636,42 +633,48 @@
   EVP_PKEY *public_key;
   certificate = SSL_get_peer_certificate (ssl);
   if (NULL == certificate)
-  {
-    die ("Getting certificate failed\n");
-  }
+    {
+      die ("Getting certificate failed\n");
+    }
   public_key = X509_get_pubkey (certificate);
   if (NULL == public_key)
-  {
-    die ("public key extraction failure\n");
-  } else {
-    verb ("V: public key is ready for inspection\n");
-  }
-
+    {
+      die ("public key extraction failure\n");
+    }
+  else
+    {
+      verb ("V: public key is ready for inspection\n");
+    }
   key_bits = get_certificate_keybits (public_key);
   if (MIN_PUB_KEY_LEN >= key_bits && public_key->type != EVP_PKEY_EC)
-  {
-    die ("Unsafe public key size: %d bits\n", key_bits);
-  } else {
-     if (public_key->type == EVP_PKEY_EC)
-       if(key_bits >= MIN_ECC_PUB_KEY_LEN
-          && key_bits <= MAX_ECC_PUB_KEY_LEN)
-       {
-         verb ("V: ECC key length appears safe\n");
-       } else {
-         die ("Unsafe ECC key size: %d bits\n", key_bits);
-     } else {
-       verb ("V: key length appears safe\n");
-     }
-  }
+    {
+      die ("Unsafe public key size: %d bits\n", key_bits);
+    }
+  else
+    {
+      if (public_key->type == EVP_PKEY_EC)
+        if (key_bits >= MIN_ECC_PUB_KEY_LEN
+            && key_bits <= MAX_ECC_PUB_KEY_LEN)
+          {
+            verb ("V: ECC key length appears safe\n");
+          }
+        else
+          {
+            die ("Unsafe ECC key size: %d bits\n", key_bits);
+          }
+      else
+        {
+          verb ("V: key length appears safe\n");
+        }
+    }
   EVP_PKEY_free (public_key);
 }
 
 void
 inspect_key (SSL *ssl, const char *hostname)
 {
-
-    verify_signature (ssl, hostname);
-    check_name (ssl, hostname);
+  verify_signature (ssl, hostname);
+  check_name (ssl, hostname);
 }
 
 /**
@@ -687,97 +690,94 @@
   SSL_CTX *ctx;
   SSL *ssl;
   struct stat statbuf;
-
   SSL_load_error_strings();
   SSL_library_init();
-
   ctx = NULL;
-  if (0 == strcmp("sslv23", protocol))
-  {
-    verb ("V: using SSLv23_client_method()\n");
-    ctx = SSL_CTX_new(SSLv23_client_method());
-  } else if (0 == strcmp("sslv3", protocol))
-  {
-    verb ("V: using SSLv3_client_method()\n");
-    ctx = SSL_CTX_new(SSLv3_client_method());
-  } else if (0 == strcmp("tlsv1", protocol))
-  {
-    verb ("V: using TLSv1_client_method()\n");
-    ctx = SSL_CTX_new(TLSv1_client_method());
-  } else
-    die("Unsupported protocol `%s'\n", protocol);
-
-  if (ctx == NULL)
-    die("OpenSSL failed to support protocol `%s'\n", protocol);
-
-  if (ca_racket)
-  {
-    if (-1 == stat(ca_cert_container, &statbuf))
+  if (0 == strcmp ("sslv23", protocol))
     {
-      die("Unable to stat CA certficate container\n");
-    } else
-    {
-      switch (statbuf.st_mode & S_IFMT)
-      {
-      case S_IFREG:
-        if (1 != SSL_CTX_load_verify_locations(ctx, ca_cert_container, NULL))
-          fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
-        break;
-      case S_IFDIR:
-        if (1 != SSL_CTX_load_verify_locations(ctx, NULL, ca_cert_container))
-          fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
-        break;
-      default:
-        die("Unable to load CA certficate container\n");
-      }
+      verb ("V: using SSLv23_client_method()\n");
+      ctx = SSL_CTX_new (SSLv23_client_method());
     }
-  }
-
-  if (NULL == (s_bio = make_ssl_bio(ctx)))
+  else if (0 == strcmp ("sslv3", protocol))
+    {
+      verb ("V: using SSLv3_client_method()\n");
+      ctx = SSL_CTX_new (SSLv3_client_method());
+    }
+  else if (0 == strcmp ("tlsv1", protocol))
+    {
+      verb ("V: using TLSv1_client_method()\n");
+      ctx = SSL_CTX_new (TLSv1_client_method());
+    }
+  else
+    die ("Unsupported protocol `%s'\n", protocol);
+  if (ctx == NULL)
+    die ("OpenSSL failed to support protocol `%s'\n", protocol);
+  if (ca_racket)
+    {
+      if (-1 == stat (ca_cert_container, &statbuf))
+        {
+          die ("Unable to stat CA certficate container\n");
+        }
+      else
+        {
+          switch (statbuf.st_mode & S_IFMT)
+            {
+            case S_IFREG:
+              if (1 != SSL_CTX_load_verify_locations (ctx, ca_cert_container, NULL))
+                fprintf (stderr, "SSL_CTX_load_verify_locations failed\n");
+              break;
+            case S_IFDIR:
+              if (1 != SSL_CTX_load_verify_locations (ctx, NULL, ca_cert_container))
+                fprintf (stderr, "SSL_CTX_load_verify_locations failed\n");
+              break;
+            default:
+              die ("Unable to load CA certficate container\n");
+            }
+        }
+    }
+  if (NULL == (s_bio = make_ssl_bio (ctx)))
     die ("SSL BIO setup failed\n");
-  BIO_get_ssl(s_bio, &ssl);
+  BIO_get_ssl (s_bio, &ssl);
   if (NULL == ssl)
     die ("SSL setup failed\n");
-
   if (time_is_an_illusion)
-  {
-    SSL_set_info_callback(ssl, openssl_time_callback);
-  }
-
-  SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
-  verb("V: opening socket to %s:%s\n", host, port);
-  if ( (1 != BIO_set_conn_hostname(s_bio, host)) ||
-       (1 != BIO_set_conn_port(s_bio, port)) )
+    {
+      SSL_set_info_callback (ssl, openssl_time_callback);
+    }
+  SSL_set_mode (ssl, SSL_MODE_AUTO_RETRY);
+  verb ("V: opening socket to %s:%s\n", host, port);
+  if ( (1 != BIO_set_conn_hostname (s_bio, host)) ||
+       (1 != BIO_set_conn_port (s_bio, port)))
     die ("Failed to initialize connection to `%s:%s'\n", host, port);
-
-  if (NULL == BIO_new_fp(stdout, BIO_NOCLOSE))
-    die ("BIO_new_fp returned error, possibly: %s", strerror(errno));
-
+  if (NULL == BIO_new_fp (stdout, BIO_NOCLOSE))
+    die ("BIO_new_fp returned error, possibly: %s", strerror (errno));
   // This should run in seccomp
   // eg:     prctl(PR_SET_SECCOMP, 1);
-  if (1 != BIO_do_connect(s_bio)) // XXX TODO: BIO_should_retry() later?
+  if (1 != BIO_do_connect (s_bio)) // XXX TODO: BIO_should_retry() later?
     die ("SSL connection failed\n");
-  if (1 != BIO_do_handshake(s_bio))
+  if (1 != BIO_do_handshake (s_bio))
     die ("SSL handshake failed\n");
-
   // Verify the peer certificate against the CA certs on the local system
-  if (ca_racket) {
-    inspect_key (ssl, hostname_to_verify);
-  } else {
-    verb ("V: Certificate verification skipped!\n");
-  }
-  check_key_length(ssl);
+  if (ca_racket)
+    {
+      inspect_key (ssl, hostname_to_verify);
+    }
+  else
+    {
+      verb ("V: Certificate verification skipped!\n");
+    }
+  check_key_length (ssl);
   // from /usr/include/openssl/ssl3.h
   //  ssl->s3->server_random is an unsigned char of 32 bits
-  memcpy(time_map, ssl->s3->server_random, sizeof (uint32_t));
-  SSL_free(ssl);
-  SSL_CTX_free(ctx);
+  memcpy (time_map, ssl->s3->server_random, sizeof (uint32_t));
+  SSL_free (ssl);
+  SSL_CTX_free (ctx);
 }
 
 /** drop root rights and become 'nobody' */
 
 int
-main(int argc, char **argv)
+main (int argc, char **argv)
 {
   uint32_t *time_map;
   struct tlsdate_time start_time, end_time, warp_time;
@@ -790,7 +790,6 @@
   int showtime_raw;
   int timewarp;
   int leap;
-
   if (argc != 12)
     return 1;
   host = argv[1];
@@ -806,147 +805,131 @@
   timewarp = (0 == strcmp ("timewarp", argv[9]));
   leap = (0 == strcmp ("leapaway", argv[10]));
   proxy = (0 == strcmp ("none", argv[11]) ? NULL : argv[11]);
-
-  clock_init_time(&warp_time, RECENT_COMPILE_DATE, 0);
-
+  clock_init_time (&warp_time, RECENT_COMPILE_DATE, 0);
   if (timewarp)
-  {
-    verb ("V: RECENT_COMPILE_DATE is %lu.%06lu\n",
-         (unsigned long) CLOCK_SEC(&warp_time),
-         (unsigned long) CLOCK_USEC(&warp_time));
-  }
-
+    {
+      verb ("V: RECENT_COMPILE_DATE is %lu.%06lu\n",
+            (unsigned long) CLOCK_SEC (&warp_time),
+            (unsigned long) CLOCK_USEC (&warp_time));
+    }
   /* We are not going to set the clock, thus no need to stay root */
   if (0 == setclock && 0 == timewarp)
-  {
-    drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
-  }
-
-  time_map = mmap (NULL, sizeof (uint32_t),
-       PROT_READ | PROT_WRITE,
-       MAP_SHARED | MAP_ANONYMOUS, -1, 0);
-  if (MAP_FAILED == time_map)
-  {
-    fprintf (stderr, "mmap failed: %s\n",
-             strerror (errno));
-    return 1;
-  }
-
-  /* Get the current time from the system clock. */
-  if (0 != clock_get_real_time(&start_time))
-  {
-    die ("Failed to read current time of day: %s\n", strerror (errno));
-  }
-
-  verb ("V: time is currently %lu.%06lu\n",
-       (unsigned long) CLOCK_SEC(&start_time),
-       (unsigned long) CLOCK_NSEC(&start_time));
-
-  if (((unsigned long) CLOCK_SEC(&start_time)) < ((unsigned long) CLOCK_SEC(&warp_time)))
-  {
-    verb ("V: local clock time is less than RECENT_COMPILE_DATE\n");
-    if (timewarp)
     {
-      verb ("V: Attempting to warp local clock into the future\n");
-      if (0 != clock_set_real_time(&warp_time))
-      {
-        die ("setting time failed: %s (Attempted to set clock to %lu.%06lu)\n",
-        strerror (errno),
-        (unsigned long) CLOCK_SEC(&warp_time),
-        (unsigned long) CLOCK_SEC(&warp_time));
-      }
-      if (0 != clock_get_real_time(&start_time))
-      {
-        die ("Failed to read current time of day: %s\n", strerror (errno));
-      }
-      verb ("V: time is currently %lu.%06lu\n",
-           (unsigned long) CLOCK_SEC(&start_time),
-           (unsigned long) CLOCK_NSEC(&start_time));
-      verb ("V: It's just a step to the left...\n");
+      drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
     }
-  } else {
-    verb ("V: time is greater than RECENT_COMPILE_DATE\n");
-  }
-
+  time_map = mmap (NULL, sizeof (uint32_t),
+                   PROT_READ | PROT_WRITE,
+                   MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+  if (MAP_FAILED == time_map)
+    {
+      fprintf (stderr, "mmap failed: %s\n",
+               strerror (errno));
+      return 1;
+    }
+  /* Get the current time from the system clock. */
+  if (0 != clock_get_real_time (&start_time))
+    {
+      die ("Failed to read current time of day: %s\n", strerror (errno));
+    }
+  verb ("V: time is currently %lu.%06lu\n",
+        (unsigned long) CLOCK_SEC (&start_time),
+        (unsigned long) CLOCK_NSEC (&start_time));
+  if ( ( (unsigned long) CLOCK_SEC (&start_time)) < ( (unsigned long) CLOCK_SEC (&warp_time)))
+    {
+      verb ("V: local clock time is less than RECENT_COMPILE_DATE\n");
+      if (timewarp)
+        {
+          verb ("V: Attempting to warp local clock into the future\n");
+          if (0 != clock_set_real_time (&warp_time))
+            {
+              die ("setting time failed: %s (Attempted to set clock to %lu.%06lu)\n",
+                   strerror (errno),
+                   (unsigned long) CLOCK_SEC (&warp_time),
+                   (unsigned long) CLOCK_SEC (&warp_time));
+            }
+          if (0 != clock_get_real_time (&start_time))
+            {
+              die ("Failed to read current time of day: %s\n", strerror (errno));
+            }
+          verb ("V: time is currently %lu.%06lu\n",
+                (unsigned long) CLOCK_SEC (&start_time),
+                (unsigned long) CLOCK_NSEC (&start_time));
+          verb ("V: It's just a step to the left...\n");
+        }
+    }
+  else
+    {
+      verb ("V: time is greater than RECENT_COMPILE_DATE\n");
+    }
   /* initialize to bogus value, just to be on the safe side */
   *time_map = 0;
-
   /* Run SSL interaction in separate process (and not as 'root') */
   ssl_child = fork ();
   if (-1 == ssl_child)
     die ("fork failed: %s\n", strerror (errno));
   if (0 == ssl_child)
-  {
-    drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
-    run_ssl (time_map, leap);
-    (void) munmap (time_map, sizeof (uint32_t));
-    _exit (0);
-  }
+    {
+      drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
+      run_ssl (time_map, leap);
+      (void) munmap (time_map, sizeof (uint32_t));
+      _exit (0);
+    }
   if (ssl_child != waitpid (ssl_child, &status, 0))
     die ("waitpid failed: %s\n", strerror (errno));
-  if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)) ))
+  if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status))))
     die ("child process failed in SSL handshake\n");
-
-  if (0 != clock_get_real_time(&end_time))
+  if (0 != clock_get_real_time (&end_time))
     die ("Failed to read current time of day: %s\n", strerror (errno));
-
   /* calculate RTT */
-  rt_time_ms = (CLOCK_SEC(&end_time) - CLOCK_SEC(&start_time)) * 1000 + (CLOCK_USEC(&end_time) - CLOCK_USEC(&start_time)) / 1000;
+  rt_time_ms = (CLOCK_SEC (&end_time) - CLOCK_SEC (&start_time)) * 1000 + (CLOCK_USEC (&end_time) - CLOCK_USEC (&start_time)) / 1000;
   if (rt_time_ms < 0)
     rt_time_ms = 0; /* non-linear time... */
   server_time_s = ntohl (*time_map);
   munmap (time_map, sizeof (uint32_t));
-
   verb ("V: server time %u (difference is about %d s) was fetched in %lld ms\n",
-  (unsigned int) server_time_s,
-  CLOCK_SEC(&start_time) - server_time_s,
-  rt_time_ms);
-
+        (unsigned int) server_time_s,
+        CLOCK_SEC (&start_time) - server_time_s,
+        rt_time_ms);
   /* warning if the handshake took too long */
-  if (rt_time_ms > TLS_RTT_THRESHOLD) {
-    verb ("V: the TLS handshake took more than %d msecs - consider using a different " \
-      "server or run it again\n", TLS_RTT_THRESHOLD);
-  }
-
+  if (rt_time_ms > TLS_RTT_THRESHOLD)
+    {
+      verb ("V: the TLS handshake took more than %d msecs - consider using a different " \
+            "server or run it again\n", TLS_RTT_THRESHOLD);
+    }
   if (showtime_raw)
-  {
-    fwrite(&server_time_s, sizeof(server_time_s), 1, stdout);
-  }
-
+    {
+      fwrite (&server_time_s, sizeof (server_time_s), 1, stdout);
+    }
   if (showtime)
-  {
-     struct tm  ltm;
-     time_t tim = server_time_s;
-     char       buf[256];
-
-     localtime_r(&tim, &ltm);
-     if (0 == strftime(buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y", &ltm))
-     {
-       die ("strftime returned 0\n");
-     }
-     fprintf(stdout, "%s\n", buf);
-  }
-
+    {
+      struct tm  ltm;
+      time_t tim = server_time_s;
+      char       buf[256];
+      localtime_r (&tim, &ltm);
+      if (0 == strftime (buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y", &ltm))
+        {
+          die ("strftime returned 0\n");
+        }
+      fprintf (stdout, "%s\n", buf);
+    }
   /* finally, actually set the time */
   if (setclock)
-  {
-    struct tlsdate_time server_time;
-
-    clock_init_time(&server_time,  server_time_s + (rt_time_ms / 2 / 1000),
-                   (rt_time_ms / 2) % 1000);
-
-    // We should never receive a time that is before the time we were last
-    // compiled; we subscribe to the linear theory of time for this program
-    // and this program alone!
-    if (CLOCK_SEC(&server_time) >= MAX_REASONABLE_TIME)
-      die("remote server is a false ticker from the future!\n");
-    if (CLOCK_SEC(&server_time) <= RECENT_COMPILE_DATE)
-      die ("remote server is a false ticker!\n");
-    if (0 != clock_set_real_time(&server_time))
-      die ("setting time failed: %s (Difference from server is about %d)\n",
-     strerror (errno),
-     CLOCK_SEC(&start_time) - server_time_s);
-    verb ("V: setting time succeeded\n");
-  }
+    {
+      struct tlsdate_time server_time;
+      clock_init_time (&server_time,  server_time_s + (rt_time_ms / 2 / 1000),
+                       (rt_time_ms / 2) % 1000);
+      // We should never receive a time that is before the time we were last
+      // compiled; we subscribe to the linear theory of time for this program
+      // and this program alone!
+      if (CLOCK_SEC (&server_time) >= MAX_REASONABLE_TIME)
+        die ("remote server is a false ticker from the future!\n");
+      if (CLOCK_SEC (&server_time) <= RECENT_COMPILE_DATE)
+        die ("remote server is a false ticker!\n");
+      if (0 != clock_set_real_time (&server_time))
+        die ("setting time failed: %s (Difference from server is about %d)\n",
+             strerror (errno),
+             CLOCK_SEC (&start_time) - server_time_s);
+      verb ("V: setting time succeeded\n");
+    }
   return 0;
 }
diff --git a/src/tlsdate-helper.h b/src/tlsdate-helper.h
index 021b8f5..222c91a 100644
--- a/src/tlsdate-helper.h
+++ b/src/tlsdate-helper.h
@@ -51,11 +51,11 @@
 // We set this manually to ensure others can reproduce a build;
 // automation of this will make every build different!
 #ifndef RECENT_COMPILE_DATE
-#define RECENT_COMPILE_DATE (uint32_t) 1342323666
+#define RECENT_COMPILE_DATE 1342323666L
 #endif
 
 #ifndef MAX_REASONABLE_TIME
-#define MAX_REASONABLE_TIME (uint32_t) 1999991337
+#define MAX_REASONABLE_TIME 1999991337L
 #endif
 
 #ifndef MIN_PUB_KEY_LEN
diff --git a/src/tlsdate-monitor.c b/src/tlsdate-monitor.c
new file mode 100644
index 0000000..a49034c
--- /dev/null
+++ b/src/tlsdate-monitor.c
@@ -0,0 +1,94 @@
+/*
+ * tlsdate-monitor.c - tlsdated monitor for tlsdate.
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "src/util.h"
+#include "src/tlsdate.h"
+
+static
+char **
+build_argv (struct opts *opts)
+{
+  int argc;
+  char **new_argv;
+  assert (opts->sources);
+  /* choose the next source in the list; if we're at the end, start over. */
+  if (!opts->cur_source || !opts->cur_source->next)
+    opts->cur_source = opts->sources;
+  else
+    opts->cur_source = opts->cur_source->next;
+  for (argc = 0; opts->base_argv[argc]; argc++)
+    ;
+  argc++; /* uncounted null terminator */
+  argc += 8;  /* -H host -p port -x proxy -Vraw -n */
+  new_argv = malloc (argc * sizeof (char *));
+  if (!new_argv)
+    return NULL;
+  for (argc = 0; opts->base_argv[argc]; argc++)
+    new_argv[argc] = opts->base_argv[argc];
+  new_argv[argc++] = "-H";
+  new_argv[argc++] = opts->cur_source->host;
+  new_argv[argc++] = "-p";
+  new_argv[argc++] = opts->cur_source->port;
+  if (opts->cur_source->proxy || opts->proxy)
+    {
+      char *proxy = opts->proxy ? opts->proxy : opts->cur_source->proxy;
+      if (strcmp (proxy, ""))
+        {
+          new_argv[argc++] = (char *) "-x";
+          new_argv[argc++] = proxy;
+        }
+    }
+  new_argv[argc++] = "-Vraw";
+  new_argv[argc++] = "-n";
+  new_argv[argc++] = NULL;
+  return new_argv;
+}
+
+/* Run tlsdate and redirects stdout to the monitor_fd */
+int
+tlsdate (struct state *state)
+{
+  char **new_argv;
+  pid_t pid;
+  switch ((pid = fork()))
+    {
+    case 0: /* child! */
+      break;
+    case -1:
+      perror ("fork() failed!");
+      return -1;
+    default:
+      debug ("[tlsdate-monitor] spawned tlsdate: %d", pid);
+      state->tlsdate_pid = pid;
+      return 0;
+   }
+  if (!(new_argv = build_argv (&state->opts)))
+    fatal ("out of memory building argv");
+  /* Replace stdout with the pipe back to tlsdated */
+  if (dup2 (state->tlsdate_monitor_fd, STDOUT_FILENO) < 0)
+    {
+      perror ("dup2 failed");
+      _exit (2);
+    }
+  execve (new_argv[0], new_argv, state->envp);
+  perror ("execve() failed");
+  _exit (1);
+}
diff --git a/src/tlsdate-setter.c b/src/tlsdate-setter.c
new file mode 100644
index 0000000..fccb987
--- /dev/null
+++ b/src/tlsdate-setter.c
@@ -0,0 +1,211 @@
+/*
+ * tlsdate-setter.c - privileged time setter for tlsdated
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/rtc.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/prctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/dbus.h"
+#include "src/seccomp.h"
+#include "src/tlsdate.h"
+#include "src/util.h"
+
+/* Atomically writes the timestamp to the specified fd. */
+int
+save_timestamp_to_fd (int fd, time_t t)
+{
+  struct iovec iov[1];
+  ssize_t ret;
+  iov[0].iov_base = &t;
+  iov[0].iov_len = sizeof (t);
+  ret = IGNORE_EINTR (pwritev (fd, iov, 1, 0));
+  if (ret != sizeof (t))
+    return 1;
+  return 0;
+}
+
+/*
+ * Set the hardware clock referred to by fd (which should be a descriptor to
+ * some device that implements the interface documented in rtc(4)) to the system
+ * time. See hwclock(8) for details of why this is important. If we fail, we
+ * just return - there's nothing the caller can really do about a failure of
+ * this function except try later.
+ */
+int
+sync_hwclock (int fd, time_t sec)
+{
+  struct tm tm;
+  struct rtc_time rtctm;
+  gmtime_r (&sec, &tm);
+  /* these structs are identical, but separately defined */
+  rtctm.tm_sec = tm.tm_sec;
+  rtctm.tm_min = tm.tm_min;
+  rtctm.tm_hour = tm.tm_hour;
+  rtctm.tm_mday = tm.tm_mday;
+  rtctm.tm_mon = tm.tm_mon;
+  rtctm.tm_year = tm.tm_year;
+  rtctm.tm_wday = tm.tm_wday;
+  rtctm.tm_yday = tm.tm_yday;
+  rtctm.tm_isdst = tm.tm_isdst;
+  return ioctl (fd, RTC_SET_TIME, &rtctm);
+}
+
+void
+report_setter_error (siginfo_t *info)
+{
+  const char *code;
+  int killit = 0;
+  switch (info->si_code)
+    {
+    case CLD_EXITED:
+      code = "EXITED";
+      break;
+    case CLD_KILLED:
+      code = "KILLED";
+      break;
+    case CLD_DUMPED:
+      code = "DUMPED";
+      break;
+    case CLD_STOPPED:
+      code = "STOPPED";
+      killit = 1;
+      break;
+    case CLD_TRAPPED:
+      code = "TRAPPED";
+      killit = 1;
+      break;
+    case CLD_CONTINUED:
+      code = "CONTINUED";
+      killit = 1;
+      break;
+    default:
+      code = "???";
+      killit = 1;
+    }
+  info ("tlsdate-setter exitting: code:%s status:%d pid:%d uid:%d",
+        code, info->si_status, info->si_pid, info->si_uid);
+  if (killit)
+    kill (info->si_pid, SIGKILL);
+}
+
+void
+time_setter_coprocess (int time_fd, int notify_fd, struct state *state)
+{
+  int save_fd = -1;
+  int status;
+  prctl (PR_SET_NAME, "tlsdated-setter");
+  if (state->opts.should_save_disk && !state->opts.dry_run)
+    {
+      if ( (save_fd = open (state->timestamp_path,
+                            O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC,
+                            S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0)
+        {
+          /* Attempt to unlink the path on the way out. */
+          unlink (state->timestamp_path);
+          status = SETTER_NO_SAVE;
+          goto notify_and_die;
+        }
+    }
+  /* XXX: Drop all privs but CAP_SYS_TIME */
+#ifdef HAVE_SECCOMP_FILTER
+  if (enable_setter_seccomp())
+    {
+      status = SETTER_NO_SBOX;
+      goto notify_and_die;
+    }
+#endif
+  while (1)
+    {
+      struct timeval tv = { 0, 0 };
+      /* The wire protocol is a time_t, but the caller should
+       * always be the unprivileged tlsdated process which spawned this
+       * helper.
+       * There are two special messages:
+       * (time_t)   0: requests a clean shutdown
+       * (time_t) < 0: indicates not to write to disk
+       * On Linux, time_t is a signed long.  Expanding the protocol
+       * is easy, but writing one long only is ideal.
+       */
+      ssize_t bytes = read (time_fd, &tv.tv_sec, sizeof (tv.tv_sec));
+      int save = 1;
+      if (bytes == -1)
+        {
+          if (errno == EINTR)
+            continue;
+          status = SETTER_READ_ERR;
+          goto notify_and_die;
+        }
+      if (bytes == 0)
+        {
+          /* End of pipe */
+          status = SETTER_READ_ERR;
+          goto notify_and_die;
+        }
+      if (bytes != sizeof (tv.tv_sec))
+        continue;
+      if (tv.tv_sec < 0)
+        {
+          /* Don't write to disk */
+          tv.tv_sec = -tv.tv_sec;
+          save = 0;
+        }
+      if (tv.tv_sec == 0)
+        {
+          status = SETTER_EXIT;
+          goto notify_and_die;
+        }
+      if (is_sane_time (tv.tv_sec))
+        {
+          /* It would be nice if time was only allowed to move forward, but
+           * if a single time source is wrong, then it could make it impossible
+           * to recover from once the time is written to disk.
+           */
+          status = SETTER_BAD_TIME;
+          if (!state->opts.dry_run)
+            {
+              if (settimeofday (&tv, NULL) < 0)
+                {
+                  status = SETTER_SET_ERR;
+                  goto notify_and_die;
+                }
+              if (state->opts.should_sync_hwclock &&
+                  sync_hwclock (state->hwclock_fd, tv.tv_sec))
+                {
+                  status = SETTER_NO_RTC;
+                  goto notify_and_die;
+                }
+              if (save && save_fd != -1 &&
+                  save_timestamp_to_fd (save_fd, tv.tv_sec))
+                {
+                  status = SETTER_NO_SAVE;
+                  goto notify_and_die;
+                }
+            }
+          status = SETTER_TIME_SET;
+        }
+      IGNORE_EINTR (write (notify_fd, &status, sizeof(status)));
+    }
+notify_and_die:
+  IGNORE_EINTR (write (notify_fd, &status, sizeof(status)));
+  close (notify_fd);
+  close (save_fd);
+  _exit (status);
+}
diff --git a/src/tlsdate.c b/src/tlsdate.c
index 26e9432..90d88cb 100644
--- a/src/tlsdate.c
+++ b/src/tlsdate.c
@@ -80,26 +80,26 @@
 
 /** Return the proper commandline switches when the user needs information. */
 static void
-usage(void)
+usage (void)
 {
-  fprintf(stderr, "tlsdate usage:\n"
-          " [-h|--help]\n"
-          " [-s|--skip-verification]\n"
-          " [-n|--dont-set-clock]\n"
-          " [-H|--host] [hostname|ip]\n"
-          " [-p|--port] [port number]\n"
-          " [-P|--protocol] [sslv23|sslv3|tlsv1]\n"
-          " [-C|--certcontainer] [dirname|filename]\n"
-          " [-v|--verbose]\n"
-          " [-V|--showtime] [human|raw]\n"
-          " [-t|--timewarp]\n"
-          " [-l|--leap]\n"
-    " [-x|--proxy] [url]\n");
+  fprintf (stderr, "tlsdate usage:\n"
+           " [-h|--help]\n"
+           " [-s|--skip-verification]\n"
+           " [-n|--dont-set-clock]\n"
+           " [-H|--host] [hostname|ip]\n"
+           " [-p|--port] [port number]\n"
+           " [-P|--protocol] [sslv23|sslv3|tlsv1]\n"
+           " [-C|--certcontainer] [dirname|filename]\n"
+           " [-v|--verbose]\n"
+           " [-V|--showtime] [human|raw]\n"
+           " [-t|--timewarp]\n"
+           " [-l|--leap]\n"
+           " [-x|--proxy] [url]\n");
 }
 
 
 int
-main(int argc, char **argv)
+main (int argc, char **argv)
 {
   int verbose;
   int ca_racket;
@@ -112,7 +112,6 @@
   int timewarp;
   int leap;
   const char *proxy;
-
   host = DEFAULT_HOST;
   port = DEFAULT_PORT;
   protocol = DEFAULT_PROTOCOL;
@@ -124,12 +123,11 @@
   timewarp = 0;
   leap = 0;
   proxy = NULL;
-
-  while (1) {
-    int option_index = 0;
-    int c;
-
-    static struct option long_options[] =
+  while (1)
+    {
+      int option_index = 0;
+      int c;
+      static struct option long_options[] =
       {
         {"verbose", 0, 0, 'v'},
         {"showtime", 2, 0, 'V'},
@@ -145,56 +143,83 @@
         {"proxy", 0, 0, 'x'},
         {0, 0, 0, 0}
       };
-
-    c = getopt_long(argc, argv, "vV::shH:p:P:nC:tlx:",
-                    long_options, &option_index);
-    if (c == -1)
-      break;
-
-    switch (c) {
-      case 'v': verbose = 1; break;
-      case 'V': showtime = (optarg && 0 == strcmp("raw", optarg) ? 2:1); break;
-      case 's': ca_racket = 0; break;
-      case 'h': usage(); exit(1); break;
-      case 'H': host = optarg; break;
-      case 'p': port = optarg; break;
-      case 'P': protocol = optarg; break;
-      case 'n': setclock = 0; break;
-      case 'C': ca_cert_container = optarg; break;
-      case 't': timewarp = 1; break;
-      case 'l': leap = 1; break;
-      case 'x': proxy = optarg; break;
-      case '?': break;
-      default : fprintf(stderr, "Unknown option!\n"); usage(); exit(1);
+      c = getopt_long (argc, argv, "vV::shH:p:P:nC:tlx:",
+                       long_options, &option_index);
+      if (c == -1)
+        break;
+      switch (c)
+        {
+        case 'v':
+          verbose = 1;
+          break;
+        case 'V':
+          showtime = (optarg && 0 == strcmp ("raw", optarg) ? 2:1);
+          break;
+        case 's':
+          ca_racket = 0;
+          break;
+        case 'h':
+          usage();
+          exit (1);
+          break;
+        case 'H':
+          host = optarg;
+          break;
+        case 'p':
+          port = optarg;
+          break;
+        case 'P':
+          protocol = optarg;
+          break;
+        case 'n':
+          setclock = 0;
+          break;
+        case 'C':
+          ca_cert_container = optarg;
+          break;
+        case 't':
+          timewarp = 1;
+          break;
+        case 'l':
+          leap = 1;
+          break;
+        case 'x':
+          proxy = optarg;
+          break;
+        case '?':
+          break;
+        default :
+          fprintf (stderr, "Unknown option!\n");
+          usage();
+          exit (1);
+        }
     }
-  }
-
-  if (verbose) {
-    fprintf(stderr,
-      "V: tlsdate version %s\n"
-            "V: We were called with the following arguments:\n"
-            "V: %s host = %s:%s\n",
-            PACKAGE_VERSION,
-      ca_racket ? "validate SSL certificates" : "disable SSL certificate check",
-            host, port);
-    if (0 == ca_racket)
-      fprintf(stderr, "WARNING: Skipping certificate verification!\n");
-  }
-
+  if (verbose)
+    {
+      fprintf (stderr,
+               "V: tlsdate version %s\n"
+               "V: We were called with the following arguments:\n"
+               "V: %s host = %s:%s\n",
+               PACKAGE_VERSION,
+               ca_racket ? "validate SSL certificates" : "disable SSL certificate check",
+               host, port);
+      if (0 == ca_racket)
+        fprintf (stderr, "WARNING: Skipping certificate verification!\n");
+    }
   execlp (TLSDATE_HELPER,
-    "tlsdate",
-    host,
-    port,
-    protocol,
-    (ca_racket ? "racket" : "unchecked"),
-    (verbose ? "verbose" : "quiet"),
-    ca_cert_container,
-    (setclock ? "setclock" : "dont-set-clock"),
-    (showtime ? (showtime == 2 ? "showtime=raw" : "showtime") : "no-showtime"),
-    (timewarp ? "timewarp" : "no-fun"),
-    (leap ? "leapaway" : "holdfast"),
-    (proxy ? proxy : "none"),
-    NULL);
-  perror("Failed to run tlsdate-helper");
+          "tlsdate",
+          host,
+          port,
+          protocol,
+          (ca_racket ? "racket" : "unchecked"),
+          (verbose ? "verbose" : "quiet"),
+          ca_cert_container,
+          (setclock ? "setclock" : "dont-set-clock"),
+          (showtime ? (showtime == 2 ? "showtime=raw" : "showtime") : "no-showtime"),
+            (timewarp ? "timewarp" : "no-fun"),
+            (leap ? "leapaway" : "holdfast"),
+            (proxy ? proxy : "none"),
+            NULL);
+  perror ("Failed to run tlsdate-helper");
   return 1;
 }
diff --git a/src/tlsdate.h b/src/tlsdate.h
index e2ec8b2..3862756 100644
--- a/src/tlsdate.h
+++ b/src/tlsdate.h
@@ -16,6 +16,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <getopt.h>
+#include <limits.h>
+#include <signal.h>
 #include <time.h>
 #include <unistd.h>
 
@@ -35,19 +37,47 @@
 #define MAX_TRIES 10
 #define WAIT_BETWEEN_TRIES 10
 #define SUBPROCESS_TRIES 10
-#define SUBPROCESS_WAIT_BETWEEN_TRIES 3
-#define STEADY_STATE_INTERVAL 86400
+#define SUBPROCESS_WAIT_BETWEEN_TRIES 10
+#define RESOLVER_TIMEOUT 30
+/* Invalidate the network sync once per day. */
+#define STEADY_STATE_INTERVAL (60*60*24)
+/* Check if the clock has drifted once an hour */
+#define CONTINUITY_INTERVAL (60*60)
 #define DEFAULT_SYNC_HWCLOCK 1
 #define DEFAULT_LOAD_FROM_DISK 1
 #define DEFAULT_SAVE_TO_DISK 1
 #define DEFAULT_USE_NETLINK 1
 #define DEFAULT_DRY_RUN 0
-#define MAX_SANE_BACKOFF 600 /* exponential backoff should only go this far */
+#define MAX_SANE_BACKOFF (10*60) /* exponential backoff should only go this far */
 
 #ifndef TLSDATED_MAX_DATE
-#define TLSDATED_MAX_DATE 1999991337 /* this'll be a great bug some day */
+#define TLSDATED_MAX_DATE 1999991337L /* this'll be a great bug some day */
 #endif
 
+#define MAX_EVENT_PRIORITIES 2
+#define PRI_SAVE 0
+#define PRI_NET 1
+#define PRI_WAKE 1
+#define PRI_ANY 1
+
+/* Sync sources in order of "reliability" */
+#define SYNC_TYPE_NONE  (0)
+#define SYNC_TYPE_BUILD  (1 << 0)
+#define SYNC_TYPE_DISK  (1 << 1)
+#define SYNC_TYPE_RTC  (1 << 2)
+#define SYNC_TYPE_PLATFORM  (1 << 3)
+#define SYNC_TYPE_NET  (1 << 4)
+
+/* Simple time setter<>tlsdated protocol */
+#define SETTER_EXIT 0
+#define SETTER_BAD_TIME 1
+#define SETTER_NO_SAVE 2
+#define SETTER_READ_ERR 3
+#define SETTER_TIME_SET 4
+#define SETTER_SET_ERR 5
+#define SETTER_NO_SBOX 6
+#define SETTER_NO_RTC 7
+
 #define TEST_HOST 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', \
                   'c', 'o', 'm'
 #define TEST_HOST_SIZE 14
@@ -57,20 +87,26 @@
 /** The current version of tlsdate. */
 #define tlsdate_version VERSION
 
-struct source {
-	struct source *next;
-	char *host;
-	char *port;
-	char *proxy;
+struct source
+{
+  struct source *next;
+  char *host;
+  char *port;
+  char *proxy;
+  int id;
 };
 
-struct opts {
+struct opts
+{
+  const char *user;
+  const char *group;
   int max_tries;
   int min_steady_state_interval;
   int wait_between_tries;
   int subprocess_tries;
   int subprocess_wait_between_tries;
   int steady_state_interval;
+  int continuity_interval;
   const char *base_path;
   char **base_argv;
   char **argv;
@@ -86,14 +122,96 @@
   char *proxy;
 };
 
+#define MAX_FQDN_LEN 255
+#define MAX_SCHEME_LEN 9
+#define MAX_PORT_LEN 6  /* incl. : */
+#define MAX_PROXY_URL (MAX_FQDN_LEN + MAX_SCHEME_LEN + MAX_PORT_LEN + 1)
+
+enum event_id_t
+{
+  E_RESOLVER = 0,
+  E_TLSDATE,
+  E_TLSDATE_STATUS,
+  E_TLSDATE_TIMEOUT,
+  E_SAVE,
+  E_SIGCHLD,
+  E_SIGTERM,
+  E_STEADYSTATE,
+  E_ROUTEUP,
+  E_MAX
+};
+
+struct event_base;
+/* This struct is used for passing tlsdated runtime state between
+ * events/ in its event loop.
+ */
+struct state
+{
+  struct opts opts;
+  struct event_base *base;
+  void *dbus;
+  char **envp;
+
+  time_t clock_delta;
+  int last_sync_type;
+  time_t last_time;
+
+  char timestamp_path[PATH_MAX];
+  int hwclock_fd;
+  char dynamic_proxy[MAX_PROXY_URL];
+  /* Event triggered events */
+
+  struct event *events[E_MAX];
+  int tlsdate_monitor_fd;
+  pid_t tlsdate_pid;
+  pid_t setter_pid;
+  int setter_save_fd;
+  int setter_notify_fd;
+  uint32_t backoff;
+  int tries;
+  int resolving;
+  int running;  /* tlsdate itself */
+  int exitting;
+};
+
 int is_sane_time (time_t ts);
 int load_disk_timestamp (const char *path, time_t * t);
 void save_disk_timestamp (const char *path, time_t t);
 int add_jitter (int base, int jitter);
-int tlsdate (struct opts *opts, char *argv[]);
+void time_setter_coprocess (int time_fd, int notify_fd, struct state *state);
+int tlsdate (struct state *state);
+
+int save_timestamp_to_fd (int fd, time_t t);
+void set_conf_defaults (struct opts *opts);
+int new_tlsdate_monitor_pipe (int fds[2]);
+int read_tlsdate_response (int fd, time_t *t);
+
+void invalidate_time (struct state *state);
+int check_continuity (time_t *delta);
+
+void action_check_continuity (int fd, short what, void *arg);
+void action_kickoff_time_sync (int fd, short what, void *arg);
+void action_invalidate_time (int fd, short what, void *arg);
+void action_stdin_wakeup (int fd, short what, void *arg);
+void action_netlink_ready (int fd, short what, void *arg);
+void action_run_tlsdate (int fd, short what, void *arg);
+void action_sigterm (int fd, short what, void *arg);
+void action_sync_and_save (int fd, short what, void *arg);
+void action_time_set (int fd, short what, void *arg);
+void action_tlsdate_status (int fd, short what, void *arg);
+
+int setup_event_timer_continuity (struct state *state);
+int setup_event_timer_sync (struct state *state);
+int setup_event_route_up (struct state *state);
+int setup_time_setter (struct state *state);
+int setup_tlsdate_status (struct state *state);
+int setup_sigchld_event (struct state *state, int persist);
+
+void report_setter_error (siginfo_t *info);
 
 /** This is where we store parsed commandline options. */
-typedef struct {
+typedef struct
+{
   int verbose;
   int ca_racket;
   int help;
diff --git a/src/tlsdated-unittest.c b/src/tlsdated-unittest.c
index 7093d6f..0709467 100644
--- a/src/tlsdated-unittest.c
+++ b/src/tlsdated-unittest.c
@@ -9,193 +9,301 @@
 
 #include "src/test_harness.h"
 #include "src/tlsdate.h"
+#include "src/util.h"
 
+#include <event2/event.h>
 #include <fcntl.h>
 #include <limits.h>
 #include <stdlib.h>
 #include <unistd.h>
 
-FIXTURE(tempdir) {
+FIXTURE (tempdir)
+{
   char path[PATH_MAX];
 };
 
-FIXTURE_SETUP(tempdir) {
+FIXTURE_SETUP (tempdir)
+{
   char *p;
-  strncpy(self->path, "/tmp/tlsdated-unit-XXXXXX", sizeof(self->path));
-  p = mkdtemp(self->path);
-  ASSERT_NE(NULL, p);
+  strncpy (self->path, "/tmp/tlsdated-unit-XXXXXX", sizeof (self->path));
+  p = mkdtemp (self->path);
+  ASSERT_NE (NULL, p);
 }
 
-int rmrf(char *dir) {
+int rmrf (char *dir)
+{
   char buf[256];
-  snprintf(buf, sizeof(buf), "rm -rf %s", dir);
-  return system(buf);
+  snprintf (buf, sizeof (buf), "rm -rf %s", dir);
+  return system (buf);
 }
 
-FIXTURE_TEARDOWN(tempdir) {
-  ASSERT_EQ(0, rmrf(self->path));
+FIXTURE_TEARDOWN (tempdir)
+{
+  ASSERT_EQ (0, rmrf (self->path));
 }
 
-int write_time(const char *path, time_t time) {
-  int fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, 0600);
+int write_time (const char *path, time_t time)
+{
+  int fd = open (path, O_WRONLY | O_TRUNC | O_CREAT, 0600);
   if (fd == -1)
     return 1;
-  if (write(fd, &time, sizeof(time)) != sizeof(time)) {
-    close(fd);
+  if (save_timestamp_to_fd (fd, time))
     return 1;
-  }
-  return close(fd);
+  if (write (fd, &time, sizeof (time)) != sizeof (time))
+    {
+      close (fd);
+      return 1;
+    }
+  return close (fd);
 }
 
-int read_time(const char *path, time_t* time) {
-  int fd = open(path, O_RDONLY);
+int read_time (const char *path, time_t* time)
+{
+  int fd = open (path, O_RDONLY);
   if (fd == -1)
     return 1;
-  if (read(fd, time, sizeof(*time)) != sizeof(*time)) {
-    close(fd);
-    return 1;
-  }
-  return close(fd);
+  if (read (fd, time, sizeof (*time)) != sizeof (*time))
+    {
+      close (fd);
+      return 1;
+    }
+  return close (fd);
 }
 
-TEST(sane_time) {
-  ASSERT_EQ(0, is_sane_time(0));
-  ASSERT_EQ(0, is_sane_time(INT_MAX));
+TEST (sane_time)
+{
+  ASSERT_EQ (0, is_sane_time (0));
+  ASSERT_EQ (0, is_sane_time (INT_MAX));
 }
 
-TEST(sane_host_time) {
-  ASSERT_EQ(1, is_sane_time(time(NULL)));
+TEST (sane_host_time)
+{
+  ASSERT_EQ (1, is_sane_time (time (NULL)));
 }
 
-TEST_F(tempdir, load_time) {
+TEST_F (tempdir, load_time)
+{
   char buf[PATH_MAX];
   time_t tm = 3;
-  time_t now = time(NULL);
-  snprintf(buf, sizeof(buf), "%s/load", self->path);
-
-  ASSERT_EQ(0, write_time(buf, 0));
-  ASSERT_EQ(-1, load_disk_timestamp(buf, &tm));
-  ASSERT_EQ(3, tm);
-
-  ASSERT_EQ(0, write_time(buf, INT_MAX));
-  ASSERT_EQ(-1, load_disk_timestamp(buf, &tm));
-  ASSERT_EQ(3, tm);
-
-  ASSERT_EQ(0, write_time(buf, now));
-  ASSERT_EQ(0, truncate(buf, 2));
-  ASSERT_EQ(-1, load_disk_timestamp(buf, &tm));
-  ASSERT_EQ(3, tm);
-
-  ASSERT_EQ(0, unlink(buf));
-  ASSERT_EQ(-1, load_disk_timestamp(buf, &tm));
-  ASSERT_EQ(3, tm);
-
-  ASSERT_EQ(0, write_time(buf, now));
-  ASSERT_EQ(0, load_disk_timestamp(buf, &tm));
-  ASSERT_EQ(now, tm);
+  time_t now = time (NULL);
+  snprintf (buf, sizeof (buf), "%s/load", self->path);
+  ASSERT_EQ (0, write_time (buf, 0));
+  ASSERT_EQ (-1, load_disk_timestamp (buf, &tm));
+  ASSERT_EQ (3, tm);
+  ASSERT_EQ (0, write_time (buf, INT_MAX));
+  ASSERT_EQ (-1, load_disk_timestamp (buf, &tm));
+  ASSERT_EQ (3, tm);
+  ASSERT_EQ (0, write_time (buf, now));
+  ASSERT_EQ (0, truncate (buf, 2));
+  ASSERT_EQ (-1, load_disk_timestamp (buf, &tm));
+  ASSERT_EQ (3, tm);
+  ASSERT_EQ (0, unlink (buf));
+  ASSERT_EQ (-1, load_disk_timestamp (buf, &tm));
+  ASSERT_EQ (3, tm);
+  ASSERT_EQ (0, write_time (buf, now));
+  ASSERT_EQ (0, load_disk_timestamp (buf, &tm));
+  ASSERT_EQ (now, tm);
 }
 
-TEST_F(tempdir, save_time) {
+
+TEST_F (tempdir, save_time)
+{
   char buf[PATH_MAX];
-  time_t now = time(NULL);
+  time_t now = time (NULL);
   time_t tm;
-  snprintf(buf, sizeof(buf), "%s/save", self->path);
-
-  save_disk_timestamp(buf, now);
-  ASSERT_EQ(0, read_time(buf, &tm));
-  EXPECT_EQ(now, tm);
+  snprintf (buf, sizeof (buf), "%s/save", self->path);
+  ASSERT_EQ (0, write_time (buf, now));
+  ASSERT_EQ (0, read_time (buf, &tm));
+  EXPECT_EQ (now, tm);
 }
 
-TEST(tlsdate_tests) {
-  struct source source = {
+FIXTURE (tlsdate)
+{
+  struct state state;
+  struct timeval timeout;
+};
+
+
+FIXTURE_SETUP (tlsdate)
+{
+  memset (self, 0, sizeof (self));
+  /* TODO(wad) make this use the same function tlsdated uses. */
+  self->state.base = event_base_new();
+  set_conf_defaults (&self->state.opts);
+  ASSERT_NE (NULL, self->state.base);
+  event_base_priority_init (self->state.base, MAX_EVENT_PRIORITIES);
+  ASSERT_EQ (0, setup_sigchld_event (&self->state, 1));
+  self->state.events[E_TLSDATE] = event_new (self->state.base, -1, EV_TIMEOUT,
+                                  action_run_tlsdate, &self->state);
+  ASSERT_NE (NULL, self->state.events[E_TLSDATE]);
+  event_priority_set (self->state.events[E_TLSDATE], PRI_NET);
+  /* The timeout and fd will be filled in per-call. */
+  ASSERT_EQ (0, setup_tlsdate_status (&self->state));
+  self->timeout.tv_sec = 1;
+}
+
+FIXTURE_TEARDOWN (tlsdate)
+{
+  int i;
+  for (i = 0; i < E_MAX; ++i)
+    {
+      struct event *e = self->state.events[i];
+      if (e)
+        {
+          int fd = event_get_fd (e);
+          if (fd >= 0 && ! (event_get_events (e) & EV_SIGNAL))
+            close (fd);
+          event_free (e);
+          self->state.events[i] = NULL;
+        }
+    }
+  /* The other half was closed above. */
+  close (self->state.tlsdate_monitor_fd);
+  if (self->state.tlsdate_pid)
+    {
+      kill (self->state.tlsdate_pid, SIGKILL);
+      waitpid (self->state.tlsdate_pid, NULL, WNOHANG);
+    }
+  if (self->state.base)
+    event_base_free (self->state.base);
+}
+
+static int
+runner (FIXTURE_DATA (tlsdate) *self, time_t *newtime)
+{
+  if (newtime)
+    *newtime = 0;
+  trigger_event (&self->state, E_TLSDATE, 0);
+  event_base_loopexit (self->state.base, &self->timeout);
+  if (event_base_dispatch (self->state.base))
+    return -1;
+  if (self->state.last_time)
+    {
+      if (newtime)
+        *newtime = self->state.last_time;
+      return 0;
+    }
+  return 1;
+}
+
+TEST_F (tlsdate, runner)
+{
+  struct source source =
+  {
     .next = NULL,
-    .host = "<host>",
-    .port = "<port>",
-    .proxy = "<proxy>"
+    .host = "host1",
+    .port = "port1",
+    .proxy = "proxy1"
   };
   char *args[] = { "/nonexistent", NULL, NULL };
-  struct opts opts;
-  memset(&opts, 0, sizeof(opts));
-  opts.sources = &source;
-  opts.base_argv = args;
-  opts.subprocess_tries = 2;
-  opts.subprocess_wait_between_tries = 1;
   extern char **environ;
-  EXPECT_EQ(1, tlsdate(&opts, environ));
+  self->state.opts.sources = &source;
+  self->state.opts.base_argv = args;
+  self->state.opts.subprocess_tries = 2;
+  self->state.opts.subprocess_wait_between_tries = 1;
+  self->state.opts.max_tries = 3;
+  self->state.envp = environ;
+  EXPECT_EQ (1, runner (self, NULL));
   args[0] = "/bin/false";
-  EXPECT_EQ(1, tlsdate(&opts, environ));
-  args[0] = "/bin/true";
-  EXPECT_EQ(0, tlsdate(&opts, environ));
+  self->state.tries = 0;
+  self->state.last_sync_type = SYNC_TYPE_NONE;
+  EXPECT_EQ (1, runner (self, NULL));
+  args[0] = "src/test/check-host-1";
+  self->state.tries = 0;
+  self->state.last_sync_type = SYNC_TYPE_NONE;
+  EXPECT_EQ (0, runner (self, NULL));
   args[0] = "src/test/sleep-wrap";
   args[1] = "3";
-  EXPECT_EQ(-1, tlsdate(&opts, environ));
-  opts.subprocess_wait_between_tries = 5;
-  EXPECT_EQ(0, tlsdate(&opts, environ));
+  self->state.tries = 0;
+  self->state.last_sync_type = SYNC_TYPE_NONE;
+  EXPECT_EQ (0, runner (self, NULL));
 }
 
-TEST(jitter) {
+TEST (jitter)
+{
   int i = 0;
   int r;
   const int kBase = 100;
   const int kJitter = 25;
   int nonequal = 0;
-  for (i = 0; i < 1000; i++) {
-    r = add_jitter(kBase, kJitter);
-    EXPECT_GE(r, kBase - kJitter);
-    EXPECT_LE(r, kBase + kJitter);
-    if (r != kBase)
-      nonequal++;
-  }
-  EXPECT_NE(nonequal, 0);
+  for (i = 0; i < 1000; i++)
+    {
+      r = add_jitter (kBase, kJitter);
+      EXPECT_GE (r, kBase - kJitter);
+      EXPECT_LE (r, kBase + kJitter);
+      if (r != kBase)
+        nonequal++;
+    }
+  EXPECT_NE (nonequal, 0);
 }
 
-TEST(rotate_hosts) {
-  struct source s2 = {
+TEST_F (tlsdate, rotate_hosts)
+{
+  struct source s2 =
+  {
     .next = NULL,
     .host = "host2",
     .port = "port2",
     .proxy = "proxy2"
   };
-  struct source s1 = {
+  struct source s1 =
+  {
     .next = &s2,
     .host = "host1",
     .port = "port1",
     .proxy = "proxy1"
   };
-  struct opts opts;
-  char *args[] = { "src/test/rotate", NULL };
-  memset(&opts, 0, sizeof(opts));
-  opts.sources = &s1;
-  opts.base_argv = args;
-  opts.subprocess_tries = 2;
-  opts.subprocess_wait_between_tries = 1;
+  char *args[] = { "src/test/check-host-1",  NULL };
   extern char **environ;
-  EXPECT_EQ(1, tlsdate(&opts, environ));
-  EXPECT_EQ(2, tlsdate(&opts, environ));
-  EXPECT_EQ(1, tlsdate(&opts, environ));
-  EXPECT_EQ(2, tlsdate(&opts, environ));
+  self->state.envp = environ;
+  self->state.opts.sources = &s1;
+  self->state.opts.base_argv = args;
+  self->state.opts.subprocess_tries = 2;
+  self->state.opts.subprocess_wait_between_tries = 1;
+  self->state.opts.max_tries = 5;
+  self->timeout.tv_sec = 2;
+  EXPECT_EQ (0, runner (self, NULL));
+  self->state.tries = 0;
+  args[0] = "src/test/check-host-2";
+  self->state.last_sync_type = SYNC_TYPE_NONE;
+  EXPECT_EQ (0, runner (self, NULL));
+  self->state.tries = 0;
+  args[0] = "src/test/check-host-1";
+  self->state.last_sync_type = SYNC_TYPE_NONE;
+  EXPECT_EQ (0, runner (self, NULL));
+  self->state.tries = 0;
+  args[0] = "src/test/check-host-2";
+  self->state.last_sync_type = SYNC_TYPE_NONE;
+  EXPECT_EQ (0, runner (self, NULL));
 }
 
-TEST(proxy_override) {
-  struct source s1 = {
+TEST_F (tlsdate, proxy_override)
+{
+  struct source s1 =
+  {
     .next = NULL,
     .host = "host",
     .port = "port",
     .proxy = NULL,
   };
-  struct opts opts;
   char *args[] = { "src/test/proxy-override", NULL };
-  memset(&opts, 0, sizeof(opts));
-  opts.sources = &s1;
-  opts.base_argv = args;
-  opts.subprocess_tries = 2;
-  opts.subprocess_wait_between_tries = 1;
   extern char **environ;
-  EXPECT_EQ(1, tlsdate(&opts, environ));
+  self->state.envp = environ;
+  self->state.opts.sources = &s1;
+  self->state.opts.base_argv = args;
+  self->state.opts.subprocess_tries = 2;
+  self->state.opts.subprocess_wait_between_tries = 1;
+  EXPECT_EQ (0, runner (self, NULL));
+  EXPECT_EQ (RECENT_COMPILE_DATE + 1, self->state.last_time);
   s1.proxy = "socks5://bad.proxy";
-  EXPECT_EQ(2, tlsdate(&opts, environ));
-  opts.proxy = "socks5://good.proxy";
-  EXPECT_EQ(0, tlsdate(&opts, environ));
+  self->state.tries = 0;
+  self->state.last_sync_type = SYNC_TYPE_NONE;
+  EXPECT_EQ (0, runner (self, NULL));
+  EXPECT_EQ (RECENT_COMPILE_DATE + 3, self->state.last_time);
+  self->state.opts.proxy = "socks5://good.proxy";
+  self->state.tries = 0;
+  self->state.last_sync_type = SYNC_TYPE_NONE;
+  EXPECT_EQ (0, runner (self, NULL));
+  EXPECT_EQ (RECENT_COMPILE_DATE + 2, self->state.last_time);
 }
-
 TEST_HARNESS_MAIN
diff --git a/src/tlsdated.c b/src/tlsdated.c
index 5723ddf..b54f02b 100644
--- a/src/tlsdated.c
+++ b/src/tlsdated.c
@@ -15,11 +15,13 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <grp.h> /* setgroups */
 #include <fcntl.h>
 #include <limits.h>
 #include <linux/rtc.h>
 #include <openssl/rand.h>
 #include <stdarg.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -28,16 +30,20 @@
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/wait.h>
+#include <sys/uio.h>
 #include <time.h>
 #include <unistd.h>
 
+#include <event2/event.h>
+
 #include "src/conf.h"
 #include "src/routeup.h"
 #include "src/util.h"
 #include "src/tlsdate.h"
+#include "src/dbus.h"
+#include "src/platform.h"
 
 const char *kCacheDir = DEFAULT_DAEMON_CACHEDIR;
-const char *kTempSuffix = DEFAULT_DAEMON_TMPSUFFIX;
 
 int
 is_sane_time (time_t ts)
@@ -45,96 +51,6 @@
   return ts > RECENT_COMPILE_DATE && ts < TLSDATED_MAX_DATE;
 }
 
-void
-build_argv(struct opts *opts)
-{
-  int argc;
-  char **new_argv;
-
-  assert(opts->sources);
-  /* choose the next source in the list; if we're at the end, start over. */
-  if (!opts->cur_source || !opts->cur_source->next)
-    opts->cur_source = opts->sources;
-  else
-    opts->cur_source = opts->cur_source->next;
-
-  if (opts->argv) {
-    free(opts->argv);
-    opts->argv = NULL;
-  }
-
-  for (argc = 0; opts->base_argv[argc]; argc++)
-    ;
-  argc++; /* uncounted null terminator */
-  argc += 6;  /* -H host -p port -x proxy */
-  new_argv = malloc (argc * sizeof(char *));
-  if (!new_argv)
-    fatal ("out of memory building argv");
-  for (argc = 0; opts->base_argv[argc]; argc++)
-    new_argv[argc] = opts->base_argv[argc];
-  new_argv[argc++] = "-H";
-  new_argv[argc++] = opts->cur_source->host;
-  new_argv[argc++] = "-p";
-  new_argv[argc++] = opts->cur_source->port;
-  if (opts->cur_source->proxy || opts->proxy) {
-    new_argv[argc++] = (char *) "-x";
-    new_argv[argc++] = opts->proxy ? opts->proxy : opts->cur_source->proxy;
-  }
-  new_argv[argc++] = NULL;
-  opts->argv = new_argv;
-}
-
-/*
- * Run tlsdate in a child process. We fork it off, then wait a specified time
- * for it to exit; if it hasn't exited by then, we kill it and log a baffled
- * message. We return tlsdate's exit code if tlsdate exits normally, and a
- * negative value if we can't launch it or it exits uncleanly, so this function
- * returns 0 for success and nonzero for failure, with >0 being a tlsdate exit
- * code and <0 being an exec/fork/wait error.
- */
-int
-tlsdate (struct opts *opts, char *envp[])
-{
-  pid_t pid;
-  build_argv(opts);
-  
-  if ((pid = fork ()) > 0)
-    {
-      /*
-       * We launched tlsdate; wait for up to kMaxTries intervals of
-       * kWaitBetweenTries for it to exit, then kill it if it still
-       * hasn't.
-       */
-      int status = -1;
-      int i = 0;
-      for (i = 0; i < opts->subprocess_tries; ++i)
-  {
-    info ("wait for child attempt %d", i);
-    if (waitpid (-1, &status, WNOHANG) > 0)
-      break;
-    sleep (opts->subprocess_wait_between_tries);
-  }
-      if (i == opts->subprocess_tries)
-  {
-    error ("child hung?");
-    kill (pid, SIGKILL);
-    /* still have to wait() so we don't leak the child. */
-    wait (&status);
-    return -1;
-  }
-      info ("child exited with %d", status);
-      return WIFEXITED (status) ? WEXITSTATUS (status) : -1;
-    }
-  else if (pid < 0)
-    {
-      pinfo ("fork() failed");
-      return -1;
-    }
-  execve (opts->argv[0], opts->argv, envp);
-  pinfo ("execve() failed");
-  exit (1);
-}
-
 /*
  * Load a time value out of the file named by path. Returns 0 if successful,
  * -1 if not. The file contains the time in seconds since epoch in host byte
@@ -143,14 +59,17 @@
 int
 load_disk_timestamp (const char *path, time_t * t)
 {
-  int fd = open (path, O_RDONLY | O_NOFOLLOW);
+  struct iovec iov[1];
+  int fd = open (path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
   time_t tmpt;
+  iov[0].iov_base = &tmpt;
+  iov[0].iov_len = sizeof (tmpt);
   if (fd < 0)
     {
       perror ("Can't open %s for reading", path);
       return -1;
     }
-  if (read (fd, &tmpt, sizeof (tmpt)) != sizeof (tmpt))
+  if (preadv (fd, iov, 1, 0) != sizeof (tmpt))
     {
       perror ("Can't read seconds from %s", path);
       close (fd);
@@ -159,178 +78,13 @@
   close (fd);
   if (!is_sane_time (tmpt))
     {
-      perror ("Timevalue not sane: %lu", tmpt);
+      error ("Disk timestamp is not sane: %ld", tmpt);
       return -1;
     }
   *t = tmpt;
   return 0;
 }
 
-/* Save a time value to the file named by path. */
-void
-save_disk_timestamp (const char *path, time_t t)
-{
-  char tmp[PATH_MAX];
-  int fd;
-
-  if (snprintf (tmp, sizeof (tmp), "%s%s", path, kTempSuffix) >= sizeof (tmp))
-    {
-      pinfo ("Path %s too long to use", path);
-      exit (1);
-    }
-
-  if ((fd = open (tmp, O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC,
-      S_IRUSR | S_IWUSR)) < 0)
-    {
-      pinfo ("open failed");
-      return;
-    }
-  if (write (fd, &t, sizeof (t)) != sizeof (t))
-    {
-      pinfo ("write failed");
-      close (fd);
-      return;
-    }
-  if (close (fd))
-    {
-      pinfo ("close failed");
-      return;
-    }
-  if (rename (tmp, path))
-    pinfo ("rename failed");
-}
-
-/*
- * Set the hardware clock referred to by fd (which should be a descriptor to
- * some device that implements the interface documented in rtc(4)) to the system
- * time. See hwclock(8) for details of why this is important. If we fail, we
- * just return - there's nothing the caller can really do about a failure of
- * this function except try later.
- */
-void
-sync_hwclock (int fd)
-{
-  struct timeval tv;
-  struct tm *tm;
-  struct rtc_time rtctm;
-
-  if (gettimeofday (&tv, NULL))
-    {
-      pinfo ("gettimeofday() failed");
-      return;
-    }
-
-  tm = gmtime (&tv.tv_sec);
-
-  /* these structs are identical, but separately defined */
-  rtctm.tm_sec = tm->tm_sec;
-  rtctm.tm_min = tm->tm_min;
-  rtctm.tm_hour = tm->tm_hour;
-  rtctm.tm_mday = tm->tm_mday;
-  rtctm.tm_mon = tm->tm_mon;
-  rtctm.tm_year = tm->tm_year;
-  rtctm.tm_wday = tm->tm_wday;
-  rtctm.tm_yday = tm->tm_yday;
-  rtctm.tm_isdst = tm->tm_isdst;
-
-  if (ioctl (fd, RTC_SET_TIME, &rtctm))
-    {
-      pinfo ("ioctl(%d, RTC_SET_TIME, ...) failed", fd);
-      return;
-    }
-
-  info ("synced rtc to sysclock");
-}
-
-/*
- * Wait for a single event to happen. If should_netlink is true, we ask the
- * supplied routeup context to wait for an event; otherwise, we wait for a byte
- * of input on stdin. Semantics (for return value) are the same as for
- * routeup_once().
- */
-int
-wait_for_event (struct routeup *rtc, int should_netlink, int timeout)
-{
-  char buf[1];
-  fd_set fds;
-  struct timeval tv;
-  int r;
-
-  if (should_netlink)
-    return routeup_once (rtc, timeout);
-
-  tv.tv_sec = timeout;
-  tv.tv_usec = 0;
-  FD_ZERO (&fds);
-  FD_SET (STDIN_FILENO, &fds);
-  r = select (STDIN_FILENO + 1, &fds, NULL, NULL, &tv);
-  if (r > 0)
-    return read (STDIN_FILENO, buf, sizeof (buf)) != 1;
-  return r == 0 ? 1 : -1;
-}
-
-char timestamp_path[PATH_MAX];
-
-void
-sync_and_save (int hwclock_fd, int should_sync, int should_save)
-{
-  struct timeval tv;
-  if (should_sync)
-    sync_hwclock (hwclock_fd);
-  if (should_save)
-    {
-      if (gettimeofday (&tv, NULL))
-  pfatal ("gettimeofday() failed");
-      save_disk_timestamp (timestamp_path, tv.tv_sec);
-    }
-}
-
-int
-add_jitter (int base, int jitter)
-{
-  int n = 0;
-  if (!jitter)
-    return base;
-  if (RAND_bytes((unsigned char *)&n, sizeof(n)) != 1)
-    fatal ("RAND_bytes() failed");
-  return base + (abs(n) % (2 * jitter)) - jitter;
-}
-
-#ifdef TLSDATED_MAIN
-#ifdef HAVE_DBUS
-void
-dbus_announce (void)
-{
-  char *argv[] = { TLSDATE_DBUS_ANNOUNCE, NULL };
-  pid_t pid = fork();
-  if (!pid) {
-    drop_privs_to (DBUS_USER, DBUS_GROUP);
-    pid = fork();
-    if (!pid)
-      exit(execve(argv[0], argv, NULL));
-    else
-      exit(pid < 0);
-  } else if (pid > 0) {
-    wait(NULL);
-  }
-}
-#else
-void dbus_announce(void)
-{
-}
-#endif
-
-void
-sigterm_handler (int _unused)
-{
-  struct timeval tv;
-  if (gettimeofday (&tv, NULL))
-    /* can't use stdio or syslog inside a sig handler */
-    exit (2);
-  save_disk_timestamp (timestamp_path, tv.tv_sec);
-  exit (0);
-}
-
 void
 usage (const char *progn)
 {
@@ -348,23 +102,29 @@
   printf ("  -j <n>    add up to n seconds jitter to steady state checks\n");
   printf ("  -l        don't load disk timestamps\n");
   printf ("  -s        don't save disk timestamps\n");
+  printf ("  -u <user> user to change to\n");
+  printf ("  -g <grp>  group to change to\n");
   printf ("  -v        be verbose\n");
   printf ("  -x <h>    set proxy for subprocs to h\n");
   printf ("  -h        this\n");
 }
 
 void
-set_conf_defaults(struct opts *opts)
+set_conf_defaults (struct opts *opts)
 {
-  static char *kDefaultArgv[] = {
+  static char *kDefaultArgv[] =
+  {
     DEFAULT_TLSDATE, "-H", DEFAULT_HOST, NULL
   };
+  opts->user = UNPRIV_USER;
+  opts->group = UNPRIV_GROUP;
   opts->max_tries = MAX_TRIES;
   opts->min_steady_state_interval = STEADY_STATE_INTERVAL;
   opts->wait_between_tries = WAIT_BETWEEN_TRIES;
   opts->subprocess_tries = SUBPROCESS_TRIES;
   opts->subprocess_wait_between_tries = SUBPROCESS_WAIT_BETWEEN_TRIES;
   opts->steady_state_interval = STEADY_STATE_INTERVAL;
+  opts->continuity_interval = CONTINUITY_INTERVAL;
   opts->base_path = kCacheDir;
   opts->base_argv = kDefaultArgv;
   opts->argv = NULL;
@@ -381,80 +141,83 @@
 }
 
 void
-parse_argv(struct opts *opts, int argc, char *argv[])
+parse_argv (struct opts *opts, int argc, char *argv[])
 {
   int opt;
-
-  while ((opt = getopt (argc, argv, "hwrpt:d:T:D:c:a:lsvm:j:f:x:")) != -1)
+  while ((opt = getopt (argc, argv, "hwrpt:d:T:D:c:a:lsvm:j:f:x:u:g:")) != -1)
     {
       switch (opt)
-  {
-  case 'w':
-    opts->should_sync_hwclock = 0;
-    break;
-  case 'r':
-    opts->should_netlink = 0;
-    break;
-  case 'p':
-    opts->dry_run = 1;
-    break;
-  case 't':
-    opts->max_tries = atoi (optarg);
-    break;
-  case 'd':
-    opts->wait_between_tries = atoi (optarg);
-    break;
-  case 'T':
-    opts->subprocess_tries = atoi (optarg);
-    break;
-  case 'D':
-    opts->subprocess_wait_between_tries = atoi (optarg);
-    break;
-  case 'c':
-    opts->base_path = optarg;
-    break;
-  case 'a':
-    opts->steady_state_interval = atoi (optarg);
-    break;
-  case 'l':
-    opts->should_load_disk = 0;
-    break;
-  case 's':
-    opts->should_save_disk = 0;
-    break;
-  case 'v':
-    verbose = 1;
-    break;
-  case 'm':
-    opts->min_steady_state_interval = atoi (optarg);
-    break;
-  case 'j':
-    opts->jitter = atoi (optarg);
-    break;
-  case 'f':
-    opts->conf_file = optarg;
-    break;
-  case 'x':
-    opts->proxy = optarg;
-    break;
-  case 'h':
-  default:
-    usage (argv[0]);
-    exit (1);
-  }
+        {
+        case 'w':
+          opts->should_sync_hwclock = 0;
+          break;
+        case 'r':
+          opts->should_netlink = 0;
+          break;
+        case 'p':
+          opts->dry_run = 1;
+          break;
+        case 't':
+          opts->max_tries = atoi (optarg);
+          break;
+        case 'd':
+          opts->wait_between_tries = atoi (optarg);
+          break;
+        case 'T':
+          opts->subprocess_tries = atoi (optarg);
+          break;
+        case 'D':
+          opts->subprocess_wait_between_tries = atoi (optarg);
+          break;
+        case 'c':
+          opts->base_path = optarg;
+          break;
+        case 'a':
+          opts->steady_state_interval = atoi (optarg);
+          break;
+        case 'l':
+          opts->should_load_disk = 0;
+          break;
+        case 's':
+          opts->should_save_disk = 0;
+          break;
+        case 'v':
+          verbose = 1;
+          break;
+        case 'm':
+          opts->min_steady_state_interval = atoi (optarg);
+          break;
+        case 'j':
+          opts->jitter = atoi (optarg);
+          break;
+        case 'f':
+          opts->conf_file = optarg;
+          break;
+        case 'x':
+          opts->proxy = optarg;
+          break;
+        case 'u':
+          opts->user = optarg;
+          break;
+        case 'g':
+          opts->group = optarg;
+          break;
+        case 'h':
+        default:
+          usage (argv[0]);
+          exit (1);
+        }
     }
-
   if (optind < argc)
     opts->base_argv = argv + optind;
-
   /* Validate arguments */
 }
 
 static
-void add_source_to_conf(struct opts *opts, char *host, char *port, char *proxy)
+void add_source_to_conf (struct opts *opts, char *host, char *port, char *proxy)
 {
   struct source *s;
-  struct source *source = malloc (sizeof *source);
+  struct source *source = calloc (1, sizeof *source);
   if (!source)
     fatal ("out of memory for source");
   source->host = strdup (host);
@@ -463,22 +226,28 @@
   source->port = strdup (port);
   if (!source->port)
     fatal ("out of memory for port");
-  if (proxy) {
-    source->proxy = strdup (proxy);
-    if (!source->proxy)
-      fatal ("out of memory for proxy");
-  }
-  if (!opts->sources) {
-    opts->sources = source;
-  } else {
-    for (s = opts->sources; s->next; s = s->next)
-      ;
-    s->next = source;
-  }
+  if (proxy)
+    {
+      source->proxy = strdup (proxy);
+      if (!source->proxy)
+        fatal ("out of memory for proxy");
+    }
+  if (!opts->sources)
+    {
+      opts->sources = source;
+      source->id = 0;
+    }
+  else
+    {
+      for (s = opts->sources; s->next; s = s->next)
+        ;
+      source->id = s->id + 1;
+      s->next = source;
+    }
 }
 
 static struct conf_entry *
-parse_source(struct opts *opts, struct conf_entry *conf)
+parse_source (struct opts *opts, struct conf_entry *conf)
 {
   char *host = NULL;
   char *port = NULL;
@@ -490,29 +259,30 @@
    *   [proxy <proxy>]
    * end
    */
-  assert(!strcmp(conf->key, "source"));
+  assert (!strcmp (conf->key, "source"));
   conf = conf->next;
-  while (conf && strcmp(conf->key, "end")) {
-    if (!strcmp(conf->key, "host"))
-      host = conf->value;
-    else if (!strcmp(conf->key, "port"))
-      port = conf->value;
-    else if (!strcmp(conf->key, "proxy"))
-      proxy = conf->value;
-    else
-      fatal ("malformed config: '%s' in source stanza", conf->key);
-    conf = conf->next;
-  }
+  while (conf && strcmp (conf->key, "end"))
+    {
+      if (!strcmp (conf->key, "host"))
+        host = conf->value;
+      else if (!strcmp (conf->key, "port"))
+        port = conf->value;
+      else if (!strcmp (conf->key, "proxy"))
+        proxy = conf->value;
+      else
+        fatal ("malformed config: '%s' in source stanza", conf->key);
+      conf = conf->next;
+    }
   if (!conf)
     fatal ("unclosed source stanza");
   if (!host || !port)
     fatal ("incomplete source stanza (needs host, port)");
-  add_source_to_conf(opts, host, port, proxy);
+  add_source_to_conf (opts, host, port, proxy);
   return conf;
 }
 
 void
-load_conf(struct opts *opts)
+load_conf (struct opts *opts)
 {
   FILE *f;
   struct conf_entry *conf, *e;
@@ -520,58 +290,92 @@
   if (!opts->conf_file)
     conf_file = DEFAULT_CONF_FILE;
   f = fopen (conf_file, "r");
-  if (!f) {
-    if (opts->conf_file) {
-      pfatal ("can't open conf file '%s'", opts->conf_file);
-    } else {
-      pinfo ("can't open conf file '%s'", conf_file);
-      return;
+  if (!f)
+    {
+      if (opts->conf_file)
+        {
+          pfatal ("can't open conf file '%s'", opts->conf_file);
+        }
+      else
+        {
+          pinfo ("can't open conf file '%s'", conf_file);
+          return;
+        }
     }
-  }
   conf = conf_parse (f);
   if (!conf)
     pfatal ("can't parse config file");
-
-  for (e = conf; e; e = e->next) {
-    if (!strcmp (e->key, "max-tries") && e->value) {
-      opts->max_tries = atoi (e->value);
-    } else if (!strcmp (e->key, "min-steady-state-interval") && e->value) {
-      opts->min_steady_state_interval = atoi (e->value);
-    } else if (!strcmp (e->key, "wait-between-tries") && e->value) {
-      opts->wait_between_tries = atoi (e->value);
-    } else if (!strcmp (e->key, "subprocess-tries") && e->value) {
-      opts->subprocess_tries = atoi (e->value);
-    } else if (!strcmp (e->key, "subprocess-wait-between-tries") && e->value) {
-      opts->subprocess_wait_between_tries = atoi (e->value);
-    } else if (!strcmp (e->key, "steady-state-interval") && e->value) {
-      opts->steady_state_interval = atoi (e->value);
-    } else if (!strcmp (e->key, "base-path") && e->value) {
-      opts->base_path = strdup (e->value);
-      if (!opts->base_path)
-        fatal ("out of memory for base path");
-    } else if (!strcmp (e->key, "should-sync-hwclock")) {
-      opts->should_sync_hwclock = e->value ? !strcmp(e->value, "yes") : 1;
-    } else if (!strcmp (e->key, "should-load-disk")) {
-      opts->should_load_disk = e->value ? !strcmp(e->value, "yes") : 1;
-    } else if (!strcmp (e->key, "should-save-disk")) {
-      opts->should_save_disk = e->value ? !strcmp(e->value, "yes") : 1;
-    } else if (!strcmp (e->key, "should-netlink")) {
-      opts->should_netlink = e->value ? !strcmp(e->value, "yes") : 1;
-    } else if (!strcmp (e->key, "dry-run")) {
-      opts->dry_run = e->value ? !strcmp(e->value, "yes") : 1;
-    } else if (!strcmp (e->key, "jitter") && e->value) {
-      opts->jitter = atoi (e->value);
-    } else if (!strcmp (e->key, "verbose")) {
-      verbose = e->value ? !strcmp(e->value, "yes") : 1;
-    } else if (!strcmp (e->key, "source")) {
-      e = parse_source(opts, e);
+  for (e = conf; e; e = e->next)
+    {
+      if (!strcmp (e->key, "max-tries") && e->value)
+        {
+          opts->max_tries = atoi (e->value);
+        }
+      else if (!strcmp (e->key, "min-steady-state-interval") && e->value)
+        {
+          opts->min_steady_state_interval = atoi (e->value);
+        }
+      else if (!strcmp (e->key, "wait-between-tries") && e->value)
+        {
+          opts->wait_between_tries = atoi (e->value);
+        }
+      else if (!strcmp (e->key, "subprocess-tries") && e->value)
+        {
+          opts->subprocess_tries = atoi (e->value);
+        }
+      else if (!strcmp (e->key, "subprocess-wait-between-tries") && e->value)
+        {
+          opts->subprocess_wait_between_tries = atoi (e->value);
+        }
+      else if (!strcmp (e->key, "steady-state-interval") && e->value)
+        {
+          opts->steady_state_interval = atoi (e->value);
+        }
+      else if (!strcmp (e->key, "base-path") && e->value)
+        {
+          opts->base_path = strdup (e->value);
+          if (!opts->base_path)
+            fatal ("out of memory for base path");
+        }
+      else if (!strcmp (e->key, "should-sync-hwclock"))
+        {
+          opts->should_sync_hwclock = e->value ? !strcmp (e->value, "yes") : 1;
+        }
+      else if (!strcmp (e->key, "should-load-disk"))
+        {
+          opts->should_load_disk = e->value ? !strcmp (e->value, "yes") : 1;
+        }
+      else if (!strcmp (e->key, "should-save-disk"))
+        {
+          opts->should_save_disk = e->value ? !strcmp (e->value, "yes") : 1;
+        }
+      else if (!strcmp (e->key, "should-netlink"))
+        {
+          opts->should_netlink = e->value ? !strcmp (e->value, "yes") : 1;
+        }
+      else if (!strcmp (e->key, "dry-run"))
+        {
+          opts->dry_run = e->value ? !strcmp (e->value, "yes") : 1;
+        }
+      else if (!strcmp (e->key, "jitter") && e->value)
+        {
+          opts->jitter = atoi (e->value);
+        }
+      else if (!strcmp (e->key, "verbose"))
+        {
+          verbose = e->value ? !strcmp (e->value, "yes") : 1;
+        }
+      else if (!strcmp (e->key, "source"))
+        {
+          e = parse_source (opts, e);
+        }
     }
-  }
 }
 
 void
-check_conf(struct opts *opts)
+check_conf (struct state *state)
 {
+  struct opts *opts = &state->opts;
   if (!opts->max_tries)
     fatal ("-t argument must be nonzero");
   if (!opts->wait_between_tries)
@@ -582,116 +386,204 @@
     fatal ("-D argument must be nonzero");
   if (!opts->steady_state_interval)
     fatal ("-a argument must be nonzero");
-  if (snprintf (timestamp_path, sizeof (timestamp_path), "%s/timestamp",
-    opts->base_path) >= sizeof (timestamp_path))
-    fatal ("supplied base path is too long: '%s'", opts->base_path);
-  if (strlen (timestamp_path) + strlen (kTempSuffix) >= PATH_MAX)
+  if (snprintf (state->timestamp_path, sizeof (state->timestamp_path),
+                "%s/timestamp", opts->base_path) >= sizeof (state->timestamp_path))
     fatal ("supplied base path is too long: '%s'", opts->base_path);
   if (opts->jitter >= opts->steady_state_interval)
     fatal ("jitter must be less than steady state interval (%d >= %d)",
            opts->jitter, opts->steady_state_interval);
 }
 
+int
+cleanup_main (struct state *state)
+{
+  int i;
+  for (i = 0; i < E_MAX; ++i)
+    {
+      struct event *e = state->events[i];
+      if (e)
+        {
+          int fd = event_get_fd (e);
+          if (fd >= 0 && ! (event_get_events (e) & EV_SIGNAL))
+            close (fd);
+          event_free (e);
+        }
+    }
+  /* The other half was closed above. */
+  close (state->tlsdate_monitor_fd);
+  if (state->tlsdate_pid)
+    {
+      kill (state->tlsdate_pid, SIGKILL);
+      waitpid (state->tlsdate_pid, NULL, WNOHANG);
+    }
+  /* Best effort to tear it down if it is still alive. */
+  close(state->setter_notify_fd);
+  close(state->setter_save_fd);
+  if (state->setter_pid)
+    {
+      kill (state->setter_pid, SIGKILL);
+      waitpid (state->setter_pid, NULL, WNOHANG);
+    }
+  /* TODO(wad) Add dbus_cleanup() */
+  if (state->base)
+    event_base_free (state->base);
+  memset(state, 0, sizeof(*state));
+  return 0;
+}
+
+#ifdef TLSDATED_MAIN
 int API
 main (int argc, char *argv[], char *envp[])
 {
-  struct routeup rtc;
-  int hwclock_fd = -1;
-  time_t last_success = 0;
-  struct opts opts;
-  int wait_time = 0;
-
-  set_conf_defaults(&opts);
-  parse_argv(&opts, argc, argv);
-  check_conf(&opts);
-  load_conf(&opts);
-  check_conf(&opts);
-  if (!opts.sources)
-    add_source_to_conf(&opts, DEFAULT_HOST, DEFAULT_PORT, DEFAULT_PROXY);
-
+  struct state state;
+  /* TODO(wad) EVENT_BASE_FLAG_PRECISE_TIMER | EVENT_BASE_FLAG_PRECISE_TIMER */
+  struct event_base *base = event_base_new();
+  if (!base)
+    {
+      fatal ("could not allocated new event base");
+    }
+  /* Add three priority levels:
+   * 0 - time saving.  Must be done before any other events are handled.
+   * 1 - network synchronization events
+   * 2 - any other events (wake, platform, etc)
+   */
+  event_base_priority_init (base, MAX_EVENT_PRIORITIES);
+  memset (&state, 0, sizeof (state));
+  set_conf_defaults (&state.opts);
+  parse_argv (&state.opts, argc, argv);
+  check_conf (&state);
+  load_conf (&state.opts);
+  check_conf (&state);
+  if (!state.opts.sources)
+    add_source_to_conf (&state.opts, DEFAULT_HOST, DEFAULT_PORT, DEFAULT_PROXY);
+  state.base = base;
+  state.envp = envp;
+  state.hwclock_fd = -1;
+  state.backoff = state.opts.wait_between_tries;
+  /* TODO(wad) move this into setup_time_setter */
   /* grab a handle to /dev/rtc for sync_hwclock() */
-  if (opts.should_sync_hwclock && (hwclock_fd = open (DEFAULT_RTC_DEVICE, O_RDONLY)) < 0)
+  if (state.opts.should_sync_hwclock &&
+      (state.hwclock_fd = open (DEFAULT_RTC_DEVICE, O_RDONLY)) < 0)
     {
       pinfo ("can't open hwclock fd");
-      opts.should_sync_hwclock = 0;
+      state.opts.should_sync_hwclock = 0;
     }
-
-  /* set up a netlink context if we need one */
-  if (opts.should_netlink && routeup_setup (&rtc))
-    pfatal ("Can't open netlink socket");
-
-  if (!is_sane_time (time (NULL)))
+  /* install the SIGCHLD handler for the setter and tlsdate */
+  if (setup_sigchld_event (&state, 1))
     {
-      struct timeval tv = { 0, 0 };
-      /*
-       * If the time is before the build timestamp, we're probably on
-       * a system with a broken rtc. Try loading the timestamp off
-       * disk.
-       */
-      tv.tv_sec = RECENT_COMPILE_DATE;
-      if (opts.should_load_disk &&
-    load_disk_timestamp (timestamp_path, &tv.tv_sec))
-  pinfo ("can't load disk timestamp");
-      if (!opts.dry_run && settimeofday (&tv, NULL))
-  pfatal ("settimeofday() failed");
-      dbus_announce();
-      /*
-       * don't save here - we either just loaded this time or used the
-       * default time, and neither of those are good to save
-       */
-      sync_and_save (hwclock_fd, opts.should_sync_hwclock, 0);
+      error ("Failed to setup SIGCHLD event");
+      goto out;
     }
-
+  /* fork off the privileged helper */
+  info ("spawning time setting helper . . .");
+  if (setup_time_setter (&state))
+    {
+      error ("could not fork privileged coprocess");
+      goto out;
+    }
+  /* release the hwclock now that the time-setter is running. */
+  close (state.hwclock_fd);
+  state.hwclock_fd = -1;
+  /* drop privileges before touching any untrusted data */
+  drop_privs_to (state.opts.user, state.opts.group);
   /* register a signal handler to save time at shutdown */
-  if (opts.should_save_disk)
-    signal (SIGTERM, sigterm_handler);
-
-  /*
-   * Try once right away. If we fail, wait for a route to appear, then try
-   * for a while; repeat whenever another route appears. Try until we
-   * succeed.
-   */
-  if (!tlsdate (&opts, envp)) {
-    last_success = time (NULL);
-    sync_and_save (hwclock_fd, opts.should_sync_hwclock, opts.should_save_disk);
-    dbus_announce();
-  }
-
-  /*
-   * Loop until we catch a fatal signal or routeup_once() fails. We run
-   * tlsdate at least once a day, but possibly as often as routes come up;
-   * this should handle cases like a VPN being brought up and down
-   * periodically.
-   */
-  wait_time = add_jitter(opts.steady_state_interval, opts.jitter);
-  while (wait_for_event (&rtc, opts.should_netlink, wait_time) >= 0)
+  if (state.opts.should_save_disk)
     {
-      /*
-       * If a route just came up, run tlsdate; if it
-       * succeeded, then we're good and can keep time locally
-       * from now on.
-       */
-      int i;
-      int backoff = opts.wait_between_tries;
-      wait_time = add_jitter(opts.steady_state_interval, opts.jitter);
-      if (time (NULL) - last_success < opts.min_steady_state_interval)
-        continue;
-      for (i = 0; i < opts.max_tries && tlsdate (&opts, envp); ++i) {
-        if (backoff < 1)
-          fatal ("backoff too small? %d", backoff);
-        sleep (backoff);
-        if (backoff < MAX_SANE_BACKOFF)
-          backoff *= 2;
-      }
-      if (i != opts.max_tries)
-      {
-        last_success = time (NULL);
-        info ("tlsdate succeeded");
-        sync_and_save (hwclock_fd, opts.should_sync_hwclock, opts.should_save_disk);
-        dbus_announce();
-      }
+      struct event *event = event_new (base, SIGTERM, EV_SIGNAL|EV_PERSIST,
+                                       action_sigterm, &state);
+      if (!event)
+        fatal ("Failed to create SIGTERM event");
+      event_priority_set (event, PRI_SAVE);
+      event_add (event, NULL);
     }
-
-  return 1;
+  if (init_dbus (&state))
+    {
+      error ("Failed to initialize DBus");
+      goto out;
+    }
+  /* Register the tlsdate event before any listeners could show up. */
+  state.events[E_TLSDATE] = event_new (base, -1, EV_TIMEOUT,
+                                       action_run_tlsdate, &state);
+  if (!state.events[E_TLSDATE])
+    {
+      error ("Failed to create tlsdate event");
+      goto out;
+    }
+  event_priority_set (state.events[E_TLSDATE], PRI_NET);
+  /* The timeout and fd will be filled in per-call. */
+  if (setup_tlsdate_status (&state))
+    {
+      error ("Failed to create tlsdate status event");
+      goto out;
+    }
+  /* TODO(wad) Could use a timeout on this to catch setter death? */
+  /* EV_READ is for truncation/EPIPE notification */
+  state.events[E_SAVE] = event_new (base, state.setter_save_fd,
+                                    EV_READ|EV_WRITE, action_sync_and_save,
+                                    &state);
+  if (!state.events[E_SAVE])
+    {
+      error ("Failed to create sync & save event");
+      goto out;
+    }
+  event_priority_set (state.events[E_SAVE], PRI_SAVE);
+  /* Start by grabbing the system time. */
+  state.last_sync_type = SYNC_TYPE_RTC;
+  state.last_time = time (NULL);
+  /* If possible, grab disk time and check the two. */
+  if (state.opts.should_load_disk)
+    {
+      time_t disk_time = state.last_time;
+      if (!load_disk_timestamp (state.timestamp_path, &disk_time))
+        {
+          info ("disk timestamp available: yes");
+          if (!is_sane_time (state.last_time) ||
+              state.last_time < disk_time)
+            {
+              state.last_sync_type = SYNC_TYPE_DISK;
+              state.last_time = disk_time;
+            }
+        }
+      else
+        {
+          info ("disk timestamp available: no");
+        }
+    }
+  if (!is_sane_time (state.last_time))
+    {
+      state.last_sync_type = SYNC_TYPE_BUILD;
+      state.last_time = RECENT_COMPILE_DATE + 1;
+    }
+  /* Save and announce the initial time source. */
+  trigger_event (&state, E_SAVE, -1);
+  info ("initial time sync type: %s", sync_type_str (state.last_sync_type));
+  /* Initialize platform specific loop behavior */
+  if (platform_init_cros (&state))
+    {
+      error ("Failed to initialize platform code");
+      goto out;
+    }
+  if (setup_event_route_up (&state))
+    {
+      error ("Failed to setup route up monitoring");
+      goto out;
+    }
+  if (setup_event_timer_sync (&state))
+    {
+      error ("Failed to setup a timer event");
+      goto out;
+    }
+  if (setup_event_timer_continuity (&state))
+    {
+      error ("Failed to setup continuity timer");
+      goto out;
+    }
+  /* Add a forced sync event to the event list. */
+  action_kickoff_time_sync (-1, EV_TIMEOUT, &state);
+  info ("Entering dispatch . . .");
+  event_base_dispatch (base);
+  info ("tlsdated terminating gracefully");
+out:
+  return cleanup_main (&state);
 }
 #endif /* !TLSDATED_MAIN */
diff --git a/src/util.c b/src/util.c
index 68f3a98..2ae748e 100644
--- a/src/util.c
+++ b/src/util.c
@@ -15,6 +15,11 @@
 #include <syslog.h>
 #include <unistd.h>
 
+#ifdef WITH_EVENTS
+#include <event2/event.h>
+#endif
+
+#include "src/tlsdate.h"
 #include "src/util.h"
 
 /** helper function to print message and die */
@@ -22,11 +27,10 @@
 die (const char *fmt, ...)
 {
   va_list ap;
-
-  va_start(ap, fmt);
-  vfprintf(stderr, fmt, ap);
-  va_end(ap);
-  exit(1);
+  va_start (ap, fmt);
+  vfprintf (stderr, fmt, ap);
+  va_end (ap);
+  exit (1);
 }
 
 /** helper function for 'verbose' output */
@@ -34,24 +38,23 @@
 verb (const char *fmt, ...)
 {
   va_list ap;
-
   if (! verbose) return;
-  va_start(ap, fmt);
-  vfprintf(stderr, fmt, ap);
-  va_end(ap);
+  va_start (ap, fmt);
+  vfprintf (stderr, fmt, ap);
+  va_end (ap);
 }
-void API logat(int isverbose, const char *fmt, ...)
+void API logat (int isverbose, const char *fmt, ...)
 {
   if (isverbose && !verbose)
     return;
   va_list ap;
-  va_start(ap, fmt);
-  vfprintf(stderr, fmt, ap);
-  fprintf(stderr, "\n");
-  va_end(ap);
-  va_start(ap, fmt);
-  vsyslog(LOG_INFO, fmt, ap);
-  va_end(ap);
+  va_start (ap, fmt);
+  vfprintf (stderr, fmt, ap);
+  fprintf (stderr, "\n");
+  va_end (ap);
+  va_start (ap, fmt);
+  vsyslog (LOG_INFO, fmt, ap);
+  va_end (ap);
 }
 
 void
@@ -61,12 +64,11 @@
   gid_t gid;
   struct passwd *pw;
   struct group  *gr;
-
   if (0 != getuid ())
     return; /* not running as root to begin with; should (!) be harmless to continue
          without dropping to 'nobody' (setting time will fail in the end) */
-  pw = getpwnam(user);
-  gr = getgrnam(group);
+  pw = getpwnam (user);
+  gr = getgrnam (group);
   if (NULL == pw)
     die ("Failed to obtain UID for `%s'\n", user);
   if (NULL == gr)
@@ -79,12 +81,10 @@
     die ("GID for `%s' is 0, refusing to run SSL\n", user);
   if (pw->pw_gid != gr->gr_gid)
     die ("GID for `%s' is not `%s' as expected, refusing to run SSL\n",
-          user, group);
-
-  if (0 != initgroups((const char *)user, gr->gr_gid))
+         user, group);
+  if (0 != initgroups ( (const char *) user, gr->gr_gid))
     die ("Unable to initgroups for `%s' in group `%s' as expected\n",
-          user, group);
-
+         user, group);
 #ifdef HAVE_SETRESGID
   if (0 != setresgid (gid, gid, gid))
     die ("Failed to setresgid: %s\n", strerror (errno));
@@ -101,3 +101,48 @@
 #endif
 }
 
+/* TODO(wad) rename to schedule_event */
+void
+trigger_event (struct state *state, enum event_id_t id, int sec)
+{
+#ifdef WITH_EVENTS
+  struct event *e = state->events[id];
+  struct timeval delay = { sec, 0 };
+  /* Fallthrough to tlsdate if there is no resolver. */
+  if (!e && id == E_RESOLVER)
+    e = state->events[E_TLSDATE];
+  if (!e)
+    {
+      info ("trigger_event with NULL |e|. I hope this is a test!");
+      return;
+    }
+  if (event_pending (e, EV_READ|EV_WRITE|EV_TIMEOUT|EV_SIGNAL, NULL))
+    event_del (e);
+  if (sec >= 0)
+    event_add (e, &delay);
+  else /* Note! This will not fire a TIMEOUT event. */
+    event_add (e, NULL);
+#endif
+}
+
+const char *
+sync_type_str (int sync_type)
+{
+  switch (sync_type)
+    {
+    case SYNC_TYPE_NONE:
+      return "none";
+    case SYNC_TYPE_BUILD:
+      return "build-timestamp";
+    case SYNC_TYPE_DISK:
+      return "disk-timestamp";
+    case SYNC_TYPE_RTC:
+      return "system-clock";
+    case SYNC_TYPE_PLATFORM:
+      return "platform-feature";
+    case SYNC_TYPE_NET:
+      return "network";
+    default:
+      return "error";
+    }
+}
diff --git a/src/util.h b/src/util.h
index 7d7cb11..55c77c8 100644
--- a/src/util.h
+++ b/src/util.h
@@ -14,10 +14,27 @@
 
 #define API __attribute__((visibility("default")))
 
+#define IGNORE_EINTR(expr) ({ \
+  typeof(expr) _r; \
+  while ((_r = (expr)) == -1 && errno == EINTR); \
+  _r; \
+})
+
 extern int verbose;
 void die (const char *fmt, ...);
 void verb (const char *fmt, ...);
-extern void logat(int isverbose, const char *fmt, ...);
+extern void logat (int isverbose, const char *fmt, ...);
+
+#ifdef NDEBUG
+#  define _SUPPORT_DEBUG 0
+#else
+#  define _SUPPORT_DEBUG 1
+#endif
+
+#define debug(fmt, ...) do { \
+  if (_SUPPORT_DEBUG) \
+    logat(1, fmt, ## __VA_ARGS__); \
+} while (0)
 
 #define info(fmt, ...) logat(1, fmt, ## __VA_ARGS__)
 #define pinfo(fmt, ...) logat(1, fmt ": %s", ## __VA_ARGS__, strerror(errno))
@@ -29,8 +46,16 @@
   exit(1); \
 } while (0)
 
-static inline int min(int x, int y) { return x < y ? x : y; }
+static inline int min (int x, int y)
+{
+  return x < y ? x : y;
+}
 
 void drop_privs_to (const char *user, const char *group);
+const char *sync_type_str (int sync_type);
+
+struct state;
+enum event_id_t;
+void trigger_event (struct state *state, enum event_id_t e, int sec);
 
 #endif /* !UTIL_H */
diff --git a/src/visibility.h b/src/visibility.h
index cd06c3e..b9452f1 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -42,7 +42,7 @@
 #  define TLSDATE_API __global
 #  define TLSDATE_LOCAL __global
 # elif defined(_MSC_VER)
-#  define TLSDATE_API extern __declspec(dllexport) 
+#  define TLSDATE_API extern __declspec(dllexport)
 #  define TLSDATE_LOCAL extern __declspec(dllexport)
 # else
 #  define TLSDATE_API
@@ -57,7 +57,7 @@
 #   define TLSDATE_API __global
 #   define TLSDATE_LOCAL __hidden
 #  elif defined(_MSC_VER)
-#   define TLSDATE_API extern __declspec(dllexport) 
+#   define TLSDATE_API extern __declspec(dllexport)
 #   define TLSDATE_LOCAL
 #  else
 #   define TLSDATE_API
@@ -65,7 +65,7 @@
 #  endif /* defined(HAVE_VISIBILITY) */
 # else  /* defined(BUILDING_TLSDATE) */
 #  if defined(_MSC_VER)
-#   define TLSDATE_API extern __declspec(dllimport) 
+#   define TLSDATE_API extern __declspec(dllimport)
 #   define TLSDATE_LOCAL
 #  else
 #   define TLSDATE_API