132 lines
4.1 KiB
Python
132 lines
4.1 KiB
Python
#!/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() |