Commit bef61ec6 authored by Guillaume Bury's avatar Guillaume Bury

Merge branch 'master' of https://git.erp5.org/repos/vifibnet

Conflicts:
	TODO
parents 622530d9 2b839604
Bugs :
When no peer is avalaible, the setup crash without the --no-boot option
G : see below
U : this is still a bug to be solved
G : since the server is now a node it shouldn't ( the server will always
have a peer availabel which is himself )
To be done : To be done :
use the server as a bootstrap node
Use an algorithm to choose which connections to keep and/or establish Use an algorithm to choose which connections to keep and/or establish
instead of pure randomness instead of pure randomness
...@@ -19,13 +14,10 @@ To be done : ...@@ -19,13 +14,10 @@ To be done :
Use the server events ( client connection/deconnection ) to do something Use the server events ( client connection/deconnection ) to do something
useful useful
In peers DB, remove some peers when they are too many of them -> remove the In peers DB, flag the dead peers so we only choose them if necessary and we can remove them if we have enought peers
dead peers
Use a timeout for the peersDB Use a timeout for the server peersDB so we can rflag unreachable peers and
G : removing the dead peers should be enough remove the peers whose certificate is no longer valid
U : I was speaking of the server peers DB
G : the timeout is the duration of the certificate delivered ( 1y for now )
Specify a lease duration in ForwardViaUPnP Specify a lease duration in ForwardViaUPnP
...@@ -71,23 +63,3 @@ To be discussed: ...@@ -71,23 +63,3 @@ To be discussed:
enought DB to ensure we can still choose a peer as if it was choosen enought DB to ensure we can still choose a peer as if it was choosen
directly from the server. The requiered db size can be calculated from directly from the server. The requiered db size can be calculated from
the number of connections and the refresh time. the number of connections and the refresh time.
U : Remove the --no-boot option since we know when no node is avalaible
G : the no-boot option is only useful when the server knows no peer,
irl it should never happen, no-boot is a debug option
U : Ok, but the server knows when no peers is avalaible, doesn't he ?
G : Well when no peer is available the SQL request ( + next() method ) raise
a StopIteration exception
U : Well, I don't think this is a good thing. When not in debug, a node
cannot now if there is anyone else already connected
G : don't reconnect to server each time we repopulate in peers_db ?
U : From what I've read on the internet, when you create a server object,
you don't connect to the server, You only connect to the server once you
send a request for a methode and then you can automatically use the same
connection for 15sec
G : ok, it justs need testing ( for when some requests for the server will
require to be plugged in the network )
U : Use more than one boostrap node
G : we'll use the server as a bootstrap node
...@@ -17,7 +17,8 @@ def openvpn(hello_interval, *args, **kw): ...@@ -17,7 +17,8 @@ def openvpn(hello_interval, *args, **kw):
utils.log(str(args), 5) utils.log(str(args), 5)
return subprocess.Popen(args, **kw) return subprocess.Popen(args, **kw)
def server(server_ip, network, max_clients, dh_path, pipe_fd, port, proto, hello_interval, *args, **kw): def server(server_ip, network, max_clients, dh_path, pipe_fd, port, proto,
hello_interval, *args, **kw):
utils.log('Starting server', 3) utils.log('Starting server', 3)
return openvpn(hello_interval, return openvpn(hello_interval,
'--tls-server', '--tls-server',
......
...@@ -2,21 +2,63 @@ import os, random, traceback, time ...@@ -2,21 +2,63 @@ import os, random, traceback, time
import plib, utils, db import plib, utils, db
log = None log = None
smooth = 0.3
class Connection:
def __init__(self, ip, write_pipe, hello, port, proto, iface, peer_id,
ovpn_args):
self.process = plib.client(ip, write_pipe, hello,
'--dev', iface, '--proto', proto, '--rport', str(port),
*ovpn_args, stdout=os.open(os.path.join(log,
'vifibnet.client.%s.log' % (peer_id,)),
os.O_WRONLY|os.O_CREAT|os.O_TRUNC) )
self.iface = iface
self._lastTrafic = self._getTrafic()
self._bandwidth = None
# TODO : update the stats
def refresh(self):
# Check that the connection is alive
if self.process.poll() != None:
utils.log('Connection with %s has failed with return code %s'
% (id, self.process.returncode), 3)
return False
trafic = self._getTrafic()
if self._bandwidth == None:
self._bandwidth = trafic - self._lastTrafic
else:
self._bandwidth = (1-smooth)*self._bandwidth + smooth*trafic
self._lastTrafic = trafic
utils.log('New bandwidth calculated on iface %s : %sb' % self._bandwidth, 4)
return True
def _getTrafic(self):
try:
f_rx = open('/sys/class/net/%s/statistics/rx_bytes' % self.iface, 'r')
f_tx = open('/sys/class/net/%s/statistics/tx_bytes' % self.iface, 'r')
return int(f_rx.read()) + int(f_tx.read())
except Exception: # TODO : change this
return 0
class TunnelManager: class TunnelManager:
def __init__(self, write_pipe, peer_db, openvpn_args, hello_interval, refresh, connection_count, refresh_rate): def __init__(self, write_pipe, peer_db, openvpn_args, hello_interval,
refresh, connection_count, refresh_rate):
self._write_pipe = write_pipe self._write_pipe = write_pipe
self._peer_db = peer_db self._peer_db = peer_db
self._connection_dict = {} self._connection_dict = {}
self._ovpn_args = openvpn_args self._ovpn_args = openvpn_args
self._hello = hello_interval self._hello = hello_interval
self._refresh_time = refresh self._refresh_time = refresh
self.free_interface_set = set(('client1', 'client2', 'client3', 'client4', 'client5', self.free_interface_set = set(('client1', 'client2', 'client3',
'client6', 'client7', 'client8', 'client9', 'client10')) 'client4', 'client5', 'client6',
'client7', 'client8', 'client9',
'client10', 'client11', 'client12'))
self.next_refresh = time.time() self.next_refresh = time.time()
# TODO : choose this automatically
self._client_count = connection_count/2 self._client_count = connection_count/2
self._refresh_count = refresh_rate*self._client_count self._refresh_count = refresh_rate*self._client_count
...@@ -29,39 +71,41 @@ class TunnelManager: ...@@ -29,39 +71,41 @@ class TunnelManager:
def _cleanDeads(self): def _cleanDeads(self):
for id in self._connection_dict.keys(): for id in self._connection_dict.keys():
p, iface = self._connection_dict[id] if not self._connection_dict[id].refresh():
if p.poll() != None: self._kill(id)
utils.log('Connection with %s has failed with return code %s' % (id, p.returncode), 3)
self.free_interface_set.add(iface)
self._peer_db.unusePeer(id)
del self._connection_dict[id]
def _removeSomeTunnels(self): def _removeSomeTunnels(self):
for i in range(0, max(0, len(self._connection_dict) - self._client_count + self._refresh_count)): for i in range(0, max(0, len(self._connection_dict) -
self._client_count + self._refresh_count)):
peer_id = random.choice(self._connection_dict.keys()) peer_id = random.choice(self._connection_dict.keys())
self._kill(peer_id) self._kill(peer_id)
def _kill(self, peer_id): def _kill(self, peer_id):
utils.log('Killing the connection with id ' + str(peer_id), 2) utils.log('Killing the connection with id ' + str(peer_id), 2)
p, iface = self._connection_dict.pop(peer_id) connection = self._connection_dict.pop(peer_id)
p.kill() try:
self.free_interface_set.add(iface) connection.process.kill()
except OSError:
# If the process is already exited
pass
self.free_interface_set.add(connection.iface)
self._peer_db.unusePeer(peer_id) self._peer_db.unusePeer(peer_id)
def _makeNewTunnels(self): def _makeNewTunnels(self):
#utils.log('Making %i new tunnels' % (self._client_count - len(self._connection_dict)), 3) utils.log('Trying to make %i new tunnels' %
(self._client_count - len(self._connection_dict)), 3)
try: try:
for peer_id, ip, port, proto in self._peer_db.getUnusedPeers(self._client_count - len(self._connection_dict)): for peer_id, ip, port, proto in self._peer_db.getUnusedPeers(
utils.log('Establishing a connection with id %s (%s:%s)' % (peer_id, ip, port), 2) self._client_count - len(self._connection_dict)):
utils.log('Establishing a connection with id %s (%s:%s)'
% (peer_id, ip, port), 2)
iface = self.free_interface_set.pop() iface = self.free_interface_set.pop()
self._connection_dict[peer_id] = ( self._connection_dict[peer_id] = Connection(ip,
plib.client( ip, self._write_pipe, self._hello, self._write_pipe, self._hello, port, proto, iface,
'--dev', iface, '--proto', proto, '--rport', str(port), *self._ovpn_args, peer_id, 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)
self._peer_db.usePeer(peer_id) self._peer_db.usePeer(peer_id)
except KeyError: except KeyError:
utils.log("Can't establish connection with %s : no available interface" % ip, 2) utils.log("Can't establish connection with %s"
": no available interface" % ip, 2)
except Exception: except Exception:
traceback.print_exc() traceback.print_exc()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment