vagus/UDPHandler.py
Ivan Skytte Jørgensen da0aa9c427 Python3 support
Python2 is still supported.
2022-03-13 01:04:20 +01:00

112 lines
3.3 KiB
Python

from __future__ import print_function
import Config
import getifaddrs
import AnnouncementHandler
import socket
import logging
import string
import threading
#broadcast configuration cases:
# 1: broadcast: *
# 2: broadcast: eth0
# 3: broadcast: 10.0.0.255
# 4: broadcast: enp5s0:10.0.1.255
#which results in these actions
# 1: single unbound socket, send to 255.255.255.255
# 2: one of more sockets bound to nets on that interface, sending to whatever broadcast address is appropriate
# 3: single unbound socket, send to 10.0.0.255
# 4: one of more sockets bound to nets on that interface, sending to that broadcast address
broadcast_socket = None
broadcast_addresses = []
unicast_socket = None
handler_thread = None
logger = None
def initialize():
global logger
logger = logging.getLogger(__name__)
if len(Config.udp.peer)==0 and len(Config.udp.broadcast)==0:
logger.info("Broadcasts not configured")
return True
if Config.udp.port==0:
logger.info("Broadcasts disabled with port=0")
return True
#Go through the broadcast specifications
ifaddrs = getifaddrs.get_network_interfaces()
global broadcast_addresses
broadcast_addresses = []
for b in Config.udp.broadcast:
if b=="*":
#global broadcast
broadcast_addresses.append("255.255.255.255")
elif b[0] in string.ascii_letters:
#ifname
if_name = b
for ifa in ifaddrs:
if ifa.name==if_name and ifa.flags&getifaddrs.IFF_BROADCAST and ifa.broadcast_addr:
broadcast_addresses.append(ifa.broadcast_addr)
else:
#addr
broadcast_addresses.append(b)
logger.debug("Broadcast addresses: %s",broadcast_addresses)
if len(Config.udp.broadcast)!=0 and len(broadcast_addresses)==0:
logger.info("No broadcast addresses (did you reference a non-existing interface?)")
return True
#first create a wildcard socket, bound only to the port.
global broadcast_socket
broadcast_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
broadcast_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
broadcast_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
broadcast_socket.bind(("", Config.udp.port))
#then create an unbound IPv6 socket for unicasts
global unicast_socket
unicast_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
global handler_thread
handler_thread = UDPHandlerThread()
handler_thread.start()
return True
class UDPHandlerThread(threading.Thread):
def run(self):
while True:
(datagram,address) = broadcast_socket.recvfrom(65535)
logger.debug("Got datagram from %s",address)
AnnouncementHandler.process_message(datagram,address)
def send_announce(datagram):
if len(datagram)>65507:
logger.debug("Datagram too large")
return
if broadcast_socket:
for addr in broadcast_addresses:
broadcast_socket.sendto(datagram,(addr,Config.udp.port))
if unicast_socket:
for addr in Config.udp.peer:
logger.debug("Sending unicast to %s",addr)
#grumble, apparently pythons sendto() doesn't handle ipv6-mapped-ipv4 directly
if ":" in addr:
unicast_socket.sendto(datagram,(addr,Config.udp.port))
else:
unicast_socket.sendto(datagram,("::ffff:"+addr,Config.udp.port))
if __name__ == "__main__":
logging.basicConfig(format='%(asctime)s %(process)d %(levelname)s %(module)s:%(message)s',level=logging.DEBUG)
Config.initialize("vagus.ini")
initialize()
send_announce("foo")
print("done")