From 4eb4e01e49d78a4a74b1e8f9bccaebd16d9ebcb1 Mon Sep 17 00:00:00 2001
From: Christopher Baines <cb15g11@soton.ac.uk>
Date: Thu, 10 Apr 2014 23:21:51 +0100
Subject: Test the intro selection code better

---
 lib/chutney/Testing.py         |  16 +++++
 networks/hs-intro-select-2     |  35 +++++++++++
 networks/hs_intro_selection.py | 131 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 182 insertions(+)
 create mode 100644 networks/hs-intro-select-2
 create mode 100644 networks/hs_intro_selection.py

diff --git a/lib/chutney/Testing.py b/lib/chutney/Testing.py
index 369d260..8b1b356 100644
--- a/lib/chutney/Testing.py
+++ b/lib/chutney/Testing.py
@@ -19,6 +19,8 @@ introduction_point_circuits = {}
 
 nodes_by_fingerprint = {}
 
+next_intro_points = {}
+
 def get_node_fingerprints(nodes):
 
     for n in nodes:
@@ -27,6 +29,9 @@ def get_node_fingerprints(nodes):
 
     return nodes_by_fingerprint
 
+def get_next_intro_points():
+    return next_intro_points
+
 def track_introduction_points(node):
     nodenum = node._env["nodenum"]
     nodenick = node._env["nick"]
@@ -70,6 +75,17 @@ def track_introduction_points(node):
                 node_intro_events[nodenum].put(("removed", fingerprint))
                 del node_intro_circuits[nodenum][circuit]
 
+        prefix = "rend_services_introduce(): next intro "
+        if logevent.message.startswith(prefix):
+            fingerprint = logevent.message[len(prefix):].split(" ")[0][1:41]
+
+            logging.info("%s: next intro %s" % (nodenick, fingerprint))
+
+            if nodenum in next_intro_points:
+                next_intro_points[nodenum].append(fingerprint)
+            else:
+                next_intro_points[nodenum] = [fingerprint]
+
         logging.debug(nodenick + ": " + logevent.message)
 
 
diff --git a/networks/hs-intro-select-2 b/networks/hs-intro-select-2
new file mode 100644
index 0000000..411fd3c
--- /dev/null
+++ b/networks/hs-intro-select-2
@@ -0,0 +1,35 @@
+from hs_intro_selection import *
+
+network = Network()
+
+hs_nodes, hs_servers = testing.create_hidden_service(2)
+
+network.add(hs_nodes);
+
+network.add(Node.create(3, {
+    "tag": "a",
+    "authority": 1,
+    "relay": 1,
+    "torrc": "authority.tmpl"
+}))
+
+network.add(Node.create(12, {
+    "tag": "c",
+    "torrc": "client.tmpl"
+}))
+
+network.add(Node.create(10, {
+    "tag": "r",
+    "relay": 1,
+    "torrc": "intro.tmpl"
+}))
+
+def start():
+    results = hs_select_test(network)
+
+    for server in hs_servers:
+        server.stopListening()
+
+    network.stop()
+
+    return results
diff --git a/networks/hs_intro_selection.py b/networks/hs_intro_selection.py
new file mode 100644
index 0000000..deed5ac
--- /dev/null
+++ b/networks/hs_intro_selection.py
@@ -0,0 +1,131 @@
+from chutney.Testing import *
+from chutney.TorNet import *
+
+from twisted.internet import reactor
+
+from stem.control import EventType
+
+def hs_select_test(network, failures=1):
+    hs_nodes = network.get("h")
+
+    initial_nodes = network.get("a") + network.get("r") + network.get("c") + hs_nodes[:1]
+
+    if not all([ n.getController().start() for n in initial_nodes ]):
+        return False
+
+    logging.info("All initial nodes running")
+
+    thread.start_new_thread(reactor.run, (), {"installSignalHandlers": 0})
+
+    nodes_by_fingerprint = get_node_fingerprints(network.get("a") + network.get("r"))
+
+    track_introduction_points(hs_nodes[0])
+
+    node_0_published_descriptor = threading.Event()
+
+    def hs_node_0_listener(logevent):
+        if "Successfully uploaded v2 rend descriptors" in logevent.message:
+            node_0_published_descriptor.set()
+
+
+    hs_nodes[0].getStemController().add_event_listener(hs_node_0_listener, EventType.INFO)
+
+    node_0_published_descriptor.wait()
+
+    hs_nodes[0].getStemController().remove_event_listener(hs_node_0_listener)
+
+    # list to cope with scope problems
+    node_counter = [len(hs_nodes) - 1]
+    node_counter_lock = threading.RLock()
+
+    nodes_published_descriptors = threading.Event()
+
+    def hs_node_listener(logevent):
+        if "Successfully uploaded v2 rend descriptors" in logevent.message:
+            with node_counter_lock:
+                node_counter[0] -= 1
+
+                if node_counter[0] == 0:
+                    nodes_published_descriptors.set()
+
+    for node in hs_nodes[1:]:
+        node.getController().start()
+        track_introduction_points(node)
+
+        node.getStemController().add_event_listener(hs_node_listener, EventType.INFO)
+
+    nodes_published_descriptors.wait()
+
+    for node in hs_nodes[1:]:
+        node.getStemController().remove_event_listener(hs_node_listener)
+
+    # Now begin testing
+
+    connection_test(network.get("c"), len(hs_nodes))
+
+    time.sleep(5)
+
+    # Prediction
+
+    next_intro_points = get_next_intro_points()
+
+    print("Predicted new introduction points")
+    print(next_intro_points)
+
+    fingerprint = next_intro_points[0][0]
+    node = nodes_by_fingerprint[fingerprint]
+    logging.info("stopping " + node._env["nick"] + " (" + fingerprint + ")")
+
+    node.getStemController().close()
+    node.getController().stop()
+
+    time.sleep(10)
+
+    check_same_intro_points()
+
+    logging.info("About to stop %d introduction points" % failures)
+
+    fingerprints = set()
+
+    while len(fingerprints) != failures:
+        # Select a random node that is being used as an introduction point
+        nodenum = random.choice(node_intro_circuits.keys())
+        fingerprint = random.choice(node_intro_circuits[nodenum].values())
+
+        fingerprints.add(fingerprint)
+
+    for fingerprint in fingerprints:
+        node = nodes_by_fingerprint[fingerprint]
+
+        logging.info("stopping " + node._env["nick"] + " (" + fingerprint + ")")
+
+        node.getStemController().close()
+        node.getController().stop()
+
+    logging.info("begining to watch for the establishment of new introduction points")
+
+    changed = [False for n in hs_nodes]
+
+    intro_points_before = [set(node_intro_circuits[n._env["nodenum"]].values()) for n in hs_nodes]
+
+    time.sleep(60)
+
+    intro_points_after = [set(node_intro_circuits[n._env["nodenum"]].values()) for n in hs_nodes]
+
+    for i, node in enumerate(hs_nodes):
+        before = intro_points_before[i]
+        after = intro_points_after[i]
+
+        if before != after:
+            changed[i] = True
+
+    if all(changed):
+        logging.info("All changed")
+    else:
+        logging.info("All did not change")
+
+    check_same_intro_points()
+
+    connection_test(network.get("c"), len(hs_nodes))
+
+    reactor.stop()
-- 
cgit v1.2.3