mirror of
https://github.com/isj4/vagus.git
synced 2025-01-22 17:48:42 -05:00
da0aa9c427
Python2 is still supported.
112 lines
3.3 KiB
Python
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")
|