Browse Source

Merge remote-tracking branch 'github/prop297'

Nick Mathewson 5 years ago
parent
commit
b915b6cd21

+ 1 - 1
Makefile.am

@@ -418,7 +418,7 @@ endif
 
 
 .PHONY: update-versions
 .PHONY: update-versions
 update-versions:
 update-versions:
-	$(PERL) $(top_builddir)/scripts/maint/updateVersions.pl
+	abs_top_srcdir="$(abs_top_srcdir)" $(PYTHON) $(top_srcdir)/scripts/maint/update_versions.py
 
 
 .PHONY: callgraph
 .PHONY: callgraph
 callgraph:
 callgraph:

+ 7 - 0
changes/prop297

@@ -0,0 +1,7 @@
+  o Minor features (required protocols):
+    - Tor no longer exits if it is missing a required protocol, if the
+      consensus that requires the protocol predates the release date of the
+      version of Tor. This change prevents Tor releases from exiting because
+      of an old cached consensus, on the theory that a newer cached
+      consensus might not require the protocol.  Implements proposal 297;
+      closes ticket 27735.

+ 9 - 1
configure.ac

@@ -8,6 +8,15 @@ AC_INIT([tor],[0.4.0.0-alpha-dev])
 AC_CONFIG_SRCDIR([src/app/main/tor_main.c])
 AC_CONFIG_SRCDIR([src/app/main/tor_main.c])
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_MACRO_DIR([m4])
 
 
+# DO NOT EDIT THIS DEFINITION BY HAND UNLESS YOU KNOW WHAT YOU'RE DOING.
+#
+# The update_versions.py script updates this definition when the
+# version number changes.  Tor uses it to make sure that it
+# only shuts down for missing "required protocols" when those protocols
+# are listed as required by a consensus after this date.
+AC_DEFINE(APPROX_RELEASE_DATE, ["2019-01-15"], # for 0.4.0.0-alpha-dev
+          [Approximate date when this software was released. (Updated when the version changes.)])
+
 # "foreign" means we don't follow GNU package layout standards
 # "foreign" means we don't follow GNU package layout standards
 # "1.11" means we require automake version 1.11 or newer
 # "1.11" means we require automake version 1.11 or newer
 # "subdir-objects" means put .o files in the same directory as the .c files
 # "subdir-objects" means put .o files in the same directory as the .c files
@@ -2417,7 +2426,6 @@ AC_CONFIG_FILES([
 	src/config/torrc.minimal
 	src/config/torrc.minimal
 	src/rust/.cargo/config
 	src/rust/.cargo/config
 	scripts/maint/checkOptionDocs.pl
 	scripts/maint/checkOptionDocs.pl
-	scripts/maint/updateVersions.pl
 ])
 ])
 
 
 if test "x$asciidoc" = "xtrue" && test "$ASCIIDOC" = "none"; then
 if test "x$asciidoc" = "xtrue" && test "$ASCIIDOC" = "none"; then

+ 1 - 5
doc/HACKING/ReleasingTor.md

@@ -135,13 +135,9 @@ new Tor release:
 === III. Making the source release.
 === III. Making the source release.
 
 
 1. In `maint-0.?.x`, bump the version number in `configure.ac` and run
 1. In `maint-0.?.x`, bump the version number in `configure.ac` and run
-   `perl scripts/maint/updateVersions.pl` to update version numbers in other
+   `make update-versions` to update version numbers in other
    places, and commit.  Then merge `maint-0.?.x` into `release-0.?.x`.
    places, and commit.  Then merge `maint-0.?.x` into `release-0.?.x`.
 
 
-   (NOTE: To bump the version number, edit `configure.ac`, and then run
-   either `make`, or `perl scripts/maint/updateVersions.pl`, depending on
-   your version.)
-
    When you merge the maint branch forward to the next maint branch, or into
    When you merge the maint branch forward to the next maint branch, or into
    master, merge it with "-s ours" to avoid a needless version bump.
    master, merge it with "-s ours" to avoid a needless version bump.
 
 

+ 0 - 59
scripts/maint/updateVersions.pl.in

