Thursday 18 March 2021

Recieve foreign UDP Broadcast with Python

I have a device in the Network at 192.168.123.204 which broadcast the UPD Packages (Artnet) as 2.168.123.204 to 2.255.255.255:6454. (The network address is 192.168.123.204 but the upd is send as 2.168.123.204) The address 2.255.255.255 can't be changed (no setting for that). My python script runs on the device 192.168.123.148. I can recieve the Packets there with wireshark. But a python socket bound to 0.0.0.0:6454 cant receive them. Binding it to 2.168.123.204 or 2.255.255.255 does not work. The script is working, since I can receive Packets from 127.0.0.1.

If it can't be solved with python can I redirect the udp broadcast with iptables (linux)?

basic script:

import socket
import asyncio


HOST, PORT = 'localhost', 6454


class SyslogProtocol(asyncio.DatagramProtocol):
    def __init__(self):
        super().__init__()

    def connection_made(self, transport) -> "Used by asyncio":
        self.transport = transport

    def datagram_received(self, data, addr) -> "Main entrypoint for processing message":
        # Here is where you would push message to whatever methods/classes you want.
      
        print(data)


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    t = loop.create_datagram_endpoint(SyslogProtocol, local_addr=('0.0.0.0', PORT))
    loop.run_until_complete(t) # Server starts listening
    loop.run_forever()

full script:

#import pygame
from ctypes import *
import socket
import asyncio
import os, random

class ArtNetPackage(LittleEndianStructure):
    PORT = 0x1936
    _fields_ = [("id", c_char * 8),
                ("opcode", c_ushort),
                ("protverh", c_ubyte),
                ("protver", c_ubyte),
                ("sequence", c_ubyte),
                ("physical", c_ubyte),         
                ("universe", c_ushort),
                ("lengthhi", c_ubyte),
                ("length", c_ubyte),
                ("payload", c_ubyte * 512)]
    
    def get_length(self):
        return self.lengthhi*256+self.length
        
    def __init__(self,data=b''):
        if len(data) == 0:
            self.id = b"Art-Net"
            self.opcode = 0x5000
            self.protver = 14
            self.universe = 0
            self.lengthhi = 2
        else:
            self.id = data[:8]
            self.opcode = data[8]+data[9]*256
            if self.opcode == 0x5000:
                self.protverh = data[10]
                self.protver = data[11]
                self.sequence = data[12]
                self.physical = data[13]
                self.universe = data[14]+data[15]*256
                self.lengthhi = data[16]
                self.length = data[17]
                self.payload = (c_ubyte * 512).from_buffer_copy(
                        data[18:530])#.ljust(512,b'\x00'))

#pygame.init()

HOST, PORT = 'localhost', 6454


class SyslogProtocol(asyncio.DatagramProtocol):
    def __init__(self):
        super().__init__()
        
    def connection_made(self, transport) -> "Used by asyncio":
        self.transport = transport

    def datagram_received(self, data, addr) -> "Main entrypoint for processing message":
        # Here is where you would push message to whatever methods/classes you want.
        try:
            dmx = ArtNetPackage(data)
            if not dmx.opcode == 0x5000:
                return
            print(dmx.payload[0])
        except:
            print("error")


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    t = loop.create_datagram_endpoint(SyslogProtocol, local_addr=('0.0.0.0', PORT))
    loop.run_until_complete(t) # Server starts listening
    loop.run_forever()


from Recieve foreign UDP Broadcast with Python

No comments:

Post a Comment