-fix warning
[oweals/gnunet.git] / src / sensor / profiler.py
1 import argparse
2 import math
3 import networkx
4 import random
5 import tempfile
6 import os
7 import time
8 import matplotlib.pyplot as plt
9 from subprocess import Popen, PIPE, STDOUT
10
11 node_colors = None
12 graph = None
13 pos = None
14
15 def get_args():
16   parser = argparse.ArgumentParser(description="Sensor profiler")
17   parser.add_argument('-p', '--peers', action='store', type=int, required=True,
18                       help='Number of peers to run')
19   parser.add_argument('-l', '--links', action='store', type=int, required=False,
20                       help='Number of links to create')
21   parser.add_argument('-i', '--sensors-interval', action='store', type=int,
22                       required=False,
23                       help='Change the interval of running sensors to given value')
24   parser.add_argument('-a', '--anomalous-peers', action='store', type=int,
25                       required=True,
26                       help='Number of peers to simulate anomalies on')
27   return parser.parse_args()
28
29 def generate_topology(peers, links):
30   global graph
31   global node_colors
32   global pos
33   graph = networkx.empty_graph(peers)
34   for i in range(0, links):
35     a = 0
36     b = 0
37     while a == b:
38       a = random.randint(0, peers - 1)
39       b = random.randint(0, peers - 1)
40     graph.add_edge(a, b)
41   node_colors = [0] * peers
42   pos = networkx.layout.spring_layout(graph)
43
44 def create_topology_file():
45   global graph
46   nodes = list()
47   for i in range(len(graph.edge)):
48     nodes.append(list())
49   for e in graph.edges():
50     nodes[e[0]].append(e[1])
51   print nodes
52   f = tempfile.NamedTemporaryFile(delete=False)
53   for i in range(len(nodes)):
54     if len(nodes[i]) == 0:
55       continue
56     f.write('%d:' % i)
57     f.write('|'.join(map(str, nodes[i])))
58     f.write('\n')
59   # f.close()
60   return f.name
61
62 def draw_graph():
63   global graph
64   global node_colors
65   global pos
66   t = int(time.time())
67   inc = 2
68   name = str(t) + '.png'
69   while os.path.exists(name):
70     name = '%d(%d).png' % (t, inc)
71     inc += 1
72   print 'Drawing graph to file: %s' % name
73   plt.clf()
74   anomaly_lbls = {}
75   for i in range(len(graph.node)):
76     if node_colors[i] >= 1:
77       anomaly_lbls[i] = '\n\n\n' + str(node_colors[i] - 1)
78   networkx.draw(graph, pos=pos, node_color=node_colors, with_labels=range(len(graph.node)), cmap=plt.cm.Reds, vmin=0, vmax=2)
79   networkx.draw_networkx_labels(graph, pos, anomaly_lbls)
80   plt.savefig(name)
81
82 def peers_reconnected(p1, p2):
83   global graph
84   if p2 in graph[p1]:
85     print 'Link already exists'
86     return
87   graph.add_edge(p1, p2)
88   draw_graph()
89
90 def peers_disconnected(p1, p2):
91   global graph
92   print 'Disconnected peers %d and %d' % (p1, p2)
93   if p2 not in graph[p1]:
94     print 'Link does not exist'
95     return
96   graph.remove_edge(p1, p2)
97   draw_graph()
98
99 def anomaly_report(report):
100   global node_colors
101   if 0 == report['anomalous']:
102     node_colors[report['peer']] = 0
103   else:
104     clr = 1 + report['neighbors']
105     if node_colors[report['peer']] >= clr:
106       return
107     node_colors[report['peer']] = clr
108   draw_graph()
109
110 def handle_profiler_line(line):
111   if not line:
112     return
113   print line
114   if 'Peer disconnection request sent' in line: # Peers disconnected
115     parts = line.split(':')
116     peers = parts[-1].split(',')
117     peers_disconnected(int(peers[0]), int(peers[1]))
118     return
119   if 'Anomaly report:' in line:
120     parts = line.split('Anomaly report:')
121     anomaly_report(eval(parts[1]))
122     return
123   if 'Peer connection request sent' in line: # Peers reconnected
124     parts = line.split(':')
125     peers = parts[-1].split(',')
126     peers_reconnected(int(peers[0]), int(peers[1]))
127
128 def run_profiler(peers, topology_file, sensors_interval, anomalous_peers):
129   cmd1 = "./gnunet-sensor-profiler -p %d -t %s -a %d" % (peers, topology_file, anomalous_peers)
130   if sensors_interval:
131     cmd1 += " -i %d" % sensors_interval
132   cmd2 = "> log 2>&1"
133   cmd = "%s %s" % (cmd1, cmd2)
134   print cmd
135   process = Popen([cmd], shell=True)
136   time.sleep(0.5)
137   line = ''
138   f = open('log')
139   while process.poll() is None:
140     for c in f.read():
141       if not c or c == '\n':
142         handle_profiler_line(line)
143         line = ''
144       else:
145         line += c
146
147 def main():
148   args = vars(get_args())
149   num_peers = args['peers']
150   if num_peers < 3:
151     print 'Min number of peers is 3'
152     return
153   sensors_interval = None
154   if 'sensors_interval' in args:
155     sensors_interval = args['sensors_interval']
156   if 'links' in args:
157     num_links = args['links']
158   else:
159     #num_links = int(math.log(num_peers) * math.log(num_peers) * num_peers / 2)
160     num_links = int(math.log(num_peers) * num_peers)
161   # Generate random topology
162   generate_topology(num_peers, num_links)
163   print 'Generated random topology with %d peers and %d links' % (num_peers, num_links)
164   # Create a file with links to cut to split the topology into two
165   # Create TESTBED topology file
166   top_file = create_topology_file()
167   print 'Created TESTBED topology file %s' % top_file
168   draw_graph()
169   # Run c profiler
170   if os.path.isfile('log'):
171     os.remove('log')
172   run_profiler(num_peers, top_file, sensors_interval, args['anomalous_peers'])
173   
174 if __name__ == "__main__":
175   main()