lokinet/test/hive/hive.py

284 lines
8.0 KiB
Python
Raw Normal View History

2020-02-27 22:05:25 +00:00
#!/usr/bin/env python3
2020-02-27 21:32:56 +00:00
import pyllarp
2020-02-28 01:23:36 +00:00
from time import sleep
2020-02-28 02:19:47 +00:00
from signal import signal, SIGINT
from shutil import rmtree
from os import makedirs
from socket import AF_INET, htons, inet_aton
from pprint import pprint
2020-02-28 18:44:27 +00:00
import sys
from argparse import ArgumentParser as ap
2020-03-03 00:42:06 +00:00
import threading
from collections import deque
2020-03-03 00:42:06 +00:00
class RouterHive(object):
2020-03-03 00:42:06 +00:00
def __init__(self, n_relays=10, n_clients=10, netid="hive"):
2020-03-03 00:42:06 +00:00
self.endpointName = "pyllarp"
self.tmpdir = "/tmp/lokinet_hive"
self.netid = netid
2020-02-28 18:44:27 +00:00
2020-03-03 00:42:06 +00:00
self.n_relays = n_relays
self.n_clients = n_clients
2020-02-28 16:29:15 +00:00
2020-03-03 00:42:06 +00:00
self.addrs = []
self.events = deque()
2020-03-03 00:42:06 +00:00
self.hive = None
self.RCs = []
2020-03-03 00:42:06 +00:00
pyllarp.EnableDebug()
if not self.RemoveTmpDir():
raise RuntimeError("Failed to initialize Router Hive")
2020-03-03 00:42:06 +00:00
def RemoveTmpDir(self):
if self.tmpdir.startswith("/tmp/") and len(self.tmpdir) > 5:
print("calling rmdir -r %s" % self.tmpdir)
rmtree(self.tmpdir, ignore_errors=True)
return True
2020-03-03 00:42:06 +00:00
else:
print("not removing dir %s because it doesn't start with /tmp/" % self.tmpdir)
2020-03-03 00:42:06 +00:00
return False
2020-03-03 00:42:06 +00:00
def MakeEndpoint(self, router, after):
if router.IsRelay():
return
ep = pyllarp.Endpoint(self.endpointName, router)
router.AddEndpoint(ep)
if after is not None:
router.CallSafe(lambda : after(ep))
2020-03-03 00:42:06 +00:00
def AddRelay(self, index):
dirname = "%s/relays/%d" % (self.tmpdir, index)
makedirs("%s/netdb" % dirname, exist_ok=True)
2020-03-03 00:42:06 +00:00
config = pyllarp.Config()
2020-03-03 00:42:06 +00:00
port = index + 30000
tunname = "lokihive%d" % index
2020-03-03 00:42:06 +00:00
config.router.encryptionKeyfile = "%s/encryption.key" % dirname
config.router.transportKeyfile = "%s/transport.key" % dirname
config.router.identKeyfile = "%s/identity.key" % dirname
config.router.ourRcFile = "%s/rc.signed" % dirname
config.router.netid = self.netid
config.router.nickname = "Router%d" % index
config.router.publicOverride = True
config.router.overrideAddress("127.0.0.1", '{}'.format(port))
"""
config.router.ip4addr.sin_family = AF_INET
config.router.ip4addr.sin_port = htons(port)
config.router.ip4addr.sin_addr.set("127.0.0.1")
"""
config.router.blockBogons = False
2020-02-28 16:29:15 +00:00
2020-03-03 00:42:06 +00:00
config.network.enableProfiling = False
config.network.routerProfilesFile = "%s/profiles.dat" % dirname
config.network.netConfig = {"type": "null"}
2020-02-28 16:29:15 +00:00
2020-03-03 00:42:06 +00:00
config.netdb.nodedbDir = "%s/netdb" % dirname
2020-02-28 01:23:36 +00:00
2020-03-03 00:42:06 +00:00
config.links.InboundLinks = [("lo", AF_INET, port, set())]
2020-02-28 18:44:27 +00:00
2020-03-03 00:42:06 +00:00
config.system.pidfile = "%s/lokinet.pid" % dirname
2020-02-28 18:44:27 +00:00
2020-03-03 00:42:06 +00:00
config.dns.netConfig = {"local-dns": ("127.3.2.1:%d" % port)}
2020-02-27 21:32:56 +00:00
2020-03-03 00:42:06 +00:00
if index != 1:
config.bootstrap.routers = ["%s/relays/1/rc.signed" % self.tmpdir]
2020-02-28 18:44:27 +00:00
2020-03-03 00:42:06 +00:00
self.hive.AddRelay(config)
2020-02-28 18:44:27 +00:00
2020-03-03 00:42:06 +00:00
def AddClient(self, index):
dirname = "%s/clients/%d" % (self.tmpdir, index)
makedirs("%s/netdb" % dirname, exist_ok=True)
2020-02-28 18:44:27 +00:00
2020-03-03 00:42:06 +00:00
config = pyllarp.Config()
2020-02-28 18:44:27 +00:00
2020-03-03 00:42:06 +00:00
port = index + 40000
tunname = "lokihive%d" % index
2020-02-28 18:44:27 +00:00
2020-03-03 00:42:06 +00:00
config.router.encryptionKeyfile = "%s/encryption.key" % dirname
config.router.transportKeyfile = "%s/transport.key" % dirname
config.router.identKeyfile = "%s/identity.key" % dirname
config.router.ourRcFile = "%s/rc.signed" % dirname
config.router.netid = self.netid
config.router.blockBogons = False
2020-02-28 02:19:47 +00:00
2020-03-03 00:42:06 +00:00
config.network.enableProfiling = False
config.network.routerProfilesFile = "%s/profiles.dat" % dirname
config.network.netConfig = {"type": "null"}
2020-02-28 02:19:47 +00:00
2020-03-03 00:42:06 +00:00
config.netdb.nodedbDir = "%s/netdb" % dirname
2020-02-28 02:19:47 +00:00
2020-03-03 00:42:06 +00:00
config.system.pidfile = "%s/lokinet.pid" % dirname
2020-03-03 00:42:06 +00:00
config.dns.netConfig = {"local-dns": ("127.3.2.1:%d" % port)}
2020-03-03 00:42:06 +00:00
config.bootstrap.routers = ["%s/relays/1/rc.signed" % self.tmpdir]
2020-03-03 00:42:06 +00:00
self.hive.AddClient(config)
2020-02-28 16:29:15 +00:00
2020-03-03 00:42:06 +00:00
def onGotEndpoint(self, ep):
2020-02-28 16:29:15 +00:00
addr = ep.OurAddress()
2020-03-03 00:42:06 +00:00
self.addrs.append(pyllarp.ServiceAddress(addr))
2020-02-28 16:29:15 +00:00
2020-03-03 00:42:06 +00:00
def sendToAddress(self, router, toaddr, pkt):
2020-02-28 18:44:27 +00:00
if router.IsRelay():
return
if router.TrySendPacket("default", toaddr, pkt):
print("sending {} bytes to {}".format(len(pkt), toaddr))
2020-02-28 16:29:15 +00:00
2020-03-03 00:42:06 +00:00
def broadcastTo(self, addr, pkt):
self.hive.ForEachRouter(lambda r : sendToAddress(r, addr, pkt))
def InitFirstRC(self):
print("Starting first router to init its RC for bootstrap")
self.hive = pyllarp.RouterHive()
self.AddRelay(1)
self.hive.StartRelays()
print("sleeping 2 sec to give plenty of time to save bootstrap rc")
sleep(2)
2020-02-28 16:29:15 +00:00
2020-03-03 00:42:06 +00:00
self.hive.StopAll()
2020-02-28 18:44:27 +00:00
2020-03-03 00:42:06 +00:00
def Start(self):
2020-03-03 00:42:06 +00:00
self.InitFirstRC()
2020-03-03 00:42:06 +00:00
print("Resetting hive. Creating %d relays and %d clients" % (self.n_relays, self.n_clients))
2020-03-03 00:42:06 +00:00
self.hive = pyllarp.RouterHive()
2020-03-03 00:42:06 +00:00
for i in range(1, self.n_relays + 1):
self.AddRelay(i)
2020-03-03 00:42:06 +00:00
for i in range(1, self.n_clients + 1):
self.AddClient(i)
2020-03-03 00:42:06 +00:00
print("Starting relays")
self.hive.StartRelays()
sleep(0.2)
2020-03-03 00:42:06 +00:00
self.hive.ForEachRelay(lambda r: self.MakeEndpoint(r, self.onGotEndpoint))
print("Sleeping 2 seconds before starting clients")
sleep(2)
self.RCs = self.hive.GetRelayRCs()
2020-03-03 00:42:06 +00:00
self.hive.StartClients()
sleep(0.2)
2020-03-03 00:42:06 +00:00
self.hive.ForEachClient(lambda r: self.MakeEndpoint(r, self.onGotEndpoint))
2020-02-28 18:44:27 +00:00
2020-03-03 00:42:06 +00:00
def Stop(self):
self.hive.StopAll()
def CollectNextEvent(self):
self.events.append(self.hive.GetNextEvent())
def CollectAllEvents(self):
self.events.extend(self.hive.GetAllEvents())
def PopEvent(self):
self.CollectAllEvents()
if len(self.events):
return self.events.popleft()
return None
def DistanceSortedRCs(self, dht_key):
rcs = []
distances = []
for rc in self.RCs:
distances.append(rc.AsDHTKey ^ dht_key)
rcs.append(rc)
distances, rcs = (list(t) for t in zip(*sorted(zip(distances, rcs))))
return rcs
2020-03-03 00:42:06 +00:00
def main(n_relays=10, n_clients=10, print_each_event=True):
running = True
def handle_sigint(sig, frame):
nonlocal running
running = False
print("SIGINT received, attempting to stop all routers")
signal(SIGINT, handle_sigint)
try:
hive = RouterHive(n_relays, n_clients)
hive.Start()
except Exception as err:
print(err)
return 1
2020-02-28 02:19:47 +00:00
first_dht_pub = False
dht_pub_sorted = None
dht_pub_location = None
total_events = 0
event_counts = dict()
2020-02-28 02:19:47 +00:00
while running:
hive.CollectAllEvents()
print("Hive collected {} events this second.".format(len(hive.events)))
for event in hive.events:
event_name = event.__class__.__name__
if event:
if print_each_event:
print("Event: %s -- Triggered: %s" % (event_name, event.triggered))
print(event)
hops = getattr(event, "hops", None)
if hops:
for hop in hops:
print(hop)
total_events = total_events + 1
if event_name in event_counts:
event_counts[event_name] = event_counts[event_name] + 1
else:
event_counts[event_name] = 1
if total_events % 10 == 0:
pprint(event_counts)
if event_name == "DhtPubIntroReceivedEvent":
if not first_dht_pub:
dht_pub_sorted = hive.DistanceSortedRCs(event.location)
dht_pub_location = event.location
print("location: {} landed at: {}, sorted distance list:".format(dht_pub_location.ShortString(), event.routerID.ShortString()))
print([x.routerID.ShortString() for x in dht_pub_sorted[:4]])
first_dht_pub = True
else:
if event.location == dht_pub_location:
print("location: {}, landed at: {}".format(dht_pub_location.ShortString(), event.routerID.ShortString()))
# won't have printed event count above in this case.
if len(hive.events) == 0:
pprint(event_counts)
hive.events = []
sleep(1)
2020-03-03 00:42:06 +00:00
2020-02-28 18:44:27 +00:00
print('stopping')
2020-03-03 00:42:06 +00:00
hive.Stop()
2020-02-28 23:29:30 +00:00
print('stopped')
2020-02-28 18:44:27 +00:00
del hive
2020-02-27 21:32:56 +00:00
if __name__ == '__main__':
parser = ap()
print_events = False
relay_count = 10
client_count = 10
parser.add_argument('--print-events', dest="print_events", action='store_true')
parser.add_argument('--relay-count', dest="relay_count", type=int, default=10)
parser.add_argument('--client-count', dest="client_count", type=int, default=10)
args = parser.parse_args()
main(n_relays=args.relay_count, n_clients=args.client_count, print_each_event = args.print_events)