diff options
Diffstat (limited to 'host/crap.py')
-rw-r--r-- | host/crap.py | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/host/crap.py b/host/crap.py new file mode 100644 index 0000000..db9f7ee --- /dev/null +++ b/host/crap.py @@ -0,0 +1,68 @@ + +import socket +import struct +import zlib +import io +from time import time + +import config + +class CRAPClient: + def __init__(self, ip='127.0.0.1', port=1337): + self.ip, self.port = ip, port + self.sock = socket.Socket(socket.AF_INET, socket.SOCK_DGRAM) + self.close = self.sock.close + + def sendframe(self, frame): + self.sock.sendto(frame, (self.ip, self.port)) + + +def _timestamped_recv(sock): + while True: + try: + data, addr = sock.recvfrom(config.frame_size*3+4) + except io.BlockingIOError as e: + raise StopIteration() + else: + yield time(), data, addr + + +class CRAPServer: + def __init__(self, ip='', port=1337, blocking=False, log=print): + self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.sock.setblocking(blocking) + self.sock.bind((ip, port)) + + self.current_client = None + self.last_timestamp = 0 + self.begin_timestamp = 0 + self.log = log + + def close(self): + self.sock.close() + + def __iter__(self): + for timestamp, data, (addr, sport) in _timestamped_recv(self.sock): + if data is None: + yield None + + if timestamp - self.last_timestamp > config.udp_timeout\ + or timestamp - self.begin_timestamp > config.udp_switch_interval: + self.current_client = addr + self.begin_timestamp = timestamp + self.log('\x1B[91mAccepting UDP data from\x1B[0m', addr) + + if addr == self.current_client: + if len(data) == config.frame_size*3+4: + (crc1,), crc2 = struct.unpack('!I', data[-4:]), zlib.crc32(data, 0), + data = data[:-4] # crop CRC + if crc1 and crc1 != crc2: # crc1 zero-check for backward-compatibility + self.log('Error receiving UDP frame: Invalid frame CRC checksum: Expected {}, got {}'.format(crc2, crc1)) + continue + elif len(data) != config.frame_size*3: + self.log('Error receiving UDP frame: Invalid frame size: {}'.format(len(data))) + self.last_timestamp = timestamp + yield data + + |