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