@@ -1,59 +0,0 @@
-#!/usr/bin/perl -w
-
-$CONFIGURE_IN = '@abs_top_srcdir@/configure.ac';
-$ORCONFIG_H = '@abs_top_srcdir@/src/win32/orconfig.h';
-$TOR_NSI = '@abs_top_srcdir@/contrib/win32build/tor-mingw.nsi.in';
-
-$quiet = 1;
-
-sub demand {
-    my $fn = shift;
-    die "Missing file $fn" unless (-f $fn);
-}
-
-demand($CONFIGURE_IN);
-demand($ORCONFIG_H);
-demand($TOR_NSI);
-
-# extract version from configure.ac
-
-open(F, $CONFIGURE_IN) or die "$!";
-$version = undef;
-while (<F>) {
-    if (/AC_INIT\(\[tor\],\s*\[([^\]]*)\]\)/) {
-	$version = $1;
-	last;
-    }
-}
-die "No version found" unless $version;
-print "Tor version is $version\n" unless $quiet;
-close F;
-
-sub correctversion {
-    my ($fn, $defchar) = @_;
-    undef $/;
-    open(F, $fn) or die "$!";
-    my $s = <F>;
-    close F;
-    if ($s =~ /^$defchar(?:)define\s+VERSION\s+\"([^\"]+)\"/m) {
-	$oldver = $1;
-	if ($oldver ne $version) {
-	    print "Version mismatch in $fn: It thinks that the version is $oldver.  I think it's $version.  Fixing.\n";
-	    $line = $defchar . "define VERSION \"$version\"";
-	    open(F, ">$fn.bak");
-	    print F $s;
-	    close F;
-	    $s =~ s/^$defchar(?:)define\s+VERSION.*?$/$line/m;
-	    open(F, ">$fn");
-	    print F $s;
-	    close F;
-	} else {
-	    print "$fn has the correct version. Good.\n" unless $quiet;
-	}
-    } else {
-	print "Didn't find a version line in $fn -- uh oh.\n";
-    }
-}
-
-correctversion($TOR_NSI, "!");
-correctversion($ORCONFIG_H, "#");

+ 133 - 0
scripts/maint/update_versions.py

@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+
+import io
+import os
+import re
+import sys
+import time
+
+def P(path):
+    """
+    Give 'path' as a path relative to the abs_top_srcdir environment
+    variable.
+    """
+    return os.path.join(
+        os.environ.get('abs_top_srcdir', "."),
+        path)
+
+def warn(msg):
+    """
+    Print an warning message.
+    """
+    print("WARNING: {}".format(msg), file=sys.stderr)
+
+def find_version(infile):
+    """
+    Given an open file (or some other iterator of lines) holding a
+    configure.ac file, find the current version line.
+    """
+    for line in infile:
+        m = re.search(r'AC_INIT\(\[tor\],\s*\[([^\]]*)\]\)', line)
+        if m:
+            return m.group(1)
+
+    return None
+
+def update_version_in(infile, outfile, regex, versionline):
+    """
+    Copy every line from infile to outfile. If any line matches 'regex',
+    replace it with 'versionline'.  Return True if any line was changed;
+    false otherwise.
+
+    'versionline' is either a string -- in which case it is used literally,
+    or a function that receives the output of 'regex.match'.
+    """
+    found = False
+    have_changed = False
+    for line in infile:
+        m = regex.match(line)
+        if m:
+            found = True
+            oldline = line
+            if type(versionline) == type(u""):
+                line = versionline
+            else:
+                line = versionline(m)
+            if not line.endswith("\n"):
+                line += "\n"
+            if oldline != line:
+                have_changed = True
+        outfile.write(line)
+
+    if not found:
+        warn("didn't find any version line to replace in {}".format(infile.name))
+
+    return have_changed
+
+def replace_on_change(fname, change):
+    """
+    If "change" is true, replace fname with fname.tmp.  Otherwise,
+    delete fname.tmp.  Log what we're doing to stderr.
+    """
+    if not change:
+        print("No change in {}".format(fname))
+        os.unlink(fname+".tmp")
+    else:
+        print("Updating {}".format(fname))
+        os.rename(fname+".tmp", fname)
+
+
+def update_file(fname,
+                regex,
+                versionline,
+                encoding="utf-8"):
+    """
+    Replace any line matching 'regex' in 'fname' with 'versionline'.
+    Do not modify 'fname' if there are no changes made.  Use the
+    provided encoding to read and write.
+    """
+    with io.open(fname, "r", encoding=encoding) as f, \
+         io.open(fname+".tmp", "w", encoding=encoding) as outf:
+        have_changed = update_version_in(f, outf, regex, versionline)
+
+    replace_on_change(fname, have_changed)
+
+# Find out our version
+with open("configure.ac") as f:
+    version = find_version(f)
+
+# If we have no version, we can't proceed.
+if version == None:
+    print("No version found in configure.ac", file=sys.stderr())
+    sys.exit(1)
+
+print("The version is {}".format(version))
+
+today = time.strftime("%Y-%m-%d", time.gmtime())
+
+# In configure.ac, we replace the definition of APPROX_RELEASE_DATE
+# with "{today} for {version}", but only if the version does not match
+# what is already there.
+def replace_fn(m):
+    if m.group(1) != version:
+        # The version changed -- we change the date.
+        return u'AC_DEFINE(APPROX_RELEASE_DATE, ["{}"], # for {}'.format(today, version)
+    else:
+        # No changes.
+        return m.group(0)
+update_file(P("configure.ac"),
+            re.compile(r'AC_DEFINE\(APPROX_RELEASE_DATE.* for (.*)'),
+            replace_fn)
+
+# In tor-mingw.nsi.in, we replace the definition of VERSION.
+update_file(P("contrib/win32build/tor-mingw.nsi.in"),
+            re.compile(r'!define VERSION .*'),
+            u'!define VERSION "{}"'.format(version),
+            encoding="iso-8859-1")
+
+# In src/win32/orconfig.h, we replace the definition of VERSION.
+update_file(P("src/win32/orconfig.h"),
+            re.compile(r'#define VERSION .*'),
+            u'#define VERSION "{}"'.format(version))

