diff --git a/.gitignore b/.gitignore
index fc86adc8e309d365f88226743990c0cfeeae4df9..b5d4442ca6896567fc75acd4f349078434388e59 100644
--- a/.gitignore
+++ b/.gitignore
@@ -142,6 +142,7 @@
 /src/or/or_sha1.i
 /src/or/micro-revision.*
 /src/or/tor
+/src/or/tor.exe
 /src/or/libtor.a
 
 # /src/test
@@ -154,6 +155,9 @@
 /src/tools/tor-checkkey
 /src/tools/tor-resolve
 /src/tools/tor-gencert
+/src/tools/tor-checkkey.exe
+/src/tools/tor-resolve.exe
+/src/tools/tor-gencert.exe
 /src/tools/Makefile
 /src/tools/Makefile.in
 
diff --git a/ChangeLog b/ChangeLog
index dc4cfe86c649b0a954590aa1d5c43166481516ca..891b66703688eeabe95bda244ba7b1a91a8f836b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,57 @@
+Changes in version 0.2.2.10-alpha - 2010-03-07
+  o Major bugfixes:
+    - Fix a regression from our patch for bug 1244 that caused relays
+      to guess their IP address incorrectly if they didn't set Address
+      in their torrc and/or their address fails to resolve. Bugfix on
+      0.2.2.9-alpha; fixes bug 1269.
+
+  o Major features (performance):
+    - Directory authorities now compute consensus weightings that instruct
+      clients how to weight relays flagged as Guard, Exit, Guard+Exit,
+      and no flag. Clients that use these weightings will distribute
+      network load more evenly across these different relay types. The
+      weightings are in the consensus so we can change them globally in
+      the future. Extra thanks to "outofwords" for finding some nasty
+      security bugs in the first implementation of this feature.
+
+  o Minor features (performance):
+    - Always perform router selections using weighted relay bandwidth,
+      even if we don't need a high capacity circuit at the time. Non-fast
+      circuits now only differ from fast ones in that they can use relays
+      not marked with the Fast flag. This "feature" could turn out to
+      be a horrible bug; we should investigate more before it goes into
+      a stable release.
+
+  o Minor features:
+    - Allow disabling building of the manpages. Skipping the manpage
+      speeds up the build considerably.
+
+  o Minor bugfixes (on 0.2.2.x):
+    - Fix a memleak in the EXTENDCIRCUIT logic. Spotted by coverity.
+      Bugfix on 0.2.2.9-alpha.
+    - Disallow values larger than INT32_MAX for PerConnBWRate|Burst
+      config option. Bugfix on 0.2.2.7-alpha.
+    - Ship the asciidoc-helper file in the tarball, so that people can
+      build from source if they want to, and touching the .1.txt files
+      doesn't break the build. Bugfix on 0.2.2.9-alpha.
+
+  o Minor bugfixes (on 0.2.1.x or earlier):
+    - Fix a dereference-then-NULL-check sequence when publishing
+      descriptors. Bugfix on 0.2.1.5-alpha. Discovered by ekir; fixes
+      bug 1255.
+    - Fix another dereference-then-NULL-check sequence. Bugfix on
+      0.2.1.14-rc. Discovered by ekir; fixes bug 1256.
+    - Make sure we treat potentially not NUL-terminated strings correctly.
+      Bugfix on 0.1.1.13-alpha. Discovered by rieo; fixes bug 1257.
+
+  o Code simplifications and refactoring:
+    - Fix some urls in the exit notice file and make it XHTML1.1 strict
+      compliant. Based on a patch from Christian Kujau.
+    - Don't use sed in asciidoc-helper anymore.
+    - Make the build process fail if asciidoc cannot be found and
+      building with asciidoc isn't disabled.
+
+
 Changes in version 0.2.2.9-alpha - 2010-02-22
   o Directory authority changes:
     - Change IP address for dannenberg (v3 directory authority), and
@@ -19,9 +73,9 @@ Changes in version 0.2.2.9-alpha - 2010-02-22
       that didn't allow exiting to any ports. This bug could screw
       with load balancing and stats. Bugfix on 0.1.1.6-alpha; fixes bug
       1238. Bug discovered by Martin Kowalczyk.
-    - When freeing a cipher, zero it out completely. We only zeroed
-      the first ptrsize bytes. Bugfix on tor-0.0.2pre8. Discovered
-      and patched by ekir. Fixes bug 1254.
+    - When freeing a session key, zero it out completely. We only zeroed
+      the first ptrsize bytes. Bugfix on 0.0.2pre8. Discovered and
+      patched by ekir. Fixes bug 1254.
 
   o Minor bugfixes:
     - Fix static compilation by listing the openssl libraries in the right
@@ -79,6 +133,27 @@ Changes in version 0.2.2.9-alpha - 2010-02-22
       open() without checking it.
 
 
+Changes in version 0.2.1.25 - 2010-03-??
+  o Major bugfixes:
+    - Fix a regression from our patch for bug 1244 that caused relays
+      to guess their IP address incorrectly if they didn't set Address
+      in their torrc and/or their address fails to resolve. Bugfix on
+      0.2.1.23; fixes bug 1269.
+    - When freeing a session key, zero it out completely. We only zeroed
+      the first ptrsize bytes. Bugfix on 0.0.2pre8. Discovered and
+      patched by ekir. Fixes bug 1254.
+
+  o Minor bugfixes:
+    - Fix a dereference-then-NULL-check sequence when publishing
+      descriptors. Bugfix on 0.2.1.5-alpha. Discovered by ekir; fixes
+      bug 1255.
+    - Fix another dereference-then-NULL-check sequence. Bugfix on
+      0.2.1.14-rc. Discovered by ekir; fixes bug 1256.
+    - Make sure we treat potentially not NUL-terminated strings correctly.
+      Bugfix on 0.1.1.13-alpha. Discovered by rieo; fixes bug 1257.
+
+
+
 Changes in version 0.2.1.24 - 2010-02-21
   Tor 0.2.1.24 makes Tor work again on the latest OS X -- this time
   for sure!
diff --git a/LICENSE b/LICENSE
index bb1ebd4e488f7643a6c7cf91c041ca07fc7c8975..c70312b7ee704acc6aa27d0187e35fdf724aebb4 100644
--- a/LICENSE
+++ b/LICENSE
@@ -14,7 +14,7 @@ Tor is distributed under this license:
 
 Copyright (c) 2001-2004, Roger Dingledine
 Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson
-Copyright (c) 2007-2009, The Tor Project, Inc.
+Copyright (c) 2007-2010, The Tor Project, Inc.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
diff --git a/Makefile.am b/Makefile.am
index b7dc6c8a5ef49bcd0638b418701b3057c0c5c77f..af3746e77a16776d3d1552a9fb16cb2f856715f1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
 # Copyright (c) 2001-2004, Roger Dingledine
 # Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson
-# Copyright (c) 2007-2009, The Tor Project, Inc.
+# Copyright (c) 2007-2010, The Tor Project, Inc.
 # See LICENSE for licensing information
 
 AUTOMAKE_OPTIONS = foreign
diff --git a/configure.in b/configure.in
index 0d82bb409bb22c075cf4266d2a80156b8af437f3..4f11f16dbfb2d862b36f9124371f5e20b5cdb8e5 100644
--- a/configure.in
+++ b/configure.in
@@ -4,7 +4,7 @@ dnl Copyright (c) 2007-2008, The Tor Project, Inc.
 dnl See LICENSE for licensing information
 
 AC_INIT
-AM_INIT_AUTOMAKE(tor, 0.2.2.9-alpha)
+AM_INIT_AUTOMAKE(tor, 0.2.2.10-alpha)
 AM_CONFIG_HEADER(orconfig.h)
 
 AC_CANONICAL_HOST
@@ -49,6 +49,15 @@ AC_ARG_ENABLE(transparent,
         *) AC_MSG_ERROR(bad value for --enable-transparent) ;;
       esac], [transparent=true])
 
+AC_ARG_ENABLE(asciidoc,
+     AS_HELP_STRING(--disable-asciidoc, don't use asciidoc (disables building of manpages)),
+     [case "${enableval}" in
+        yes) asciidoc=true ;;
+        no)  asciidoc=false ;;
+        *) AC_MSG_ERROR(bad value for --disable-asciidoc) ;;
+      esac], [asciidoc=true])
+
+
 AC_ARG_ENABLE(threads,
      AS_HELP_STRING(--disable-threads, disable multi-threading support))
 
@@ -97,6 +106,20 @@ AC_CHECK_PROG([SED],[sed],[sed],[/bin/false])
 dnl check for asciidoc and a2x
 AC_PATH_PROG([ASCIIDOC], [asciidoc], none)
 AC_PATH_PROG([A2X], [a2x], none)
+AC_PATH_PROG([XSLTPROC], [xsltproc], none)
+if test x$asciidoc = xtrue ; then
+   if test x$ASCIIDOC = xnone ; then
+       AC_MSG_ERROR("Couldn't find asciidoc. reconfigure with --disable-asciidoc to build without asciidoc.")
+   fi
+   if test x$A2X = xnone ; then
+       AC_MSG_ERROR("Couldn't find a2x. reconfigure with --disable-asciidoc to build without a2x.")
+   fi
+   if test x$XSLTPROC = xnone ; then
+       AC_MSG_ERROR("Couldn't find xsltproc. reconfigure with --disable-asciidoc to build without xsltproc.")
+   fi
+fi
+
+AM_CONDITIONAL(USE_ASCIIDOC, test x$asciidoc = xtrue)
 
 AC_PATH_PROG([SHA1SUM], [sha1sum], none)
 AC_PATH_PROG([OPENSSL], [openssl], none)
diff --git a/contrib/bundle.nsi b/contrib/bundle.nsi
index 0f1d82f3e605a8b32636f1171c2834d8680c8250..ffc64df3c8851c4b584012258c84233886954d19 100644
--- a/contrib/bundle.nsi
+++ b/contrib/bundle.nsi
@@ -22,7 +22,7 @@ VIProductVersion "${VERSION}"
 VIAddVersionKey "ProductName" "Tor"
 VIAddVersionKey "Comments" "${WEBSITE}"
 VIAddVersionKey "LegalTrademarks" "Three line BSD"
-VIAddVersionKey "LegalCopyright" "©2004-2009, Roger Dingledine, Nick Mathewson, The Tor Project, Inc."
+VIAddVersionKey "LegalCopyright" "©2004-2010, Roger Dingledine, Nick Mathewson, The Tor Project, Inc."
 VIAddVersionKey "FileDescription" "Tor is an implementation of Onion Routing. You can read more at ${WEBSITE}"
 VIAddVersionKey "FileVersion" "${VERSION}"
 
diff --git a/contrib/checkSpace.pl b/contrib/checkSpace.pl
index db061a08288ce471ec58652a7fb7aa8a7171d7e9..b694abff6437a43ff42da6f197c144d1af840724 100755
--- a/contrib/checkSpace.pl
+++ b/contrib/checkSpace.pl
@@ -28,11 +28,15 @@ for $fn (@ARGV) {
         if ($C && /\s(?:if|while|for|switch)\(/) {
             print "      KW(:$fn:$.\n";
         }
-	## Warn about #else #if instead of #elif. 
-	if (($lastline =~ /^\# *else/) and ($_ =~ /^\# *if/)) {
+        ## Warn about #else #if instead of #elif. 
+        if (($lastline =~ /^\# *else/) and ($_ =~ /^\# *if/)) {
             print " #else#if:$fn:$.\n";
-	}
-	$lastline = $_;
+        }
+        $lastline = $_;
+        ## Warn about unnecessary empty lines.
+        if ($lastnil && /^\s*}\n/) {
+            print "  UnnecNL:$fn:$.\n";
+        }
         ## Warn about multiple empty lines.
         if ($lastnil && /^$/) {
             print " DoubleNL:$fn:$.\n";
diff --git a/contrib/netinst.nsi b/contrib/netinst.nsi
index ef93aa07003049ae1262927b6f6c6c61369a590b..622310e9a3ae2805312269c46533cf22812c59f1 100644
--- a/contrib/netinst.nsi
+++ b/contrib/netinst.nsi
@@ -22,7 +22,7 @@ VIProductVersion "${VERSION}"
 VIAddVersionKey "ProductName" "Tor"
 VIAddVersionKey "Comments" "${WEBSITE}"
 VIAddVersionKey "LegalTrademarks" "Three line BSD"
-VIAddVersionKey "LegalCopyright" "©2004-2009, Roger Dingledine, Nick Mathewson, The Tor Project, Inc."
+VIAddVersionKey "LegalCopyright" "©2004-2010, Roger Dingledine, Nick Mathewson, The Tor Project, Inc."
 VIAddVersionKey "FileDescription" "Tor is an implementation of Onion Routing. You can read more at ${WEBSITE}"
 VIAddVersionKey "FileVersion" "${VERSION}"
 
diff --git a/contrib/polipo/README b/contrib/polipo/README
index e05ab0ceec2e04ace8794e4e8e35e6fcdbf701f5..6670d579ec311258828dd540d5958dd8ecf15856 100644
--- a/contrib/polipo/README
+++ b/contrib/polipo/README
@@ -1,5 +1,5 @@
 Copyright 2007-2008 Andrew Lewman
-Copyright 2009 The Tor Project
+Copyright 2009-2010 The Tor Project
 
 ----------------
 General Comments
@@ -49,8 +49,10 @@ installation package.
 ---------------------------------------------
 OSX Universal Binary and Installation package
 ---------------------------------------------
+You'll need the contrib/polipo directory from Tor's source distribution.
 1) Copy Makefile.osx over Makefile.
 2) Run 'make'.
-3) Copy the contents of this directory into a directory named "contrib".
-4) Run './contrib/package.sh'
-5) You should have a Polipo-version.dmg ready for installation.
+3) Copy the contents of contrib/polipo into a directory named "contrib".
+4) Run 'chmod +x ./contrib/package.sh'
+5) Run './contrib/package.sh'
+6) You should have a Polipo-version.dmg ready for installation.
diff --git a/contrib/polipo/package.sh b/contrib/polipo/package.sh
index 4ec72c81d8a3483ec2a8b129eb2043619b887507..61bd496f55fe079cc6ff7cb449264b30693c97fe 100644
--- a/contrib/polipo/package.sh
+++ b/contrib/polipo/package.sh
@@ -17,8 +17,9 @@ if [ -x /usr/bin/sw_vers ]; then
 # the OS version
   OSVER=`/usr/bin/sw_vers | grep ProductVersion | cut -f2 | cut -d"." -f1,2`
     case "$OSVER" in
-    "10.5") ARCH="universal";;
-	"10.4") ARCH="universal";;
+	"10.6") ARCH="i386";;
+	"10.5") ARCH="i386";;
+	"10.4") ARCH="i386";;
 	"10.3") ARCH="ppc";;
 	"10.2") ARCH="ppc";;
 	"10.1") ARCH="ppc";;
@@ -62,7 +63,7 @@ EOF
 
 ### Assemble documentation
 
-groff polipo.man -T ps -m man | pstopdf -i -o $BUILD_DIR/polipo_packageroot/polipo.pdf
+groff polipo.man -T ps -m man | /usr/bin/pstopdf -i -o $BUILD_DIR/polipo_packageroot/polipo.pdf
 texi2html polipo.texi && cp polipo.html $BUILD_DIR/polipo_packageroot/polipo.html
 
 find $BUILD_DIR/polipo_packageroot -print0 |sudo xargs -0 chown root:wheel
@@ -77,8 +78,8 @@ $PACKAGEMAKER -build              \
 
 find $BUILD_DIR/output -print0 | sudo xargs -0 chown root:wheel
 
-mv $BUILD_DIR/output "$BUILD_DIR/Polipo-$VERSION-$ARCH"
-rm -f "Polipo-$VERSION-$ARCH-Bundle.dmg"
+sudo mv $BUILD_DIR/output "$BUILD_DIR/Polipo-$VERSION-$ARCH"
+sudo rm -f "Polipo-$VERSION-$ARCH-Bundle.dmg"
 USER="`whoami`"
 sudo hdiutil create -format UDZO -srcfolder "$BUILD_DIR/Polipo-$VERSION-$ARCH" "Polipo-$VERSION-$ARCH.dmg"
 sudo chown "$USER" "Polipo-$VERSION-$ARCH.dmg"
diff --git a/contrib/tor-exit-notice.html b/contrib/tor-exit-notice.html
index 4ab028fc75a09e8489673afda679be813dd740a4..78a148ccc6ee39dd3e1418f79da7a35a7ad91831 100644
--- a/contrib/tor-exit-notice.html
+++ b/contrib/tor-exit-notice.html
@@ -1,5 +1,9 @@
-<html>
+<?xml version="1.0"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
 <title>This is a Tor Exit Router</title>
 
 <!--
@@ -19,29 +23,30 @@ They are marked with FIXME.
 -->
 
 </head>
-<body bgcolor=white text=black>
+<body>
 
-<center><h1>This is a Tor Exit Router</h1></center>
+<p style="text-align:center; font-size:xx-large; font-weight:bold">This is a
+Tor Exit Router</p>
 
-<p>Most likely you are accessing this website because you had some issue with
+<p>
 the traffic coming from this IP. This router is part of the <a
 href="https://www.torproject.org/">Tor Anonymity Network</a>, which is
-dedicated to <a href="https://www.torproject.org/30seconds.html.en">providing
+dedicated to <a href="https://www.torproject.org/overview.html">providing
 privacy</a> to people who need it most: average computer users. This
 router IP should be generating no other traffic, unless it has been
-compromised.
-
-<p>
+compromised.</p>
 
 
 <!-- FIXME: you should probably grab your own copy of how_tor_works_thumb.png
-and serve it locally -->
-<center><a href="https://www.torproject.org/overview.html">
-<img src="https://www.torproject.org/images/how_tor_works_thumb.png"></a></center>
+     and serve it locally -->
 
-<p>
+<p style="text-align:center">
+<a href="https://www.torproject.org/overview.html">
+<img src="https://www.torproject.org/images/how_tor_works_thumb.png" alt="How Tor works" style="border-style:none"/>
+</a></p>
 
-Tor sees use by <a href="https://www.torproject.org/torusers.html.en">many
+<p>
+Tor sees use by <a href="https://www.torproject.org/torusers.html">many
 important segments of the population</a>, including whistle blowers,
 journalists, Chinese dissidents skirting the Great Firewall and oppressive
 censorship, abuse victims, stalker targets, the US military, and law
@@ -59,44 +64,41 @@ powerful networks</a> than Tor on a daily basis. Thus, in the mind of this
 operator, the social need for easily accessible censorship-resistant private,
 anonymous communication trumps the risk of unskilled bad actors, who are
 almost always more easily uncovered by traditional police work than by
-extensive monitoring and surveillance anyway.
+extensive monitoring and surveillance anyway.</p>
 
 <p>
-
 In terms of applicable law, the best way to understand Tor is to consider it a
 network of routers operating as common carriers, much like the Internet
 backbone. However, unlike the Internet backbone routers, Tor routers
 explicitly do not contain identifiable routing information about the source of
 a packet, and no single Tor node can determine both the origin and destination
-of a given transmission.
+of a given transmission.</p>
 
 <p>
-
 As such, there is little the operator of this router can do to help you track
 the connection further. This router maintains no logs of any of the Tor
 traffic, so there is little that can be done to trace either legitimate or
 illegitimate traffic (or to filter one from the other).  Attempts to
