import socket
import random
import string
import threading
import time
import signal
import xml.etree.ElementTree as ET

CONFIG_FILE = "E:\Dropbox\PythonDev\stress_balanceador\config.xml"
stop_event = threading.Event()

def leer_configuracion():
    tree = ET.parse(CONFIG_FILE)
    root = tree.getroot()
    dns = root.find('dns').text
    threads_per_port = int(root.find('threads_per_port').text)
    start_port = int(root.find('start_port').text)
    end_port = int(root.find('end_port').text)
    return dns, threads_per_port, start_port, end_port

def generar_numero_aleatorio(longitud):
    return ''.join(random.choices(string.digits, k=longitud))

def generar_fecha_hora():
    now = time.strftime("%Y%m%d%H%M%S")
    return now

def generar_numero_hexadecimal():
    return ''.join(random.choices(string.hexdigits.lower(), k=4))

def generar_latitud_longitud():
    latitud = round(random.uniform(-90, 90), 6)
    longitud = round(random.uniform(-180, 180), 6)
    return latitud, longitud

def generar_ultimos_digitos():
    return ''.join(random.choices(string.hexdigits.lower(), k=4))

def generar_mensaje():
    equipo = generar_numero_aleatorio(15)
    latitud, longitud = generar_latitud_longitud()
    fecha_hora = generar_fecha_hora()
    numero_mensaje = generar_numero_hexadecimal()
    ultimos_digitos = generar_ultimos_digitos()
    mensaje = f"+RESP:GTFRI,500101,{equipo},GV55W,12703,10,1,1,0.0,229,36.3,{longitud},{latitud},{fecha_hora},{numero_mensaje},0007,1168,16C073,00,0.0,,,,96,110000,,,,{fecha_hora},{ultimos_digitos}$"
    return mensaje

def enviar_paquetes(domain, puerto, contador, lock):
    while not stop_event.is_set():
        sock = None
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(1)
            sock.connect((domain, puerto))
            mensaje = generar_mensaje()
            sock.sendall(mensaje.encode())
            with lock:
                contador[0] += 1
        except Exception:
            pass
        finally:
            if sock is not None:
                sock.close()

def estresar_puerto(domain, puerto, contador, threads_per_port):
    threads = []
    lock = threading.Lock()
    for _ in range(threads_per_port):
        t = threading.Thread(target=enviar_paquetes, args=(domain, puerto, contador, lock))
        t.daemon = True
        threads.append(t)
        t.start()
    return threads

def signal_handler(sig, frame):
    print('\nDeteniendo el test...')
    stop_event.set()

def main():
    dns, threads_per_port, start_port, end_port = leer_configuracion()
    print(f"Comenzando stress test a {dns} puertos {start_port}-{end_port} con {threads_per_port} threads/puerto... (Ctrl+C para detener)\n")
    signal.signal(signal.SIGINT, signal_handler)
    start_time = time.time()

    puertos = range(start_port, end_port + 1)
    contadores = {p: [0] for p in puertos}
    todos_threads = []
    for puerto in puertos:
        threads = estresar_puerto(dns, puerto, contadores[puerto], threads_per_port)
        todos_threads.extend(threads)

    try:
        while not stop_event.is_set():
            time.sleep(5)
            total = sum(contadores[p][0] for p in puertos)
            print(f"Total paquetes enviados hasta ahora: {total}")
    except KeyboardInterrupt:
        pass

    stop_event.set()
    end_time = time.time()
    tiempo_total = end_time - start_time
    total_paquetes = sum(contadores[p][0] for p in puertos)
    print("\nResumen de la prueba:")
    print(f"Total de paquetes enviados: {total_paquetes}")
    print(f"Tiempo total de prueba: {int(tiempo_total // 60)} min {int(tiempo_total % 60)} seg")
    print(f"Promedio por segundo: {total_paquetes / tiempo_total:.2f}")

if __name__ == "__main__":
    main()
