Solving all the bugs that were their when I arrived this morning.
[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._lastTrafic = self._getTrafic()
17 self._bandwidth = None
18 self._prefix = prefix
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 % (self._prefix, 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' % self._bandwidth, 4)
35
36 return True
37
38 def _getTrafic(self):
39 try:
40 f_rx = open('/sys/class/net/%s/statistics/rx_bytes' % self.iface, 'r')
41 f_tx = open('/sys/class/net/%s/statistics/tx_bytes' % self.iface, 'r')
42 return int(f_rx.read()) + int(f_tx.read())
43 except Exception:
44 return 0
45
46 class TunnelManager:
47
48 def __init__(self, write_pipe, peer_db, openvpn_args, hello_interval,
49 refresh, connection_count, refresh_rate):
50 self._write_pipe = write_pipe
51 self._peer_db = peer_db
52 self._connection_dict = {}
53 self._ovpn_args = openvpn_args
54 self._hello = hello_interval
55 self._refresh_time = refresh
56 self.free_interface_set = set(('client1', 'client2', 'client3',
57 'client4', 'client5', 'client6',
58 'client7', 'client8', 'client9',
59 'client10', 'client11', 'client12'))
60 self.next_refresh = time.time()
61
62 self._client_count = connection_count/2
63 self._refresh_count = refresh_rate*self._client_count
64
65 def refresh(self):
66 utils.log('Refreshing the tunnels', 2)
67 self._cleanDeads()
68 self._removeSomeTunnels()
69 self._makeNewTunnels()
70 self.next_refresh = time.time() + self._refresh_time
71
72 def _cleanDeads(self):
73 for prefix in self._connection_dict.keys():
74 if not self._connection_dict[prefix].refresh():
75 self._kill(prefix)
76
77 def _removeSomeTunnels(self):
78 for i in range(0, max(0, len(self._connection_dict) -
79 self._client_count + self._refresh_count)):
80 prefix = random.choice(self._connection_dict.keys())
81 self._kill(prefix)
82
83 def _kill(self, prefix):
84 utils.log('Killing the connection with ' + prefix, 2)
85 connection = self._connection_dict.pop(prefix)
86 try:
87 connection.process.kill()
88 except OSError:
89 # If the process is already exited
90 pass
91 self.free_interface_set.add(connection.iface)
92 self._peer_db.unusePeer(prefix)
93
94 def _makeNewTunnels(self):
95 utils.log('Trying to make %i new tunnels' %
96 (self._client_count - len(self._connection_dict)), 5)
97 try:
98 for prefix, address in self._peer_db.getUnusedPeers(
99 self._client_count - len(self._connection_dict)):
100 utils.log('Establishing a connection with %s' % prefix, 2)
101 iface = self.free_interface_set.pop()
102 self._connection_dict[prefix] = Connection(address,
103 self._write_pipe, self._hello, iface,
104 prefix, self._ovpn_args)
105 self._peer_db.usePeer(prefix)
106 except KeyError:
107 utils.log("""Can't establish connection with %s
108 : no available interface""" % prefix, 2)
109 except Exception:
110 traceback.print_exc()