broadcast mdns on each local interface with the matching local ip
This commit is contained in:
parent
6f5deada62
commit
ad03b7ef2e
2 changed files with 47 additions and 79 deletions
|
@ -2,10 +2,9 @@
|
|||
# vi:si:et:sw=4:sts=4:ts=4
|
||||
|
||||
import socket
|
||||
import time
|
||||
|
||||
import netifaces
|
||||
from zeroconf import (
|
||||
get_all_addresses,
|
||||
ServiceBrowser, ServiceInfo, ServiceStateChange, Zeroconf
|
||||
)
|
||||
from tornado.ioloop import PeriodicCallback
|
||||
|
@ -13,7 +12,6 @@ from tornado.ioloop import PeriodicCallback
|
|||
import settings
|
||||
import state
|
||||
from tor_request import get_opener
|
||||
from utils import get_local_ipv4
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -45,6 +43,14 @@ def can_connect(data):
|
|||
#logger.debug('failed to connect to local node %s', data, exc_info=True)
|
||||
return False
|
||||
|
||||
def get_broadcast_interfaces():
|
||||
return list(set(
|
||||
addr['addr']
|
||||
for iface in netifaces.interfaces()
|
||||
for addr in netifaces.ifaddresses(iface).get(socket.AF_INET, [])
|
||||
if addr.get('netmask') != '255.255.255.255' and addr.get('broadcast')
|
||||
))
|
||||
|
||||
class LocalNodes(dict):
|
||||
service_type = '_oml._tcp.local.'
|
||||
local_info = None
|
||||
|
@ -57,57 +63,71 @@ class LocalNodes(dict):
|
|||
self._ip_changed = PeriodicCallback(self._update_if_ip_changed, 60000)
|
||||
|
||||
def setup(self):
|
||||
self.local_ips = sorted(get_all_addresses(socket.AF_INET))
|
||||
self.zeroconf = Zeroconf()
|
||||
time.sleep(0.02)
|
||||
self.local_ips = get_broadcast_interfaces()
|
||||
self.zeroconf = {ip: Zeroconf(interfaces=[ip]) for ip in self.local_ips}
|
||||
self.register_service()
|
||||
self.browse()
|
||||
|
||||
def _update_if_ip_changed(self):
|
||||
local_ips = sorted(get_all_addresses(socket.AF_INET))
|
||||
local_ips = get_broadcast_interfaces()
|
||||
if local_ips != self.local_ips:
|
||||
self.close()
|
||||
self.setup()
|
||||
|
||||
def browse(self):
|
||||
self.browser = ServiceBrowser(self.zeroconf, self.service_type, handlers=[self.on_service_state_change])
|
||||
self.browser = {
|
||||
ip: ServiceBrowser(self.zeroconf[ip], self.service_type, handlers=[self.on_service_state_change])
|
||||
for ip in self.zeroconf
|
||||
}
|
||||
|
||||
def register_service(self):
|
||||
if self.local_info:
|
||||
self.zeroconf.unregister_service(self.local_info)
|
||||
for local_ip, local_info in self.local_info:
|
||||
self.zeroconf[local_ip].unregister_service(local_info)
|
||||
self.local_info = None
|
||||
local_ip = get_local_ipv4()
|
||||
if local_ip:
|
||||
local_name = socket.gethostname().partition('.')[0] + '.local.'
|
||||
|
||||
port = settings.server['node_port']
|
||||
desc = {
|
||||
'username': settings.preferences.get('username', 'anonymous'),
|
||||
}
|
||||
self.local_info = ServiceInfo(self.service_type,
|
||||
'%s.%s' % (settings.USER_ID, self.service_type),
|
||||
socket.inet_aton(local_ip), port, 0, 0,
|
||||
desc, local_name)
|
||||
self.zeroconf.register_service(self.local_info)
|
||||
local_name = socket.gethostname().partition('.')[0] + '.local.'
|
||||
port = settings.server['node_port']
|
||||
desc = {
|
||||
'username': settings.preferences.get('username', 'anonymous')
|
||||
}
|
||||
self.local_info = []
|
||||
for i, local_ip in enumerate(get_broadcast_interfaces()):
|
||||
if i:
|
||||
name = '%s-%s [%s].%s' % (desc['username'], i, settings.USER_ID, self.service_type)
|
||||
else:
|
||||
name = '%s [%s].%s' % (desc['username'], settings.USER_ID, self.service_type)
|
||||
local_info = ServiceInfo(self.service_type, name,
|
||||
socket.inet_aton(local_ip), port, 0, 0, desc, local_name)
|
||||
self.zeroconf[local_ip].register_service(local_info)
|
||||
self.local_info.append((local_ip, local_info))
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
def close(self):
|
||||
if self.local_info:
|
||||
self.zeroconf.unregister_service(self.local_info)
|
||||
for local_ip, local_info in self.local_info:
|
||||
try:
|
||||
self.zeroconf[local_ip].unregister_service(local_info)
|
||||
except:
|
||||
logger.debug('exception closing zeroconf', exc_info=True)
|
||||
self.local_info = None
|
||||
if self.zeroconf:
|
||||
try:
|
||||
self.zeroconf.close()
|
||||
except:
|
||||
logger.debug('exception closing zeroconf', exc_info=True)
|
||||
for local_ip in self.zeroconf:
|
||||
try:
|
||||
self.zeroconf[local_ip].close()
|
||||
except:
|
||||
logger.debug('exception closing zeroconf', exc_info=True)
|
||||
self.zeroconf = None
|
||||
for id in list(self):
|
||||
self.pop(id, None)
|
||||
|
||||
def on_service_state_change(self, zeroconf, service_type, name, state_change):
|
||||
id = name.split('.')[0]
|
||||
if not '[' in name:
|
||||
id = name.split('.')[0]
|
||||
else:
|
||||
id = name.split('[')[1].split(']')[0]
|
||||
if id == settings.USER_ID:
|
||||
return
|
||||
if state_change is ServiceStateChange.Added:
|
||||
|
|
52
oml/utils.py
52
oml/utils.py
|
@ -218,58 +218,6 @@ def get_interface():
|
|||
interface = ''
|
||||
return interface
|
||||
|
||||
def get_local_ipv4():
|
||||
ip = None
|
||||
if sys.platform == 'darwin' or sys.platform.startswith('freebsd'):
|
||||
cmd = ['/sbin/route', '-n', 'get', 'default']
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, close_fds=True)
|
||||
stdout, stderr = p.communicate()
|
||||
stdout = stdout.decode('utf-8')
|
||||
interface = [[p.strip() for p in s.split(':', 1)]
|
||||
for s in stdout.strip().split('\n') if 'interface' in s]
|
||||
if interface:
|
||||
interface = interface[0][1]
|
||||
cmd = ['ifconfig', interface]
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, close_fds=True)
|
||||
stdout, stderr = p.communicate()
|
||||
stdout = stdout.decode('utf-8')
|
||||
ips = [l for l in stdout.split('\n') if 'inet ' in l]
|
||||
if ips:
|
||||
ip = ips[0].strip().split(' ')[1]
|
||||
elif sys.platform.startswith('linux'):
|
||||
cmd = ['ip', 'route', 'show']
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, close_fds=True)
|
||||
stdout, stderr = p.communicate()
|
||||
stdout = stdout.decode('utf-8')
|
||||
local = [l for l in stdout.split('\n') if 'default' in l]
|
||||
if local:
|
||||
dev = local[0].split(' ')[4]
|
||||
local_ip = [l for l in stdout.split('\n')
|
||||
if dev in l and not 'default' in l and 'src' in l]
|
||||
if local_ip:
|
||||
local_ip = [p for p in local_ip[0].split(' ')[1:] if '.' in p]
|
||||
if local_ip:
|
||||
ip = local_ip[0]
|
||||
if not ip:
|
||||
cmd = ['ip', 'addr', 'show']
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, close_fds=True)
|
||||
stdout, stderr = p.communicate()
|
||||
stdout = stdout.decode('utf-8')
|
||||
parts = stdout.split(' ')
|
||||
local_ip = [p for p in parts if dev in p]
|
||||
if local_ip:
|
||||
local_ip = re.compile('inet (\d+\.\d+\.\d+.\d+)').findall(local_ip[0])
|
||||
if local_ip:
|
||||
ip = local_ip[0]
|
||||
if not ip:
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.connect(("8.8.8.8", 53))
|
||||
return s.getsockname()[0]
|
||||
except:
|
||||
pass
|
||||
return ip
|
||||
|
||||
def update_dict(root, data):
|
||||
for key in data:
|
||||
keys = [part.replace('\0', '.') for part in key.replace('\\.', '\0').split('.')]
|
||||
|
|
Loading…
Reference in a new issue