[tor-commits] [tor/master] Merge bug5595-v2-squashed into maint-0.2.4

andrea at torproject.org andrea at torproject.org
Sat May 11 04:08:17 UTC 2013


commit aaa3a085db05c4d98b7c51b5ef16da166e7c7f0a
Merge: bae5dd6 54f41d6
Author: Andrea Shepard <andrea at torproject.org>
Date:   Fri May 10 19:39:48 2013 -0700

    Merge bug5595-v2-squashed into maint-0.2.4

 changes/bug5595            |    8 +
 src/or/Makefile.nmake      |    1 +
 src/or/directory.c         |   73 +++++--
 src/or/dirvote.c           |    2 +-
 src/or/fp_pair.c           |  308 ++++++++++++++++++++++++++
 src/or/fp_pair.h           |   45 ++++
 src/or/include.am          |    2 +
 src/or/router.c            |    3 +-
 src/or/routerlist.c        |  516 ++++++++++++++++++++++++++++++++++++--------
 src/or/routerlist.h        |   18 ++-
 src/test/test_containers.c |   84 +++++++
 11 files changed, 949 insertions(+), 111 deletions(-)

diff --cc src/or/Makefile.nmake
index d67123a,146866e..3b627b1
--- a/src/or/Makefile.nmake
+++ b/src/or/Makefile.nmake
@@@ -1,74 -1,28 +1,75 @@@
  all: tor.exe
  
 -CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common
 +CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common \
 +    /I ..\ext
  
 -LIBS = ..\..\..\build-alpha\lib\libevent.a \
 - ..\..\..\build-alpha\lib\libcrypto.a \
 - ..\..\..\build-alpha\lib\libssl.a \
 - ..\..\..\build-alpha\lib\libz.a \
 - ws2_32.lib advapi32.lib shell32.lib
 +LIBS = ..\..\..\build-alpha\lib\libevent.lib \
 + ..\..\..\build-alpha\lib\libcrypto.lib \
 + ..\..\..\build-alpha\lib\libssl.lib \
 + ..\..\..\build-alpha\lib\libz.lib \
 + ws2_32.lib advapi32.lib shell32.lib \
 + crypt32.lib gdi32.lib user32.lib
  
 -LIBTOR_OBJECTS = buffers.obj circuitbuild.obj circuitlist.obj circuituse.obj \
 -	command.obj config.obj connection.obj connection_edge.obj \
 -	connection_or.obj control.obj cpuworker.obj directory.obj \
 -	dirserv.obj dirvote.obj dns.obj dnsserv.obj fp_pair.obj geoip.obj \
 -	hibernate.obj main.obj microdesc.obj networkstatus.obj \
 -	nodelist.obj onion.obj policies.obj reasons.obj relay.obj \
 -	rendclient.obj rendcommon.obj rendmid.obj rendservice.obj \
 -	rephist.obj router.obj routerlist.obj routerparse.obj status.obj \
 -	config_codedigest.obj ntmain.obj
 +LIBTOR_OBJECTS = \
 +  addressmap.obj \
 +  buffers.obj \
 +  channel.obj \
 +  channeltls.obj \
 +  circuitbuild.obj \
 +  circuitlist.obj \
 +  circuitmux.obj \
 +  circuitmux_ewma.obj \
 +  circuitstats.obj \
 +  circuituse.obj \
 +  command.obj \
 +  config.obj \
 +  config_codedigest.obj \
 +  confparse.obj \
 +  connection.obj \
 +  connection_edge.obj \
 +  connection_or.obj \
 +  control.obj \
 +  cpuworker.obj \
 +  directory.obj \
 +  dirserv.obj \
 +  dirvote.obj \
 +  dns.obj \
 +  dnsserv.obj \