+ 19 - 0
src/core/or/versions.c

@@ -16,6 +16,25 @@
 
 
 #include "core/or/tor_version_st.h"
 #include "core/or/tor_version_st.h"
 
 
+/**
+ * Return the approximate date when this release came out, or was
+ * scheduled to come out, according to the APPROX_RELEASE_DATE set in
+ * configure.ac
+ **/
+time_t
+tor_get_approx_release_date(void)
+{
+  char tbuf[ISO_TIME_LEN+1];
+  tor_snprintf(tbuf, sizeof(tbuf),
+               "%s 00:00:00", APPROX_RELEASE_DATE);
+  time_t result = 0;
+  int r = parse_iso_time(tbuf, &result);
+  if (BUG(r < 0)) {
+    result = 0;
+  }
+  return result;
+}
+
 /** Return VS_RECOMMENDED if <b>myversion</b> is contained in
 /** Return VS_RECOMMENDED if <b>myversion</b> is contained in
  * <b>versionlist</b>.  Else, return VS_EMPTY if versionlist has no
  * <b>versionlist</b>.  Else, return VS_EMPTY if versionlist has no
  * entries. Else, return VS_OLD if every member of
  * entries. Else, return VS_OLD if every member of

+ 2 - 0
src/core/or/versions.h

@@ -26,6 +26,8 @@ typedef enum version_status_t {
   VS_UNKNOWN, /**< We have no idea. */
   VS_UNKNOWN, /**< We have no idea. */
 } version_status_t;
 } version_status_t;
 
 
+time_t tor_get_approx_release_date(void);
+
 version_status_t tor_version_is_obsolete(const char *myversion,
 version_status_t tor_version_is_obsolete(const char *myversion,
                                          const char *versionlist);
                                          const char *versionlist);
 int tor_version_parse_platform(const char *platform,
 int tor_version_parse_platform(const char *platform,

+ 4 - 1
src/feature/nodelist/networkstatus.c

@@ -2681,6 +2681,9 @@ networkstatus_check_required_protocols(const networkstatus_t *ns,
   const char *required, *recommended;
   const char *required, *recommended;
   char *missing = NULL;
   char *missing = NULL;
 
 
+  const bool consensus_postdates_this_release =
+    ns->valid_after >= tor_get_approx_release_date();
+
   tor_assert(warning_out);
   tor_assert(warning_out);
 
 
   if (client_mode) {
   if (client_mode) {
@@ -2698,7 +2701,7 @@ networkstatus_check_required_protocols(const networkstatus_t *ns,
                  "%s on the Tor network. The missing protocols are: %s",
                  "%s on the Tor network. The missing protocols are: %s",
                  func, missing);
                  func, missing);
     tor_free(missing);
     tor_free(missing);
-    return 1;
+    return consensus_postdates_this_release ? 1 : 0;
   }
   }
 
 
   if (! protover_all_supported(recommended, &missing)) {
   if (! protover_all_supported(recommended, &missing)) {