Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 25 additions & 23 deletions PyStageLinQ/PyStageLinQ.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ def __init__(self, ip=None, discovery_port=51337):
self.target_interfaces = []
self.discovery_port = discovery_port
self.get_interface_from_ip(ip)
logger.info(f"Found {len(self.target_interfaces)} network interfaces:")
for iface in self.target_interfaces:
logger.info(f" - {iface.name}: {iface.addr_str}")

def get_interface_from_ip(self, ip):
if ip is None:
Expand Down Expand Up @@ -72,21 +75,19 @@ def get_interface_from_ip(self, ip):

def send_discovery_frame(self, discovery_frame):
for interface in self.target_interfaces:
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as discovery_socket:
discovery_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
discovery_socket.bind((interface.addr_str, 0))
try:
try:
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as discovery_socket:
discovery_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
discovery_socket.bind((interface.addr_str, 0))
discovery_socket.sendto(
discovery_frame,
("255.255.255.255", self.discovery_port),
)
self.target_interfaces[interface.id].n_disc_msg_send += 1
except PermissionError:
logger.warning(
f"Cannot send message on interface {interface.name}, "
f"this error could be due to that there is no network interface set up with this IP range"
)
raise PermissionError
except Exception as e:
logger.debug(
f"Cannot send discovery on interface {interface.name} ({interface.addr_str}): {e}"
)

def determine_interface_of_remote_ip(self, ip):
for interface in self.target_interfaces:
Expand All @@ -98,13 +99,13 @@ def determine_interface_of_remote_ip(self, ip):
return None

def send_desc_on_all_if(self):
# Check if at least one working interface has sent 3+ discovery messages
any_working = False
for interface in self.target_interfaces:
# Wait until a few discovery frames have been sent to make sure the other devices have seen us. If they have
# not and we are asking for services it will be denied.
if interface.n_disc_msg_send < 3:
return False

return True
# Skip interfaces that have failed (never sent any messages after multiple attempts)
if interface.n_disc_msg_send >= 3:
any_working = True
return any_working


class PyStageLinQ:
Expand Down Expand Up @@ -190,7 +191,6 @@ def _stop(self):
logger.info(f"Gracefully shutdown complete")
except Exception as e:
logger.debug('Could not send "EXIT" discovery frame during shutdown')
raise e

def _announce_self(self):
discovery = StageLinQDiscovery()
Expand Down Expand Up @@ -219,10 +219,10 @@ async def _discover_stagelinq_device(self, host_ip, timeout=10):
) # bind socket to broadcast
except Exception as e:
# Cannot bind to socket, check if IP is correct and link is up
logger.warning(
logger.debug(
f"Cannot bind to IP socket: {host_ip} on port {self.StageLinQ_discovery_port}"
)
raise e
return PyStageLinQError.CANNOTBINDSOCKET
discover_socket.setblocking(False)

loop_timeout = time.time() + timeout
Expand Down Expand Up @@ -390,11 +390,13 @@ async def _periodic_announcement(self):

async def _py_stagelinq_strapper(self):
strapper_tasks = set()
logger.info(f"Starting to look for StageLinQ discovery frames:")
logger.info(f"Looking for discovery frames on {len(self.network_interface.target_interfaces)} IP addresses:")

strapper_tasks.add(
asyncio.create_task(self._discover_stagelinq_device("", timeout=2))
)
for interface in self.network_interface.target_interfaces:
logger.info(f"{interface.addr_str}")
strapper_tasks.add(
asyncio.create_task(self._discover_stagelinq_device(interface.addr_str, timeout=2))
)

while self.get_loop_condition():
all_tasks_done = True
Expand Down