++  fp_pair.obj \
 +  entrynodes.obj \
 +  geoip.obj \
 +  hibernate.obj \
 +  main.obj \
 +  microdesc.obj \
 +  networkstatus.obj \
 +  nodelist.obj \
 +  ntmain.obj \
 +  onion.obj \
 +  onion_fast.obj \
 +  onion_ntor.obj \
 +  onion_tap.obj \
 +  policies.obj \
 +  reasons.obj \
 +  relay.obj \
 +  rendclient.obj \
 +  rendcommon.obj \
 +  rendmid.obj \
 +  rendservice.obj \
 +  rephist.obj \
 +  replaycache.obj \
 +  router.obj \
 +  routerlist.obj \
 +  routerparse.obj \
 +  routerset.obj \
 +  statefile.obj \
 +  status.obj \
 +  transports.obj
  
  libtor.lib: $(LIBTOR_OBJECTS)
 -	lib $(LIBTOR_OBJECTS) /out:libtor.lib
 +	lib $(LIBTOR_OBJECTS) /out:$@
  
  tor.exe: libtor.lib tor_main.obj
 -	$(CC) $(CFLAGS) $(LIBS) libtor.lib ..\common\*.lib tor_main.obj
 +	$(CC) $(CFLAGS) $(LIBS) libtor.lib ..\common\*.lib tor_main.obj /Fe$@
  
  clean:
  	del $(LIBTOR_OBJECTS) *.lib tor.exe
diff --cc src/or/directory.c
index 38a423c,f65ac87..b4381ac
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@@ -856,8 -803,10 +856,10 @@@ connection_dir_bridge_routerdesc_failed
  static void
  connection_dir_download_cert_failed(dir_connection_t *conn, int status)
  {
+   const char *fp_pfx = "fp/";
+   const char *fpsk_pfx = "fp-sk/";
    smartlist_t *failed;
 -  tor_assert(conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE);
 +  tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE);
  
    if (!conn->requested_resource)
      return;
