|
@@ -19,6 +19,7 @@ import re
|
|
|
import errno
|
|
|
import time
|
|
|
import shutil
|
|
|
+import importlib
|
|
|
|
|
|
import chutney.Templating
|
|
|
import chutney.Traffic
|
|
@@ -903,199 +904,6 @@ class Network(object):
|
|
|
for c in controllers:
|
|
|
c.check(listNonRunning=False)
|
|
|
|
|
|
- def verify(self):
|
|
|
- print("Verifying data transmission:")
|
|
|
- status = self._verify_traffic()
|
|
|
- print("Transmission: %s" % ("Success" if status else "Failure"))
|
|
|
- if not status:
|
|
|
-
|
|
|
-
|
|
|
- print("Set 'debug_flag = True' in Traffic.py to diagnose.")
|
|
|
- return status
|
|
|
-
|
|
|
- def _verify_traffic(self):
|
|
|
- """Verify (parts of) the network by sending traffic through it
|
|
|
- and verify what is received."""
|
|
|
- LISTEN_PORT = 4747
|
|
|
-
|
|
|
-
|
|
|
- HS_PORT = 5858
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- DATALEN = self._dfltEnv['data_bytes']
|
|
|
-
|
|
|
- DOTDATALEN = 5 * 1024 * 1024
|
|
|
- TIMEOUT = 3
|
|
|
-
|
|
|
- randomlen = self._calculate_randomlen(DATALEN)
|
|
|
- reps = self._calculate_reps(DATALEN, randomlen)
|
|
|
-
|
|
|
- if reps == 0:
|
|
|
- DATALEN = 0
|
|
|
-
|
|
|
- if randomlen > 0:
|
|
|
-
|
|
|
- dot_reps = self._calculate_reps(DOTDATALEN, randomlen)
|
|
|
-
|
|
|
- dot_reps = min(reps, dot_reps)
|
|
|
- with open('/dev/urandom', 'r') as randfp:
|
|
|
- tmpdata = randfp.read(randomlen)
|
|
|
- else:
|
|
|
- dot_reps = 0
|
|
|
- tmpdata = {}
|
|
|
-
|
|
|
- bind_to = (DEFAULTS['ip'], LISTEN_PORT)
|
|
|
- tt = chutney.Traffic.TrafficTester(bind_to, tmpdata, TIMEOUT, reps,
|
|
|
- dot_reps)
|
|
|
- client_list = filter(lambda n:
|
|
|
- n._env['tag'] == 'c' or n._env['tag'] == 'bc',
|
|
|
- self._nodes)
|
|
|
- exit_list = filter(lambda n:
|
|
|
- ('exit' in n._env.keys()) and n._env['exit'] == 1,
|
|
|
- self._nodes)
|
|
|
- hs_list = filter(lambda n:
|
|
|
- n._env['tag'] == 'h',
|
|
|
- self._nodes)
|
|
|
- if len(client_list) == 0:
|
|
|
- print(" Unable to verify network: no client nodes available")
|
|
|
- return False
|
|
|
- if len(exit_list) == 0 and len(hs_list) == 0:
|
|
|
- print(" Unable to verify network: no exit/hs nodes available")
|
|
|
- print(" Exit nodes must be declared 'relay=1, exit=1'")
|
|
|
- print(" HS nodes must be declared 'tag=\"hs\"'")
|
|
|
- return False
|
|
|
- print("Connecting:")
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- total_path_node_count = 0
|
|
|
- total_path_node_count += self._configure_exits(tt, bind_to, tmpdata,
|
|
|
- reps, client_list,
|
|
|
- exit_list, LISTEN_PORT)
|
|
|
- total_path_node_count += self._configure_hs(tt, tmpdata, reps,
|
|
|
- client_list, hs_list,
|
|
|
- HS_PORT, LISTEN_PORT)
|
|
|
- print("Transmitting Data:")
|
|
|
- start_time = time.clock()
|
|
|
- status = tt.run()
|
|
|
- end_time = time.clock()
|
|
|
-
|
|
|
- if not status:
|
|
|
- return status
|
|
|
-
|
|
|
- self._report_bandwidth(DATALEN, total_path_node_count,
|
|
|
- start_time, end_time)
|
|
|
- return status
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- def _calculate_randomlen(self, datalen):
|
|
|
- MAX_RANDOMLEN = 128 * 1024
|
|
|
- if datalen > MAX_RANDOMLEN:
|
|
|
- return MAX_RANDOMLEN
|
|
|
- else:
|
|
|
- return datalen
|
|
|
-
|
|
|
- def _calculate_reps(self, datalen, replen):
|
|
|
-
|
|
|
- if datalen == 0 or replen == 0:
|
|
|
- return 0
|
|
|
-
|
|
|
- if replen < datalen:
|
|
|
- return (datalen + replen - 1) / replen
|
|
|
- else:
|
|
|
- return 1
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- def _configure_exits(self, tt, bind_to, tmpdata, reps, client_list,
|
|
|
- exit_list, LISTEN_PORT):
|
|
|
- CLIENT_EXIT_PATH_NODES = 4
|
|
|
- connection_count = self._dfltEnv['connection_count']
|
|
|
- exit_path_node_count = 0
|
|
|
- if len(exit_list) > 0:
|
|
|
- exit_path_node_count += (len(client_list) *
|
|
|
- CLIENT_EXIT_PATH_NODES *
|
|
|
- connection_count)
|
|
|
- for op in client_list:
|
|
|
- print(" Exit to %s:%d via client %s:%s"
|
|
|
- % (DEFAULTS['ip'], LISTEN_PORT,
|
|
|
- 'localhost', op._env['socksport']))
|
|
|
- for i in range(connection_count):
|
|
|
- proxy = ('localhost', int(op._env['socksport']))
|
|
|
- tt.add(chutney.Traffic.Source(tt, bind_to, tmpdata, proxy,
|
|
|
- reps))
|
|
|
- return exit_path_node_count
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- def _configure_hs(self, tt, tmpdata, reps, client_list, hs_list, HS_PORT,
|
|
|
- LISTEN_PORT):
|
|
|
- CLIENT_HS_PATH_NODES = 8
|
|
|
- connection_count = self._dfltEnv['connection_count']
|
|
|
- hs_path_node_count = (len(hs_list) * CLIENT_HS_PATH_NODES *
|
|
|
- connection_count)
|
|
|
-
|
|
|
- if self._dfltEnv['hs_multi_client']:
|
|
|
- hs_client_list = client_list
|
|
|
- hs_path_node_count *= len(client_list)
|
|
|
- else:
|
|
|
-
|
|
|
- hs_client_list = client_list[:1]
|
|
|
-
|
|
|
- for hs in hs_list:
|
|
|
- hs_bind_to = (hs._env['hs_hostname'], HS_PORT)
|
|
|
- for client in hs_client_list:
|
|
|
- print(" HS to %s:%d (%s:%d) via client %s:%s"
|
|
|
- % (hs._env['hs_hostname'], HS_PORT,
|
|
|
- DEFAULTS['ip'], LISTEN_PORT,
|
|
|
- 'localhost', client._env['socksport']))
|
|
|
- for i in range(connection_count):
|
|
|
- proxy = ('localhost', int(client._env['socksport']))
|
|
|
- tt.add(chutney.Traffic.Source(tt, hs_bind_to, tmpdata,
|
|
|
- proxy, reps))
|
|
|
- return hs_path_node_count
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- def _report_bandwidth(self, data_length, total_path_node_count,
|
|
|
- start_time, end_time):
|
|
|
-
|
|
|
-
|
|
|
- MIN_BWDATA = 5 * 1024 * 1024
|
|
|
- MIN_ELAPSED_TIME = 1.0
|
|
|
- cumulative_data_sent = total_path_node_count * data_length
|
|
|
- elapsed_time = end_time - start_time
|
|
|
- if (cumulative_data_sent >= MIN_BWDATA and
|
|
|
- elapsed_time >= MIN_ELAPSED_TIME):
|
|
|
-
|
|
|
- BWDIVISOR = 1024*1024
|
|
|
- single_stream_bandwidth = (data_length / elapsed_time / BWDIVISOR)
|
|
|
- overall_bandwidth = (cumulative_data_sent / elapsed_time /
|
|
|
- BWDIVISOR)
|
|
|
- print("Single Stream Bandwidth: %.2f MBytes/s"
|
|
|
- % single_stream_bandwidth)
|
|
|
- print("Overall tor Bandwidth: %.2f MBytes/s"
|
|
|
- % overall_bandwidth)
|
|
|
-
|
|
|
|
|
|
def ConfigureNodes(nodelist):
|
|
|
network = _THE_NETWORK
|
|
@@ -1106,11 +914,22 @@ def ConfigureNodes(nodelist):
|
|
|
network._dfltEnv['hasbridgeauth'] = True
|
|
|
|
|
|
|
|
|
+def getTests():
|
|
|
+ tests = []
|
|
|
+ for x in os.listdir("scripts/chutney_tests/"):
|
|
|
+ if not x.startswith("_") and os.path.splitext(x)[1] == ".py":
|
|
|
+ tests.append(os.path.splitext(x)[0])
|
|
|
+ return tests
|
|
|
+
|
|
|
+
|
|
|
def usage(network):
|
|
|
- return "\n".join(["Usage: chutney {command} {networkfile}",
|
|
|
+ return "\n".join(["Usage: chutney {command/test} {networkfile}",
|
|
|
"Known commands are: %s" % (
|
|
|
" ".join(x for x in dir(network)
|
|
|
- if not x.startswith("_")))])
|
|
|
+ if not x.startswith("_"))),
|
|
|
+ "Known tests are: %s" % (
|
|
|
+ " ".join(getTests()))
|
|
|
+ ])
|
|
|
|
|
|
|
|
|
def exit_on_error(err_msg):
|
|
@@ -1128,6 +947,16 @@ def runConfigFile(verb, data):
|
|
|
exec(data, _GLOBALS)
|
|
|
network = _GLOBALS['_THE_NETWORK']
|
|
|
|
|
|
+
|
|
|
+ if verb in getTests():
|
|
|
+ test_module = importlib.import_module("chutney_tests.{}".format(verb))
|
|
|
+ try:
|
|
|
+ return test_module.run_test(network)
|
|
|
+ except AttributeError:
|
|
|
+ print("Test {!r} has no 'run_test(network)' function".format(verb))
|
|
|
+ return False
|
|
|
+
|
|
|
+
|
|
|
if not hasattr(network, verb):
|
|
|
print(usage(network))
|
|
|
print("Error: I don't know how to %s." % verb)
|