You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
4.1 KiB
132 lines
4.1 KiB
#!/usr/bin/env python3 |
|
""" |
|
utun control socket monitor client |
|
Usage: python3 monitor.py [host] [port] |
|
Default: localhost:5555 |
|
""" |
|
import socket |
|
import struct |
|
import sys |
|
import json |
|
import time |
|
|
|
# Command types from control_socket.h |
|
CONTROL_CMD_GET_STATS = 1 |
|
CONTROL_CMD_RESET_STATS = 2 |
|
CONTROL_CMD_GET_STATUS = 3 |
|
|
|
# Response types |
|
CONTROL_RESP_STATS = 1 |
|
CONTROL_RESP_STATUS = 2 |
|
CONTROL_RESP_ERROR = 3 |
|
|
|
# Error codes |
|
CONTROL_ERR_NONE = 0 |
|
CONTROL_ERR_INVALID_CMD = 1 |
|
CONTROL_ERR_INTERNAL = 2 |
|
|
|
def send_command(host='192.168.29.117', port=5555, command=CONTROL_CMD_GET_STATS, sequence=1): |
|
"""Send a control command and receive response""" |
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
|
sock.settimeout(2.0) |
|
|
|
# Build request packet (4 bytes: command + sequence) |
|
# struct control_request_packet_t { uint16_t command; uint16_t sequence; } |
|
request = struct.pack('<HH', command, sequence) |
|
|
|
try: |
|
sock.sendto(request, (host, port)) |
|
data, addr = sock.recvfrom(4096) |
|
except socket.timeout: |
|
print("Timeout: No response from server") |
|
return None |
|
finally: |
|
sock.close() |
|
|
|
return data |
|
|
|
def parse_stats_response(data): |
|
"""Parse statistics response packet""" |
|
# Unpack header (common for all responses) |
|
# struct control_response_header { uint16_t response_type; uint16_t error_code; uint16_t sequence; } |
|
if len(data) < 6: |
|
print("Invalid response length") |
|
return None |
|
|
|
resp_type, err_code, seq = struct.unpack('<HHH', data[:6]) |
|
|
|
if err_code != CONTROL_ERR_NONE: |
|
print(f"Error response: code {err_code}") |
|
return None |
|
|
|
if resp_type == CONTROL_RESP_STATS: |
|
# Parse full stats packet (need to know exact structure) |
|
# For now, just print raw data size |
|
print(f"Received stats packet: {len(data)} bytes") |
|
# TODO: Implement full parsing based on control_socket.h structures |
|
# This requires matching the packed C structures |
|
return data |
|
elif resp_type == CONTROL_RESP_STATUS: |
|
# Parse status packet |
|
print("Status response") |
|
return data |
|
elif resp_type == CONTROL_RESP_ERROR: |
|
print("Error response") |
|
return None |
|
else: |
|
print(f"Unknown response type: {resp_type}") |
|
return None |
|
|
|
def print_hex(data): |
|
"""Print hex dump of data""" |
|
for i in range(0, len(data), 16): |
|
chunk = data[i:i+16] |
|
hex_str = ' '.join(f'{b:02x}' for b in chunk) |
|
ascii_str = ''.join(chr(b) if 32 <= b < 127 else '.' for b in chunk) |
|
print(f'{i:04x}: {hex_str:<48} {ascii_str}') |
|
|
|
def main(): |
|
host = '127.0.0.1' |
|
port = 5555 |
|
|
|
if len(sys.argv) > 1: |
|
host = sys.argv[1] |
|
if len(sys.argv) > 2: |
|
port = int(sys.argv[2]) |
|
|
|
print(f"Connecting to {host}:{port}") |
|
|
|
# Send GET_STATS command |
|
data = send_command(host, port, CONTROL_CMD_GET_STATS, 1) |
|
if data is None: |
|
return |
|
|
|
print(f"Received {len(data)} bytes") |
|
print_hex(data) |
|
|
|
# Attempt to parse basic info |
|
if len(data) >= 6: |
|
resp_type, err_code, seq = struct.unpack('<HHH', data[:6]) |
|
print(f"Response type: {resp_type}, Error: {err_code}, Sequence: {seq}") |
|
|
|
if resp_type == CONTROL_RESP_STATS: |
|
# Try to parse timestamp (uint64_t after header) |
|
if len(data) >= 14: |
|
timestamp = struct.unpack('<Q', data[6:14])[0] |
|
print(f"Timestamp: {timestamp} μs ({timestamp/1000000:.3f} s)") |
|
|
|
# Print approximate stats structure size |
|
# The full stats packet should be 1024+ bytes |
|
print(f"Expected stats size ~1024 bytes, got {len(data)}") |
|
|
|
# Send GET_STATUS command |
|
print("\n--- Requesting status ---") |
|
data = send_command(host, port, CONTROL_CMD_GET_STATUS, 2) |
|
if data: |
|
print(f"Status response {len(data)} bytes") |
|
if len(data) >= 6: |
|
resp_type, err_code, seq = struct.unpack('<HHH', data[:6]) |
|
print(f"Response type: {resp_type}, Error: {err_code}, Sequence: {seq}") |
|
|
|
if __name__ == '__main__': |
|
main() |