-seize this router will accomplish nothing.
-<p>
+seize this router will accomplish nothing.</p>
 
-<!--- FIXME: US-Only section. Remove if you are a non-US operator -->
+<!-- FIXME: US-Only section. Remove if you are a non-US operator -->
 
+<p>
 Furthermore, this machine also serves as a carrier of email, which means that
 its contents are further protected under the ECPA. <a
 href="http://www4.law.cornell.edu/uscode/html/uscode18/usc_sec_18_00002707----000-.html">18
 USC 2707</a> explicitly allows for civil remedies ($1000/account
-<i><b><u>plus</u></b></i>  legal fees)
+<i><b>plus</b></i>  legal fees)
 in the event of a seizure executed without good faith or probable cause (it
 should be clear at this point that traffic with an originating IP address of
 FIXME_DNS_NAME should not constitute probable cause to seize the
 machine). Similar considerations exist for 1st amendment content on this
-machine.
-
-<p>
+machine.</p>
 
 <!-- FIXME: May or may not be US-only. Some non-US tor nodes have in
-fact reported DMCA harassment... -->
+     fact reported DMCA harassment... -->
 
+<p>
 If you are a representative of a company who feels that this router is being
 used to violate the DMCA, please be aware that this machine does not host or
 contain any illegal content. Also be aware that network infrastructure
@@ -106,35 +108,36 @@ href="http://www4.law.cornell.edu/uscode/html/uscode17/usc_sec_17_00000512----00
 "safe harbor" provisions</a>. In other words, you will have just as much luck
 sending a takedown notice to the Internet backbone providers. Please consult
 <a href="https://www.torproject.org/eff/tor-dmca-response.html">EFF's prepared
-response</a> for more information on this matter.
+response</a> for more information on this matter.</p>
 
-<p>For more information, please consult the following documentation:
+<p>For more information, please consult the following documentation:</p>
 
 <ol>
 <li><a href="https://www.torproject.org/overview.html">Tor Overview</a></li>
 <li><a href="https://www.torproject.org/faq-abuse.html">Tor Abuse FAQ</a></li>
 <li><a href="https://www.torproject.org/eff/tor-legal-faq.html">Tor Legal FAQ</a></li>
 </ol>
-<p>
 
+<p>
 That being said, if you still have a complaint about the router,  you may
 email the <a href="mailto:FIXME_YOUR_EMAIL_ADDRESS">maintainer</a>. If
 complaints are related to a particular service that is being abused, I will
 consider removing that service from my exit policy, which would prevent my
 router from allowing that traffic to exit through it. I can only do this on an
 IP+destination port basis, however. Common P2P ports are
-already blocked.
+already blocked.</p>
 
-<p>You also have the option of blocking this IP address and others on
+<p>
+You also have the option of blocking this IP address and others on
 the Tor network if you so desire. The Tor project provides a <a
-href="https://tor-svn.freehaven.net/svn/tor/trunk/contrib/exitlist">python script</a> to
-extract all IP addresses of Tor exit nodes, and an official <a
+href="https://check.torproject.org/cgi-bin/TorBulkExitList.py">web service</a>
+to fetch a list of all IP addresses of Tor exit nodes that allow exiting to a
+specified IP:port combination, and an official <a
 href="https://www.torproject.org/tordnsel/">DNSRBL</a> is also available to
 determine if a given IP address is actually a Tor exit server. Please
 be considerate
 when using these options. It would be unfortunate to deny all Tor users access
-to your site indefinitely simply because of a few bad apples.
+to your site indefinitely simply because of a few bad apples.</p>
 
 </body>
 </html>
-
diff --git a/contrib/tor-mingw.nsi.in b/contrib/tor-mingw.nsi.in
index e4fef695618ea2d9035d21bb21ec13179c2c44da..bc9eef08aff2223168c4514cdb7523593248de83 100644
--- a/contrib/tor-mingw.nsi.in
+++ b/contrib/tor-mingw.nsi.in
@@ -9,7 +9,7 @@
 !include "FileFunc.nsh"
 !insertmacro GetParameters
 
-!define VERSION "0.2.2.9-alpha"
+!define VERSION "0.2.2.10-alpha"
 !define INSTALLER "tor-${VERSION}-win32.exe"
 !define WEBSITE "https://www.torproject.org/"
 !define LICENSE "LICENSE"
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 492dd3bd51d4a07ecbfb650d3819552a133bee05..e7edb0476bd0db071d6e0ff067d5f1585d59c2e3 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -13,13 +13,17 @@
 # part of the source distribution, so that people without asciidoc can
 # just use the .1 and .html files.
 
+if USE_ASCIIDOC
 asciidoc_files = tor tor-gencert tor-resolve torify
+else
+asciidoc_files =
+endif
 
 html_in = $(asciidoc_files:=.html.in)
 
 man_in = $(asciidoc_files:=.1.in)
 
-EXTRA_DIST = HACKING                                         \
+EXTRA_DIST = HACKING asciidoc-helper.sh                      \
              $(html_in) $(man_in) $(asciidoc_files:=.1.txt)  \
              tor-osx-dmg-creation.txt tor-rpm-creation.txt   \
              tor-win32-mingw-creation.txt
@@ -39,7 +43,7 @@ DIST_SUBDIRS = spec
 # Generate the html documentation from asciidoc, but don't do
 # machine-specific replacements yet
 $(html_in) :
-	$(top_srcdir)/doc/asciidoc-helper.sh html @ASCIIDOC@ @SED@ $(top_srcdir)/doc/$@
+	$(top_srcdir)/doc/asciidoc-helper.sh html @ASCIIDOC@ $(top_srcdir)/doc/$@
 
 tor.html.in : tor.1.txt
 torify.html.in : torify.1.txt
@@ -49,7 +53,7 @@ tor-resolve.html.in : tor-resolve.1.txt
 # Generate the manpage from asciidoc, but don't do
 # machine-specific replacements yet
 $(man_in) :
-	$(top_srcdir)/doc/asciidoc-helper.sh man @A2X@ @SED@ $(top_srcdir)/doc/$@
+	$(top_srcdir)/doc/asciidoc-helper.sh man @A2X@ $(top_srcdir)/doc/$@
 
 tor.1.in : tor.1.txt
 torify.1.in : torify.1.txt
diff --git a/doc/asciidoc-helper.sh b/doc/asciidoc-helper.sh
index 90a003d496f485997c8be6238ca1cc3cfa65722e..d24b31918c6290752cce08ea4066488d75d9a294 100755
--- a/doc/asciidoc-helper.sh
+++ b/doc/asciidoc-helper.sh
@@ -4,51 +4,34 @@
 # See LICENSE for licensing information
 # Run this to generate .html.in or .1.in files from asciidoc files.
 # Arguments:
-# html|man asciidocpath sedpath outputfile
+# html|man asciidocpath outputfile
 
 set -e
 
