From 6d36f21822675fedcb645387b5cddc3db9fbf1a5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com>
Date: Wed, 15 Jul 2015 12:49:08 -0400
Subject: [PATCH] python: add dhtscanner implementation

---
 tools/python/scanner.py | 139 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 139 insertions(+)
 create mode 100644 tools/python/scanner.py

diff --git a/tools/python/scanner.py b/tools/python/scanner.py
new file mode 100644
index 00000000..98bfb8a6
--- /dev/null
+++ b/tools/python/scanner.py
@@ -0,0 +1,139 @@
+import time
+from pprint import pprint
+from math import cos, sin, pi
+
+from opendht import *
+
+import numpy as np
+import matplotlib.pyplot as plt
+import matplotlib.patches as mpatches
+from matplotlib.colors import colorConverter
+from matplotlib.collections import RegularPolyCollection
+from mpl_toolkits.basemap import Basemap
+
+import GeoIP
+
+done = 0
+all_nodes = PyNodeSet()
+
+gi = GeoIP.open("GeoLiteCity.dat", GeoIP.GEOIP_INDEX_CACHE | GeoIP.GEOIP_CHECK_CACHE)
+gi6 = GeoIP.open("GeoLiteCityv6.dat", GeoIP.GEOIP_INDEX_CACHE | GeoIP.GEOIP_CHECK_CACHE)
+
+plt.ion()
+plt.figaspect(2.)
+
+fig, axes = plt.subplots(2, 1)
+fig.set_size_inches(12,16,forward=True)
+fig.tight_layout()
+
+mpx = axes[0]
+mpx.set_title("Node GeoIP")
+
+m = Basemap(projection='robin', resolution = 'l', area_thresh = 1000.0, lat_0=0, lon_0=0, ax=mpx)
+#m.drawcoastlines()
+m.fillcontinents(color='#cccccc',lake_color='white')
+m.drawparallels(np.arange(-90.,120.,30.))
+m.drawmeridians(np.arange(0.,420.,60.))
+m.drawmapboundary(fill_color='white')
+plt.show()
+
+ringx = axes[1]
+ringx.set_title("Node IDs")
+ringx.set_autoscale_on(False)
+ringx.set_aspect('equal', 'datalim')
+ringx.set_xlim(-2.,2.)
+ringx.set_ylim(-1.5,1.5)
+
+def gcb(v):
+    return True
+
+r = PyDhtRunner()
+i = PyIdentity()
+i.generate()
+
+r.run(i, port=4112)
+r.bootstrap("37.187.30.78", "4241")
+
+plt.pause(2)
+
+def step(cur_h, cur_depth):
+    global done, all_nodes
+    done += 1
+    a = 2.*pi*cur_h.toFloat()
+    b = a + 2.*pi/(2**(cur_depth))
+    print("step", cur_h, cur_depth)
+    arc = ringx.add_patch(mpatches.Wedge([0.,0,], 1., a*180/pi, b*180/pi, fill=True, color="blue", alpha=0.5))
+    r.get(cur_h, gcb, lambda d, nodes: nextstep(cur_h, cur_depth, d, nodes, arc=arc))
+
+def nextstep(cur_h, cur_depth, ok, nodes, arc=None):
+    global done, all_nodes
+    if arc:
+        arc.remove()
+    snodes = PyNodeSet()
+    snodes.extend(nodes)
+    all_nodes.extend(nodes)
+    depth = PyInfoHash.commonBits(snodes.first(), snodes.last())+2
+    if cur_depth < depth:
+        for b in range(cur_depth, depth):
+            new_h = PyInfoHash(cur_h.toString());
+            new_h.setBit(b, 1);
+            step(new_h, b+1);
+    done -= 1
+
+# start first step
+start_h = PyInfoHash()
+start_h.setBit(159, 1)
+step(start_h, 0)
+
+collection = None
+not_found = []
+
+def update_plot():
+    global done, m, collection, not_found
+    lats = []
+    lons = []
+    cities=[]
+    not_found.clear()
+    for n in all_nodes:
+        addr = n.getNode().getAddr().decode().split(':')[0]
+        if addr[0] == '[':
+            res = gi6.record_by_name_v6(addr[1:-1])
+        else:
+            res = gi.record_by_name(addr)
+        if res:
+            pprint(res)
+            lats.append(res['latitude'])
+            lons.append(res['longitude'])
+            cities.append(res['city'] if res['city'] else (str(int(res['latitude']))+'-'+str(int(res['longitude']))))
+        else:
+            not_found.append(n)
+
+    x,y = m(lons,lats)
+    m.plot(x,y,'bo')
+    for name, xpt, ypt in zip(cities, x, y):
+        mpx.text(xpt+50000, ypt+50000, name)
+    node_val = [n.getId().toFloat() for n in all_nodes]
+    xys = [(cos(d*2*pi), sin(d*2*pi)) for d in node_val]
+    if collection:
+        collection.remove()
+    collection = ringx.add_collection(RegularPolyCollection(
+                fig.dpi, 6, sizes=(10,), facecolors=colorConverter.to_rgba('blue'),
+                offsets = xys, transOffset = ringx.transData))
+
+while done > 0:
+    update_plot()
+    plt.draw()
+    plt.pause(.25)
+plt.draw()
+
+print(all_nodes.size(), " nodes found")
+print(all_nodes)
+print(len(not_found), " nodes not geolocalized")
+for n in not_found:
+    print(n.getNode().getId().toString().decode(), n.getNode().getAddr().decode())
+
+all_nodes = []
+r.join()
+
+plt.ioff()
+plt.show()
-- 
GitLab