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