aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2017-03-07 13:45:32 -0500
committerNick Mathewson <nickm@torproject.org>2017-03-16 14:39:54 -0400
commit6a36e5ff3b7233e430ce8b1ec567d3235ff04999 (patch)
tree21a5916d7f87809f33d15577646bf3edd4eaeebc
parenteff9fbd17d5fb4b1c196c241da4513d51893f52e (diff)
downloadtor-6a36e5ff3b7233e430ce8b1ec567d3235ff04999.tar.gz
tor-6a36e5ff3b7233e430ce8b1ec567d3235ff04999.zip
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.
-rw-r--r--src/or/consdiff.c118
-rw-r--r--src/or/consdiff.h26
2 files changed, 130 insertions, 14 deletions
diff --git a/src/or/consdiff.c b/src/or/consdiff.c
index 6fe8360902..3266abd64f 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 42cd3afa83..eef3653f69 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 {
/**