diff --git a/doc/spec/control-spec.txt b/doc/spec/control-spec.txt
index 883c78f407..86bdf84052 100644
--- a/doc/spec/control-spec.txt
+++ b/doc/spec/control-spec.txt
@@ -1556,7 +1556,13 @@ $Id$
4.1.12. Network status has changed
Syntax:
- "650" "+" "NS" CRLF 1*NetworkStatus "." CRLF "650" SP "OK" CRLF
+ "650" "+" "NS" CRLF 1*NetworkStatus "." CRLF "650" SP "OK" CRLF
+
+ The event is used whenever our local view of a relay status changes.
+ This happens when we get a new v3 consensus (in which case the entries
+ we see are a duplicate of what we see in the NEWCONSENSUS event,
+ below), but it also happens when we decide to mark a relay as up or
+ down in our local status, for example based on connection attempts.
[First added in 0.1.2.3-alpha]
@@ -1596,6 +1602,20 @@ $Id$
set of "countrycode=count" pairs. For example,
650-CLIENTS_SEEN TimeStarted="Thu Dec 25 23:50:43 EST 2008"
650 CountrySummary=us=16,de=8,uk=8
+[XXX Matt Edman informs me that the time format above is wrong. -RD]
+
+4.1.15. New consensus networkstatus has arrived.
+
+ The syntax is:
+ "650" "+" "NEWCONSENSUS" CRLF 1*NetworkStatus "." CRLF "650" SP
+ "OK" CRLF
+
+ A new consensus networkstatus has arrived. We include NS-style lines for
+ every relay in the consensus. NEWCONSENSUS is a separate event from the
+ NS event, because the list here represents every usable relay: so any
+ relay *not* mentioned in this list is implicitly no longer recommended.
+
+ [First added in 0.2.1.13-alpha]
5. Implementation notes
diff --git a/src/or/control.c b/src/or/control.c
index f435251751..222a6e0762 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -42,7 +42,8 @@
#define EVENT_GUARD 0x0013
#define EVENT_STREAM_BANDWIDTH_USED 0x0014
#define EVENT_CLIENTS_SEEN 0x0015
-#define _EVENT_MAX 0x0015
+#define EVENT_NEWCONSENSUS 0x0016
+#define _EVENT_MAX 0x0016
/* If _EVENT_MAX ever hits 0x0020, we need to make the mask wider. */
/** Bitfield: The bit 1<<e is set if any open control
@@ -999,6 +1000,8 @@ handle_control_setevents(control_connection_t *conn, uint32_t len,
event_code = EVENT_STREAM_BANDWIDTH_USED;
else if (!strcasecmp(ev, "CLIENTS_SEEN"))
event_code = EVENT_CLIENTS_SEEN;
+ else if (!strcasecmp(ev, "NEWCONSENSUS"))
+ event_code = EVENT_NEWCONSENSUS;
else {
connection_printf_to_buf(conn, "552 Unrecognized event \"%s\"\r\n",
ev);
@@ -3516,16 +3519,20 @@ control_event_or_authdir_new_descriptor(const char *action,
/** Called when the routerstatus_ts statuses have changed: sends
* an NS event to any controller that cares. */
-int
-control_event_networkstatus_changed(smartlist_t *statuses)
+static int
+control_event_networkstatus_changed_helper(smartlist_t *statuses,
+ uint16_t event,
+ const char *event_string)
{
smartlist_t *strs;
char *s, *esc = NULL;
- if (!EVENT_IS_INTERESTING(EVENT_NS) || !smartlist_len(statuses))
+ if (!EVENT_IS_INTERESTING(event) || !smartlist_len(statuses))
return 0;
strs = smartlist_create();
- smartlist_add(strs, tor_strdup("650+NS\r\n"));
+ smartlist_add(strs, tor_strdup("650+"));
+ smartlist_add(strs, tor_strdup(event_string));
+ smartlist_add(strs, tor_strdup("\r\n"));
SMARTLIST_FOREACH(statuses, routerstatus_t *, rs,
{
s = networkstatus_getinfo_helper_single(rs);
@@ -3538,14 +3545,27 @@ control_event_networkstatus_changed(smartlist_t *statuses)
SMARTLIST_FOREACH(strs, char *, cp, tor_free(cp));
smartlist_free(strs);
tor_free(s);
- send_control_event_string(EVENT_NS, ALL_NAMES|ALL_FORMATS, esc);
- send_control_event_string(EVENT_NS, ALL_NAMES|ALL_FORMATS,
+ send_control_event_string(event, ALL_NAMES|ALL_FORMATS, esc);
+ send_control_event_string(event, ALL_NAMES|ALL_FORMATS,
"650 OK\r\n");
tor_free(esc);
return 0;
}
+int
+control_event_networkstatus_changed(smartlist_t *statuses)
+{
+ return control_event_networkstatus_changed_helper(statuses, EVENT_NS, "NS");
+}
+
+int
+control_event_newconsensus(const networkstatus_t *consensus)
+{
+ return control_event_networkstatus_changed_helper(
+ consensus->routerstatus_list, EVENT_NEWCONSENSUS, "NEWCONSENSUS");
+}
+
/** Called when a single local_routerstatus_t has changed: Sends an NS event
* to any countroller that cares. */
int
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index 306ecb4278..81b1d07115 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -1317,6 +1317,9 @@ notify_control_networkstatus_changed(const networkstatus_t *old_c,
smartlist_t *changed;
if (old_c == new_c)
return;
+
+ control_event_newconsensus(new_c);
+
if (!old_c) {
control_event_networkstatus_changed(new_c->routerstatus_list);
return;
diff --git a/src/or/or.h b/src/or/or.h
index d8122dbbc3..7c191eeaf3 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -3236,6 +3236,7 @@ int control_event_or_authdir_new_descriptor(const char *action,
const char *msg);
int control_event_my_descriptor_changed(void);
int control_event_networkstatus_changed(smartlist_t *statuses);
+int control_event_newconsensus(const networkstatus_t *consensus);
int control_event_networkstatus_changed_single(routerstatus_t *rs);
int control_event_general_status(int severity, const char *format, ...)
CHECK_PRINTF(2,3);