2018-09-21 22:02:07 +02:00
|
|
|
#!/usr/bin/python
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
"""!
|
|
|
|
|
____ ____ ______ __ __ __ _____
|
|
|
|
|
/ __ )/ __ \/ ___/ | / /___ _/ /______/ /_ |__ /
|
|
|
|
|
/ __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ /_ <
|
|
|
|
|
/ /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / ___/ /
|
|
|
|
|
/_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ /____/
|
|
|
|
|
German BOS Information Script
|
|
|
|
|
by Bastian Schroll
|
|
|
|
|
|
|
|
|
|
@file: broadcast.py
|
|
|
|
|
@date: 21.09.2018
|
|
|
|
|
@author: Bastian Schroll
|
|
|
|
|
@description: UDP broadcast server and client class
|
|
|
|
|
"""
|
|
|
|
|
import logging
|
|
|
|
|
import socket
|
2018-09-21 22:36:11 +02:00
|
|
|
import threading
|
2018-09-21 22:02:07 +02:00
|
|
|
|
|
|
|
|
logging.debug("- %s loaded", __name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BroadcastClient:
|
2018-09-22 22:58:19 +02:00
|
|
|
"""!BroadcastClient class"""
|
2018-09-21 22:02:07 +02:00
|
|
|
|
|
|
|
|
def __init__(self, port=5000):
|
2018-09-22 08:39:41 +02:00
|
|
|
"""!Create an BroadcastClient instance
|
|
|
|
|
|
|
|
|
|
@param port: port to send broadcast packets (5000)"""
|
2018-09-21 22:02:07 +02:00
|
|
|
self._broadcastPort = port
|
|
|
|
|
|
|
|
|
|
self._serverIP = ""
|
|
|
|
|
self._serverPort = 0
|
|
|
|
|
|
|
|
|
|
self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
|
|
|
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
|
|
|
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
2018-09-22 08:39:41 +02:00
|
|
|
self._socket.settimeout(5)
|
2018-09-21 22:02:07 +02:00
|
|
|
|
|
|
|
|
def sendBroadcast(self):
|
2018-09-22 08:39:41 +02:00
|
|
|
"""!Send broadcastpackets
|
|
|
|
|
|
|
|
|
|
This function will block until the connection Info
|
2018-09-22 22:58:19 +02:00
|
|
|
from server will be received.
|
|
|
|
|
|
|
|
|
|
- send the magic packet <BW-Request> on broadcast address.
|
|
|
|
|
- wait for a <BW-Result> magic packet.
|
|
|
|
|
- extract the connection data from the magic packet and return
|
|
|
|
|
|
|
|
|
|
@return True or False"""
|
2018-09-21 22:02:07 +02:00
|
|
|
while True:
|
|
|
|
|
try:
|
2018-09-21 22:36:11 +02:00
|
|
|
logging.debug("send magic <BW3-Request> as broadcast")
|
2018-09-21 22:02:07 +02:00
|
|
|
self._socket.sendto("<BW3-Request>".encode(), ('255.255.255.255', self._broadcastPort))
|
|
|
|
|
payload, address = self._socket.recvfrom(1024)
|
|
|
|
|
payload = str(payload, "UTF-8")
|
|
|
|
|
|
|
|
|
|
if payload.startswith("<BW3-Result>"):
|
2018-09-21 22:36:11 +02:00
|
|
|
logging.debug("received magic <BW3-Result> from: %s", address[0])
|
2018-09-21 22:02:07 +02:00
|
|
|
self._serverIP = address[0]
|
|
|
|
|
self._serverPort = int(payload.split(";")[1])
|
|
|
|
|
logging.info("got connection info: %s:%d", self._serverIP, self._serverPort)
|
|
|
|
|
return True
|
|
|
|
|
except socket.timeout:
|
2018-09-22 08:39:41 +02:00
|
|
|
logging.warning("no server found - retry sending magic")
|
2018-09-21 22:02:07 +02:00
|
|
|
continue
|
|
|
|
|
except:
|
|
|
|
|
logging.exception("error on getting connection info")
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def serverIP(self):
|
2018-09-22 08:39:41 +02:00
|
|
|
"""!Property to get the server IP after successful broadcast"""
|
2018-09-21 22:02:07 +02:00
|
|
|
return self._serverIP
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def serverPort(self):
|
2018-09-22 08:39:41 +02:00
|
|
|
"""!Property to get the server Port after successful broadcast"""
|
2018-09-21 22:02:07 +02:00
|
|
|
return self._serverPort
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BroadcastServer:
|
2018-09-22 22:58:19 +02:00
|
|
|
"""!BroadcastServer class"""
|
2018-09-21 22:02:07 +02:00
|
|
|
|
2018-09-22 08:39:41 +02:00
|
|
|
def __init__(self, servePort=8080,listenPort=5000):
|
|
|
|
|
"""!Create an BroadcastServer instance
|
|
|
|
|
|
|
|
|
|
@param listenPort: port to listen for broadcast packets (5000)"""
|
2018-09-21 22:02:07 +02:00
|
|
|
self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
2018-09-22 08:39:41 +02:00
|
|
|
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
|
|
|
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
|
|
|
|
self._socket.bind(('', listenPort))
|
2018-09-21 22:36:11 +02:00
|
|
|
self._serverThread = None
|
|
|
|
|
self._serverIsRunning = False
|
2018-09-22 08:39:41 +02:00
|
|
|
self._servePort = servePort
|
2018-09-21 22:36:11 +02:00
|
|
|
|
|
|
|
|
def start(self):
|
2018-09-22 22:58:19 +02:00
|
|
|
"""!Start the broadcast server in a new thread
|
|
|
|
|
|
|
|
|
|
@return True or False"""
|
2018-09-21 22:36:11 +02:00
|
|
|
try:
|
|
|
|
|
logging.debug("start udp broadcast server")
|
|
|
|
|
self._serverThread = threading.Thread(target=self._listen)
|
|
|
|
|
self._serverThread.name = "BroadServ"
|
|
|
|
|
self._serverThread.daemon = True
|
|
|
|
|
self._serverIsRunning = True
|
|
|
|
|
self._serverThread.start()
|
2018-09-22 22:58:19 +02:00
|
|
|
return True
|
2018-09-21 22:36:11 +02:00
|
|
|
except:
|
|
|
|
|
logging.exception("cannot start udp broadcast server thread")
|
2018-09-22 22:58:19 +02:00
|
|
|
return False
|
2018-09-21 22:36:11 +02:00
|
|
|
|
|
|
|
|
def stop(self):
|
2018-09-22 22:58:19 +02:00
|
|
|
"""!Stop the broadcast server
|
|
|
|
|
|
|
|
|
|
@return True or False"""
|
2018-09-21 22:36:11 +02:00
|
|
|
try:
|
|
|
|
|
logging.debug("stop udp broadcast server")
|
|
|
|
|
self._serverIsRunning = False
|
|
|
|
|
self._serverThread.join()
|
2018-09-22 22:58:19 +02:00
|
|
|
return True
|
2018-09-21 22:36:11 +02:00
|
|
|
except:
|
|
|
|
|
logging.exception("cannot stop udp broadcast server thread")
|
2018-09-22 22:58:19 +02:00
|
|
|
return False
|
2018-09-21 22:02:07 +02:00
|
|
|
|
2018-09-21 22:36:11 +02:00
|
|
|
def _listen(self):
|
2018-09-22 22:58:19 +02:00
|
|
|
"""!Broadcast server worker thread
|
|
|
|
|
|
|
|
|
|
This function listen for magic packets on broadcast
|
|
|
|
|
address and send the connection info to the clients.
|
|
|
|
|
|
|
|
|
|
- listen for the magic packet <BW-Request>
|
|
|
|
|
- send connection info in an <BW-Result> macig packet"""
|
2018-09-21 22:02:07 +02:00
|
|
|
try:
|
|
|
|
|
logging.debug("start listening for magic")
|
2018-09-21 22:36:11 +02:00
|
|
|
while self._serverIsRunning:
|
2018-09-22 22:58:19 +02:00
|
|
|
payload, address = self._socket.recvfrom(1024) # fixme recv is blocking, evtl we can use to wait for readable data
|
2018-09-21 22:02:07 +02:00
|
|
|
payload = str(payload, "UTF-8")
|
|
|
|
|
if payload == "<BW3-Request>":
|
|
|
|
|
logging.debug("received magic <BW3-Request> from: %s", address[0])
|
2018-09-21 22:36:11 +02:00
|
|
|
logging.info("send connection info in magic <BW3-Result> to: %s", address[0])
|
2018-09-22 08:39:41 +02:00
|
|
|
self._socket.sendto("<BW3-Result>;".encode() + str(self._servePort).encode(), address)
|
2018-09-21 22:02:07 +02:00
|
|
|
except:
|
|
|
|
|
logging.exception("error while listening for clients")
|