-if [ $# != 4 ]; then
+if [ $# != 3 ]; then
   exit 1;
 fi
 
-output=$4
-input=`echo $output | $3 -e 's/html\.in$/1\.txt/g' -e 's/1\.in$/1\.txt/g'`
-base=`echo $output | $3 -e 's/\.html\.in$//g' -e 's/\.1\.in$//g'`
+output=$3
 
 if [ "$1" = "html" ]; then
-    if [ "$2" != none ]; then
-      "$2" -d manpage -o $output $input;
-    else
-      echo "==================================";
-      echo;
-      echo "The manpage in html form for $base will ";
-      echo "NOT be available, because asciidoc doesn't appear to be ";
-      echo "installed!";
-      echo;
-      echo "==================================";
-    fi
+    input=${output%%.html.in}.1.txt
+    base=${output%%.html.in}
+    "$2" -d manpage -o $output $input;
 elif [ "$1" = "man" ]; then
-    if test "$2" != none; then
-      if $2 -f manpage $input; then
-        mv $base.1 $output;
-      else
-        echo "==================================";
-        echo;
-        echo "a2x is installed, but some required docbook support files are";
-        echo "missing. Please install docbook-xsl and docbook-xml (Debian)";
-        echo "or similar.";
-        echo;
-        echo "==================================";
-      fi;
+    input=${output%%.1.in}.1.txt
+    base=${output%%.1.in}
+    
+    if "$2" -f manpage $input; then
+      mv $base.1 $output;
     else
       echo "==================================";
       echo;
-      echo "The manpage for $base will NOT be ";
-      echo "available, because a2x doesn't appear to be installed!";
+      echo "a2x is installed, but some required docbook support files are";
+      echo "missing. Please install docbook-xsl and docbook-xml (Debian)";
+      echo "or similar.";
       echo;
       echo "==================================";
+      exit 1;
     fi
 fi
-
-touch $output; \
diff --git a/doc/spec/control-spec.txt b/doc/spec/control-spec.txt
index 7d3312a5a8c42767615b63094fcb53667ab6a69c..9ae51b0a1bfb4bcc7b4ee67343e18ed4d566a1b0 100644
--- a/doc/spec/control-spec.txt
+++ b/doc/spec/control-spec.txt
@@ -87,6 +87,10 @@
 
 2.4. General-use tokens
 
+  ; CRLF means, "the ASCII Carriage Return character (decimal value value 13)
+  ; followed by the ASCII Linefeed character (decimal value 10)."
+  CRLF = CR LF
+
   ; Identifiers for servers.
   ServerID = Nickname / Fingerprint
 
diff --git a/doc/spec/dir-spec.txt b/doc/spec/dir-spec.txt
index 19a32027afc19013087217d2e7bb3a8d987eae41..442e7d5824829264c17bc23497db97a70df3d618 100644
--- a/doc/spec/dir-spec.txt
+++ b/doc/spec/dir-spec.txt
@@ -1304,8 +1304,57 @@
         or does not support (if 'reject') for exit to "most
         addresses".
 
-   The signature section contains the following item, which appears
-   Exactly Once for a vote, and At Least Once for a consensus.
+   The footer section is delineated in all votes and consensuses supporting
+   consensus method 9 and above with the following:
+
+    "directory-footer" NL
+
+   It contains two subsections, a bandwidths-weights line and a
+   directory-signature.
+
+   The bandwidths-weights line appears At Most Once for a consensus. It does
+   not appear in votes.
+
+    "bandwidth-weights" SP
+       "Wbd=" INT SP "Wbe=" INT SP "Wbg=" INT SP "Wbm=" INT SP
+       "Wdb=" INT SP
+       "Web=" INT SP "Wed=" INT SP "Wee=" INT SP "Weg=" INT SP "Wem=" INT SP
+       "Wgb=" INT SP "Wgd=" INT SP "Wgg=" INT SP "Wgm=" INT SP
+       "Wmb=" INT SP "Wmd=" INT SP "Wme=" INT SP "Wmg=" INT SP "Wmm=" INT NL
+
+       These values represent the weights to apply to router bandwidths during
+       path selection. They are sorted in alphabetical order in the list. The
+       integer values are divided by BW_WEIGHT_SCALE=10000 or the consensus
+       param "bwweightscale". They are:
+
+         Wgg - Weight for Guard-flagged nodes in the guard position
+         Wgm - Weight for non-flagged nodes in the guard Position
+         Wgd - Weight for Guard+Exit-flagged nodes in the guard Position
+
+         Wmg - Weight for Guard-flagged nodes in the middle Position
+         Wmm - Weight for non-flagged nodes in the middle Position
+         Wme - Weight for Exit-flagged nodes in the middle Position
+         Wmd - Weight for Guard+Exit flagged nodes in the middle Position
+
+         Weg - Weight for Guard flagged nodes in the exit Position
+         Wem - Weight for non-flagged nodes in the exit Position
+         Wee - Weight for Exit-flagged nodes in the exit Position
+         Wed - Weight for Guard+Exit-flagged nodes in the exit Position
+
+         Wgb - Weight for BEGIN_DIR-supporting Guard-flagged nodes
+         Wmb - Weight for BEGIN_DIR-supporting non-flagged nodes
+         Web - Weight for BEGIN_DIR-supporting Exit-flagged nodes
+         Wdb - Weight for BEGIN_DIR-supporting Guard+Exit-flagged nodes
+
+         Wbg - Weight for Guard+Exit-flagged nodes for BEGIN_DIR requests
+         Wbm - Weight for Guard+Exit-flagged nodes for BEGIN_DIR requests
+         Wbe - Weight for Guard+Exit-flagged nodes for BEGIN_DIR requests
+         Wbd - Weight for Guard+Exit-flagged nodes for BEGIN_DIR requests
+
+       These values are calculated as specified in Section 3.4.3.
+
+   The signature contains the following item, which appears Exactly Once
+   for a vote, and At Least Once for a consensus.
 
     "directory-signature" SP identity SP signing-key-digest NL Signature
 
@@ -1554,6 +1603,9 @@
      "4" -- No longer list routers that are not running in the consensus
      "5" -- adds support for "w" and "p" lines.
      "6" -- Prefers measured bandwidth values rather than advertised
+     "7" -- Provides keyword=integer pairs of consensus parameters
+     "8" -- Provides microdescriptor summaries
+     "9" -- Provides weights for selecting flagged routers in paths
 
    Before generating a consensus, an authority must decide which consensus
    method to use.  To do this, it looks for the highest version number
@@ -1586,6 +1638,147 @@
   use an accept-style summary and list as much of the port list as is
   possible within these 1000 bytes.  [XXXX be more specific.]
 
+3.4.3. Computing Bandwidth Weights
+
+  Let weight_scale = 10000
+
+  Let G be the total bandwidth for Guard-flagged nodes.
+  Let M be the total bandwidth for non-flagged nodes.
+  Let E be the total bandwidth for Exit-flagged nodes.
+  Let D be the total bandwidth for Guard+Exit-flagged nodes.
+  Let T = G+M+E+D
+
+  Let Wgd be the weight for choosing a Guard+Exit for the guard position.
+  Let Wmd be the weight for choosing a Guard+Exit for the middle position.
+  Let Wed be the weight for choosing a Guard+Exit for the exit position.
+
+  Let Wme be the weight for choosing an Exit for the middle position.
+  Let Wmg be the weight for choosing a Guard for the middle position.
+
+  Let Wgg be the weight for choosing a Guard for the guard position.
+  Let Wee be the weight for choosing an Exit for the exit position.
+
+  Balanced network conditions then arise from solutions to the following
+  system of equations:
+
+      Wgg*G + Wgd*D == M + Wmd*D + Wme*E + Wmg*G  (guard bw = middle bw)
+      Wgg*G + Wgd*D == Wee*E + Wed*D              (guard bw = exit bw)
+      Wed*D + Wmd*D + Wgd*D == D                  (aka: Wed+Wmd+Wdg = 1)
+      Wmg*G + Wgg*G == G                          (aka: Wgg = 1-Wmg)
+      Wme*E + Wee*E == E                          (aka: Wee = 1-Wme)
+
+  We are short 2 constraints with the above set. The remaining constraints
+  come from examining different cases of network load.
+
+  Case 1: E >= T/3 && G >= T/3 (Neither Exit nor Guard Scarce)
+
+    In this case, the additional two constraints are: Wme*E == Wmd*D and
+    Wgd == 0, which maximizes Exit-flagged bandwidth in the middle position.
+
+    This leads to the solution:
+
+       Wgg = (weight_scale*(D+E+G+M))/(3*G)
+       Wmd = (weight_scale*(2*D + 2*E - G - M))/(6*D)
+       Wme = (weight_scale*(2*D + 2*E - G - M))/(6*E)
+       Wee = (weight_scale*(-2*D + 4*E + G + M))/(6*E)
+       Wmg = weight_scale - Wgg
+       Wed = weight_scale - Wmd
+       Wgd = 0
+
+  Case 2: E < T/3 && G < T/3 (Both are scarce)
+
+    Let R denote the more scarce class (Rare) between Guard vs Exit.
+    Let S denote the less scarce class.
+
+    Subcase a: R+D < S
+
+       In this subcase, we simply devote all of D bandwidth to the
+       scarce class.
+
+       Wgg = Wee = weight_scale
+       Wmg = Wme = Wmd = 0;
+       if E < G:
+         Wed = weight_scale
+         Wgd = 0
+       else:
+         Wed = 0
+         Wgd = weight_scale
+
+    Subcase b: R+D >= S
+
+      In this case, if M <= T/3, we have enough bandwidth to try to achieve
+      a balancing condition, and add the constraints Wgg == 1 and
+      Wme*E == Wmd*D:
+
+         Wgg = weight_scale
+         Wgd = (weight_scale*(D + E - 2*G + M))/(3*D)      (T/3 >= G (Ok))
+         Wmd = (weight_scale*(D + E + G - 2*M))/(6*D)      (T/3 >= M)
+         Wme = (weight_scale*(D + E + G - 2*M))/(6*E)
+         Wee = (weight_scale*(-D + 5*E - G + 2*M))/(6*E)   (2E+M >= T/3)
+         Wmg = 0;
+         Wed = weight_scale - Wgd - Wmd
+
+      If M >= T/3, the above solution will not be valid (one of the weights
+      will be < 0 or > 1). In this case, we use:
+
+         Wgg = weight_scale
+         Wee = weight_scale
+         Wmg = Wme = Wmd = 0
+         Wgd = (weight_scale*(D+E-G))/(2*D)
+         Wed = weight_scale - Wgd
+
+  Case 3: One of E < T/3 or G < T/3
+
+    Let S be the scarce class (of E or G).
+
+    Subcase a: (S+D) < T/3:
+      if G=S:
+          Wgg = Wgd = weight_scale;
+          Wmd = Wed = Wmg = 0;
+          Wme = (weight_scale*(E-M))/(2*E);
+          Wee = weight_scale-Wme;
+      if E=S:
+          Wee = Wed = weight_scale;
+          Wmd = Wgd = Wmg = 0;
+          Wmg = (weight_scale*(G-M))/(2*G);
+          Wgg = weight_scale-Wmg;
+
+    Subcase b: (S+D) >= T/3
+      if G=S:
+        Add constraints Wmg = 0, Wme*E == Wmd*D to maximize exit bandwidth
+        in the middle position:
+          Wgd = (weight_scale*(D + E - 2*G + M))/(3*D);
+          Wmd = (weight_scale*(D + E + G - 2*M))/(6*D);
+          Wme = (weight_scale*(D + E + G - 2*M))/(6*E);
+          Wee = (weight_scale*(-D + 5*E - G + 2*M))/(6*E);
+          Wgg = weight_scale;
+          Wmg = 0;
+          Wed = weight_scale - Wgd - Wmd;
+      if E=S:
+        Add constraints Wgd = 0, Wme*E == Wmd*D:
+          Wgg = (weight_scale*(D + E + G + M))/(3*G);
+          Wmd = (weight_scale*(2*D + 2*E - G - M))/(6*D);
+          Wme = (weight_scale*(2*D + 2*E - G - M))/(6*E);
+          Wee = (weight_scale*(-2*D + 4*E + G + M))/(6*E);
+          Wgd = 0;
+          Wmg = weight_scale - Wgg;
+          Wed = weight_scale - Wmd;
+
+  To ensure consensus, all calculations are performed using integer math
+  with a fixed precision determined by the bwweightscale consensus
+  parameter (defaults at 10000).
+
+  For future balancing improvements, Tor clients support 11 additional weights
+  for directory requests and middle weighting. These weights are currently
+  set at weight_scale, with the exception of the following groups of
+  assignments:
+
+  Directory requests use middle weights:
+     Wbd=Wmd, Wbg=Wmg, Wbe=Wme, Wbm=Wmm
+
+  Handle bridges and strange exit policies:
+     Wgm=Wgg, Wem=Wee, Weg=Wed
+
 3.5. Detached signatures
 
    Assuming full connectivity, every authority should compute and sign the
diff --git a/doc/spec/path-spec.txt b/doc/spec/path-spec.txt
index 78f3b63bcbfebd11402069c9741204a2debc1a6b..8a85718a089d7d8529a1f78d650d51fa37904dc5 100644
--- a/doc/spec/path-spec.txt
+++ b/doc/spec/path-spec.txt
@@ -192,23 +192,41 @@ of their choices.
        below)
      - XXXX Choosing the length
 
-   For circuits that do not need to be "fast", when choosing among
-   multiple candidates for a path element, we choose randomly.
-
-   For "fast" circuits, we pick a given router as an exit with probability
-   proportional to its bandwidth.
-
-   For non-exit positions on "fast" circuits, we pick routers as above, but
-   we weight the bandwidth of Exit-flagged nodes depending
-   on the fraction of bandwidth available from non-Exit nodes.  Call the
-   total bandwidth for Exit nodes under consideration E,
-   and the total bandwidth for all nodes under
-   consideration T.  If E<T/3, we do not consider Exit-flagged nodes.
-   Otherwise, we weight their bandwidth with the factor (E-T/3)/E. This 
-   ensures that bandwidth is evenly distributed over nodes in 3-hop paths.
-
-   Similarly, guard nodes are weighted by the factor (G-T/3)/G, and not
-   considered for non-guard positions if this value is less than 0.
+   For "fast" circuits, we only choose nodes with the Fast flag. For
+   non-"fast" circuits, all nodes are eligible.
+
+   For all circuits, we weight node selection according to router bandwidth.
+
+   We also weight the bandwidth of Exit and Guard flagged nodes depending on
+   the fraction of total bandwidth that they make up and depending upon the
+   position they are being selected for.
+
+   These weights are published in the consensus, and are computed as described
+   in Section 3.4.3 of dir-spec.txt. They are:
+
+      Wgg - Weight for Guard-flagged nodes in the guard position
+      Wgm - Weight for non-flagged nodes in the guard Position
+      Wgd - Weight for Guard+Exit-flagged nodes in the guard Position
+
+      Wmg - Weight for Guard-flagged nodes in the middle Position
+      Wmm - Weight for non-flagged nodes in the middle Position
+      Wme - Weight for Exit-flagged nodes in the middle Position
+      Wmd - Weight for Guard+Exit flagged nodes in the middle Position
+
+      Weg - Weight for Guard flagged nodes in the exit Position
+      Wem - Weight for non-flagged nodes in the exit Position
+      Wee - Weight for Exit-flagged nodes in the exit Position
+      Wed - Weight for Guard+Exit-flagged nodes in the exit Position
+
+      Wgb - Weight for BEGIN_DIR-supporting Guard-flagged nodes
+      Wmb - Weight for BEGIN_DIR-supporting non-flagged nodes
+      Web - Weight for BEGIN_DIR-supporting Exit-flagged nodes
+      Wdb - Weight for BEGIN_DIR-supporting Guard+Exit-flagged nodes
+
+      Wbg - Weight for Guard+Exit-flagged nodes for BEGIN_DIR requests
+      Wbm - Weight for Guard+Exit-flagged nodes for BEGIN_DIR requests
+      Wbe - Weight for Guard+Exit-flagged nodes for BEGIN_DIR requests
+      Wbd - Weight for Guard+Exit-flagged nodes for BEGIN_DIR requests
 
    Additionally, we may be building circuits with one or more requests in
    mind.  Each kind of request puts certain constraints on paths:
diff --git a/doc/spec/proposals/000-index.txt b/doc/spec/proposals/000-index.txt
index 664c5654dacf3352ef12aea330f3333ff103e13a..62327a1e61fa9867c1e813f3b5e3a51457431432 100644
--- a/doc/spec/proposals/000-index.txt
+++ b/doc/spec/proposals/000-index.txt
@@ -90,6 +90,7 @@ Proposals by number:
 167  Vote on network parameters in consensus [CLOSED]
 168  Reduce default circuit window [OPEN]
 169  Eliminate TLS renegotiation for the Tor connection handshake [DRAFT]
+170  Configuration options regarding circuit building [DRAFT]
 
 
 Proposals by status:
@@ -101,6 +102,7 @@ Proposals by status:
    141  Download server descriptors on demand
    144  Increase the diversity of circuits by detecting nodes belonging the same provider
    169  Eliminate TLS renegotiation for the Tor connection handshake [for 0.2.2]
+   170  Configuration options regarding circuit building
  NEEDS-REVISION:
    131  Help users to verify they are using Tor
  OPEN:
diff --git a/doc/spec/proposals/170-user-path-config.txt b/doc/spec/proposals/170-user-path-config.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fa74c76f7374e68ff36b52d1845f476abadebc67
--- /dev/null
+++ b/doc/spec/proposals/170-user-path-config.txt
@@ -0,0 +1,95 @@
+Title: Configuration options regarding circuit building
+Filename: 170-user-path-config.txt
+Author: Sebastian Hahn
+Created: 01-March-2010
+Status: Draft
+
+Overview:
+
+    This document outlines how Tor handles the user configuration
+    options to influence the circuit building process.
+
+Motivation:
+
+    Tor's treatment of the configuration *Nodes options was surprising
+    to many users, and quite a few conspiracy theories have crept up. We
+    should update our specification and code to better describe and
+    communicate what is going during circuit building, and how we're
+    honoring configuration. So far, we've been tracking a bugreport
+    about this behaviour (
+    https://bugs.torproject.org/flyspray/index.php?do=details&id=1090 )
+    and Nick replied in a thread on or-talk (
+    http://archives.seul.org/or/talk/Feb-2010/msg00117.html ).
+
+    This proposal tries to document our intention for those configuration
+    options.
+
+Design:
+
+    Five configuration options are available to users to influence Tor's
+    circuit building. EntryNodes and ExitNodes define a list of nodes
+    that are for the Entry/Exit position in all circuits. ExcludeNodes
+    is a list of nodes that are used for no circuit, and
+    ExcludeExitNodes is a list of nodes that aren't used as the last
+    hop. StrictNodes defines Tor's behaviour in case of a conflict, for
+    example when a node that is excluded is the only available
+    introduction point. Setting StrictNodes to 1 breaks Tor's
+    functionality in that case, and it will refuse to build such a
+    circuit.
+
+    Neither Nick's email nor bug 1090 have clear suggestions how we
+    should behave in each case, so I tried to come up with something
+    that made sense to me.
+
+Security implications:
+
+    Deviating from normal circuit building can break one's anonymity, so
+    the documentation of the above option should contain a warning to
+    make users aware of the pitfalls.
+
+Specification:
+
+    It is proposed that the "User configuration" part of path-spec
+    (section 2.2.2) be replaced with this:
+
+    Users can alter the default behavior for path selection with
+    configuration options. In case of conflicts (excluding and requiring
+    the same node) the "StrictNodes" option is used to determine
+    behaviour. If a nodes is both excluded and required via a
+    configuration option, the exclusion takes preference.
+
+    - If "ExitNodes" is provided, then every request requires an exit
+      node on the ExitNodes list. If a request is supported by no nodes
+      on that list, and "StrictNodes" is false, then Tor treats that
+      request as if ExitNodes were not provided.
+
+    - "EntryNodes" behaves analogously.
+
+    - If "ExcludeNodes" is provided, then no circuit uses any of the
+      nodes listed. If a circuit requires an excluded node to be used,
+      and "StrictNodes" is false, then Tor uses the node in that
+      position while not using any other of the excluded nodes.
+
+    - If "ExcludeExitNodes" is provided, then Tor will not use the nodes
+      listed for the exit position in a circuit. If a circuit requires
+      an excluded node to be used in the exit position and "StrictNodes"
+      is false, then Tor builds that circuit as if ExcludeExitNodes were
+      not provided.
+
+    - If a user tries to connect to or resolve a hostname of the form
+      <target>.<servername>.exit and the "AllowDotExit" configuration
+      option is set to 1, the request is rewritten to a request for
+      <target>, and the request is only supported by the exit whose
+      nickname or fingerprint is <servername>. If "AllowDotExit" is set
+      to 0 (default), any request for <anything>.exit is denied.
+
+    - When any of the *Nodes settings are changed, all circuits are
+      expired immediately, to prevent a situation where a previously
+      built circuit is used even though some of its nodes are now
+      excluded.
+
+
+Compatibility:
+
+    The old Strict*Nodes options are deprecated, and the StrictNodes
+    option is new. Tor users may need to update their configuration file.
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index 04b764ad6d9277aec27c932f4999925a01fc22fa..2ae5005d8c553c3af44f9bb7abdd6fb6be0d81dc 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -66,40 +66,40 @@ Other options can be specified either on the command-line (--option
     Options are case-insensitive. C-style escaped characters are allowed inside
     quoted values.
 
-**BandwidthRate** __N__ **bytes**|**KB**|**MB**|**GB**|**TB**::
+**BandwidthRate** __N__ **bytes**|**KB**|**MB**|**GB**::
     A token bucket limits the average incoming bandwidth usage on this node to
     the specified number of bytes per second, and the average outgoing
     bandwidth usage to that same value. (Default: 5 MB)
 
-**BandwidthBurst** __N__ **bytes**|**KB**|**MB**|**GB**|**TB**::
+**BandwidthBurst** __N__ **bytes**|**KB**|**MB**|**GB**::
     Limit the maximum token bucket size (also known as the burst) to the given
     number of bytes in each direction. (Default: 10 MB)
 
-**MaxAdvertisedBandwidth** __N__ **bytes**|**KB**|**MB**|**GB**|**TB**::
+**MaxAdvertisedBandwidth** __N__ **bytes**|**KB**|**MB**|**GB**::
     If set, we will not advertise more than this amount of bandwidth for our
     BandwidthRate. Server operators who want to reduce the number of clients
     who ask to build circuits through them (since this is proportional to
     advertised bandwidth rate) can thus reduce the CPU demands on their server
     without impacting network performance.
 
-**RelayBandwidthRate** __N__ **bytes**|**KB**|**MB**|**GB**|**TB**::
+**RelayBandwidthRate** __N__ **bytes**|**KB**|**MB**|**GB**::
     If defined, a separate token bucket limits the average incoming bandwidth
     usage for \_relayed traffic_ on this node to the specified number of bytes
     per second, and the average outgoing bandwidth usage to that same value.
     Relayed traffic currently is calculated to include answers to directory
     requests, but that may change in future versions. (Default: 0)
 
-**RelayBandwidthBurst** __N__ **bytes**|**KB**|**MB**|**GB**|**TB**::
+**RelayBandwidthBurst** __N__ **bytes**|**KB**|**MB**|**GB**::
     Limit the maximum token bucket size (also known as the burst) for
     \_relayed traffic_ to the given number of bytes in each direction.
     (Default: 0)
 
-**PerConnBWRate** __N__ **bytes**|**KB**|**MB**|**GB**|**TB**::
+**PerConnBWRate** __N__ **bytes**|**KB**|**MB**|**GB**::
     If set, do separate rate limiting for each connection from a non-relay.
     You should never need to change this value, since a network-wide value is
     published in the consensus and your relay will use that value. (Default: 0)
 
-**PerConnBWBurst** __N__ **bytes**|**KB**|**MB**|**GB**|**TB**::
+**PerConnBWBurst** __N__ **bytes**|**KB**|**MB**|**GB**::
     If set, do separate rate limiting for each connection from a non-relay.
     You should never need to change this value, since a network-wide value is
     published in the consensus and your relay will use that value. (Default: 0)
@@ -320,7 +320,8 @@ Other options can be specified either on the command-line (--option
 **OutboundBindAddress** __IP__::
     Make all outbound connections originate from the IP address specified. This
     is only useful when you have multiple network interfaces, and you want all
-    of Tor's outgoing connections to use a single one.
+    of Tor's outgoing connections to use a single one.  This setting will be
+    ignored for connections to the loopback addresses (127.0.0.0/8 and ::1).
 
 **PidFile** __FILE__::
     On startup, write our PID to FILE. On clean shutdown, remove
diff --git a/src/common/address.c b/src/common/address.c
index 7729f29147fb0b9eb7fd1d4cfb8f9414a4e94fd1..4569373f3b926c83d6055ab357021c494cafe169 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2003-2004, Roger Dingledine
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
@@ -726,7 +726,7 @@ tor_addr_is_loopback(const tor_addr_t *addr)
 }
 
 /** Set <b>dest</b> to equal the IPv4 address in <b>v4addr</b> (given in
- * network order. */
+ * network order). */
 void
 tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr)
 {
diff --git a/src/common/address.h b/src/common/address.h
index 4d4c91075b45a992f579898e9ac51203179d428a..6116bb4b1c1890140cefc2d7cb2c1d781f820754 100644
--- a/src/common/address.h
+++ b/src/common/address.h
@@ -1,6 +1,6 @@
 /* Copyright (c) 2003-2004, Roger Dingledine
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/common/aes.c b/src/common/aes.c
index eb7f8fe3fcf834d0aaac7446e3c70fc93c57e68c..2b6f0234b7f0575922e3445568fb776fd223dde6 100644
--- a/src/common/aes.c
+++ b/src/common/aes.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001, Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/common/aes.h b/src/common/aes.h
index f3e5796c78eb4dcdedbd63f78e95e1c10ec35cac..4fb735cfe5548c9729490bdeb5e0de3611e3c953 100644
--- a/src/common/aes.h
+++ b/src/common/aes.h
@@ -1,6 +1,6 @@
 /* Copyright (c) 2003, Roger Dingledine
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /* Implements a minimal interface to counter-mode AES. */
diff --git a/src/common/compat.c b/src/common/compat.c
index 406d74eb25436692f4233bca673f1365a7fdbf92..7f53704c6905e089a4fbbf4a6a7e5277d4c33f15 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2003-2004, Roger Dingledine
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
@@ -1789,7 +1789,6 @@ spawn_exit(void)
    * call _exit, not exit, from child processes. */
   _exit(0);
 #endif
-
 }
 
 /** Set *timeval to the current time of day.  On error, log and terminate.
diff --git a/src/common/compat.h b/src/common/compat.h
index 554ae8919f6d304519166dece9d1dd07d79510c1..f5f8bb4283d5d0bc904964180715b8e7061d8cb5 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -1,6 +1,6 @@
 /* Copyright (c) 2003-2004, Roger Dingledine
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 #ifndef _TOR_COMPAT_H
@@ -196,18 +196,26 @@ size_t strlcpy(char *dst, const char *src, size_t siz) ATTR_NONNULL((1,2));
 #define U64_SCANF_ARG(a) (a)
 /** Expands to a literal uint64_t-typed constant for the value <b>n</b>. */
 #define U64_LITERAL(n) (n ## ui64)
+#define I64_PRINTF_ARG(a) (a)
+#define I64_SCANF_ARG(a) (a)
+#define I64_LITERAL(n) (n ## i64)
 #else
 #define U64_PRINTF_ARG(a) ((long long unsigned int)(a))
 #define U64_SCANF_ARG(a) ((long long unsigned int*)(a))
 #define U64_LITERAL(n) (n ## llu)
+#define I64_PRINTF_ARG(a) ((long long signed int)(a))
+#define I64_SCANF_ARG(a) ((long long signed int*)(a))
+#define I64_LITERAL(n) (n ## ll)
 #endif
 
 #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
 /** The formatting string used to put a uint64_t value in a printf() or
  * scanf() function.  See also U64_PRINTF_ARG and U64_SCANF_ARG. */
 #define U64_FORMAT "%I64u"
+#define I64_FORMAT "%I64d"
 #else
 #define U64_FORMAT "%llu"
+#define I64_FORMAT "%lld"
 #endif
 
 /** Represents an mmaped file. Allocated via tor_mmap_file; freed with
@@ -545,6 +553,19 @@ void tor_cond_signal_all(tor_cond_t *cond);
 #endif
 #endif
 
+/** Macros for MIN/MAX.  Never use these when the arguments could have
+ * side-effects.
+ * {With GCC extensions we could probably define a safer MIN/MAX.  But
+ * depending on that safety would be dangerous, since not every platform
+ * has it.}
+ **/
+#ifndef MAX
+#define MAX(a,b) ( ((a)<(b)) ? (b) : (a) )
+#endif
+#ifndef MIN
+#define MIN(a,b) ( ((a)>(b)) ? (b) : (a) )
+#endif
+
 /* Platform-specific helpers. */
 #ifdef MS_WINDOWS
 char *format_win32_error(DWORD err);
diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c
index dcf51cbbd36a033f21ae98c31e80aa6d15b1767f..18e057f957dff9e93611611095ad3f8aee11a2fa 100644
--- a/src/common/compat_libevent.c
+++ b/src/common/compat_libevent.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, The Tor Project, Inc. */
+/* Copyright (c) 2009-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/common/container.c b/src/common/container.c
index f452a51e428b8f05b42c9da0fb77d47c3b36707d..ab5a9b0325b8792432e2c8246dea5a696e0c7582 100644
--- a/src/common/container.c
+++ b/src/common/container.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2003-2004, Roger Dingledine
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/common/container.h b/src/common/container.h
index 8077d56ebddaf5f4470434be695f2daf39820f1e..3568de01598701fda5245a592c0f1d4e5a7c80d5 100644
--- a/src/common/container.h
+++ b/src/common/container.h
@@ -1,6 +1,6 @@
 /* Copyright (c) 2003-2004, Roger Dingledine
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 #ifndef _TOR_CONTAINER_H
diff --git a/src/common/crypto.c b/src/common/crypto.c
index e7b0ff194fee462671bb17b4c8be6b1584e8e2f2..1a1dad616c1a7fbe324b28e72b4d9a2e97b878af 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001, Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/common/crypto.h b/src/common/crypto.h
index 239acb5871911b0e59b6847c2d3a7ba5d3f94ca1..1b004dd4b899ed53c4103790a8533267e8ca5228 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001, Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/common/ht.h b/src/common/ht.h
index 5187c90e6f540e3b103d88d22818072c3cebac91..f598856d8a9b17971713159f86c6741ba9b5890a 100644
--- a/src/common/ht.h
+++ b/src/common/ht.h
@@ -1,6 +1,6 @@
 /* Copyright (c) 2002, Christopher Clark.
  * Copyright (c) 2005-2006, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See license at end. */
 
 /* Based on ideas by Christopher Clark and interfaces from Niels Provos. */
diff --git a/src/common/log.c b/src/common/log.c
index dfea58f47cef225e380fa6bb1865b928bfeb8433..6bf94721f8e6f1692d19d669718b7b9f5af9daff 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001, Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/common/log.h b/src/common/log.h
index 9f9a4277fb5db86d5ae2318332ac9bf6c7a52e8d..21219569e3ddc4cd12cd20447a3720176f0ff32b 100644
--- a/src/common/log.h
+++ b/src/common/log.h
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001, Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/common/memarea.c b/src/common/memarea.c
index 661bd85da889361214e966c5b5b3466e1a42d57b..0402e5f2089878c02a93ca464f153530c6730c0d 100644
--- a/src/common/memarea.c
+++ b/src/common/memarea.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, The Tor Project, Inc. */
+/* Copyright (c) 2008-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /** \file memarea.c
diff --git a/src/common/memarea.h b/src/common/memarea.h
index 04ffae7cae9b97fe7f7520e97f4ec151dbe7b7b3..95d855f6d9e8f12eed68b34b6c6d7e4df6d79f36 100644
--- a/src/common/memarea.h
+++ b/src/common/memarea.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, The Tor Project, Inc. */
+/* Copyright (c) 2008-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 /* Tor dependencies */
 
diff --git a/src/common/mempool.c b/src/common/mempool.c
index 60fcb2ca7a133cf971a49308087f57f144db34c7..256388a9fdcae02be3c23b15f73efc4f7958112b 100644
--- a/src/common/mempool.c
+++ b/src/common/mempool.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2009, The Tor Project, Inc. */
+/* Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 #if 1
 /* Tor dependencies */
diff --git a/src/common/mempool.h b/src/common/mempool.h
index d6813f1baaa36c0fa6e69efb76f6cf90cdcb3b9b..ae1feea843eb65cbb5564cb710290d7684e2c87e 100644
--- a/src/common/mempool.h
+++ b/src/common/mempool.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2009, The Tor Project, Inc. */
+/* Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/common/sha256.c b/src/common/sha256.c
index d445ae4e6d0205a2c61283181ba584d999b14d86..4236d48f5ff3f574c522aaa4513e253dd011e4ed 100644
--- a/src/common/sha256.c
+++ b/src/common/sha256.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, The Tor Project, Inc. */
+/* Copyright (c) 2009-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 /* This SHA256 implementation is adapted from the public domain one in
    LibTomCrypt, version 1.6.  Tor uses it on platforms where OpenSSL doesn't
diff --git a/src/common/torgzip.c b/src/common/torgzip.c
index 4f1b46adde1d91e29009aa0573ec723a8851502a..27d9c42efd50d22adec789a7c672f1c47dc45793 100644
--- a/src/common/torgzip.c
+++ b/src/common/torgzip.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/common/torgzip.h b/src/common/torgzip.h
index d6432283c3200c64ce39a0ffcc9ee38880a8f168..5139f4bcad5c15ee3187cab348c7394083cd2da6 100644
--- a/src/common/torgzip.h
+++ b/src/common/torgzip.h
@@ -1,6 +1,6 @@
 /* Copyright (c) 2003, Roger Dingledine
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/common/torint.h b/src/common/torint.h
index be624e04c67223e5b33dfacdbbc8c41222cf3c5b..57f18212adb774bcf32e2ca9b5bb38d5a739cb54 100644
--- a/src/common/torint.h
+++ b/src/common/torint.h
@@ -1,6 +1,6 @@
 /* Copyright (c) 2003, Roger Dingledine
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/common/tortls.c b/src/common/tortls.c
index 82653c455ad14d089836c8109b522d57849fd96c..b4984802fb5607735271c6f0411fc232432d264d 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2003, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/common/tortls.h b/src/common/tortls.h
index 871fec3365dd3237221c355ea05d05dfe7d0bdc6..e4b1ad65f268596622023b5dd63cf21a6c7956eb 100644
--- a/src/common/tortls.h
+++ b/src/common/tortls.h
@@ -1,6 +1,6 @@
 /* Copyright (c) 2003, Roger Dingledine
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 #ifndef _TOR_TORTLS_H
diff --git a/src/common/tortls_states.h b/src/common/tortls_states.h
index 986b5a8a0d1dab659313ab54679d57888cfbc70c..00f476dd66eb9257898bd171198fa60f23b752a4 100644
--- a/src/common/tortls_states.h
+++ b/src/common/tortls_states.h
@@ -1,6 +1,6 @@
 /* Copyright (c) 2003, Roger Dingledine
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /* Helper file: included only in tortls.c */
diff --git a/src/common/util.c b/src/common/util.c
index f7e5dd06c56b884c8094f815bbad9fdd9ce5b929..1c0db392d09f9692800476b261e3dc963518c708 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2003, Roger Dingledine
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/common/util.h b/src/common/util.h
index b55bb91c51f9acfa650a530d68500779bfd436eb..ba38f4c7ed2f4a186c7040ae400abfb4e9aba599 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -1,6 +1,6 @@
 /* Copyright (c) 2003-2004, Roger Dingledine
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/buffers.c b/src/or/buffers.c
index c990b6619acf51229c1db15b08e8277344a3d6b0..4dbd9a7a0b2331b94bc6018662e762dcdb003b32 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 08ee58416b2d32ffa6c62f9dac4e4493a125c992..cd5ada8dce4bd7af0f20a9abf3dd3cb86d7a8388 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
@@ -1030,7 +1030,6 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt)
            "Set circuit build timeout to %lds (%lfms, Xm: %d, a: %lf) "
            "based on %d circuit times", tor_lround(cbt->timeout_ms/1000),
            cbt->timeout_ms, cbt->Xm, cbt->alpha, cbt->total_build_times);
-
 }
 
 /** Iterate over values of circ_id, starting from conn-\>next_circ_id,
@@ -1111,11 +1110,11 @@ circuit_list_path_impl(origin_circuit_t *circ, int verbose, int verbose_names)
     const char *id;
     if (!hop)
       break;
-    id = hop->extend_info->identity_digest;
     if (!verbose && hop->state != CPATH_STATE_OPEN)
       break;
     if (!hop->extend_info)
       break;
+    id = hop->extend_info->identity_digest;
     if (verbose_names) {
       elt = tor_malloc(MAX_VERBOSE_NICKNAME_LEN+1);
       if ((ri = router_get_by_digest(id))) {
@@ -2133,6 +2132,8 @@ circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
   smartlist_t *LongLivedServices = get_options()->LongLivedPorts;
   tor_assert(need_uptime);
   tor_assert(need_capacity);
+  // Always predict need_capacity
+  *need_capacity = 1;
   enough = (smartlist_len(sl) == 0);
   for (i = 0; i < smartlist_len(sl); ++i) {
     port = smartlist_get(sl, i);
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index fed1ccf9e631195043339bf00b10d49e6268b663..73e2e06cce5027d5599b4b2836fc2d8f84137c20 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -1,7 +1,7 @@
 /* Copyright 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 59b6998b9924a4c166b78e45ba196ea3ea154ede..9eda9e2480cd8c7e2b6dfc88429b0bce60d59142 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/command.c b/src/or/command.c
index b1e6fa23a3988b2fb9bd9ec432e2f477f3a8fa28..8d838a0a2357cd1d9256f90d6820d30e7fe8e708 100644
--- a/src/or/command.c
+++ b/src/or/command.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/config.c b/src/or/config.c
index 5ad1d3f44696210c94a9821bdcb30b38adfb2930..cbf9a5a0c691af5f262a082dd120046d6d2543a7 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
@@ -2155,7 +2155,7 @@ print_usage(void)
   printf(
 "Copyright (c) 2001-2004, Roger Dingledine\n"
 "Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson\n"
-"Copyright (c) 2007-2009, The Tor Project, Inc.\n\n"
+"Copyright (c) 2007-2010, The Tor Project, Inc.\n\n"
 "tor -f <torrc> [args]\n"
 "See man page for options, or https://www.torproject.org/ for "
 "documentation.\n");
@@ -2191,7 +2191,7 @@ resolve_my_address(int warn_severity, or_options_t *options,
                    uint32_t *addr_out, char **hostname_out)
 {
   struct in_addr in;
-  uint32_t addr;
+  uint32_t addr; /* host order */
   char hostname[256];
   int explicit_ip=1;
   int explicit_hostname=1;
@@ -2221,8 +2221,8 @@ resolve_my_address(int warn_severity, or_options_t *options,
   if (tor_inet_aton(hostname, &in) == 0) {
     /* then we have to resolve it */
     explicit_ip = 0;
-    if (!tor_lookup_hostname(hostname, &addr)) {
-      uint32_t interface_ip;
+    if (tor_lookup_hostname(hostname, &addr)) { /* failed to resolve */
+      uint32_t interface_ip; /* host order */
 
       if (explicit_hostname) {
         log_fn(warn_severity, LD_CONFIG,
@@ -2243,7 +2243,7 @@ resolve_my_address(int warn_severity, or_options_t *options,
       log_fn(notice_severity, LD_CONFIG, "Learned IP address '%s' for "
              "local interface. Using that.", tmpbuf);
       strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
-    } else {
+    } else { /* resolved hostname into addr */
       in.s_addr = htonl(addr);
 
       if (!explicit_hostname &&
@@ -3228,6 +3228,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
   if (ensure_bandwidth_cap(&options->RelayBandwidthBurst,
                            "RelayBandwidthBurst", msg) < 0)
     return -1;
+  if (ensure_bandwidth_cap(&options->PerConnBWRate,
+                           "PerConnBWRate", msg) < 0)
+    return -1;
+  if (ensure_bandwidth_cap(&options->PerConnBWBurst,
+                           "PerConnBWBurst", msg) < 0)
+    return -1;
 
   if (server_mode(options)) {
     if (options->BandwidthRate < ROUTER_REQUIRED_MIN_BANDWIDTH) {
diff --git a/src/or/connection.c b/src/or/connection.c
index cf13345741b5227b7fbd11612eb099d52eb16917..7b1493bfc5421dc2e2146c31c7fd69f1208ac0dd 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
@@ -3095,10 +3095,10 @@ alloc_http_authenticator(const char *authenticator)
 static void
 client_check_address_changed(int sock)
 {
-  uint32_t iface_ip, ip_out;
+  uint32_t iface_ip, ip_out; /* host order */
   struct sockaddr_in out_addr;
   socklen_t out_addr_len = (socklen_t) sizeof(out_addr);
-  uint32_t *ip;
+  uint32_t *ip; /* host order */
 
   if (!last_interface_ip)
     get_interface_address(LOG_INFO, &last_interface_ip);
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 8e2fcf977ec71d63ca6759c11eeb109201a89e08..861482d2af1af93a1c971d7ee441543913646673 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 1aa0bb35b77c5fbc3a86e24a599647fc3625508c..dfd0a965b067aa144312ad2b398156de2f8ba8bb 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/control.c b/src/or/control.c
index 0f71855286aafaf05a7a9b97433b68a28bbc72c6..771beaeb58f2da0412ec4670ba88170c5fb1086e 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -1,5 +1,5 @@
 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
@@ -2121,6 +2121,8 @@ handle_control_extendcircuit(control_connection_t *conn, uint32_t len,
   if (!zero_circ && !(circ = get_circ(smartlist_get(args,0)))) {
     connection_printf_to_buf(conn, "552 Unknown circuit \"%s\"\r\n",
                              (char*)smartlist_get(args, 0));
+    SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
+    smartlist_free(args);
     goto done;
   }
 
diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c
index 219fb9d9bea1245eaf2f18845de28bd70857e770..fde149978cce7e45d5b4679515fb0c28b481a3c5 100644
--- a/src/or/cpuworker.c
+++ b/src/or/cpuworker.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2003-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/directory.c b/src/or/directory.c
index ef0816eb41961c43553f30d7255ccbffbec0ec16..39e67c957fbfa1c4a8ddec8f44084ef352f5a588 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 #include "or.h"
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 8009647c91f036892f70c9a19770c158f0338865..5f1cb85431a525f1e74f47c1eb3a5783dbac4d97 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 #define DIRSERV_PRIVATE
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index 7227ac9740c4508954ba1a701d40e3c0f556b7f2..ecf236e8fe80e7205b64d60ac6a502898f4d091e 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 #define DIRVOTE_PRIVATE
@@ -39,8 +39,15 @@ static int dirvote_publish_consensus(void);
 static char *make_consensus_method_list(int low, int high, const char *sep);
 
 /** The highest consensus method that we currently support. */
-#define MAX_SUPPORTED_CONSENSUS_METHOD 8
+#define MAX_SUPPORTED_CONSENSUS_METHOD 9
 
+/** Lowest consensus method that contains a 'directory-footer' marker */
+#define MIN_METHOD_FOR_FOOTER 9
+
+/** Lowest consensus method that contains bandwidth weights */
+#define MIN_METHOD_FOR_BW_WEIGHTS 9
+
+/** Lowest consensus method that contains consensus params */
 #define MIN_METHOD_FOR_PARAMS 7
 
 /** Lowest consensus method that generates microdescriptors */
@@ -71,6 +78,7 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
   uint32_t addr;
   routerlist_t *rl = router_get_routerlist();
   char *version_lines = NULL;
+  int r;
   networkstatus_voter_info_t *voter;
 
   tor_assert(private_signing_key);
@@ -97,13 +105,22 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
     version_lines = tor_malloc(v_len);
     cp = version_lines;
     if (client_versions) {
-      tor_snprintf(cp, v_len-(cp-version_lines),
+      r = tor_snprintf(cp, v_len-(cp-version_lines),
                    "client-versions %s\n", client_versions);
+      if (r < 0) {
+        log_err(LD_BUG, "Insufficient memory for client-versions line");
+        tor_assert(0);
+      }
       cp += strlen(cp);
     }
-    if (server_versions)
-      tor_snprintf(cp, v_len-(cp-version_lines),
+    if (server_versions) {
+      r = tor_snprintf(cp, v_len-(cp-version_lines),
                    "server-versions %s\n", server_versions);
+      if (r < 0) {
+        log_err(LD_BUG, "Insufficient memory for server-versions line");
+        tor_assert(0);
+      }
+    }
   } else {
     version_lines = tor_strdup("");
   }
@@ -111,6 +128,7 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
   len = 8192;
   len += strlen(version_lines);
   len += (RS_ENTRY_LEN+MICRODESC_LINE_LEN)*smartlist_len(rl->routers);
+  len += strlen("\ndirectory-footer\n");
   len += v3_ns->cert->cache_info.signed_descriptor_len;
 
   status = tor_malloc(len);
@@ -135,7 +153,7 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
       params = tor_strdup("");
 
     tor_assert(cert);
-    tor_snprintf(status, len,
+    r = tor_snprintf(status, len,
                  "network-status-version 3\n"
                  "vote-status %s\n"
                  "consensus-methods %s\n"
@@ -159,6 +177,11 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
                  voter->nickname, fingerprint, voter->address,
                  ipaddr, voter->dir_port, voter->or_port, voter->contact);
 
+    if (r < 0) {
+      log_err(LD_BUG, "Insufficient memory for network status line");
+      tor_assert(0);
+    }
+
     tor_free(params);
     tor_free(flags);
     tor_free(methods);
@@ -168,7 +191,11 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
     if (!tor_digest_is_zero(voter->legacy_id_digest)) {
       char fpbuf[HEX_DIGEST_LEN+1];
       base16_encode(fpbuf, sizeof(fpbuf), voter->legacy_id_digest, DIGEST_LEN);
-      tor_snprintf(outp, endp-outp, "legacy-dir-key %s\n", fpbuf);
+      r = tor_snprintf(outp, endp-outp, "legacy-dir-key %s\n", fpbuf);
+      if (r < 0) {
+        log_err(LD_BUG, "Insufficient memory for legacy-dir-key line");
+        tor_assert(0);
+      }
       outp += strlen(outp);
     }
 
@@ -199,6 +226,13 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
     }
   } SMARTLIST_FOREACH_END(vrs);
 
+  r = tor_snprintf(outp, endp-outp, "directory-footer\n");
+  if (r < 0) {
+    log_err(LD_BUG, "Insufficient memory for directory-footer line");
+    tor_assert(0);
+  }
+  outp += strlen(outp);
+
   {
     char signing_key_fingerprint[FINGERPRINT_LEN+1];
     if (tor_snprintf(outp, endp-outp, "directory-signature ")<0) {
@@ -648,6 +682,385 @@ dirvote_compute_params(smartlist_t *votes)
   return result;
 }
 
+#define RANGE_CHECK(a,b,c,d,e,f,g,mx) \
+       ((a) >= 0 && (a) <= (mx) && (b) >= 0 && (b) <= (mx) && \
+        (c) >= 0 && (c) <= (mx) && (d) >= 0 && (d) <= (mx) && \
+        (e) >= 0 && (e) <= (mx) && (f) >= 0 && (f) <= (mx) && \
+        (g) >= 0 && (g) <= (mx))
+
+#define CHECK_EQ(a, b, margin) \
+     ((a)-(b) >= 0 ? (a)-(b) <= (margin) : (b)-(a) <= (margin))
+
+typedef enum {
+ BW_WEIGHTS_NO_ERROR = 0,
+ BW_WEIGHTS_RANGE_ERROR = 1,
+ BW_WEIGHTS_SUMG_ERROR = 2,
+ BW_WEIGHTS_SUME_ERROR = 3,
+ BW_WEIGHTS_SUMD_ERROR = 4,
+ BW_WEIGHTS_BALANCE_MID_ERROR = 5,
+ BW_WEIGHTS_BALANCE_EG_ERROR = 6
+} bw_weights_error_t;
+
+/**
+ * Verify that any weightings satisfy the balanced formulas.
+ */
+static bw_weights_error_t
+networkstatus_check_weights(int64_t Wgg, int64_t Wgd, int64_t Wmg,
+                            int64_t Wme, int64_t Wmd, int64_t Wee,
+                            int64_t Wed, int64_t scale, int64_t G,
+                            int64_t M, int64_t E, int64_t D, int64_t T,
+                            int64_t margin, int do_balance) {
+  bw_weights_error_t berr = BW_WEIGHTS_NO_ERROR;
+
+  // Wed + Wmd + Wgd == 1
+  if (!CHECK_EQ(Wed + Wmd + Wgd, scale, margin)) {
+    berr = BW_WEIGHTS_SUMD_ERROR;
+    goto out;
+  }
+
+  // Wmg + Wgg == 1
+  if (!CHECK_EQ(Wmg + Wgg, scale, margin)) {
+    berr = BW_WEIGHTS_SUMG_ERROR;
+    goto out;
+  }
+
+  // Wme + Wee == 1
+  if (!CHECK_EQ(Wme + Wee, scale, margin)) {
+    berr = BW_WEIGHTS_SUME_ERROR;
+    goto out;
+  }
+
+  // Verify weights within range 0->1
+  if (!RANGE_CHECK(Wgg, Wgd, Wmg, Wme, Wmd, Wed, Wee, scale)) {
+    berr = BW_WEIGHTS_RANGE_ERROR;
+    goto out;
+  }
+
+  if (do_balance) {
+    // Wgg*G + Wgd*D == Wee*E + Wed*D, already scaled
+    if (!CHECK_EQ(Wgg*G + Wgd*D, Wee*E + Wed*D, (margin*T)/3)) {
+      berr = BW_WEIGHTS_BALANCE_EG_ERROR;
+      goto out;
+    }
+
+    // Wgg*G + Wgd*D == M*scale + Wmd*D + Wme*E + Wmg*G, already scaled
+    if (!CHECK_EQ(Wgg*G + Wgd*D, M*scale + Wmd*D + Wme*E + Wmg*G,
+                (margin*T)/3)) {
+      berr = BW_WEIGHTS_BALANCE_MID_ERROR;
+      goto out;
+    }
+  }
+
+out:
+  if (berr) {
+    log_info(LD_DIR,
+             "Bw weight mismatch %d. G="I64_FORMAT" M="I64_FORMAT
+             " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT,
+             berr,
+             I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+             I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
+  }
+
+  return berr;
+}
+
+static void
+networkstatus_compute_bw_weights_v9(smartlist_t *chunks, int64_t G, int64_t M,
+                              int64_t E, int64_t D, int64_t T,
+                              int64_t weight_scale)
+{
+  int64_t Wgg = -1, Wgd = -1;
+  int64_t Wmg = -1, Wme = -1, Wmd = -1;
+  int64_t Wed = -1, Wee = -1;
+  const char *casename;
+  char buf[512];
+  int r;
+
+  if (G <= 0 || M <= 0 || E <= 0 || D <= 0) {
+    log_warn(LD_DIR, "Consensus with empty bandwidth: "
+                     "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
+                     " D="I64_FORMAT" T="I64_FORMAT,
+             I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+             I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
+    return;
+  }
+
+  /*
+   * Computed from cases in 3.4.3 of dir-spec.txt
+   *
+   * 1. Neither are scarce
+   * 2. Both Guard and Exit are scarce
+   *    a. R+D <= S
+   *    b. R+D > S
+   * 3. One of Guard or Exit is scarce
+   *    a. S+D < T/3
+   *    b. S+D >= T/3
+   */
+  if (3*E >= T && 3*G >= T) { // E >= T/3 && G >= T/3
+    bw_weights_error_t berr = 0;
+    /* Case 1: Neither are scarce.
+     *
+     * Attempt to ensure that we have a large amount of exit bandwidth
+     * in the middle position.
+     */
+    casename = "Case 1 (Wme*E = Wmd*D)";
+    Wgg = (weight_scale*(D+E+G+M))/(3*G);
+    if (D==0) Wmd = 0;
+    else Wmd = (weight_scale*(2*D + 2*E - G - M))/(6*D);
+    Wme = (weight_scale*(2*D + 2*E - G - M))/(6*E);
+    Wee = (weight_scale*(-2*D + 4*E + G + M))/(6*E);
+    Wgd = 0;
+    Wmg = weight_scale - Wgg;
+    Wed = weight_scale - Wmd;
+
+    berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed,
+                                       weight_scale, G, M, E, D, T, 10, 1);
+
+    if (berr) {
+      log_warn(LD_DIR, "Bw Weights error %d for case %s. "
+                       "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
+                       " D="I64_FORMAT" T="I64_FORMAT,
+               berr, casename,
+               I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+               I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
+    }
+  } else if (3*E < T && 3*G < T) { // E < T/3 && G < T/3
+    int64_t R = MIN(E, G);
+    int64_t S = MAX(E, G);
+    /*
+     * Case 2: Both Guards and Exits are scarce
+     * Balance D between E and G, depending upon
+     * D capacity and scarcity.
+     */
+    if (R+D < S) { // Subcase a
+      Wgg = weight_scale;
+      Wee = weight_scale;
+      Wmg = 0;
+      Wme = 0;
+      Wmd = 0;
+      if (E < G) {
+        casename = "Case 2a (E scarce)";
+        Wed = weight_scale;
+        Wgd = 0;
+      } else { /* E >= G */
+        casename = "Case 2a (G scarce)";
+        Wed = 0;
+        Wgd = weight_scale;
+      }
+    } else { // Subcase b: R+D > S
+      bw_weights_error_t berr = 0;
+      casename = "Case 2b (Wme*E == Wmd*D)";
+      if (D != 0) {
+        Wgg = weight_scale;
+        Wgd = (weight_scale*(D + E - 2*G + M))/(3*D); // T/3 >= G (Ok)
+        Wmd = (weight_scale*(D + E + G - 2*M))/(6*D); // T/3 >= M
+        Wme = (weight_scale*(D + E + G - 2*M))/(6*E);
+        Wee = (weight_scale*(-D + 5*E - G + 2*M))/(6*E); // 2E+M >= T/3
+        Wmg = 0;
+        Wed = weight_scale - Wgd - Wmd;
+
+        berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed,
+                                       weight_scale, G, M, E, D, T, 10, 1);
+      }
+
+      if (D == 0 || berr) { // Can happen if M > T/3
+        casename = "Case 2b (E=G)";
+        Wgg = weight_scale;
+        Wee = weight_scale;
+        Wmg = 0;
+        Wme = 0;
+        Wmd = 0;
+        if (D == 0) Wgd = 0;
+        else Wgd = (weight_scale*(D+E-G))/(2*D);
+        Wed = weight_scale - Wgd;
+        berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee,
+                Wed, weight_scale, G, M, E, D, T, 10, 1);
+      }
+      if (berr != BW_WEIGHTS_NO_ERROR &&
+              berr != BW_WEIGHTS_BALANCE_MID_ERROR) {
+        log_warn(LD_DIR, "Bw Weights error %d for case %s. "
+                         "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
+                         " D="I64_FORMAT" T="I64_FORMAT,
+                 berr, casename,
+                 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+                 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
+      }
+    }
+  } else { // if (E < T/3 || G < T/3) {
+    int64_t S = MIN(E, G);
+    // Case 3: Exactly one of Guard or Exit is scarce
+    if (!(3*E < T || 3*G < T) || !(3*G >= T || 3*E >= T)) {
+      log_warn(LD_BUG,
+           "Bw-Weights Case 3 but with G="I64_FORMAT" M="
+           I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT,
+               I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+               I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
+    }
+
+    if (3*(S+D) < T) { // Subcase a: S+D < T/3
+      if (G < E) {
+        casename = "Case 3a (G scarce)";
+        Wgg = Wgd = weight_scale;
+        Wmd = Wed = Wmg = 0;
+        // Minor subcase, if E is more scarce than M,
+        // keep its bandwidth in place.
+        if (E < M) Wme = 0;
+        else Wme = (weight_scale*(E-M))/(2*E);
+        Wee = weight_scale-Wme;
+      } else { // G >= E
+        casename = "Case 3a (E scarce)";
+        Wee = Wed = weight_scale;
+        Wmd = Wgd = Wme = 0;
+        // Minor subcase, if G is more scarce than M,
+        // keep its bandwidth in place.
+        if (G < M) Wmg = 0;
+        else Wmg = (weight_scale*(G-M))/(2*G);
+        Wgg = weight_scale-Wmg;
+      }
+    } else { // Subcase b: S+D >= T/3
+      bw_weights_error_t berr = 0;
+      // D != 0 because S+D >= T/3
+      if (G < E) {
+        casename = "Case 3b (G scarce, Wme*E == Wmd*D)";
+        Wgd = (weight_scale*(D + E - 2*G + M))/(3*D);
+        Wmd = (weight_scale*(D + E + G - 2*M))/(6*D);
+        Wme = (weight_scale*(D + E + G - 2*M))/(6*E);
+        Wee = (weight_scale*(-D + 5*E - G + 2*M))/(6*E);
+        Wgg = weight_scale;
+        Wmg = 0;
+        Wed = weight_scale - Wgd - Wmd;
+
+        berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee,
+                    Wed, weight_scale, G, M, E, D, T, 10, 1);
+      } else { // G >= E
+        casename = "Case 3b (E scarce, Wme*E == Wmd*D)";
+        Wgg = (weight_scale*(D + E + G + M))/(3*G);
+        Wmd = (weight_scale*(2*D + 2*E - G - M))/(6*D);
+        Wme = (weight_scale*(2*D + 2*E - G - M))/(6*E);
+        Wee = (weight_scale*(-2*D + 4*E + G + M))/(6*E);
+        Wgd = 0;
+        Wmg = weight_scale - Wgg;
+        Wed = weight_scale - Wmd;
+
+        berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee,
+                      Wed, weight_scale, G, M, E, D, T, 10, 1);
+      }
+      if (berr) {
+        log_warn(LD_DIR, "Bw Weights error %d for case %s. "
+                         "G="I64_FORMAT" M="I64_FORMAT
+                         " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT,
+                 berr, casename,
+               I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+               I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
+      }
+    }
+  }
+
+  /* We cast down the weights to 32 bit ints on the assumption that
+   * weight_scale is ~= 10000. We need to ensure a rogue authority
+   * doesn't break this assumption to rig our weights */
+  tor_assert(0 < weight_scale && weight_scale < INT32_MAX);
+
+  if (Wgg < 0 || Wgg > weight_scale) {
+    log_warn(LD_DIR, "Bw %s: Wgg="I64_FORMAT"! G="I64_FORMAT
+            " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+            " T="I64_FORMAT,
+             casename, I64_PRINTF_ARG(Wgg),
+             I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+             I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
+
+    Wgg = MAX(MIN(Wgg, weight_scale), 0);
+  }
+  if (Wgd < 0 || Wgd > weight_scale) {
+    log_warn(LD_DIR, "Bw %s: Wgd="I64_FORMAT"! G="I64_FORMAT
+            " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+            " T="I64_FORMAT,
+             casename, I64_PRINTF_ARG(Wgd),
+             I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+             I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
+    Wgd = MAX(MIN(Wgd, weight_scale), 0);
+  }
+  if (Wmg < 0 || Wmg > weight_scale) {
+    log_warn(LD_DIR, "Bw %s: Wmg="I64_FORMAT"! G="I64_FORMAT
+            " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+            " T="I64_FORMAT,
+             casename, I64_PRINTF_ARG(Wmg),
+             I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+             I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
+    Wmg = MAX(MIN(Wmg, weight_scale), 0);
+  }
+  if (Wme < 0 || Wme > weight_scale) {
+    log_warn(LD_DIR, "Bw %s: Wme="I64_FORMAT"! G="I64_FORMAT
+            " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+            " T="I64_FORMAT,
+             casename, I64_PRINTF_ARG(Wme),
+             I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+             I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
+    Wme = MAX(MIN(Wme, weight_scale), 0);
+  }
+  if (Wmd < 0 || Wmd > weight_scale) {
+    log_warn(LD_DIR, "Bw %s: Wmd="I64_FORMAT"! G="I64_FORMAT
+            " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+            " T="I64_FORMAT,
+             casename, I64_PRINTF_ARG(Wmd),
+             I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+             I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
+    Wmd = MAX(MIN(Wmd, weight_scale), 0);
+  }
+  if (Wee < 0 || Wee > weight_scale) {
+    log_warn(LD_DIR, "Bw %s: Wee="I64_FORMAT"! G="I64_FORMAT
+            " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+            " T="I64_FORMAT,
+             casename, I64_PRINTF_ARG(Wee),
+             I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+             I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
+    Wee = MAX(MIN(Wee, weight_scale), 0);
+  }
+  if (Wed < 0 || Wed > weight_scale) {
+    log_warn(LD_DIR, "Bw %s: Wed="I64_FORMAT"! G="I64_FORMAT
+            " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+            " T="I64_FORMAT,
+             casename, I64_PRINTF_ARG(Wed),
+             I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+             I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
+    Wed = MAX(MIN(Wed, weight_scale), 0);
+  }
+
+  // Add consensus weight keywords
+  smartlist_add(chunks, tor_strdup("bandwidth-weights "));
+  /*
+   * Provide Wgm=Wgg, Wmm=1, Wem=Wee, Weg=Wed. May later determine
+   * that middle nodes need different bandwidth weights for dirport traffic,
+   * or that weird exit policies need special weight, or that bridges
+   * need special weight.
+   *
+   * NOTE: This list is sorted.
+   */
+  r = tor_snprintf(buf, sizeof(buf),
+     "Wbd=%d Wbe=%d Wbg=%d Wbm=%d "
+     "Wdb=%d "
+     "Web=%d Wed=%d Wee=%d Weg=%d Wem=%d "
+     "Wgb=%d Wgd=%d Wgg=%d Wgm=%d "
+     "Wmb=%d Wmd=%d Wme=%d Wmg=%d Wmm=%d\n",
+     (int)Wmd, (int)Wme, (int)Wmg, (int)weight_scale,
+     (int)weight_scale,
+     (int)weight_scale, (int)Wed, (int)Wee, (int)Wed, (int)Wee,
+     (int)weight_scale, (int)Wgd, (int)Wgg, (int)Wgg,
+     (int)weight_scale, (int)Wmd, (int)Wme, (int)Wmg, (int)weight_scale);
+  if (r<0) {
+    log_warn(LD_BUG,
+             "Not enough space in buffer for bandwidth-weights line.");
+    *buf = '\0';
+  }
+  smartlist_add(chunks, tor_strdup(buf));
+  log_notice(LD_CIRC, "Computed bandwidth weights for %s: "
+             "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+             " T="I64_FORMAT,
+             casename,
+             I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+             I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
+}
+
 /** Given a list of vote networkstatus_t in <b>votes</b>, our public
  * authority <b>identity_key</b>, our private authority <b>signing_key</b>,
  * and the number of <b>total_authorities</b> that we believe exist in our
@@ -673,9 +1086,10 @@ networkstatus_compute_consensus(smartlist_t *votes,
   char *client_versions = NULL, *server_versions = NULL;
   smartlist_t *flags;
   const char *flavor_name;
+  int64_t G=0, M=0, E=0, D=0, T=0; /* For bandwidth weights */
   const routerstatus_format_type_t rs_format =
     flavor == FLAV_NS ? NS_V3_CONSENSUS : NS_V3_CONSENSUS_MICRODESC;
-
+  char *params = NULL;
   tor_assert(flavor == FLAV_NS || flavor == FLAV_MICRODESC);
   tor_assert(total_authorities >= smartlist_len(votes));
 
@@ -812,7 +1226,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
   }
 
   if (consensus_method >= MIN_METHOD_FOR_PARAMS) {
-    char *params = dirvote_compute_params(votes);
+    params = dirvote_compute_params(votes);
     if (params) {
       smartlist_add(chunks, tor_strdup("params "));
       smartlist_add(chunks, params);
@@ -1008,6 +1422,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
       const char *chosen_name = NULL;
       int exitsummary_disagreement = 0;
       int is_named = 0, is_unnamed = 0, is_running = 0;
+      int is_guard = 0, is_exit = 0;
       int naming_conflict = 0;
       int n_listing = 0;
       int i;
@@ -1127,7 +1542,11 @@ networkstatus_compute_consensus(smartlist_t *votes,
         } else {
           if (flag_counts[fl_sl_idx] > n_flag_voters[fl_sl_idx]/2) {
             smartlist_add(chosen_flags, (char*)fl);
-            if (!strcmp(fl, "Running"))
+            if (!strcmp(fl, "Exit"))
+              is_exit = 1;
+            else if (!strcmp(fl, "Guard"))
+              is_guard = 1;
+            else if (!strcmp(fl, "Running"))
               is_running = 1;
           }
         }
@@ -1155,6 +1574,23 @@ networkstatus_compute_consensus(smartlist_t *votes,
         rs_out.bandwidth = median_uint32(bandwidths, num_bandwidths);
       }
 
+      if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS) {
+        if (rs_out.has_bandwidth) {
+          T += rs_out.bandwidth;
+          if (is_exit && is_guard)
+            D += rs_out.bandwidth;
+          else if (is_exit)
+            E += rs_out.bandwidth;
+          else if (is_guard)
+            G += rs_out.bandwidth;
+          else
+            M += rs_out.bandwidth;
+        } else {
+          log_warn(LD_BUG, "Missing consensus bandwidth for router %s",
+              rs_out.nickname);
+        }
+      }
+
       /* Ok, we already picked a descriptor digest we want to list
        * previously.  Now we want to use the exit policy summary from
        * that descriptor.  If everybody plays nice all the voters who
@@ -1308,6 +1744,45 @@ networkstatus_compute_consensus(smartlist_t *votes,
     tor_free(measured_bws);
   }
 
+  if (consensus_method >= MIN_METHOD_FOR_FOOTER) {
+    /* Starting with consensus method 9, we clearly mark the directory
+     * footer region */
+    smartlist_add(chunks, tor_strdup("directory-footer\n"));
+  }
+
+  if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS) {
+    int64_t weight_scale = BW_WEIGHT_SCALE;
+    char *bw_weight_param = NULL;
+
+    // Parse params, extract BW_WEIGHT_SCALE if present
+    // DO NOT use consensus_param_bw_weight_scale() in this code!
+    // The consensus is not formed yet!
+    if (strcmpstart(params, "bwweightscale=") == 0)
+      bw_weight_param = params;
+    else
+      bw_weight_param = strstr(params, " bwweightscale=");
+
+    if (bw_weight_param) {
+      int ok=0;
+      char *eq = strchr(bw_weight_param, '=');
+      if (eq) {
+        weight_scale = tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok,
+                                         NULL);
+        if (!ok) {
+          log_warn(LD_DIR, "Bad element '%s' in bw weight param",
+              escaped(bw_weight_param));
+          weight_scale = BW_WEIGHT_SCALE;
+        }
+      } else {
+        log_warn(LD_DIR, "Bad element '%s' in bw weight param",
+            escaped(bw_weight_param));
+        weight_scale = BW_WEIGHT_SCALE;
+      }
+    }
+
+    networkstatus_compute_bw_weights_v9(chunks, G, M, E, D, T, weight_scale);
+  }
+
   /* Add a signature. */
   {
     char digest[DIGEST256_LEN];
@@ -1382,11 +1857,15 @@ networkstatus_compute_consensus(smartlist_t *votes,
     networkstatus_t *c;
     if (!(c = networkstatus_parse_vote_from_string(result, NULL,
                                                    NS_TYPE_CONSENSUS))) {
-      log_err(LD_BUG,"Generated a networkstatus consensus we couldn't "
+      log_err(LD_BUG, "Generated a networkstatus consensus we couldn't "
               "parse.");
       tor_free(result);
       return NULL;
     }
+    // Verify balancing parameters
+    if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS) {
+      networkstatus_verify_bw_weights(c);
+    }
     networkstatus_vote_free(c);
   }
 
diff --git a/src/or/dns.c b/src/or/dns.c
index a9f6426042edb99a6a17775b03e5ce2e79cb3ce9..54acef4be29a2032efbaaca2647cb6bf25b37e31 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2003-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c
index 8e3e55e795d5afee5cd93affa8e8e4bfcab4369c..2e5301eae0243bbe9184a482369555ad3f5b22ba 100644
--- a/src/or/dnsserv.c
+++ b/src/or/dnsserv.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2009, The Tor Project, Inc. */
+/* Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/eventdns_tor.h b/src/or/eventdns_tor.h
index 3d84fc7794802cae6000800175efc331da3c6f54..141ff09f1ecdcf1fd29ad0839059d2e2a6ef2382 100644
--- a/src/or/eventdns_tor.h
+++ b/src/or/eventdns_tor.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2009, The Tor Project, Inc. */
+/* Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 #include "orconfig.h"
diff --git a/src/or/geoip.c b/src/or/geoip.c
index 7208b89865b742657f4e2e96fc1c7d84d0ebc32f..0f4805ec9d0e8bf7c3dfa2942ad9a4a6734497d0 100644
--- a/src/or/geoip.c
+++ b/src/or/geoip.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2009, The Tor Project, Inc. */
+/* Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index d68682d73023f538a265b760bdfa3b9739c37f45..3c52a317296d34959249f9c621d5552a9172951f 100644
--- a/src/or/hibernate.c
+++ b/src/or/hibernate.c
@@ -1,5 +1,5 @@
 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/main.c b/src/or/main.c
index f4ee16ca1f35f24c7067385997b7f8930d5b77c6..74075b6257976403403b8157e420d831d272a53f 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/microdesc.c b/src/or/microdesc.c
index f29611f930da236d465f329bfe6b328110e767f8..b3c54a84f5f3b00f2a6b311414dced39fdca0516 100644
--- a/src/or/microdesc.c
+++ b/src/or/microdesc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, The Tor Project, Inc. */
+/* Copyright (c) 2009-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 #include "or.h"
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index a507f1be2d5383acdac38ac489f931d483dc68d3..8110c78388c4c486cb3db792952eda9c0483d76d 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
@@ -1264,7 +1264,6 @@ update_consensus_networkstatus_fetch_time(time_t now)
     time_to_download_next_consensus = now;
     log_info(LD_DIR, "No live consensus; we should fetch one immediately.");
   }
-
 }
 
 /** Return 1 if there's a reason we shouldn't try any directory
@@ -2038,6 +2037,25 @@ networkstatus_dump_bridge_status_to_file(time_t now)
   tor_free(status);
 }
 
+int32_t
+get_net_param_from_list(smartlist_t *net_params, const char *param_name,
+                        int default_val)
+{
+  size_t name_len = strlen(param_name);
+
+  SMARTLIST_FOREACH_BEGIN(net_params, const char *, p) {
+    if (!strcmpstart(p, param_name) && p[name_len] == '=') {
+      int ok=0;
+      long v = tor_parse_long(p+name_len+1, 10, INT32_MIN,
+                              INT32_MAX, &ok, NULL);
+      if (ok)
+        return (int32_t) v;
+    }
+  } SMARTLIST_FOREACH_END(p);
+
+  return default_val;
+}
+
 /** Return the value of a integer parameter from the networkstatus <b>ns</b>
  * whose name is <b>param_name</b>.  If <b>ns</b> is NULL, try loading the
  * latest consensus ourselves. Return <b>default_val</b> if no latest
@@ -2046,27 +2064,30 @@ int32_t
 networkstatus_get_param(networkstatus_t *ns, const char *param_name,
                         int32_t default_val)
 {
-  size_t name_len;
-
   if (!ns) /* if they pass in null, go find it ourselves */
     ns = networkstatus_get_latest_consensus();
 
   if (!ns || !ns->net_params)
     return default_val;
 
-  name_len = strlen(param_name);
+  return get_net_param_from_list(ns->net_params, param_name, default_val);
+}
 
-  SMARTLIST_FOREACH_BEGIN(ns->net_params, const char *, p) {
-    if (!strcmpstart(p, param_name) && p[name_len] == '=') {
-      int ok=0;
-      long v = tor_parse_long(p+name_len+1, 10, INT32_MIN,
-                              INT32_MAX, &ok, NULL);
-      if (ok)
-        return (int32_t) v;
-    }
-  } SMARTLIST_FOREACH_END(p);
+/** Return the value of a integer bw weight parameter from the networkstatus
+ * <b>ns</b> whose name is <b>weight_name</b>.  If <b>ns</b> is NULL, try
+ * loading the latest consensus ourselves. Return <b>default_val</b> if no
+ * latest consensus, or if it has no parameter called <b>param_name</b>. */
+int32_t
+networkstatus_get_bw_weight(networkstatus_t *ns, const char *weight_name,
+                        int32_t default_val)
+{
+  if (!ns) /* if they pass in null, go find it ourselves */
+    ns = networkstatus_get_latest_consensus();
 
-  return default_val;
+  if (!ns || !ns->weight_params)
+    return default_val;
+
+  return get_net_param_from_list(ns->weight_params, weight_name, default_val);
 }
 
 /** Return the name of the consensus flavor <b>flav</b> as used to identify
diff --git a/src/or/ntmain.c b/src/or/ntmain.c
index e5a855eec4b2139551142dd594973929fe19d20e..6f349cca6a4f7d7b7ffcd6aef04cd16773810797 100644
--- a/src/or/ntmain.c
+++ b/src/or/ntmain.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 #define MAIN_PRIVATE
diff --git a/src/or/onion.c b/src/or/onion.c
index f8913cd23b3dfd462673e71d0ba66cbf6ff89637..8870874246a616e43351004eec90bc070edf1636 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/or.h b/src/or/or.h
index 434de7819e29e92c45d9c126405f20f0f3171528..cf27520f1b96fbde7edb09c1735f513c114d8b4c 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
@@ -1771,6 +1771,10 @@ typedef struct networkstatus_t {
    * consensus, sorted by key. */
   smartlist_t *net_params;
 
+  /** List of key=value strings for the bw weight parameters in the
+   * consensus. */
+  smartlist_t *weight_params;
+
   /** List of networkstatus_voter_info_t.  For a vote, only one element
    * is included.  For a consensus, one element is included for every voter
    * whose vote contributed to the consensus. */
@@ -3950,6 +3954,9 @@ int dirserv_read_measured_bandwidths(const char *from_file,
 /** Smallest allowable voting interval. */
 #define MIN_VOTE_INTERVAL 300
 
+/** Precision multiplier for the Bw weights */
+#define BW_WEIGHT_SCALE   10000
+
 void dirvote_free_all(void);
 
 /* vote manipulation */
@@ -4345,10 +4352,14 @@ void signed_descs_update_status_from_consensus_networkstatus(
 char *networkstatus_getinfo_helper_single(routerstatus_t *rs);
 char *networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now);
 void networkstatus_dump_bridge_status_to_file(time_t now);
+int32_t get_net_param_from_list(smartlist_t *net_params, const char *name,
+                                int default_val);
 int32_t networkstatus_get_param(networkstatus_t *ns, const char *param_name,
                                 int32_t default_val);
 int getinfo_helper_networkstatus(control_connection_t *conn,
                                  const char *question, char **answer);
+int32_t networkstatus_get_bw_weight(networkstatus_t *ns, const char *weight,
+                                    int32_t default_val);
 const char *networkstatus_get_flavor_name(consensus_flavor_t flav);
 int networkstatus_parse_flavor_name(const char *flavname);
 void document_signature_free(document_signature_t *sig);
@@ -4947,11 +4958,13 @@ uint32_t router_get_advertised_bandwidth_capped(routerinfo_t *router);
 /** Possible ways to weight routers when choosing one randomly.  See
  * routerlist_sl_choose_by_bandwidth() for more information.*/
 typedef enum {
-  NO_WEIGHTING, WEIGHT_FOR_EXIT, WEIGHT_FOR_GUARD
+  NO_WEIGHTING, WEIGHT_FOR_EXIT, WEIGHT_FOR_MID, WEIGHT_FOR_GUARD,
+  WEIGHT_FOR_DIR
 } bandwidth_weight_rule_t;
 routerinfo_t *routerlist_sl_choose_by_bandwidth(smartlist_t *sl,
                                                 bandwidth_weight_rule_t rule);
-routerstatus_t *routerstatus_sl_choose_by_bandwidth(smartlist_t *sl);
+routerstatus_t *routerstatus_sl_choose_by_bandwidth(smartlist_t *sl,
+                                                bandwidth_weight_rule_t rule);
 
 /** Flags to be passed to control router_choose_random_node() to indicate what
  * kind of nodes to pick according to what algorithm. */
@@ -5133,7 +5146,7 @@ typedef struct tor_version_t {
   char git_tag[DIGEST_LEN];
 } tor_version_t;
 
-int router_get_router_hash(const char *s, char *digest);
+int router_get_router_hash(const char *s, size_t s_len, char *digest);
 int router_get_dir_hash(const char *s, char *digest);
 int router_get_runningrouters_hash(const char *s, char *digest);
 int router_get_networkstatus_v2_hash(const char *s, char *digest);
@@ -5177,6 +5190,7 @@ void dump_distinct_digest_count(int severity);
 
 int compare_routerstatus_entries(const void **_a, const void **_b);
 networkstatus_v2_t *networkstatus_v2_parse_from_string(const char *s);
+int networkstatus_verify_bw_weights(networkstatus_t *ns);
 networkstatus_t *networkstatus_parse_vote_from_string(const char *s,
                                                  const char **eos_out,
                                                  networkstatus_type_t ns_type);
diff --git a/src/or/policies.c b/src/or/policies.c
index a49de01e18342bccf10d045a30db162b3032f9cc..90e159a88077da90f4063f606303ddd29099a00d 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/reasons.c b/src/or/reasons.c
index 0544990679af6739c02b5cd37fdbb1b836799d4a..46483b2770f6197aea5169fd29d8f3cd08b5e240 100644
--- a/src/or/reasons.c
+++ b/src/or/reasons.c
@@ -1,5 +1,5 @@
 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/relay.c b/src/or/relay.c
index ae1b062cf67b6bbae446ab15eaeb0f597c00688e..599d3d9c80eb0c1a2f92a33704d42c4975a98f92 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index cbdb9a676c17a535b07cc057e54f72546e8e0720..9a31c2d73f48844a528222ed32d06e4ac003c8c0 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -1,5 +1,5 @@
 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c
index e4dc5b3d3ca7cc99e18a75ebb834b7f149afaee8..814abd8cc8010289bb24f7cd409254ebb6a68268 100644
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@ -1,5 +1,5 @@
 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
@@ -456,17 +456,17 @@ rend_encode_v2_descriptors(smartlist_t *descs_out,
   size_t ipos_len = 0, ipos_encrypted_len = 0;
   int k;
   uint32_t seconds_valid;
-  crypto_pk_env_t *service_key = auth_type == REND_STEALTH_AUTH ?
-                                 client_key : desc->pk;
+  crypto_pk_env_t *service_key;
+  if (!desc) {
+    log_warn(LD_BUG, "Could not encode v2 descriptor: No desc given.");
+    return -1;
+  }
+  service_key = (auth_type == REND_STEALTH_AUTH) ? client_key : desc->pk;
   tor_assert(service_key);
   if (auth_type == REND_STEALTH_AUTH) {
     descriptor_cookie = smartlist_get(client_cookies, 0);
     tor_assert(descriptor_cookie);
   }
-  if (!desc) {
-    log_warn(LD_REND, "Could not encode v2 descriptor: No desc given.");
-    return -1;
-  }
   /* Obtain service_id from public key. */
   crypto_pk_get_digest(service_key, service_id);
   /* Calculate current time-period. */
diff --git a/src/or/rendmid.c b/src/or/rendmid.c
index 57f5b6daedd15f554b9a0e666e79dabef0258bd5..c9f4bf8b704c96a18b445722d21dc5ce5b8db69d 100644
--- a/src/or/rendmid.c
+++ b/src/or/rendmid.c
@@ -1,5 +1,5 @@
 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index 9fcf248c37154ac60e385e82bd841c9f187a10c9..7795db0d7024f74831a115f12e18bbe602bb8c01 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -1,5 +1,5 @@
 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
diff --git a/src/or/rephist.c b/src/or/rephist.c
index e606db3b7b2e0eff2987ed3b26050579ac864d01..c8da8dfe2d4fc56bd908f8553c8e1bfe007b0eb6 100644
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@ -1,5 +1,5 @@
 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
@@ -1909,8 +1909,8 @@ rep_hist_get_predicted_internal(time_t now, int *need_uptime,
     return 0; /* too long ago */
   if (predicted_internal_uptime_time + PREDICTED_CIRCS_RELEVANCE_TIME >= now)
     *need_uptime = 1;
-  if (predicted_internal_capacity_time + PREDICTED_CIRCS_RELEVANCE_TIME >= now)
-    *need_capacity = 1;
+  // Always predict that we need capacity.
+  *need_capacity = 1;
   return 1;
 }
 
diff --git a/src/or/router.c b/src/or/router.c
index 257bca935bc5e9bc677dd2b668da4c639515053e..347d7f9eff1037d9451a9c253e21d6e4fd49c8f1 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 #define ROUTER_PRIVATE
@@ -1416,6 +1416,7 @@ router_rebuild_descriptor(int force)
     ei->cache_info.send_unencrypted = 1;
 
   router_get_router_hash(ri->cache_info.signed_descriptor_body,
+                         strlen(ri->cache_info.signed_descriptor_body),
                          ri->cache_info.signed_descriptor_digest);
 
   routerinfo_set_country(ri);
@@ -1778,7 +1779,7 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
   strlcpy(s+written, "router-signature\n", maxlen-written);
   written += strlen(s+written);
   s[written] = '\0';
-  if (router_get_router_hash(s, digest) < 0) {
+  if (router_get_router_hash(s, strlen(s), digest) < 0) {
     return -1;
   }
 
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 1b9df560315ced4841d7e62a71694a75891ed57a..0173c27e4e26e74c3189ac4d494e8469bac1e68a 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
@@ -583,8 +583,6 @@ signed_desc_append_to_journal(signed_descriptor_t *desc,
   const char *body = signed_descriptor_get_body_impl(desc,1);
   size_t len = desc->signed_descriptor_len + desc->annotations_len;
 
-  tor_assert(len == strlen(body));
-
   if (append_bytes_to_file(fname, body, len, 1)) {
     log_warn(LD_FS, "Unable to store router descriptor");
     tor_free(fname);
@@ -1096,9 +1094,10 @@ router_pick_directory_server_impl(authority_type_t type, int flags)
   } SMARTLIST_FOREACH_END(status);
 
   if (smartlist_len(tunnel)) {
-    result = routerstatus_sl_choose_by_bandwidth(tunnel);
+    result = routerstatus_sl_choose_by_bandwidth(tunnel, WEIGHT_FOR_DIR);
   } else if (smartlist_len(overloaded_tunnel)) {
-    result = routerstatus_sl_choose_by_bandwidth(overloaded_tunnel);
+    result = routerstatus_sl_choose_by_bandwidth(overloaded_tunnel,
+                                                 WEIGHT_FOR_DIR);
   } else if (smartlist_len(trusted_tunnel)) {
     /* FFFF We don't distinguish between trusteds and overloaded trusteds
      * yet. Maybe one day we should. */
@@ -1106,9 +1105,10 @@ router_pick_directory_server_impl(authority_type_t type, int flags)
      * is a feature, but it could easily be a bug. -RD */
     result = smartlist_choose(trusted_tunnel);
   } else if (smartlist_len(direct)) {
-    result = routerstatus_sl_choose_by_bandwidth(direct);
+    result = routerstatus_sl_choose_by_bandwidth(direct, WEIGHT_FOR_DIR);
   } else if (smartlist_len(overloaded_direct)) {
-    result = routerstatus_sl_choose_by_bandwidth(overloaded_direct);
+    result = routerstatus_sl_choose_by_bandwidth(overloaded_direct,
+                                                 WEIGHT_FOR_DIR);
   } else {
     result = smartlist_choose(trusted_direct);
   }
@@ -1536,6 +1536,204 @@ kb_to_bytes(uint32_t bw)
   return (bw > (INT32_MAX/1000)) ? INT32_MAX : bw*1000;
 }
 
+/** Helper function:
+ * choose a random element of smartlist <b>sl</b>, weighted by
+ * the advertised bandwidth of each element using the consensus
+ * bandwidth weights.
+ *
+ * If <b>statuses</b> is zero, then <b>sl</b> is a list of
+ * routerinfo_t's. Otherwise it's a list of routerstatus_t's.
+ *
+ * If <b>rule</b>==WEIGHT_FOR_EXIT. we're picking an exit node: consider all
+ * nodes' bandwidth equally regardless of their Exit status, since there may
+ * be some in the list because they exit to obscure ports. If
+ * <b>rule</b>==NO_WEIGHTING, we're picking a non-exit node: weight
+ * exit-node's bandwidth less depending on the smallness of the fraction of
+ * Exit-to-total bandwidth.  If <b>rule</b>==WEIGHT_FOR_GUARD, we're picking a
+ * guard node: consider all guard's bandwidth equally. Otherwise, weight
+ * guards proportionally less.
+ */
+static void *
+smartlist_choose_by_bandwidth_weights(smartlist_t *sl,
+                                      bandwidth_weight_rule_t rule,
+                                      int statuses)
+{
+  int64_t weight_scale;
+  int64_t rand_bw;
+  double Wg = -1, Wm = -1, We = -1, Wd = -1;
+  double Wgb = -1, Wmb = -1, Web = -1, Wdb = -1;
+  double weighted_bw = 0;
+  double *bandwidths;
+  double tmp = 0;
+  unsigned int i;
+
+  /* Can't choose exit and guard at same time */
+  tor_assert(rule == NO_WEIGHTING ||
+             rule == WEIGHT_FOR_EXIT ||
+             rule == WEIGHT_FOR_GUARD ||
+             rule == WEIGHT_FOR_MID ||
+             rule == WEIGHT_FOR_DIR);
+
+  if (smartlist_len(sl) == 0) {
+    log_info(LD_CIRC,
+             "Empty routerlist passed in to consensus weight node "
+             "selection for rule %d", rule);
+    return NULL;
+  }
+
+  weight_scale = networkstatus_get_param(NULL, "bwweightscale",
+                                         BW_WEIGHT_SCALE);
+
+  if (rule == WEIGHT_FOR_GUARD) {
+    Wg = networkstatus_get_bw_weight(NULL, "Wgg", -1);
+    Wm = networkstatus_get_bw_weight(NULL, "Wgm", -1); /* Bridges */
+    We = 0;
+    Wd = networkstatus_get_bw_weight(NULL, "Wgd", -1);
+
+    Wgb = networkstatus_get_bw_weight(NULL, "Wgb", -1);
+    Wmb = networkstatus_get_bw_weight(NULL, "Wmb", -1);
+    Web = networkstatus_get_bw_weight(NULL, "Web", -1);
+    Wdb = networkstatus_get_bw_weight(NULL, "Wdb", -1);
+  } else if (rule == WEIGHT_FOR_MID) {
+    Wg = networkstatus_get_bw_weight(NULL, "Wmg", -1);
+    Wm = networkstatus_get_bw_weight(NULL, "Wmm", -1);
+    We = networkstatus_get_bw_weight(NULL, "Wme", -1);
+    Wd = networkstatus_get_bw_weight(NULL, "Wmd", -1);
+
+    Wgb = networkstatus_get_bw_weight(NULL, "Wgb", -1);
+    Wmb = networkstatus_get_bw_weight(NULL, "Wmb", -1);
+    Web = networkstatus_get_bw_weight(NULL, "Web", -1);
+    Wdb = networkstatus_get_bw_weight(NULL, "Wdb", -1);
+  } else if (rule == WEIGHT_FOR_EXIT) {
+    // Guards CAN be exits if they have weird exit policies
+    // They are d then I guess...
+    We = networkstatus_get_bw_weight(NULL, "Wee", -1);
+    Wm = networkstatus_get_bw_weight(NULL, "Wem", -1); /* Odd exit policies */
+    Wd = networkstatus_get_bw_weight(NULL, "Wed", -1);
+    Wg = networkstatus_get_bw_weight(NULL, "Weg", -1); /* Odd exit policies */
+
+    Wgb = networkstatus_get_bw_weight(NULL, "Wgb", -1);
+    Wmb = networkstatus_get_bw_weight(NULL, "Wmb", -1);
+    Web = networkstatus_get_bw_weight(NULL, "Web", -1);
+    Wdb = networkstatus_get_bw_weight(NULL, "Wdb", -1);
+  } else if (rule == WEIGHT_FOR_DIR) {
+    We = networkstatus_get_bw_weight(NULL, "Wbe", -1);
+    Wm = networkstatus_get_bw_weight(NULL, "Wbm", -1);
+    Wd = networkstatus_get_bw_weight(NULL, "Wbd", -1);
+    Wg = networkstatus_get_bw_weight(NULL, "Wbg", -1);
+
+    Wgb = Wmb = Web = Wdb = weight_scale;
+  } else if (rule == NO_WEIGHTING) {
+    Wg = Wm = We = Wd = weight_scale;
+    Wgb = Wmb = Web = Wdb = weight_scale;
+  }
+
+  if (Wg < 0 || Wm < 0 || We < 0 || Wd < 0 || Wgb < 0 || Wmb < 0 || Wdb < 0
+      || Web < 0) {
+    log_debug(LD_CIRC,
+              "Got negative bandwidth weights. Defaulting to old selection"
+              " algorithm.");
+    return NULL; // Use old algorithm.
+  }
+
+  Wg /= weight_scale;
+  Wm /= weight_scale;
+  We /= weight_scale;
+  Wd /= weight_scale;
+
+  Wgb /= weight_scale;
+  Wmb /= weight_scale;
+  Web /= weight_scale;
+  Wdb /= weight_scale;
+
+  bandwidths = tor_malloc_zero(sizeof(double)*smartlist_len(sl));
+
+  // Cycle through smartlist and total the bandwidth.
+  for (i = 0; i < (unsigned)smartlist_len(sl); ++i) {
+    int is_exit = 0, is_guard = 0, is_dir = 0, this_bw = 0;
+    double weight = 1;
+    if (statuses) {
+      routerstatus_t *status = smartlist_get(sl, i);
+      is_exit = status->is_exit;
+      is_guard = status->is_possible_guard;
+      is_dir = (status->dir_port != 0);
+      if (!status->has_bandwidth) {
+        tor_free(bandwidths);
+        /* This should never happen, unless all the authorites downgrade
+         * to 0.2.0 or rogue routerstatuses get inserted into our consensus. */
+        log_warn(LD_BUG,
+                 "Consensus is not listing bandwidths. Defaulting back to "
+                 "old router selection algorithm.");
+        return NULL;
+      }
+      this_bw = kb_to_bytes(status->bandwidth);
+    } else {
+      routerstatus_t *rs;
+      routerinfo_t *router = smartlist_get(sl, i);
+      rs = router_get_consensus_status_by_id(
+             router->cache_info.identity_digest);
+      is_exit = router->is_exit;
+      is_guard = router->is_possible_guard;
+      is_dir = (router->dir_port != 0);
+      if (rs && rs->has_bandwidth) {
+        this_bw = kb_to_bytes(rs->bandwidth);
+      } else { /* bridge or other descriptor not in our consensus */
+        this_bw = router_get_advertised_bandwidth_capped(router);
+      }
+    }
+    if (is_guard && is_exit) {
+      weight = (is_dir ? Wdb*Wd : Wd);
+    } else if (is_guard) {
+      weight = (is_dir ? Wgb*Wg : Wg);
+    } else if (is_exit) {
+      weight = (is_dir ? Web*We : We);
+    } else { // middle
+      weight = (is_dir ? Wmb*Wm : Wm);
+    }
+
+    bandwidths[i] = weight*this_bw;
+    weighted_bw += weight*this_bw;
+  }
+
+  log_debug(LD_CIRC, "Choosing node for rule %d based on weights "
+            "Wg=%lf Wm=%lf We=%lf Wd=%lf with total bw %lf", rule,
+            Wg, Wm, We, Wd, weighted_bw);
+
+  /* If there is no bandwidth, choose at random */
+  if (DBL_TO_U64(weighted_bw) == 0) {
+    log_warn(LD_CIRC,
+             "Weighted bandwidth is %lf in node selection for rule %d",
+             weighted_bw, rule);
+    tor_free(bandwidths);
+    return smartlist_choose(sl);
+  }
+
+  rand_bw = crypto_rand_uint64(DBL_TO_U64(weighted_bw));
+  rand_bw++; /* crypto_rand_uint64() counts from 0, and we need to count
+              * from 1 below. See bug 1203 for details. */
+
+  /* Last, count through sl until we get to the element we picked */
+  tmp = 0.0;
+  for (i=0; i < (unsigned)smartlist_len(sl); i++) {
+    tmp += bandwidths[i];
+    if (tmp >= rand_bw)
+      break;
+  }
+
+  if (i == (unsigned)smartlist_len(sl)) {
+    /* This was once possible due to round-off error, but shouldn't be able
+     * to occur any longer. */
+    tor_fragile_assert();
+    --i;
+    log_warn(LD_BUG, "Round-off error in computing bandwidth had an effect on "
+             " which router we chose. Please tell the developers. "
+             "%lf " U64_FORMAT " %lf", tmp, U64_PRINTF_ARG(rand_bw),
+             weighted_bw);
+  }
+  tor_free(bandwidths);
+  return smartlist_get(sl, i);
+}
+
 /** Helper function:
  * choose a random element of smartlist <b>sl</b>, weighted by
  * the advertised bandwidth of each element.
@@ -1572,11 +1770,24 @@ smartlist_choose_by_bandwidth(smartlist_t *sl, bandwidth_weight_rule_t rule,
   bitarray_t *guard_bits;
   int me_idx = -1;
 
+  // This function does not support WEIGHT_FOR_DIR
+  // or WEIGHT_FOR_MID
+  if (rule == WEIGHT_FOR_DIR || rule == WEIGHT_FOR_MID) {
+    rule = NO_WEIGHTING;
+  }
+
   /* Can't choose exit and guard at same time */
   tor_assert(rule == NO_WEIGHTING ||
              rule == WEIGHT_FOR_EXIT ||
              rule == WEIGHT_FOR_GUARD);
 
+  if (smartlist_len(sl) == 0) {
+    log_info(LD_CIRC,
+             "Empty routerlist passed in to old node selection for rule %d",
+             rule);
+    return NULL;
+  }
+
   /* First count the total bandwidth weight, and make a list
    * of each value.  <0 means "unknown; no routerinfo."  We use the
    * bits of negative values to remember whether the router was fast (-x)&1
@@ -1797,17 +2008,28 @@ routerinfo_t *
 routerlist_sl_choose_by_bandwidth(smartlist_t *sl,
                                   bandwidth_weight_rule_t rule)
 {
-  return smartlist_choose_by_bandwidth(sl, rule, 0);
+  routerinfo_t *ret;
+  if ((ret = smartlist_choose_by_bandwidth_weights(sl, rule, 0))) {
+    return ret;
+  } else {
+    return smartlist_choose_by_bandwidth(sl, rule, 0);
+  }
 }
 
 /** Choose a random element of status list <b>sl</b>, weighted by
  * the advertised bandwidth of each status.
  */
 routerstatus_t *
-routerstatus_sl_choose_by_bandwidth(smartlist_t *sl)
+routerstatus_sl_choose_by_bandwidth(smartlist_t *sl,
+                                    bandwidth_weight_rule_t rule)
 {
   /* We are choosing neither exit nor guard here. Weight accordingly. */
-  return smartlist_choose_by_bandwidth(sl, NO_WEIGHTING, 1);
+  routerstatus_t *ret;
+  if ((ret = smartlist_choose_by_bandwidth_weights(sl, rule, 1))) {
+    return ret;
+  } else {
+    return smartlist_choose_by_bandwidth(sl, rule, 1);
+  }
 }
 
 /** Return a random running router from the routerlist. Never
@@ -1843,7 +2065,7 @@ router_choose_random_node(smartlist_t *excludedsmartlist,
 
   tor_assert(!(weight_for_exit && need_guard));
   rule = weight_for_exit ? WEIGHT_FOR_EXIT :
-    (need_guard ? WEIGHT_FOR_GUARD : NO_WEIGHTING);
+    (need_guard ? WEIGHT_FOR_GUARD : WEIGHT_FOR_MID);
 
   /* Exclude relays that allow single hop exit circuits, if the user
    * wants to (such relays might be risky) */
@@ -1869,10 +2091,8 @@ router_choose_random_node(smartlist_t *excludedsmartlist,
   if (excludedset)
     routerset_subtract_routers(sl,excludedset);
 
-  if (need_capacity || need_guard)
-    choice = routerlist_sl_choose_by_bandwidth(sl, rule);
-  else
-    choice = smartlist_choose(sl);
+  // Always weight by bandwidth
+  choice = routerlist_sl_choose_by_bandwidth(sl, rule);
 
   smartlist_free(sl);
   if (!choice && (need_uptime || need_capacity || need_guard)) {
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index f4af7cd5e23e77a8cc6868f681f4879bf088a702..293e8c5d98c6e2efeeb1de844661ffc49d7f35bb 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -1,7 +1,7 @@
 /* Copyright (c) 2001 Matej Pfajfar.
  * Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /**
@@ -11,6 +11,8 @@
 
 #include "or.h"
 #include "memarea.h"
+#undef log
+#include <math.h>
 
 /****************************************************************************/
 
@@ -104,6 +106,7 @@ typedef enum {
 
   K_KNOWN_FLAGS,
   K_PARAMS,
+  K_BW_WEIGHTS,
   K_VOTE_DIGEST,
   K_CONSENSUS_DIGEST,
   K_ADDITIONAL_DIGEST,
@@ -111,6 +114,7 @@ typedef enum {
   K_CONSENSUS_METHODS,
   K_CONSENSUS_METHOD,
   K_LEGACY_DIR_KEY,
+  K_DIRECTORY_FOOTER,
 
   A_PURPOSE,
   A_LAST_LISTED,
@@ -485,7 +489,9 @@ static token_rule_t networkstatus_consensus_token_table[] = {
 /** List of tokens allowable in the footer of v1/v2 directory/networkstatus
  * footers. */
 static token_rule_t networkstatus_vote_footer_token_table[] = {
-  T(  "directory-signature", K_DIRECTORY_SIGNATURE, GE(2),   NEED_OBJ ),
+  T01("directory-footer",    K_DIRECTORY_FOOTER,    NO_ARGS,   NO_OBJ ),
+  T01("bandwidth-weights",   K_BW_WEIGHTS,          ARGS,      NO_OBJ ),
+  T(  "directory-signature", K_DIRECTORY_SIGNATURE, GE(2),     NEED_OBJ ),
   END_OF_TABLE
 };
 
@@ -516,11 +522,12 @@ static int router_add_exit_policy(routerinfo_t *router,directory_token_t *tok);
 static addr_policy_t *router_parse_addr_policy(directory_token_t *tok);
 static addr_policy_t *router_parse_addr_policy_private(directory_token_t *tok);
 
-static int router_get_hash_impl(const char *s, char *digest,
+static int router_get_hash_impl(const char *s, size_t s_len, char *digest,
                                 const char *start_str, const char *end_str,
                                 char end_char,
                                 digest_algorithm_t alg);
-static int router_get_hashes_impl(const char *s, digests_t *digests,
+static int router_get_hashes_impl(const char *s, size_t s_len,
+                                  digests_t *digests,
                                   const char *start_str, const char *end_str,
                                   char end_char);
 static void token_clear(directory_token_t *tok);
@@ -602,7 +609,7 @@ dump_desc(const char *desc, const char *type)
 int
 router_get_dir_hash(const char *s, char *digest)
 {
-  return router_get_hash_impl(s,digest,
+  return router_get_hash_impl(s, strlen(s), digest,
                               "signed-directory","\ndirectory-signature",'\n',
                               DIGEST_SHA1);
 }
@@ -611,9 +618,9 @@ router_get_dir_hash(const char *s, char *digest)
  * <b>s</b>. Return 0 on success, -1 on failure.
  */
 int
-router_get_router_hash(const char *s, char *digest)
+router_get_router_hash(const char *s, size_t s_len, char *digest)
 {
-  return router_get_hash_impl(s,digest,
+  return router_get_hash_impl(s, s_len, digest,
                               "router ","\nrouter-signature", '\n',
                               DIGEST_SHA1);
 }
@@ -624,7 +631,7 @@ router_get_router_hash(const char *s, char *digest)
 int
 router_get_runningrouters_hash(const char *s, char *digest)
 {
-  return router_get_hash_impl(s,digest,
+  return router_get_hash_impl(s, strlen(s), digest,
                               "network-status","\ndirectory-signature", '\n',
                               DIGEST_SHA1);
 }
@@ -634,7 +641,7 @@ router_get_runningrouters_hash(const char *s, char *digest)
 int
 router_get_networkstatus_v2_hash(const char *s, char *digest)
 {
-  return router_get_hash_impl(s,digest,
+  return router_get_hash_impl(s, strlen(s), digest,
                               "network-status-version","\ndirectory-signature",
                               '\n',
                               DIGEST_SHA1);
@@ -645,7 +652,7 @@ router_get_networkstatus_v2_hash(const char *s, char *digest)
 int
 router_get_networkstatus_v3_hashes(const char *s, digests_t *digests)
 {
-  return router_get_hashes_impl(s,digests,
+  return router_get_hashes_impl(s,strlen(s),digests,
                                 "network-status-version",
                                 "\ndirectory-signature",
                                 ' ');
@@ -657,7 +664,7 @@ int
 router_get_networkstatus_v3_hash(const char *s, char *digest,
                                  digest_algorithm_t alg)
 {
-  return router_get_hash_impl(s,digest,
+  return router_get_hash_impl(s, strlen(s), digest,
                               "network-status-version",
                               "\ndirectory-signature",
                               ' ', alg);
@@ -668,8 +675,8 @@ router_get_networkstatus_v3_hash(const char *s, char *digest,
 int
 router_get_extrainfo_hash(const char *s, char *digest)
 {
-  return router_get_hash_impl(s,digest,"extra-info","\nrouter-signature",'\n',
-                              DIGEST_SHA1);
+  return router_get_hash_impl(s, strlen(s), digest, "extra-info",
+                              "\nrouter-signature",'\n', DIGEST_SHA1);
 }
 
 /** Helper: used to generate signatures for routers, directories and
@@ -1238,6 +1245,8 @@ dump_distinct_digest_count(int severity)
  * s through end into the signed_descriptor_body of the resulting
  * routerinfo_t.
  *
+ * If <b>end</b> is NULL, <b>s</b> must be properly NULL-terminated.
+ *
  * If <b>allow_annotations</b>, it's okay to encounter annotations in <b>s</b>
  * before the router; if it's false, reject the router if it's annotated.  If
  * <b>prepend_annotations</b> is set, it should contain some annotations:
@@ -1300,7 +1309,7 @@ router_parse_entry_from_string(const char *s, const char *end,
     }
   }
 
-  if (router_get_router_hash(s, digest) < 0) {
+  if (router_get_router_hash(s, end - s, digest) < 0) {
     log_warn(LD_DIR, "Couldn't compute router hash.");
     goto err;
   }
@@ -1722,7 +1731,7 @@ authority_cert_parse_from_string(const char *s, const char **end_of_string)
     log_warn(LD_DIR, "Error tokenizing key certificate");
     goto err;
   }
-  if (router_get_hash_impl(s, digest, "dir-key-certificate-version",
+  if (router_get_hash_impl(s, strlen(s), digest, "dir-key-certificate-version",
                            "\ndir-key-certification", '\n', DIGEST_SHA1) < 0)
     goto err;
   tok = smartlist_get(tokens, 0);
@@ -1866,23 +1875,28 @@ authority_cert_parse_from_string(const char *s, const char **end_of_string)
 
 /** Helper: given a string <b>s</b>, return the start of the next router-status
  * object (starting with "r " at the start of a line).  If none is found,
- * return the start of the next directory signature.  If none is found, return
- * the end of the string. */
+ * return the start of the directory footer, or the next directory signature.
+ * If none is found, return the end of the string. */
 static INLINE const char *
 find_start_of_next_routerstatus(const char *s)
 {
-  const char *eos = strstr(s, "\nr ");
-  if (eos) {
-    const char *eos2 = tor_memstr(s, eos-s, "\ndirectory-signature");
-    if (eos2 && eos2 < eos)
-      return eos2;
-    else
-      return eos+1;
-  } else {
-    if ((eos = strstr(s, "\ndirectory-signature")))
-      return eos+1;
-    return s + strlen(s);
-  }
+  const char *eos, *footer, *sig;
+  if ((eos = strstr(s, "\nr ")))
+    ++eos;
+  else
+    eos = s + strlen(s);
+
+  footer = tor_memstr(s, eos-s, "\ndirectory-footer");
+  sig = tor_memstr(s, eos-s, "\ndirectory-signature");
+
+  if (footer && sig)
+    return MIN(footer, sig) + 1;
+  else if (footer)
+    return footer+1;
+  else if (sig)
+    return sig+1;
+  else
+    return eos;
 }
 
 /** Given a string at *<b>s</b>, containing a routerstatus object, and an
@@ -2327,6 +2341,395 @@ networkstatus_v2_parse_from_string(const char *s)
   return ns;
 }
 
+/** Verify the bandwidth weights of a network status document */
+int
+networkstatus_verify_bw_weights(networkstatus_t *ns)
+{
+  int64_t weight_scale;
+  int64_t G=0, M=0, E=0, D=0, T=0;
+  double Wgg, Wgm, Wgd, Wmg, Wmm, Wme, Wmd, Weg, Wem, Wee, Wed;
+  double Gtotal=0, Mtotal=0, Etotal=0;
+  const char *casename = NULL;
+  int valid = 1;
+
+  weight_scale = networkstatus_get_param(ns, "bwweightscale", BW_WEIGHT_SCALE);
+  Wgg = networkstatus_get_bw_weight(ns, "Wgg", -1);
+  Wgm = networkstatus_get_bw_weight(ns, "Wgm", -1);
+  Wgd = networkstatus_get_bw_weight(ns, "Wgd", -1);
+  Wmg = networkstatus_get_bw_weight(ns, "Wmg", -1);
+  Wmm = networkstatus_get_bw_weight(ns, "Wmm", -1);
+  Wme = networkstatus_get_bw_weight(ns, "Wme", -1);
+  Wmd = networkstatus_get_bw_weight(ns, "Wmd", -1);
+  Weg = networkstatus_get_bw_weight(ns, "Weg", -1);
+  Wem = networkstatus_get_bw_weight(ns, "Wem", -1);
+  Wee = networkstatus_get_bw_weight(ns, "Wee", -1);
+  Wed = networkstatus_get_bw_weight(ns, "Wed", -1);
+
+  if (Wgg<0 || Wgm<0 || Wgd<0 || Wmg<0 || Wmm<0 || Wme<0 || Wmd<0 || Weg<0
+          || Wem<0 || Wee<0 || Wed<0) {
+    log_warn(LD_BUG, "No bandwidth weights produced in consensus!");
+    return 0;
+  }
+
+  // First, sanity check basic summing properties that hold for all cases
+  // We use > 1 as the check for these because they are computed as integers.
+  // Sometimes there are rounding errors.
+  if (fabs(Wmm - weight_scale) > 1) {
+    log_warn(LD_BUG, "Wmm=%lf != "I64_FORMAT,
+             Wmm, I64_PRINTF_ARG(weight_scale));
+    valid = 0;
+  }
+
+  if (fabs(Wem - Wee) > 1) {
+    log_warn(LD_BUG, "Wem=%lf != Wee=%lf", Wem, Wee);
+    valid = 0;
+  }
+
+  if (fabs(Wgm - Wgg) > 1) {
+    log_warn(LD_BUG, "Wgm=%lf != Wgg=%lf", Wgm, Wgg);
+    valid = 0;
+  }
+
+  if (fabs(Weg - Wed) > 1) {
+    log_warn(LD_BUG, "Wed=%lf != Weg=%lf", Wed, Weg);
+    valid = 0;
+  }
+
+  if (fabs(Wgg + Wmg - weight_scale) > 0.001*weight_scale) {
+    log_warn(LD_BUG, "Wgg=%lf != "I64_FORMAT" - Wmg=%lf", Wgg,
+             I64_PRINTF_ARG(weight_scale), Wmg);
+    valid = 0;
+  }
+
+  if (fabs(Wee + Wme - weight_scale) > 0.001*weight_scale) {
+    log_warn(LD_BUG, "Wee=%lf != "I64_FORMAT" - Wme=%lf", Wee,
+             I64_PRINTF_ARG(weight_scale), Wme);
+    valid = 0;
+  }
+
+  if (fabs(Wgd + Wmd + Wed - weight_scale) > 0.001*weight_scale) {
+    log_warn(LD_BUG, "Wgd=%lf + Wmd=%lf + Wed=%lf != "I64_FORMAT,
+             Wgd, Wmd, Wed, I64_PRINTF_ARG(weight_scale));
+    valid = 0;
+  }
+
+  Wgg /= weight_scale;
+  Wgm /= weight_scale;
+  Wgd /= weight_scale;
+
+  Wmg /= weight_scale;
+  Wmm /= weight_scale;
+  Wme /= weight_scale;
+  Wmd /= weight_scale;
+
+  Weg /= weight_scale;
+  Wem /= weight_scale;
+  Wee /= weight_scale;
+  Wed /= weight_scale;
+
+  // Then, gather G, M, E, D, T to determine case
+  SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) {
+    if (rs->has_bandwidth) {
+      T += rs->bandwidth;
+      if (rs->is_exit && rs->is_possible_guard) {
+        D += rs->bandwidth;
+        Gtotal += Wgd*rs->bandwidth;
+        Mtotal += Wmd*rs->bandwidth;
+        Etotal += Wed*rs->bandwidth;
+      } else if (rs->is_exit) {
+        E += rs->bandwidth;
+        Mtotal += Wme*rs->bandwidth;
+        Etotal += Wee*rs->bandwidth;
+      } else if (rs->is_possible_guard) {
+        G += rs->bandwidth;
+        Gtotal += Wgg*rs->bandwidth;
+        Mtotal += Wmg*rs->bandwidth;
+      } else {
+        M += rs->bandwidth;
+        Mtotal += Wmm*rs->bandwidth;
+      }
+    } else {
+      log_warn(LD_BUG, "Missing consensus bandwidth for router %s",
+          rs->nickname);
+    }
+  } SMARTLIST_FOREACH_END(rs);
+
+  // Finally, check equality conditions depending upon case 1, 2 or 3
+  // Full equality cases: 1, 3b
+  // Partial equality cases: 2b (E=G), 3a (M=E)
+  // Fully unknown: 2a
+  if (3*E >= T && 3*G >= T) {
+    // Case 1: Neither are scarce
+    casename = "Case 1";
+    if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
+      log_warn(LD_DIR,
+               "Bw Weight Failure for %s: Etotal %lf != Mtotal %lf. "
+               "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+               " T="I64_FORMAT". "
+               "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
+               casename, Etotal, Mtotal,
+               I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+               I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
+               Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
+      valid = 0;
+    }
+    if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
+      log_warn(LD_DIR,
+               "Bw Weight Failure for %s: Etotal %lf != Gtotal %lf. "
+               "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+               " T="I64_FORMAT". "
+               "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
+               casename, Etotal, Gtotal,
+               I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+               I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
+               Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
+      valid = 0;
+    }
+    if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
+      log_warn(LD_DIR,
+               "Bw Weight Failure for %s: Mtotal %lf != Gtotal %lf. "
+               "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+               " T="I64_FORMAT". "
+               "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
+               casename, Mtotal, Gtotal,
+               I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+               I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
+               Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
+      valid = 0;
+    }
+  } else if (3*E < T && 3*G < T) {
+    int64_t R = MIN(E, G);
+    int64_t S = MAX(E, G);
+    /*
+     * Case 2: Both Guards and Exits are scarce
+     * Balance D between E and G, depending upon
+     * D capacity and scarcity. Devote no extra
+     * bandwidth to middle nodes.
+     */
+    if (R+D < S) { // Subcase a
+      double Rtotal, Stotal;
+      if (E < G) {
+        Rtotal = Etotal;
+        Stotal = Gtotal;
+      } else {
+        Rtotal = Gtotal;
+        Stotal = Etotal;
+      }
+      casename = "Case 2a";
+      // Rtotal < Stotal
+      if (Rtotal > Stotal) {
+        log_warn(LD_DIR,
+                   "Bw Weight Failure for %s: Rtotal %lf > Stotal %lf. "
+                   "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+                   " T="I64_FORMAT". "
+                   "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
+                   casename, Rtotal, Stotal,
+                   I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+                   I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
+                   Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
+        valid = 0;
+      }
+      // Rtotal < T/3
+      if (3*Rtotal > T) {
+        log_warn(LD_DIR,
+                   "Bw Weight Failure for %s: 3*Rtotal %lf > T "
+                   I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
+                   " D="I64_FORMAT" T="I64_FORMAT". "
+                   "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
+                   casename, Rtotal*3, I64_PRINTF_ARG(T),
+                   I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+                   I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
+                   Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
+        valid = 0;
+      }
+      // Stotal < T/3
+      if (3*Stotal > T) {
+        log_warn(LD_DIR,
+                   "Bw Weight Failure for %s: 3*Stotal %lf > T "
+                   I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
+                   " D="I64_FORMAT" T="I64_FORMAT". "
+                   "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
+                   casename, Stotal*3, I64_PRINTF_ARG(T),
+                   I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+                   I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
+                   Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
+        valid = 0;
+      }
+      // Mtotal > T/3
+      if (3*Mtotal < T) {
+        log_warn(LD_DIR,
+                   "Bw Weight Failure for %s: 3*Mtotal %lf < T "
+                   I64_FORMAT". "
+                   "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+                   " T="I64_FORMAT". "
+                   "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
+                   casename, Mtotal*3, I64_PRINTF_ARG(T),
+                   I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+                   I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
+                   Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
+        valid = 0;
+      }
+    } else { // Subcase b: R+D > S
+      casename = "Case 2b";
+
+      /* Check the rare-M redirect case. */
+      if (D != 0 && 3*M < T) {
+        casename = "Case 2b (balanced)";
+        if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
+          log_warn(LD_DIR,
+                   "Bw Weight Failure for %s: Etotal %lf != Mtotal %lf. "
+                   "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+                   " T="I64_FORMAT". "
+                   "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
+                   casename, Etotal, Mtotal,
+                   I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+                   I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
+                   Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
+          valid = 0;
+        }
+        if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
+          log_warn(LD_DIR,
+                   "Bw Weight Failure for %s: Etotal %lf != Gtotal %lf. "
+                   "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+                   " T="I64_FORMAT". "
+                   "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
+                   casename, Etotal, Gtotal,
+                   I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+                   I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
+                   Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
+          valid = 0;
+        }
+        if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
+          log_warn(LD_DIR,
+                   "Bw Weight Failure for %s: Mtotal %lf != Gtotal %lf. "
+                   "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+                   " T="I64_FORMAT". "
+                   "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
+                   casename, Mtotal, Gtotal,
+                   I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+                   I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
+                   Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
+          valid = 0;
+        }
+      } else {
+        if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
+          log_warn(LD_DIR,
+                   "Bw Weight Failure for %s: Etotal %lf != Gtotal %lf. "
+                   "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+                   " T="I64_FORMAT". "
+                   "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
+                   casename, Etotal, Gtotal,
+                   I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+                   I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
+                   Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
+          valid = 0;
+        }
+      }
+    }
+  } else { // if (E < T/3 || G < T/3) {
+    int64_t S = MIN(E, G);
+    int64_t NS = MAX(E, G);
+    if (3*(S+D) < T) { // Subcase a:
+      double Stotal;
+      double NStotal;
+      if (G < E) {
+        casename = "Case 3a (G scarce)";
+        Stotal = Gtotal;
+        NStotal = Etotal;
+      } else { // if (G >= E) {
+        casename = "Case 3a (E scarce)";
+        NStotal = Gtotal;
+        Stotal = Etotal;
+      }
+      // Stotal < T/3
+      if (3*Stotal > T) {
+        log_warn(LD_DIR,
+                   "Bw Weight Failure for %s: 3*Stotal %lf > T "
+                   I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
+                   " D="I64_FORMAT" T="I64_FORMAT". "
+                   "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
+                   casename, Stotal*3, I64_PRINTF_ARG(T),
+                   I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+                   I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
+                   Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
+        valid = 0;
+      }
+      if (NS >= M) {
+        if (fabs(NStotal-Mtotal) > 0.01*MAX(NStotal,Mtotal)) {
+          log_warn(LD_DIR,
+                   "Bw Weight Failure for %s: NStotal %lf != Mtotal %lf. "
+                   "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+                   " T="I64_FORMAT". "
+                   "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
+                   casename, NStotal, Mtotal,
+                   I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+                   I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
+                   Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
+          valid = 0;
+        }
+      } else {
+        // if NS < M, NStotal > T/3 because only one of G or E is scarce
+        if (3*NStotal < T) {
+          log_warn(LD_DIR,
+                     "Bw Weight Failure for %s: 3*NStotal %lf < T "
+                     I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT
+                     " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT". "
+                     "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
+                     casename, NStotal*3, I64_PRINTF_ARG(T),
+                     I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+                     I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
+                     Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
+          valid = 0;
+        }
+      }
+    } else { // Subcase b: S+D >= T/3
+      casename = "Case 3b";
+      if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
+        log_warn(LD_DIR,
+                 "Bw Weight Failure for %s: Etotal %lf != Mtotal %lf. "
+                 "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+                 " T="I64_FORMAT". "
+                 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
+                 casename, Etotal, Mtotal,
+                 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+                 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
+                 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
+        valid = 0;
+      }
+      if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
+        log_warn(LD_DIR,
+                 "Bw Weight Failure for %s: Etotal %lf != Gtotal %lf. "
+                 "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+                 " T="I64_FORMAT". "
+                 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
+                 casename, Etotal, Gtotal,
+                 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+                 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
+                 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
+        valid = 0;
+      }
+      if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
+        log_warn(LD_DIR,
+                 "Bw Weight Failure for %s: Mtotal %lf != Gtotal %lf. "
+                 "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
+                 " T="I64_FORMAT". "
+                 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
+                 casename, Mtotal, Gtotal,
+                 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
+                 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
+                 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
+        valid = 0;
+      }
+    }
+  }
+
+  if (valid)
+    log_notice(LD_DIR, "Bandwidth-weight %s is verified and valid.",
+               casename);
+
+  return valid;
+}
+
 /** Parse a v3 networkstatus vote, opinion, or consensus (depending on
  * ns_type), from <b>s</b>, and return the result.  Return NULL on failure. */
 networkstatus_t *
@@ -2675,6 +3078,46 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
     goto err;
   }
 
+  {
+    int found_sig = 0;
+    SMARTLIST_FOREACH_BEGIN(footer_tokens, directory_token_t *, _tok) {
+      tok = _tok;
+      if (tok->tp == K_DIRECTORY_SIGNATURE)
+        found_sig = 1;
+      else if (found_sig) {
+        log_warn(LD_DIR, "Extraneous token after first directory-signature");
+        goto err;
+      }
+    } SMARTLIST_FOREACH_END(_tok);
+  }
+
+  if ((tok = find_opt_by_keyword(footer_tokens, K_DIRECTORY_FOOTER))) {
+    if (tok != smartlist_get(footer_tokens, 0)) {
+      log_warn(LD_DIR, "Misplaced directory-footer token");
+      goto err;
+    }
+  }
+
+  tok = find_opt_by_keyword(footer_tokens, K_BW_WEIGHTS);
+  if (tok) {
+    ns->weight_params = smartlist_create();
+    for (i = 0; i < tok->n_args; ++i) {
+      int ok=0;
+      char *eq = strchr(tok->args[i], '=');
+      if (!eq) {
+        log_warn(LD_DIR, "Bad element '%s' in weight params",
+                 escaped(tok->args[i]));
+        goto err;
+      }
+      tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok, NULL);
+      if (!ok) {
+        log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i]));
+        goto err;
+      }
+      smartlist_add(ns->weight_params, tor_strdup(tok->args[i]));
+    }
+  }
+
   SMARTLIST_FOREACH_BEGIN(footer_tokens, directory_token_t *, _tok) {
     char declared_identity[DIGEST_LEN];
     networkstatus_voter_info_t *v;
@@ -3632,13 +4075,13 @@ find_all_exitpolicy(smartlist_t *s)
 }
 
 static int
-router_get_hash_impl_helper(const char *s,
+router_get_hash_impl_helper(const char *s, size_t s_len,
                             const char *start_str,
                             const char *end_str, char end_c,
                             const char **start_out, const char **end_out)
 {
-  char *start, *end;
-  start = strstr(s, start_str);
+  const char *start, *end;
+  start = tor_memstr(s, s_len, start_str);
   if (!start) {
     log_warn(LD_DIR,"couldn't find start of hashed material \"%s\"",start_str);
     return -1;
@@ -3649,12 +4092,13 @@ router_get_hash_impl_helper(const char *s,
              start_str);
     return -1;
   }
-  end = strstr(start+strlen(start_str), end_str);
+  end = tor_memstr(start+strlen(start_str),
+                   s_len - (start-s) - strlen(start_str), end_str);
   if (!end) {
     log_warn(LD_DIR,"couldn't find end of hashed material \"%s\"",end_str);
     return -1;
   }
-  end = strchr(end+strlen(end_str), end_c);
+  end = memchr(end+strlen(end_str), end_c, s_len - (end-s) - strlen(end_str));
   if (!end) {
     log_warn(LD_DIR,"couldn't find EOL");
     return -1;
@@ -3674,13 +4118,14 @@ router_get_hash_impl_helper(const char *s,
  * If no such substring exists, return -1.
  */
 static int
-router_get_hash_impl(const char *s, char *digest,
+router_get_hash_impl(const char *s, size_t s_len, char *digest,
                      const char *start_str,
                      const char *end_str, char end_c,
                      digest_algorithm_t alg)
 {
   const char *start=NULL, *end=NULL;
-  if (router_get_hash_impl_helper(s,start_str,end_str,end_c,&start,&end)<0)
+  if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,
+                                  &start,&end)<0)
     return -1;
 
   if (alg == DIGEST_SHA1) {
@@ -3700,12 +4145,13 @@ router_get_hash_impl(const char *s, char *digest,
 
 /** As router_get_hash_impl, but compute all hashes. */
 static int
-router_get_hashes_impl(const char *s, digests_t *digests,
+router_get_hashes_impl(const char *s, size_t s_len, digests_t *digests,
                        const char *start_str,
                        const char *end_str, char end_c)
 {
   const char *start=NULL, *end=NULL;
-  if (router_get_hash_impl_helper(s,start_str,end_str,end_c,&start,&end)<0)
+  if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,
+                                  &start,&end)<0)
     return -1;
 
   if (crypto_digest_all(digests, start, end-start)) {
@@ -4123,7 +4569,7 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
     goto err;
   }
   /* Compute descriptor hash for later validation. */
-  if (router_get_hash_impl(desc, desc_hash,
+  if (router_get_hash_impl(desc, strlen(desc), desc_hash,
                            "rendezvous-service-descriptor ",
                            "\nsignature", '\n', DIGEST_SHA1) < 0) {
     log_warn(LD_REND, "Couldn't compute descriptor hash.");
diff --git a/src/or/tor_main.c b/src/or/tor_main.c
index 4a6be7cddd8fde801fec644069d3b7a98ca6f2bb..117369c5656a09c9432cf7b81c96832cea7e9682 100644
--- a/src/or/tor_main.c
+++ b/src/or/tor_main.c
@@ -1,6 +1,6 @@
 /* Copyright 2001-2004 Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /** String describing which Tor subversion repository version the source was
diff --git a/src/test/test.c b/src/test/test.c
index 760558b65a71026b9e735c333a228a5b18b2d9e1..8d596981ef4e23e0d12d51e34bf91438fc924168 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /* Ordinarily defined in tor_main.c; this bit is just here to provide one
@@ -607,7 +607,6 @@ test_circuit_timeout(void)
 
     if (circuit_build_times_add_timeout(&final, 1, approx_time()-1))
       final.have_computed_timeout = 1;
-
   }
 
 done:
diff --git a/src/test/test.h b/src/test/test.h
index ed0eb316ad05ea0ec1090c789c646580c838d98e..550c57a8122f59eb77a4977683ec183bd74ea45c 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -1,6 +1,6 @@
 /* Copyright (c) 2001-2003, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 #ifndef _TOR_TEST_H
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index 327fc651f64265232310a4e6d83c787b2e546931..bafc0a968ef01380b6697713db8d10154c064767 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 #include "orconfig.h"
diff --git a/src/test/test_containers.c b/src/test/test_containers.c
index efc879b8c28c9038fe8aab5348e0c2523f4937d2..1fc248cb465bd27f7307cfb8703fc4a70efbeb09 100644
--- a/src/test/test_containers.c
+++ b/src/test/test_containers.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 #include "orconfig.h"
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index 656c3c94fc0ebe2a184e4d178800fc3c9fbaa5a9..7aca098bc78fe0b2328f56bba2959a6063663426 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 #include "orconfig.h"
diff --git a/src/test/test_data.c b/src/test/test_data.c
index bd7d9898566c8b04d8e110e88c04b27458be2c3a..f926ee17ddee1b1c2299927cc30cde282736fbca 100644
--- a/src/test/test_data.c
+++ b/src/test/test_data.c
@@ -1,6 +1,6 @@
 /* Copyright 2001-2004 Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 /** First of 3 example authority certificates for unit testing. */
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index b7ee4032991d900b7a0d0193b5cbef22afd42e31..a746beda2cc1fb2598dfb346ad993c1a4f2852e9 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 #include "orconfig.h"
diff --git a/src/test/test_util.c b/src/test/test_util.c
index ad8d82b4c0b48af3978c4eee750d26a2fd8b378b..34a6f4d66216a13d8ce9e32ea1ca8ba924e8e4e9 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2001-2004, Roger Dingledine.
  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2009, The Tor Project, Inc. */
+ * Copyright (c) 2007-2010, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 #include "orconfig.h"
diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c
index 04d53be072e69b61feb8e46f390036c9876e27ea..9eb9c798e00f5d82e6a0dd90a2b15db00d0318ef 100644
--- a/src/tools/tor-gencert.c
+++ b/src/tools/tor-gencert.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2009 The Tor Project, Inc. */
+/* Copyright (c) 2007-2010 The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
 #include "orconfig.h"
diff --git a/src/tools/tor-resolve.c b/src/tools/tor-resolve.c
index fe7f793dbba0df160be70825128a4ddd31728f45..dbab3da9c61a22d6aee08038ad36f515ff25a052 100644
--- a/src/tools/tor-resolve.c
+++ b/src/tools/tor-resolve.c
@@ -1,5 +1,5 @@
 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson
- * Copyright (c) 2007-2009, The Tor Project, Inc.
+ * Copyright (c) 2007-2010, The Tor Project, Inc.
  */
 /* See LICENSE for licensing information */
 
diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h
index ce1bcd4a3d0a4769cc4a3aca2345d769e49738f7..6751ff8f9883b4cd6e2975675ca95eaa2a0d33fc 100644
--- a/src/win32/orconfig.h
+++ b/src/win32/orconfig.h
@@ -226,5 +226,5 @@
 #define USING_TWOS_COMPLEMENT
 
 /* Version number of package */
-#define VERSION "0.2.2.9-alpha"
+#define VERSION "0.2.2.10-alpha"