diff --git a/sockets/rtmp_server.py b/sockets/rtmp_server.py new file mode 100644 index 0000000..487ab2a --- /dev/null +++ b/sockets/rtmp_server.py @@ -0,0 +1,149 @@ +import socket, threading, os, time, traceback, struct + +class RTMPClientState: + """Enumeration of RTMP client states.""" + EPOCH = 0 + +class RTMPServer: + def __init__(self, host='192.168.1.15', port=1935): + self.host = host + self.port = port + self.server_socket = None + self.is_running = True + self.clients = [] + + def start(self): + """Starts a basic server to display incoming packets.""" + # Create a TCP socket + self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.server_socket.bind((self.host, self.port)) + self.server_socket.listen(1) + print(f"RTMP Server started on {self.host}:{self.port}. Waiting for connections...") + + while self.is_running: + try: + client_socket, address = self.server_socket.accept() + print(f"Connection accepted from {address}") + client_thread = threading.Thread(target=self.handle_client, args=(client_socket,)) + client_thread.daemon = True + client_thread.start() + except Exception as e: + print(f"Error accepting connection: {e}") + print(traceback.format_exc()) + break + + def handle_client(self, client_socket): + """ + Handle an incoming RTMP client connection. + + :param client_socket: The client socket object. + """ + try: + # Perform RTMP handshake + if not self._attempt_handshake(client_socket): + print("Handshake failed.") + client_socket.close() + return + + print("Handshake successful. Ready to handle RTMP stream.") + except Exception as e: + print(f"Error handling client: {e}") + print(traceback.format_exc()) + finally: + client_socket.close() + + def _attempt_handshake(self, client_socket): + """Performs the RTMP handshake with the client.""" + # Receive C0 and C1 packets and validate + c0 = int.from_bytes(client_socket.recv(1)) + if c0 != 3: + print("Invalid RTMP version.") + return False + + c1 = client_socket.recv(1536) + time_epoch = int.from_bytes(c1[:4]) + zeros = int.from_bytes(c1[4:8]) + random_bytes = c1[8:] + + if zeros != 0: + print("Invalid C1 packet.") + return False + + # Send S0 + s0 = bytes([3]) + client_socket.send(s0) + + # Send S1 + s1 = bytearray(c1) + server_random = os.urandom(1528) + current_timestamp = struct.pack(">I" ,int(time.time())) + s1[:4] = current_timestamp + s1[8:] = server_random + client_socket.send(bytes(s1)) + + # Receive C2 + c2 = client_socket.recv(1536) + if c2[8:] != server_random: + print("Invalid C2 packet.") + return False + + + + + # debug + print(f"Version: {c0}") + print(f"Epoch time: {time_epoch}") + print(f"Zeros: {zeros}") + #print(f"Random bytes: {random_bytes}") + + + def stop(self): + """ + Stop the RTMP server. + """ + self.is_running = False + if self.server_socket: + self.server_socket.close() + print("RTMP Server stopped.") + + +def start_rtmp_server(host='127.0.0.1', port=1935): + """Starts a basic RTMP server to display incoming packets.""" + try: + # Create a TCP socket + server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server_socket.bind((host, port)) + server_socket.listen(1) + print(f"RTMP server started on {host}:{port}. Waiting for connections...") + + # Accept a connection + conn, addr = server_socket.accept() + print(f"Connection established with {addr}") + + while True: + # Receive RTMP C0 and C1 packets + data = conn.recv(1) + if not data: + print("Connection closed by client.") + break + + # Display the received RTMP packets + print(f"Version: {int.from_bytes(data)}") + break + + except KeyboardInterrupt: + print("\nServer shutting down.") + except Exception as e: + print(f"Error: {e}") + finally: + server_socket.close() + print("Server socket closed.") + +if __name__ == "__main__": + c = RTMPServer() + try: + c.start() + except KeyboardInterrupt: + print("Shutting down RTMP Server...") + c.stop() + diff --git a/core/stream_generator.py b/sockets/stream_generator.py similarity index 100% rename from core/stream_generator.py rename to sockets/stream_generator.py