frappy-cli: connect to servers on localhost by default
--scan option: specify where to scan if not on localhost Change-Id: I51a694eb3cb045e7d18c19a332db8e6ba063009b
This commit is contained in:
@@ -23,6 +23,9 @@
|
||||
import os
|
||||
import json
|
||||
import socket
|
||||
import select
|
||||
from time import monotonic
|
||||
from collections import namedtuple
|
||||
|
||||
from frappy.lib import closeSocket
|
||||
from frappy.protocol.interface.tcp import format_address
|
||||
@@ -32,6 +35,79 @@ UDP_PORT = 10767
|
||||
MAX_MESSAGE_LEN = 508
|
||||
|
||||
|
||||
Answer = namedtuple('Answer',
|
||||
'address, hostname, port, equipment_id, firmware, description')
|
||||
|
||||
|
||||
def decode(msg, addr):
|
||||
msg = msg.decode('utf-8')
|
||||
try:
|
||||
data = json.loads(msg)
|
||||
except Exception:
|
||||
return None
|
||||
if not isinstance(data, dict):
|
||||
return None
|
||||
if data.get('SECoP') != 'node':
|
||||
return None
|
||||
try:
|
||||
eq_id = data['equipment_id']
|
||||
fw = data['firmware']
|
||||
desc = data['description']
|
||||
port = data['port']
|
||||
except KeyError:
|
||||
return None
|
||||
try:
|
||||
hostname = socket.gethostbyaddr(addr[0])[0]
|
||||
except Exception:
|
||||
hostname = addr[0]
|
||||
return Answer(addr[0], hostname, port, eq_id, fw, desc)
|
||||
|
||||
|
||||
def scan(max_wait=1.0):
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||
# send a general broadcast
|
||||
try:
|
||||
s.sendto(json.dumps(dict(SECoP='discover')).encode('utf-8'),
|
||||
('255.255.255.255', UDP_PORT))
|
||||
except OSError as e:
|
||||
print('could not send the broadcast:', e)
|
||||
# we still keep listening for self-announcements
|
||||
seen = set()
|
||||
start = monotonic()
|
||||
while monotonic() < start + max_wait:
|
||||
res = select.select([s], [], [], 0.1)
|
||||
if res[0]:
|
||||
try:
|
||||
msg, addr = s.recvfrom(1024)
|
||||
except socket.error: # pragma: no cover
|
||||
continue
|
||||
answer = decode(msg, addr)
|
||||
if answer is None:
|
||||
continue
|
||||
if (answer.address, answer.equipment_id, answer.port) in seen:
|
||||
continue
|
||||
seen.add((answer.address, answer.equipment_id, answer.port))
|
||||
yield answer
|
||||
|
||||
|
||||
def listen():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
if os.name == 'nt':
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
else:
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
|
||||
s.bind(('0.0.0.0', UDP_PORT))
|
||||
while True:
|
||||
try:
|
||||
msg, addr = s.recvfrom(1024)
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
answer = decode(msg, addr)
|
||||
if answer:
|
||||
yield answer
|
||||
|
||||
|
||||
class UDPListener:
|
||||
def __init__(self, equipment_id, description, ifaces, logger, *,
|
||||
startup_broadcast=True):
|
||||
|
||||
Reference in New Issue
Block a user