Better calculation of the bandidth
[re6stnet.git] / tunnel.py
1 import os, random, traceback, time
2 import plib, utils, db
3
4 log = None
5 smooth = 0.3
6
7 class Connection:
8 def __init__(self, address, write_pipe, hello, iface, prefix,
9 ovpn_args):
10 self.process = plib.client(address, write_pipe, hello, '--dev', iface,
11 *ovpn_args, stdout=os.open(os.path.join(log,
12 'vifibnet.client.%s.log' % (prefix,)),
13 os.O_WRONLY|os.O_CREAT|os.O_TRUNC) )
14
15 self.iface = iface
16 self._prefix = prefix
17 self._creation_date = time.time()
18 self._bandwidth = None
19 self._last_trafic = None
20
21 # TODO : update the stats
22 def refresh(self):
23 # Check that the connection is alive
24 if self.process.poll() != None:
25 utils.log('Connection with %s has failed with return code %s'
26 % (self._prefix, self.process.returncode), 3)
27 return False
28
29 self._updateBandwidth()
30 return True
31
32 def _updateBandwidth(self):
33 try:
34 f_rx = open('/sys/class/net/%s/statistics/rx_bytes' %
35 self.iface, 'r')
36 f_tx = open('/sys/class/net/%s/statistics/tx_bytes' %
37 self.iface, 'r')
38
39 trafic = int(f_rx.read()) + int(f_tx.read())
40 t = time.time()
41
42 if bool(self._last_trafic):
43 bw = (trafic - self._last_trafic)/(t -
44 self._last_trafic_update)
45 if bool(self._bandwidth):
46 self._bandwidth = (1-smooth)*self._bandwidth + smooth*bw
47 else:
48 self._bandwidth = bw
49
50 utils.log('New bandwidth calculated on iface %s : %s' %
51 (self.iface, self._bandwidth), 4)
52
53 self._last_trafic_update = t
54 self._last_trafic = trafic
55 except IOError: # This just means that the interface is downs
56 utils.log('Unable to calculate bandwidth on iface %s' %
57 self.iface, 4)
58
59 class TunnelManager:
60
61 def __init__(self, write_pipe, peer_db, openvpn_args, hello_interval,
62 refresh, connection_count, refresh_rate):
63 self._write_pipe = write_pipe
64 self._peer_db = peer_db
65 self._connection_dict = {}
66 self._ovpn_args = openvpn_args
67 self._hello = hello_interval
68 self._refresh_time = refresh
69 self.free_interface_set = set(('client1', 'client2', 'client3',
70 'client4', 'client5', 'client6',
71 'client7', 'client8', 'client9',
72 'client10', 'client11', 'client12'))
73 self.next_refresh = time.time()
74
75 self._client_count = connection_count/2
76 self._refresh_count = refresh_rate*self._client_count
77
78 def refresh(self):
79 utils.log('Refreshing the tunnels', 2)
80 self._cleanDeads()
81 self._removeSomeTunnels()
82 self._makeNewTunnels()
83 self.next_refresh = time.time() + self._refresh_time
84
85 def _cleanDeads(self):
86 for prefix in self._connection_dict.keys():
87 if not self._connection_dict[prefix].refresh():
88 self._kill(prefix)
89
90 def _removeSomeTunnels(self):
91 for i in range(0, max(0, len(self._connection_dict) -
92 self._client_count + self._refresh_count)):
93 prefix = random.choice(self._connection_dict.keys())
94 self._kill(prefix)
95
96 def _kill(self, prefix):
97 utils.log('Killing the connection with ' + prefix, 2)
98 connection = self._connection_dict.pop(prefix)
99 try:
100 connection.process.kill()
101 except OSError:
102 # If the process is already exited
103 pass
104 self.free_interface_set.add(connection.iface)
105 self._peer_db.unusePeer(prefix)
106
107 def _makeNewTunnels(self):
108 utils.log('Trying to make %i new tunnels' %
109 (self._client_count - len(self._connection_dict)), 5)
110 try:
111 for prefix, address in self._peer_db.getUnusedPeers(
112 self._client_count - len(self._connection_dict)):
113 utils.log('Establishing a connection with %s' % prefix, 2)
114 iface = self.free_interface_set.pop()
115 self._connection_dict[prefix] = Connection(address,
116 self._write_pipe, self._hello, iface,
117 prefix, self._ovpn_args)
118 self._peer_db.usePeer(prefix)
119 except KeyError:
120 utils.log("""Can't establish connection with %s
121 : no available interface""" % prefix, 2)
122 except Exception:
123 traceback.print_exc()