@@@ -1629,11 -1608,12 +1653,12 @@@ connection_dir_client_reached_eof(dir_c
    compress_method_t compression;
    int plausible;
    int skewed=0;
 -  int allow_partial = (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
 -                       conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
 -                       conn->_base.purpose == DIR_PURPOSE_FETCH_MICRODESC);
 +  int allow_partial = (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
 +                       conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO ||
 +                       conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC);
    int was_compressed=0;
    time_t now = time(NULL);
+   int src_code;
  
    switch (connection_fetch_from_buf_http(TO_CONN(conn),
                                &headers, MAX_HEADERS_SIZE,
@@@ -1901,18 -1881,37 +1926,38 @@@
        return -1;
      }
      log_info(LD_DIR,"Received authority certificates (size %d) from server "
 -             "'%s:%d'", (int)body_len, conn->_base.address, conn->_base.port);
 +             "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port);
-     if (trusted_dirs_load_certs_from_string(body, 0, 1)<0) {
-       log_warn(LD_DIR, "Unable to parse fetched certificates");
-       /* if we fetched more than one and only some failed, the successful
-        * ones got flushed to disk so it's safe to call this on them */
-       connection_dir_download_cert_failed(conn, status_code);
++
+     /*
+      * Tell trusted_dirs_load_certs_from_string() whether it was by fp
+      * or fp-sk pair.
+      */
+     src_code = -1;
+     if (!strcmpstart(conn->requested_resource, "fp/")) {
+       src_code = TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST;
+     } else if (!strcmpstart(conn->requested_resource, "fp-sk/")) {
+       src_code = TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_SK_DIGEST;
+     }
+ 
+     if (src_code != -1) {
+       if (trusted_dirs_load_certs_from_string(body, src_code, 1)<0) {
+         log_warn(LD_DIR, "Unable to parse fetched certificates");
+         /* if we fetched more than one and only some failed, the successful
+          * ones got flushed to disk so it's safe to call this on them */
+         connection_dir_download_cert_failed(conn, status_code);
+       } else {
+         directory_info_has_arrived(now, 0);
+         log_info(LD_DIR, "Successfully loaded certificates from fetch.");
+       }
      } else {
-       directory_info_has_arrived(now, 0);
-       log_info(LD_DIR, "Successfully loaded certificates from fetch.");
+       log_warn(LD_DIR,
+                "Couldn't figure out what to do with fetched certificates for "
+                "unknown resource %s",
+                conn->requested_resource);
+       connection_dir_download_cert_failed(conn, status_code);
      }
    }
 -  if (conn->_base.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
 +  if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
      const char *msg;
      int st;
      log_info(LD_DIR,"Got votes (size %d) from server %s:%d",
diff --cc src/or/include.am
index d2be1fb,0000000..65dbeff
mode 100644,000000..100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@@ -1,193 -1,0 +1,195 @@@
 +bin_PROGRAMS+= src/or/tor
 +noinst_LIBRARIES+= src/or/libtor.a
 +
 +if BUILD_NT_SERVICES
 +tor_platform_source=src/or/ntmain.c
 +else
 +tor_platform_source=
 +endif
 +
 +EXTRA_DIST+= src/or/ntmain.c src/or/or_sha1.i src/or/Makefile.nmake
 +
 +if USE_EXTERNAL_EVDNS
 +evdns_source=
 +else
 +evdns_source=src/ext/eventdns.c
 +endif
 +
 +if CURVE25519_ENABLED
 +onion_ntor_source=src/or/onion_ntor.c
 +else
 +onion_ntor_source=
 +endif
 +
 +src_or_libtor_a_SOURCES = \
 +	src/or/addressmap.c				\
 +	src/or/buffers.c				\
 +	src/or/channel.c				\
 +	src/or/channeltls.c				\
 +	src/or/circuitbuild.c				\
 +	src/or/circuitlist.c				\
 +	src/or/circuitmux.c				\
 +	src/or/circuitmux_ewma.c			\
 +	src/or/circuitstats.c				\
 +	src/or/circuituse.c				\
 +	src/or/command.c				\
 +	src/or/config.c					\
 +	src/or/confparse.c				\
 +	src/or/connection.c				\
 +	src/or/connection_edge.c			\
 +	src/or/connection_or.c				\
 +	src/or/control.c				\
 +	src/or/cpuworker.c				\
 +	src/or/directory.c				\
 +	src/or/dirserv.c				\
 +	src/or/dirvote.c				\
 +	src/or/dns.c					\
 +	src/or/dnsserv.c				\
++        src/or/fp_pair.c				\
 +	src/or/geoip.c					\
 +	src/or/entrynodes.c				\
 +	src/or/hibernate.c				\
 +	src/or/main.c					\
 +	src/or/microdesc.c				\
 +	src/or/networkstatus.c				\
 +	src/or/nodelist.c				\
 +	src/or/onion.c					\
 +	src/or/onion_fast.c				\
 +	src/or/onion_tap.c				\
 +	src/or/transports.c				\
 +	src/or/policies.c				\
 +	src/or/reasons.c				\
 +	src/or/relay.c					\
 +	src/or/rendclient.c				\
 +	src/or/rendcommon.c				\
 +	src/or/rendmid.c				\
 +	src/or/rendservice.c				\
 +	src/or/rephist.c				\
 +	src/or/replaycache.c				\
 +	src/or/router.c					\
 +	src/or/routerlist.c				\
 +	src/or/routerparse.c				\
 +	src/or/routerset.c				\
 +	src/or/statefile.c				\
 +	src/or/status.c					\
 +	$(evdns_source)					\
 +	$(tor_platform_source)				\
 +	$(onion_ntor_source)				\
 +	src/or/config_codedigest.c
 +
 +#libtor_a_LIBADD = ../common/libor.a ../common/libor-crypto.a \
 +#	../common/libor-event.a
 +
 +
 +src_or_tor_SOURCES = src/or/tor_main.c
 +AM_CPPFLAGS += -I$(srcdir)/src/or -Isrc/or
 +
 +src/or/tor_main.o: micro-revision.i
 +
 +AM_CPPFLAGS += -DSHARE_DATADIR="\"$(datadir)\"" \
 +        -DLOCALSTATEDIR="\"$(localstatedir)\"" \
 +        -DBINDIR="\"$(bindir)\""
 +
 +# -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
 +# This seems to matter nowhere but on windows, but I assure you that it
 +# matters a lot there, and is quite hard to debug if you forget to do it.
 +
 +
 +src_or_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
 +src_or_tor_LDADD = src/or/libtor.a src/common/libor.a \
 +	src/common/libor-crypto.a $(LIBDONNA) \
 +	src/common/libor-event.a \
 +	@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
 +	@TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
 +
 +ORHEADERS = \
 +	src/or/addressmap.h				\
 +	src/or/buffers.h				\
 +	src/or/channel.h				\
 +	src/or/channeltls.h				\
 +	src/or/circuitbuild.h				\
 +	src/or/circuitlist.h				\
 +	src/or/circuitmux.h				\
 +	src/or/circuitmux_ewma.h			\
 +	src/or/circuitstats.h				\
 +	src/or/circuituse.h				\
 +	src/or/command.h				\
 +	src/or/config.h					\
 +	src/or/confparse.h				\
 +	src/or/connection.h				\
 +	src/or/connection_edge.h			\
 +	src/or/connection_or.h				\
 +	src/or/control.h				\
 +	src/or/cpuworker.h				\
 +	src/or/directory.h				\
 +	src/or/dirserv.h				\
 +	src/or/dirvote.h				\
 +	src/or/dns.h					\
 +	src/or/dnsserv.h				\
 +	src/or/eventdns_tor.h				\
++	src/or/fp_pair.h				\
 +	src/or/geoip.h					\
 +	src/or/entrynodes.h				\
 +	src/or/hibernate.h				\
 +	src/or/main.h					\
 +	src/or/microdesc.h				\
 +	src/or/networkstatus.h				\
 +	src/or/nodelist.h				\
 +	src/or/ntmain.h					\
 +	src/or/onion.h					\
 +	src/or/onion_fast.h				\
 +	src/or/onion_ntor.h				\
 +	src/or/onion_tap.h				\
 +	src/or/or.h					\
 +	src/or/transports.h				\
 +	src/or/policies.h				\
 +	src/or/reasons.h				\
 +	src/or/relay.h					\
 +	src/or/rendclient.h				\
 +	src/or/rendcommon.h				\
 +	src/or/rendmid.h				\
 +	src/or/rendservice.h				\
 +	src/or/rephist.h				\
 +	src/or/replaycache.h				\
 +	src/or/router.h					\
 +	src/or/routerlist.h				\
 +	src/or/routerset.h				\
 +	src/or/routerparse.h				\
 +	src/or/statefile.h				\
 +	src/or/status.h
 +
 +noinst_HEADERS+= $(ORHEADERS) micro-revision.i
 +
 +src/or/config_codedigest.o: src/or/or_sha1.i
 +
 +micro-revision.i: FORCE
 +	@rm -f micro-revision.tmp;				\
 +	if test -d "$(top_srcdir)/.git" &&				\
 +	  test -x "`which git 2>&1;true`"; then				\
 +	  HASH="`cd "$(top_srcdir)" && git rev-parse --short=16 HEAD`";	\
 +	  echo \"$$HASH\" > micro-revision.tmp; 			\
 +        fi;								\
 +	if test ! -f micro-revision.tmp ; then			\
 +	  if test ! -f micro-revision.i ; then			\
 +	    echo '""' > micro-revision.i;			\
 +	  fi;								\
 +	elif test ! -f micro-revision.i ||			\
 +	  test x"`cat micro-revision.tmp`" != x"`cat micro-revision.i`"; then \
 +	  mv micro-revision.tmp micro-revision.i;		\
 +	fi; true
 +
 +src/or/or_sha1.i: $(src_or_tor_SOURCES) $(src_or_libtor_a_SOURCES) $(ORHEADERS)
 +	$(AM_V_GEN)if test "@SHA1SUM@" != none; then \
 +	  (cd "$(srcdir)" && "@SHA1SUM@" $(src_or_tor_SOURCES) $(src_or_libtor_a_SOURCES) $(ORHEADERS) ) | \
 +	  "@SED@" -n 's/^\(.*\)$$/"\1\\n"/p' > src/or/or_sha1.i; \
 +	elif test "@OPENSSL@" != none; then \
 +	  (cd "$(srcdir)" && "@OPENSSL@" sha1 $(src_or_tor_SOURCES) $(src_or_libtor_a_SOURCES) $(ORHEADERS)) | \
 +	  "@SED@" -n 's/SHA1(\(.*\))= \(.*\)/"\2  \1\\n"/p' > src/or/or_sha1.i; \
 +	else \
 +	  rm src/or/or_sha1.i; \
 +	  touch src/or/or_sha1.i; \
 +	fi
 +
 +CLEANFILES+= micro-revision.i src/or/micro-revision.i
 +
 +FORCE:
diff --cc src/or/routerlist.c
index 6ed168e,aa1660f..c2220f4
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@@ -20,7 -19,7 +20,8 @@@
  #include "directory.h"
  #include "dirserv.h"
  #include "dirvote.h"
 +#include "entrynodes.h"
+ #include "fp_pair.h"
  #include "geoip.h"
  #include "hibernate.h"
  #include "main.h"
@@@ -41,10 -39,25 +42,28 @@@
  
  /****************************************************************************/
  
+ DECLARE_TYPED_DIGESTMAP_FNS(sdmap_, digest_sd_map_t, signed_descriptor_t)
+ DECLARE_TYPED_DIGESTMAP_FNS(rimap_, digest_ri_map_t, routerinfo_t)
+ DECLARE_TYPED_DIGESTMAP_FNS(eimap_, digest_ei_map_t, extrainfo_t)
+ DECLARE_TYPED_DIGESTMAP_FNS(dsmap_, digest_ds_map_t, download_status_t)
+ #define SDMAP_FOREACH(map, keyvar, valvar)                              \
+   DIGESTMAP_FOREACH(sdmap_to_digestmap(map), keyvar, signed_descriptor_t *, \
+                     valvar)
+ #define RIMAP_FOREACH(map, keyvar, valvar) \
+   DIGESTMAP_FOREACH(rimap_to_digestmap(map), keyvar, routerinfo_t *, valvar)
+ #define EIMAP_FOREACH(map, keyvar, valvar) \
+   DIGESTMAP_FOREACH(eimap_to_digestmap(map), keyvar, extrainfo_t *, valvar)
+ #define DSMAP_FOREACH(map, keyvar, valvar) \
+   DIGESTMAP_FOREACH(dsmap_to_digestmap(map), keyvar, download_status_t *, \
+                     valvar)
+ 
+ /* Forward declaration for cert_list_t */
+ typedef struct cert_list_t cert_list_t;
+ 
  /* static function prototypes */
 +static int compute_weighted_bandwidths(const smartlist_t *sl,
 +                                       bandwidth_weight_rule_t rule,
 +                                       u64_dbl_t **bandwidths_out);
  static const routerstatus_t *router_pick_directory_server_impl(
                                             dirinfo_type_t auth, int flags);
  static const routerstatus_t *router_pick_trusteddirserver_impl(
@@@ -190,17 -272,23 +280,23 @@@ already_have_cert(authority_cert_t *cer
  }
  
  /** Load a bunch of new key certificates from the string <b>contents</b>.  If
-  * <b>from_store</b> is true, the certificates are from the cache, and we
-  * don't need to flush them to disk. If <b>flush</b> is true, we need
-  * to flush any changed certificates to disk now.  Return 0 on success, -1
-  * if any certs fail to parse. */
+  * <b>source</b> is TRUSTED_DIRS_CERTS_SRC_FROM_STORE, the certificates are
+  * from the cache, and we don't need to flush them to disk.  If we are a
+  * dirauth loading our own cert, source is TRUSTED_DIRS_CERTS_SRC_SELF.
+  * Otherwise, source is download type: TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST
+  * or TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_SK_DIGEST.  If <b>flush</b> is true, we
+  * need to flush any changed certificates to disk now.  Return 0 on success,
+  * -1 if any certs fail to parse.
+  */
+ 
  int
- trusted_dirs_load_certs_from_string(const char *contents, int from_store,
+ trusted_dirs_load_certs_from_string(const char *contents, int source,
                                      int flush)
  {
 -  trusted_dir_server_t *ds;
 +  dir_server_t *ds;
    const char *s, *eos;
    int failure_code = 0;
+   int from_store = (source == TRUSTED_DIRS_CERTS_SRC_FROM_STORE);
  
    for (s = contents; *s; s = eos) {
      authority_cert_t *cert = authority_cert_parse_from_string(s, &eos);
@@@ -504,10 -659,62 +666,63 @@@ authority_certs_fetch_missing(networkst
    if (should_delay_dir_fetches(get_options()))
      return;
  
-   pending = digestmap_new();
-   missing_digests = smartlist_new();
+   pending_cert = fp_pair_map_new();
+   pending_id = digestmap_new();
+   missing_cert_digests = smartlist_new();
+   missing_id_digests = smartlist_new();
+ 
+   /*
+    * First, we get the lists of already pending downloads so we don't
+    * duplicate effort.
+    */
+   list_pending_downloads(pending_id, DIR_PURPOSE_FETCH_CERTIFICATE, "fp/");
+   list_pending_fpsk_downloads(pending_cert);
  
-   list_pending_downloads(pending, DIR_PURPOSE_FETCH_CERTIFICATE, "fp/");
+   /*
+    * Now, we download any trusted authority certs we don't have by
+    * identity digest only.  This gets the latest cert for that authority.
+    */
 -  SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, trusted_dir_server_t *, ds) {
++  SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, dir_server_t *, ds) {
+     int found = 0;
+     if (!(ds->type & V3_DIRINFO))
+       continue;
 -    if (smartlist_digest_isin(missing_id_digests, ds->v3_identity_digest))
++    if (smartlist_contains_digest(missing_id_digests,
++                                  ds->v3_identity_digest))
+       continue;
+     cl = get_cert_list(ds->v3_identity_digest);
+     SMARTLIST_FOREACH_BEGIN(cl->certs, authority_cert_t *, cert) {
+       if (now < cert->expires) {
+         /* It's not expired, and we weren't looking for something to
+          * verify a consensus with.  Call it done. */
+         download_status_reset(&(cl->dl_status_by_id));
+         /* No sense trying to download it specifically by signing key hash */
+         download_status_reset_by_sk_in_cl(cl, cert->signing_key_digest);
+         found = 1;
+         break;
+       }
+     } SMARTLIST_FOREACH_END(cert);
+     if (!found &&
+         download_status_is_ready(&(cl->dl_status_by_id), now,
+                                  MAX_CERT_DL_FAILURES) &&
+         !digestmap_get(pending_id, ds->v3_identity_digest)) {
+       log_info(LD_DIR,
+                "No current certificate known for authority %s "
+                "(ID digest %s); launching request.",
+                ds->nickname, hex_str(ds->v3_identity_digest, DIGEST_LEN));
+       smartlist_add(missing_id_digests, ds->v3_identity_digest);
+     }
+   } SMARTLIST_FOREACH_END(ds);
+ 
+   /*
+    * Next, if we have a consensus, scan through it and look for anything
+    * signed with a key from a cert we don't have.  Those get downloaded
+    * by (fp,sk) pair, but if we don't know any certs at all for the fp
+    * (identity digest), and it's one of the trusted dir server certs
+    * we started off above or a pending download in pending_id, don't
+    * try to get it yet.  Most likely, the one we'll get for that will
+    * have the right signing key too, and we'd just be downloading
+    * redundantly.
+    */
    if (status) {
      SMARTLIST_FOREACH_BEGIN(status->voters, networkstatus_voter_info_t *,
                              voter) {
@@@ -517,7 -724,28 +732,29 @@@
        if (!cache &&
            !trusteddirserver_get_by_v3_auth_digest(voter->identity_digest))
          continue; /* We are not a cache, and we don't know this authority.*/
+ 
+       /*
+        * If we don't know *any* cert for this authority, and a download by ID
+        * is pending or we added it to missing_id_digests above, skip this
+        * one for now to avoid duplicate downloads.
+        */
        cl = get_cert_list(voter->identity_digest);
+       if (smartlist_len(cl->certs) == 0) {
+         /* We have no certs at all for this one */
+ 
+         /* Do we have a download of one pending? */
+         if (digestmap_get(pending_id, voter->identity_digest))
+           continue;
+ 
+         /*
+          * Are we about to launch a download of one due to the trusted
+          * dir server check above?
+          */
 -        if (smartlist_digest_isin(missing_id_digests, voter->identity_digest))
++        if (smartlist_contains_digest(missing_id_digests,
++                                      voter->identity_digest))
+           continue;
+       }
+ 
        SMARTLIST_FOREACH_BEGIN(voter->sigs, document_signature_t *, sig) {
          cert = authority_cert_get_by_digests(voter->identity_digest,
                                               sig->signing_key_digest);
diff --cc src/test/test_containers.c
index ca90162,5fee5c9..005e102
--- a/src/test/test_containers.c
+++ b/src/test/test_containers.c
@@@ -782,50 -783,88 +783,132 @@@ test_container_order_functions(void
    ;
  }
  
 +static void
 +test_di_map(void *arg)
 +{
 +  di_digest256_map_t *map = NULL;
 +  const uint8_t key1[] = "In view of the fact that it was ";
 +  const uint8_t key2[] = "superficially convincing, being ";
 +  const uint8_t key3[] = "properly enciphered in a one-tim";
 +  const uint8_t key4[] = "e cipher scheduled for use today";
 +  char *v1 = tor_strdup(", it came close to causing a disaster...");
 +  char *v2 = tor_strdup("I regret to have to advise you that the mission");
 +  char *v3 = tor_strdup("was actually initiated...");
 +  /* -- John Brunner, _The Shockwave Rider_ */
 +
 +  (void)arg;
 +
 +  /* Try searching on an empty map. */
 +  tt_ptr_op(NULL, ==, dimap_search(map, key1, NULL));
 +  tt_ptr_op(NULL, ==, dimap_search(map, key2, NULL));
 +  tt_ptr_op(v3, ==, dimap_search(map, key2, v3));
 +  dimap_free(map, NULL);
 +  map = NULL;
 +
 +  /* Add a single entry. */
 +  dimap_add_entry(&map, key1, v1);
 +  tt_ptr_op(NULL, ==, dimap_search(map, key2, NULL));
 +  tt_ptr_op(v3, ==, dimap_search(map, key2, v3));
 +  tt_ptr_op(v1, ==, dimap_search(map, key1, NULL));
 +
 +  /* Now try it with three entries in the map. */
 +  dimap_add_entry(&map, key2, v2);
 +  dimap_add_entry(&map, key3, v3);
 +  tt_ptr_op(v1, ==, dimap_search(map, key1, NULL));
 +  tt_ptr_op(v2, ==, dimap_search(map, key2, NULL));
 +  tt_ptr_op(v3, ==, dimap_search(map, key3, NULL));
 +  tt_ptr_op(NULL, ==, dimap_search(map, key4, NULL));
 +  tt_ptr_op(v1, ==, dimap_search(map, key4, v1));
 +
 + done:
 +  tor_free(v1);
 +  tor_free(v2);
 +  tor_free(v3);
 +  dimap_free(map, NULL);
 +}
 +
+ /** Run unit tests for fp_pair-to-void* map functions */
+ static void
+ test_container_fp_pair_map(void)
+ {
+   fp_pair_map_t *map;
+   fp_pair_t fp1, fp2, fp3, fp4, fp5, fp6;
+   void *v;
+   fp_pair_map_iter_t *iter;
+   fp_pair_t k;
+ 
+   map = fp_pair_map_new();
+   test_assert(map);
+   test_eq(fp_pair_map_size(map), 0);
+   test_assert(fp_pair_map_isempty(map));
+ 
+   memset(fp1.first, 0x11, DIGEST_LEN);
+   memset(fp1.second, 0x12, DIGEST_LEN);
+   memset(fp2.first, 0x21, DIGEST_LEN);
+   memset(fp2.second, 0x22, DIGEST_LEN);
+   memset(fp3.first, 0x31, DIGEST_LEN);
+   memset(fp3.second, 0x32, DIGEST_LEN);
+   memset(fp4.first, 0x41, DIGEST_LEN);
+   memset(fp4.second, 0x42, DIGEST_LEN);
+   memset(fp5.first, 0x51, DIGEST_LEN);
+   memset(fp5.second, 0x52, DIGEST_LEN);
+   memset(fp6.first, 0x61, DIGEST_LEN);
+   memset(fp6.second, 0x62, DIGEST_LEN);
+ 
+   v = fp_pair_map_set(map, &fp1, (void*)99);
+   test_eq(v, NULL);
+   test_assert(!fp_pair_map_isempty(map));
+   v = fp_pair_map_set(map, &fp2, (void*)101);
+   test_eq(v, NULL);
+   v = fp_pair_map_set(map, &fp1, (void*)100);
+   test_eq(v, (void*)99);
+   test_eq_ptr(fp_pair_map_get(map, &fp1), (void*)100);
+   test_eq_ptr(fp_pair_map_get(map, &fp2), (void*)101);
+   test_eq_ptr(fp_pair_map_get(map, &fp3), NULL);
+   fp_pair_map_assert_ok(map);
+ 
+   v = fp_pair_map_remove(map, &fp2);
+   fp_pair_map_assert_ok(map);
+   test_eq_ptr(v, (void*)101);
+   test_eq_ptr(fp_pair_map_get(map, &fp2), NULL);
+   test_eq_ptr(fp_pair_map_remove(map, &fp2), NULL);
+ 
+   fp_pair_map_set(map, &fp2, (void*)101);
+   fp_pair_map_set(map, &fp3, (void*)102);
+   fp_pair_map_set(map, &fp4, (void*)103);
+   test_eq(fp_pair_map_size(map), 4);
+   fp_pair_map_assert_ok(map);
+   fp_pair_map_set(map, &fp5, (void*)104);
+   fp_pair_map_set(map, &fp6, (void*)105);
+   fp_pair_map_assert_ok(map);
+ 
+   /* Test iterator. */
+   iter = fp_pair_map_iter_init(map);
+   while (!fp_pair_map_iter_done(iter)) {
+     fp_pair_map_iter_get(iter, &k, &v);
+     test_eq_ptr(v, fp_pair_map_get(map, &k));
+ 
+     if (tor_memeq(&fp2, &k, sizeof(fp2))) {
+       iter = fp_pair_map_iter_next_rmv(map, iter);
+     } else {
+       iter = fp_pair_map_iter_next(map, iter);
+     }
+   }
+ 
+   /* Make sure we removed fp2, but not the others. */
+   test_eq_ptr(fp_pair_map_get(map, &fp2), NULL);
+   test_eq_ptr(fp_pair_map_get(map, &fp5), (void*)104);
+ 
+   fp_pair_map_assert_ok(map);
+   /* Clean up after ourselves. */
+   fp_pair_map_free(map, NULL);
+   map = NULL;
+ 
+  done:
+   if (map)
+     fp_pair_map_free(map, NULL);
+ }
+ 
  #define CONTAINER_LEGACY(name)                                          \
    { #name, legacy_test_helper, 0, &legacy_setup, test_container_ ## name }
  
@@@ -840,7 -879,7 +923,8 @@@ struct testcase_t container_tests[] = 
    CONTAINER_LEGACY(strmap),
    CONTAINER_LEGACY(pqueue),
    CONTAINER_LEGACY(order_functions),
 +  { "di_map", test_di_map, 0, NULL, NULL },
+   CONTAINER_LEGACY(fp_pair_map),
    END_OF_TESTCASES
  };
  





More information about the tor-commits mailing list