tunnel.py 2.83 KB
Newer Older
Guillaume Bury's avatar
Guillaume Bury committed
1
#!/usr/bin/env python
2
import os, random, traceback, time
3
import plib, utils, db
4

Guillaume Bury's avatar
Guillaume Bury committed
5 6
log = None

Ulysse Beaugnon's avatar
Ulysse Beaugnon committed
7 8
class TunnelManager:

9
    def __init__(self, write_pipe, peer_db, openvpn_args, refresh, connection_count, refresh_rate):
10
        self._write_pipe = write_pipe
Guillaume Bury's avatar
Guillaume Bury committed
11
        self._peer_db = peer_db
12
        self._connection_dict = {}
Guillaume Bury's avatar
Guillaume Bury committed
13
        self._ovpn_args = openvpn_args
14
        self._refresh_time = refresh
Guillaume Bury's avatar
Guillaume Bury committed
15 16
        self.free_interface_set = set(('client1', 'client2', 'client3', 'client4', 'client5',
                                       'client6', 'client7', 'client8', 'client9', 'client10'))
17 18 19 20 21
        self.next_refresh = time.time()

        # TODO : choose this automatically
        self._client_count = connection_count/2
        self._refresh_count = refresh_rate*self._client_count
Ulysse Beaugnon's avatar
Ulysse Beaugnon committed
22 23

    def refresh(self):
24
        utils.log('Refreshing the tunnels', 2)
25 26 27
        self._cleanDeads()
        self._removeSomeTunnels()
        self._makeNewTunnels()
28
        self.next_refresh = time.time() + self._refresh_time
Ulysse Beaugnon's avatar
Ulysse Beaugnon committed
29

30 31 32
    def _cleanDeads(self):
        for id in self._connection_dict.keys():
            p, iface = self._connection_dict[id]
Ulysse Beaugnon's avatar
Ulysse Beaugnon committed
33 34
            if p.poll() != None:
                utils.log('Connection with %s has failed with return code %s' % (id, p.returncode), 3)
Guillaume Bury's avatar
Guillaume Bury committed
35
                self.free_interface_set.add(iface)
36 37
                self._peer_db.unusePeer(id)
                del self._connection_dict[id]
Ulysse Beaugnon's avatar
Ulysse Beaugnon committed
38

39
    def _removeSomeTunnels(self):
Guillaume Bury's avatar
Guillaume Bury committed
40
        for i in range(0, max(0, len(self._connection_dict) - self._client_count + self._refresh_count)):
41
            peer_id = random.choice(self._connection_dict.keys())
Guillaume Bury's avatar
Guillaume Bury committed
42
            self._kill(peer_id)
Ulysse Beaugnon's avatar
Ulysse Beaugnon committed
43

44
    def _kill(self, peer_id):
45
        utils.log('Killing the connection with id ' + str(peer_id), 2)
46
        p, iface = self._connection_dict.pop(peer_id)
47
        p.kill()
Guillaume Bury's avatar
Guillaume Bury committed
48
        self.free_interface_set.add(iface)
Guillaume Bury's avatar
Guillaume Bury committed
49
        self._peer_db.unusePeer(peer_id)
50

51
    def _makeNewTunnels(self):
52
        utils.log('Making %i new tunnels' % (self._client_count - len(self._connection_dict)), 3)
Ulysse Beaugnon's avatar
Ulysse Beaugnon committed
53
        try:
Guillaume Bury's avatar
Guillaume Bury committed
54
            for peer_id, ip, port, proto in self._peer_db.getUnusedPeers(self._client_count - len(self._connection_dict)):
Ulysse Beaugnon's avatar
Ulysse Beaugnon committed
55
                utils.log('Establishing a connection with id %s (%s:%s)' % (peer_id, ip, port), 2)
Guillaume Bury's avatar
Guillaume Bury committed
56
                iface = self.free_interface_set.pop()
Guillaume Bury's avatar
Guillaume Bury committed
57 58 59 60
                self._connection_dict[peer_id] = ( plib.client( ip, self._write_pipe,
                    '--dev', iface, '--proto', proto, '--rport', str(port), *self._ovpn_args,
                    stdout=os.open(os.path.join(log, 'vifibnet.client.%s.log' % (peer_id,)),
                                   os.O_WRONLY|os.O_CREAT|os.O_TRUNC) ), iface)
Guillaume Bury's avatar
Guillaume Bury committed
61
                self._peer_db.usePeer(peer_id)
Ulysse Beaugnon's avatar
Ulysse Beaugnon committed
62 63 64 65
        except KeyError:
            utils.log("Can't establish connection with %s : no available interface" % ip, 2)
        except Exception:
            traceback.print_exc()