[tor-commits] [tor/master] String-based API for consensus diffs.

nickm at torproject.org nickm at torproject.org
Thu Mar 16 19:01:08 UTC 2017


commit 6a36e5ff3b7233e430ce8b1ec567d3235ff04999
Author: Nick Mathewson <nickm at torproject.org>
Date:   Tue Mar 7 13:45:32 2017 -0500

    String-based API for consensus diffs.
    
    Also, add very strict split/join functions, and totally forbid
    nonempty files that end with somethig besides a newline.  This
    change is necessary to ensure that diff/apply are actually reliable
    inverse operations.
---
 src/or/consdiff.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/or/consdiff.h |  26 +++++++-----
 2 files changed, 130 insertions(+), 14 deletions(-)

diff --git a/src/or/consdiff.c b/src/or/consdiff.c
index 6fe8360..3266abd 100644
--- a/src/or/consdiff.c
+++ b/src/or/consdiff.c
@@ -39,9 +39,12 @@
 static const char* ns_diff_version = "network-status-diff-version 1";
 static const char* hash_token = "hash";
 
-STATIC int
-consensus_compute_digest(const char *cons,
-                         consensus_digest_t *digest_out)
+static char *consensus_join_lines(const smartlist_t *inp);
+
+/** DOCDOC */
+MOCK_IMPL(STATIC int,
+consensus_compute_digest,(const char *cons,
+                          consensus_digest_t *digest_out))
 {
   int r = crypto_digest256((char*)digest_out->sha3_256,
                            cons, strlen(cons), DIGEST_SHA3_256);
@@ -987,7 +990,7 @@ consdiff_apply_diff(const smartlist_t *cons1,
     goto error_cleanup;
   }
 
-  cons2_str = smartlist_join_strings(cons2, "\n", 1, NULL);
+  cons2_str = consensus_join_lines(cons2);
 
   consensus_digest_t cons2_digests;
   if (consensus_compute_digest(cons2_str, &cons2_digests) < 0) {
@@ -1029,3 +1032,110 @@ consdiff_apply_diff(const smartlist_t *cons1,
   return cons2_str;
 }
 
+/**DOCDOC*/
+static int
+consensus_split_lines(smartlist_t *out, const char *s)
+{
+  /* XXXX If we used string slices, we could avoid a bunch of copies here. */
+  while (*s) {
+    const char *eol = strchr(s, '\n');
+    if (!eol) {
+      /* File doesn't end with newline. */
+      return -1;
+    }
+    smartlist_add(out, tor_strndup(s, eol-s));
+    s = eol+1;
+  }
+  return 0;
+}
+
+/** DOCDOC */
+static char *
+consensus_join_lines(const smartlist_t *inp)
+{
+  size_t n = 0;
+  SMARTLIST_FOREACH(inp, const char *, cp, n += strlen(cp) + 1);
+  n += 1;
+  char *result = tor_malloc(n);
+  char *out = result;
+  SMARTLIST_FOREACH_BEGIN(inp, const char *, cp) {
+    size_t len = strlen(cp);
+    memcpy(out, cp, len);
+    out += len;
+    *out++ = '\n';
+  } SMARTLIST_FOREACH_END(cp);
+  *out++ = '\0';
+  tor_assert(out == result+n);
+  return result;
+}
+
+/**DOCDOC */
+char *
+consensus_diff_generate(const char *cons1,
+                        const char *cons2)
+{
+  consensus_digest_t d1, d2;
+  smartlist_t *lines1 = NULL, *lines2 = NULL, *result_lines = NULL;
+  int r1, r2;
+  char *result = NULL;
+
+  r1 = consensus_compute_digest(cons1, &d1);
+  r2 = consensus_compute_digest(cons2, &d2);
+  if (BUG(r1 < 0 || r2 < 0))
+    return NULL; // LCOV_EXCL_LINE
+
+  lines1 = smartlist_new();
+  lines2 = smartlist_new();
+  if (consensus_split_lines(lines1, cons1) < 0)
+    goto done;
+  if (consensus_split_lines(lines2, cons2) < 0)
+    goto done;
+
+  result_lines = consdiff_gen_diff(lines1, lines2, &d1, &d2);
+
+ done:
+  SMARTLIST_FOREACH(lines1, char *, cp, tor_free(cp));
+  smartlist_free(lines1);
+  SMARTLIST_FOREACH(lines2, char *, cp, tor_free(cp));
+  smartlist_free(lines2);
+
+  if (result_lines) {
+    result = consensus_join_lines(result_lines);
+    SMARTLIST_FOREACH(result_lines, char *, cp, tor_free(cp));
+    smartlist_free(result_lines);
+  }
+  return result;
+}
+
+/** DOCDOC */
+char *
+consensus_diff_apply(const char *consensus,
+                     const char *diff)
+{
+  consensus_digest_t d1;
+  smartlist_t *lines1 = NULL, *lines2 = NULL;
+  int r1;
+  char *result = NULL;
+
+  r1 = consensus_compute_digest(consensus, &d1);
+  if (BUG(r1 < 0))
+    return NULL; // LCOV_EXCL_LINE
+
+  lines1 = smartlist_new();
+  lines2 = smartlist_new();
+  if (consensus_split_lines(lines1, consensus) < 0)
+    goto done;
+  if (consensus_split_lines(lines2, diff) < 0)
+    goto done;
+
+  result = consdiff_apply_diff(lines1, lines2, &d1);
+
+ done:
+  SMARTLIST_FOREACH(lines1, char *, cp, tor_free(cp));
+  smartlist_free(lines1);
+  SMARTLIST_FOREACH(lines2, char *, cp, tor_free(cp));
+  smartlist_free(lines2);
+
+  return result;
+}
+
diff --git a/src/or/consdiff.h b/src/or/consdiff.h
index 42cd3af..eef3653 100644
--- a/src/or/consdiff.h
+++ b/src/or/consdiff.h
@@ -7,21 +7,27 @@
 
 #include "or.h"
 
+char *consensus_diff_generate(const char *cons1,
+                              const char *cons2);
+char *consensus_diff_apply(const char *consensus,
+                           const char *diff);
+
+#ifdef CONSDIFF_PRIVATE
 typedef struct consensus_digest_t {
   uint8_t sha3_256[DIGEST256_LEN];
 } consensus_digest_t;
 
-smartlist_t *consdiff_gen_diff(const smartlist_t *cons1,
-                               const smartlist_t *cons2,
-                               const consensus_digest_t *digests1,
-                               const consensus_digest_t *digests2);
-char *consdiff_apply_diff(const smartlist_t *cons1, const smartlist_t *diff,
-                          const consensus_digest_t *digests1);
-int consdiff_get_digests(const smartlist_t *diff,
-                         char *digest1_out,
-                         char *digest2_out);
+STATIC smartlist_t *consdiff_gen_diff(const smartlist_t *cons1,
+                                      const smartlist_t *cons2,
+                                      const consensus_digest_t *digests1,
+                                      const consensus_digest_t *digests2);
+STATIC char *consdiff_apply_diff(const smartlist_t *cons1,
+                                 const smartlist_t *diff,
+                                 const consensus_digest_t *digests1);
+STATIC int consdiff_get_digests(const smartlist_t *diff,
+                                char *digest1_out,
+                                char *digest2_out);
 
-#ifdef CONSDIFF_PRIVATE
 /** Data structure to define a slice of a smarltist. */
 typedef struct smartlist_slice_t {
   /**





More information about the tor-commits mailing list