
/*
 * WSSSH Tunnel (wsssht) - Mode Functions Implementation
 * Mode-specific functions for wsssht
 *
 * Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <getopt.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/select.h>
#include <time.h>
#include <errno.h>

#include "wssshlib.h"
#include "websocket.h"
#include "wssh_ssl.h"
#include "tunnel.h"
#include "modes.h"
#include "control_messages.h"
#include "data_messages.h"

// External signal handling variables from wsssht.c
extern volatile sig_atomic_t graceful_shutdown;

int run_bridge_mode(wsssh_config_t *config, const char *client_id, const char *wssshd_host, int wssshd_port) {
    // Bridge mode: Pure transport layer - no tunnel setup, just WebSocket transport
    if (config->debug) {
        printf("[DEBUG] Starting bridge mode (pure transport) with client_id=%s, host=%s, port=%d\n",
                client_id, wssshd_host, wssshd_port);
        fflush(stdout);
    }

    // Send initial status
    fprintf(stderr, "{\"type\":\"bridge_started\",\"client_id\":\"%s\",\"host\":\"%s\",\"port\":%d,\"timestamp\":%ld}\n",
            client_id, wssshd_host, wssshd_port, time(NULL));

    // Establish WebSocket connection (no tunnel setup)
    SSL_CTX *ws_ctx = NULL;
    int ws_sock = setup_websocket_connection(wssshd_host, wssshd_port, client_id, config->debug, &ws_ctx);
    if (ws_sock < 0) {
        fprintf(stderr, "{\"type\":\"error\",\"message\":\"Failed to establish WebSocket connection\",\"timestamp\":%ld}\n", time(NULL));
        if (ws_ctx) SSL_CTX_free(ws_ctx);
        return 1;
    }

    // Get the SSL connection for sending messages
    SSL *ws_ssl = active_tunnel ? active_tunnel->ssl : NULL;
    if (!ws_ssl) {
        fprintf(stderr, "{\"type\":\"error\",\"message\":\"Failed to get SSL connection\",\"timestamp\":%ld}\n", time(NULL));
        close(ws_sock);
        if (ws_ctx) SSL_CTX_free(ws_ctx);
        return 1;
    }

    // Send connection established message
    fprintf(stderr, "{\"type\":\"websocket_connected\",\"socket\":%d,\"timestamp\":%ld}\n", ws_sock, time(NULL));

    // Main bridge loop - pure transport layer
    char buffer[BUFFER_SIZE];
    fd_set readfds;
    struct timeval tv;

    // Frame accumulation buffer for handling partial WebSocket frames
    static char frame_buffer[BUFFER_SIZE * 4];
    static int frame_buffer_used = 0;

    fprintf(stderr, "{\"type\":\"bridge_ready\",\"message\":\"Pure transport layer active\",\"timestamp\":%ld}\n", time(NULL));

    while (1) {
        // Check for stdin input (messages to send to server)
        FD_ZERO(&readfds);
        FD_SET(STDIN_FILENO, &readfds);
        FD_SET(ws_sock, &readfds);

        tv.tv_sec = 0;
        tv.tv_usec = 50000; // 50ms timeout

        int max_fd = (ws_sock > STDIN_FILENO) ? ws_sock : STDIN_FILENO;
        int retval = select(max_fd + 1, &readfds, NULL, NULL, &tv);

        if (retval > 0) {
            // Handle stdin input (messages to send to server)
            if (FD_ISSET(STDIN_FILENO, &readfds)) {
                if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
                    // EOF or error on stdin
                    fprintf(stderr, "{\"type\":\"stdin_closed\",\"timestamp\":%ld}\n", time(NULL));
                    break;
                }

                // Remove trailing newline
                size_t len = strlen(buffer);
                if (len > 0 && buffer[len-1] == '\n') {
                    buffer[len-1] = '\0';
                    len--;
                }

                if (len > 0) {
                    // Determine channel based on message content
                    const char *channel = "control";
                    if (strstr(buffer, "\"type\":\"tunnel_data\"") || strstr(buffer, "tunnel_data")) {
                        channel = "data";
                    }

                    // Send message to appropriate WebSocket channel using SSL
                    if (send_websocket_frame(ws_ssl, buffer)) {
                        fprintf(stderr, "{\"type\":\"message_sent\",\"channel\":\"%s\",\"message\":\"%s\",\"timestamp\":%ld}\n",
                                channel, buffer, time(NULL));
                    } else {
                        fprintf(stderr, "{\"type\":\"send_error\",\"channel\":\"%s\",\"timestamp\":%ld}\n", channel, time(NULL));
                    }
                }
            }

            // Handle WebSocket data (messages from server)
            if (FD_ISSET(ws_sock, &readfds)) {
                if ((size_t)frame_buffer_used < sizeof(frame_buffer)) {
                    // Use SSL to read WebSocket data
                    int bytes_read = SSL_read(ws_ssl, frame_buffer + frame_buffer_used,
                                              sizeof(frame_buffer) - frame_buffer_used);

                    if (bytes_read > 0) {
                        frame_buffer_used += bytes_read;

                        if (config->debug) {
                            printf("[DEBUG - Bridge] Accumulated %d bytes from WebSocket\n", frame_buffer_used);
                            fflush(stdout);
                        }

                        // Try to parse WebSocket frame
                        char *payload;
                        int payload_len;
                        if (parse_websocket_frame(frame_buffer, frame_buffer_used, &payload, &payload_len)) {
                            // Frame is complete, determine frame type
                            unsigned char frame_type = frame_buffer[0] & 0x8F;

                            if (frame_type == 0x81 || frame_type == 0x82) { // Text or binary frame
                                // Copy payload to buffer for processing
                                if ((size_t)payload_len < sizeof(buffer)) {
                                    memcpy(buffer, payload, payload_len);
                                    buffer[payload_len] = '\0';

                                    // Determine channel and forward message
                                    const char *channel = "control";
                                    if (strstr(buffer, "\"type\":\"tunnel_data\"") || strstr(buffer, "tunnel_data")) {
                                        channel = "data";
                                    }

                                    fprintf(stderr, "{\"type\":\"message_received\",\"channel\":\"%s\",\"message\":\"%s\",\"timestamp\":%ld}\n",
                                            channel, buffer, time(NULL));
                                }
                            } else if (frame_type == 0x88) { // Close frame
                                fprintf(stderr, "{\"type\":\"websocket_close\",\"timestamp\":%ld}\n", time(NULL));
                                break;
                            } else if (frame_type == 0x89) { // Ping frame
                                fprintf(stderr, "{\"type\":\"ping_received\",\"timestamp\":%ld}\n", time(NULL));
                                // Send pong
                                if (!send_pong_frame(ws_ssl, payload, payload_len)) {
                                    fprintf(stderr, "{\"type\":\"pong_send_error\",\"timestamp\":%ld}\n", time(NULL));
                                }
                            } else if (frame_type == 0x8A) { // Pong frame
                                fprintf(stderr, "{\"type\":\"pong_received\",\"timestamp\":%ld}\n", time(NULL));
                            }

                            // Remove processed frame from buffer
                            int frame_size = (payload - frame_buffer) + payload_len;
                            if (frame_size < frame_buffer_used) {
                                memmove(frame_buffer, frame_buffer + frame_size, frame_buffer_used - frame_size);
                                frame_buffer_used -= frame_size;
                            } else {
                                frame_buffer_used = 0;
                            }
                        }
                    } else if (bytes_read == 0) {
                        // Connection closed
                        fprintf(stderr, "{\"type\":\"websocket_connection_closed\",\"timestamp\":%ld}\n", time(NULL));
                        break;
                    } else {
                        // Error
                        fprintf(stderr, "{\"type\":\"websocket_error\",\"timestamp\":%ld}\n", time(NULL));
                        break;
                    }
                }
            }
        }

        // Small delay to prevent busy looping
        usleep(25000); // 25ms
    }

    // Cleanup
    close(ws_sock);

    // Clean up SSL resources for bridge mode
    if (active_tunnel && active_tunnel->ssl) {
        SSL_free(active_tunnel->ssl);
        active_tunnel->ssl = NULL;
    }
    if (ws_ctx) {
        SSL_CTX_free(ws_ctx);
        ws_ctx = NULL;
    }

    fprintf(stderr, "{\"type\":\"bridge_ended\",\"timestamp\":%ld}\n", time(NULL));

    return 0;
}

int run_script_mode(wsssh_config_t *config, const char *client_id, const char *wssshd_host, int wssshd_port) {
    // Script mode: JSON protocol for scripting
    if (config->debug) {
        printf("[DEBUG] Starting script mode with client_id=%s, host=%s, port=%d\n",
               client_id, wssshd_host, wssshd_port);
        fflush(stdout);
    }

    // Send initial status for scripting
    fprintf(stderr, "{\"type\":\"script_started\",\"client_id\":\"%s\",\"host\":\"%s\",\"port\":%d,\"tunnel_host\":\"%s\",\"tunnel_port\":\"%s\",\"service\":\"%s\",\"timestamp\":%ld}\n",
            client_id, wssshd_host, wssshd_port,
            config->tunnel_host ? config->tunnel_host : "127.0.0.1",
            config->local_port ? config->local_port : "auto",
            config->service ? config->service : "ssh",
            time(NULL));

    // Establish tunnel
    tunnel_setup_result_t setup_result = setup_tunnel(wssshd_host, wssshd_port, client_id, config->local_port ? atoi(config->local_port) : find_available_port(),
                                                       config->debug, 0, config->tunnel_host, config->encoding, 1);
    int listen_sock = setup_result.listen_sock;

    if (listen_sock < 0) {
        fprintf(stderr, "{\"type\":\"script_error\",\"message\":\"Failed to establish tunnel\",\"timestamp\":%ld}\n", time(NULL));
        return 1;
    }

    // Send tunnel established message
    fprintf(stderr, "{\"type\":\"tunnel_ready\",\"listen_sock\":%d,\"timestamp\":%ld}\n", listen_sock, time(NULL));

    // Wait for connection
    struct sockaddr_in client_addr;
    socklen_t client_len = sizeof(client_addr);
    int accepted_sock = accept(listen_sock, (struct sockaddr *)&client_addr, &client_len);

    if (accepted_sock < 0) {
        fprintf(stderr, "{\"type\":\"script_error\",\"message\":\"Failed to accept connection\",\"timestamp\":%ld}\n", time(NULL));
        close(listen_sock);
        return 1;
    }

    close(listen_sock);

    // Send connection accepted message
    fprintf(stderr, "{\"type\":\"connection_established\",\"socket\":%d,\"timestamp\":%ld}\n", accepted_sock, time(NULL));

    // Send tunnel status information
    fprintf(stderr, "{\"type\":\"tunnel_status\",\"status\":\"active\",\"local_socket\":%d,\"request_id\":\"%s\",\"timestamp\":%ld}\n",
           accepted_sock, active_tunnel->request_id, time(NULL));

    // Send transport information if available
    if (active_tunnel) {
        fprintf(stderr, "{\"type\":\"transport_info\",\"data_channel\":\"%s\",\"control_channel\":\"%s\",\"timestamp\":%ld}\n",
               config->tunnel ? config->tunnel : "any",
               config->tunnel_control ? config->tunnel_control : "any",
               time(NULL));
    }

    // Set up tunnel for accepted connection
    pthread_mutex_lock(&tunnel_mutex);
    active_tunnel->local_sock = accepted_sock;

    // Send any buffered data info
    if (active_tunnel->incoming_buffer && active_tunnel->incoming_buffer->used > 0) {
        fprintf(stderr, "{\"type\":\"buffer_available\",\"bytes\":%zu,\"timestamp\":%ld}\n", active_tunnel->incoming_buffer->used, time(NULL));
    }

    pthread_mutex_unlock(&tunnel_mutex);

    // Start forwarding thread
    thread_args_t *thread_args = malloc(sizeof(thread_args_t));
    if (thread_args) {
        thread_args->ssl = active_tunnel->ssl;
        thread_args->tunnel = active_tunnel;
        thread_args->debug = config->debug;

        pthread_t thread;
        pthread_create(&thread, NULL, forward_tcp_to_ws, thread_args);
        pthread_detach(thread);
    }

    // Script mode main loop - handle WebSocket messages and script commands
    fprintf(stderr, "{\"type\":\"script_ready\",\"message\":\"Script mode active\",\"timestamp\":%ld}\n", time(NULL));

    // Frame accumulation buffer for handling partial WebSocket frames
    static char frame_buffer[BUFFER_SIZE * 4];
    static int frame_buffer_used = 0;

    // Buffer for processing messages
    char buffer[BUFFER_SIZE];

    int last_status_time = time(NULL);

    while (1) {
        // Check tunnel status
        pthread_mutex_lock(&tunnel_mutex);
        int tunnel_active = active_tunnel && active_tunnel->active;
        int tunnel_broken = active_tunnel && active_tunnel->broken;
        SSL *current_ssl = active_tunnel ? active_tunnel->ssl : NULL;
        int ssl_fd = current_ssl ? SSL_get_fd(current_ssl) : -1;
        pthread_mutex_unlock(&tunnel_mutex);

        if (!tunnel_active) {
            if (tunnel_broken) {
                fprintf(stderr, "{\"type\":\"tunnel_broken\",\"timestamp\":%ld}\n", time(NULL));
            } else {
                fprintf(stderr, "{\"type\":\"tunnel_closed\",\"timestamp\":%ld}\n", time(NULL));
            }
            break;
        }

        // Send periodic status updates every 30 seconds
        int current_time = time(NULL);
        if (current_time - last_status_time >= 30) {
            fprintf(stderr, "{\"type\":\"status\",\"message\":\"Tunnel active\",\"uptime\":%d,\"timestamp\":%d}\n", current_time - last_status_time, current_time);
            fflush(stdout);
            last_status_time = current_time;
        }

        // Check for stdin input and WebSocket data
        fd_set readfds;
        struct timeval tv;
        FD_ZERO(&readfds);
        FD_SET(STDIN_FILENO, &readfds);
        if (ssl_fd >= 0) {
            FD_SET(ssl_fd, &readfds);
        }
        tv.tv_sec = 0;
        tv.tv_usec = 100000; // 100ms timeout

        int max_fd = (ssl_fd > STDIN_FILENO) ? ssl_fd : STDIN_FILENO;
        int retval = select(max_fd + 1, &readfds, NULL, NULL, &tv);
        if (retval > 0) {
            // Handle stdin input (script commands)
            if (FD_ISSET(STDIN_FILENO, &readfds)) {
                if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
                    // EOF or error on stdin
                    fprintf(stderr, "{\"type\":\"script_input_closed\",\"timestamp\":%ld}\n", time(NULL));
                    break;
                }

                // Remove trailing newline
                size_t len = strlen(buffer);
                if (len > 0 && buffer[len-1] == '\n') {
                    buffer[len-1] = '\0';
                }

                // Process script command
                fprintf(stderr, "{\"type\":\"script_command\",\"command\":\"%s\",\"timestamp\":%ld}\n", buffer, time(NULL));

                // Handle basic script commands
                if (strcmp(buffer, "status") == 0) {
                    fprintf(stderr, "{\"type\":\"tunnel_status\",\"active\":%d,\"timestamp\":%ld}\n", tunnel_active, time(NULL));
                    fflush(stdout);
                } else if (strcmp(buffer, "close") == 0 || strcmp(buffer, "quit") == 0 || strcmp(buffer, "exit") == 0) {
                    // Send tunnel_close message before exiting
                    if (current_ssl && active_tunnel) {
                        fprintf(stderr, "{\"type\":\"sending_tunnel_close\",\"timestamp\":%ld}\n", time(NULL));
                        send_tunnel_close(current_ssl, active_tunnel->request_id, config->debug);
                    }
                    fprintf(stderr, "{\"type\":\"script_ending\",\"reason\":\"user_request\",\"timestamp\":%ld}\n", time(NULL));
                    break;
                }
            }

            // Handle WebSocket data (messages from server)
            if (ssl_fd >= 0 && FD_ISSET(ssl_fd, &readfds)) {
                if ((size_t)frame_buffer_used < sizeof(frame_buffer)) {
                    // Use SSL to read WebSocket data
                    int bytes_read = SSL_read(current_ssl, frame_buffer + frame_buffer_used,
                                              sizeof(frame_buffer) - frame_buffer_used);

                    if (bytes_read > 0) {
                        frame_buffer_used += bytes_read;

                        if (config->debug) {
                            printf("[DEBUG - Script] Accumulated %d bytes from WebSocket\n", frame_buffer_used);
                            fflush(stdout);
                        }

                        // Try to parse WebSocket frame
                        char *payload;
                        int payload_len;
                        if (parse_websocket_frame(frame_buffer, frame_buffer_used, &payload, &payload_len)) {
                            // Frame is complete, determine frame type
                            unsigned char frame_type = frame_buffer[0] & 0x8F;

                            if (frame_type == 0x81 || frame_type == 0x82) { // Text or binary frame
                                // Copy payload to buffer for processing
                                if ((size_t)payload_len < sizeof(buffer)) {
                                    memcpy(buffer, payload, payload_len);
                                    buffer[payload_len] = '\0';

                                    // Determine channel and forward message
                                    const char *channel = "control";
                                    if (strstr(buffer, "\"type\":\"tunnel_data\"") || strstr(buffer, "tunnel_data") ||
                                        strstr(buffer, "\"type\":\"tunnel_response\"") || strstr(buffer, "tunnel_response")) {
                                        channel = "data";
                                    }

                                    // In script mode, only print control channel messages (not data channel)
                                    if (strcmp(channel, "control") == 0) {
                                        fprintf(stderr, "{\"type\":\"message_received\",\"channel\":\"%s\",\"message\":\"%s\",\"timestamp\":%ld}\n",
                                               channel, buffer, time(NULL));
                                        fflush(stdout);
                                    }

                                    // Handle all message types
                                    if (strstr(buffer, "tunnel_request")) {
                                        fprintf(stderr, "{\"type\":\"tunnel_request_received\",\"message\":\"Server requested tunnel\",\"timestamp\":%ld}\n", time(NULL));
                                    } else if (strstr(buffer, "tunnel_ack")) {
                                        fprintf(stderr, "{\"type\":\"tunnel_ack_received\",\"message\":\"Tunnel acknowledged by server\",\"timestamp\":%ld}\n", time(NULL));
                                    } else if (strstr(buffer, "tunnel_data")) {
                                        // In script mode, suppress data channel message notifications
                                        // Extract request_id and data for processing (but don't print)
                                        char *id_start = strstr(buffer, "\"request_id\"");
                                        char *data_start = strstr(buffer, "\"data\"");
                                        if (id_start && data_start) {
                                            char *colon = strchr(id_start, ':');
                                            if (colon) {
                                                char *open_quote = strchr(colon, '"');
                                                if (open_quote) {
                                                    id_start = open_quote + 1;
                                                    char *close_quote = strchr(id_start, '"');
                                                    if (close_quote) {
                                                        // Make a copy of the request_id to avoid corrupting the buffer
                                                        size_t id_len = close_quote - id_start;
                                                        char *request_id_copy = malloc(id_len + 1);
                                                        if (request_id_copy) {
                                                            memcpy(request_id_copy, id_start, id_len);
                                                            request_id_copy[id_len] = '\0';

                                                            char *data_colon = strchr(data_start, ':');
                                                            if (data_colon) {
                                                                char *data_quote = strchr(data_colon, '"');
                                                                if (data_quote) {
                                                                    data_start = data_quote + 1;
                                                                    char *data_end = strchr(data_start, '"');
                                                                    if (data_end) {
                                                                        // Make a copy of the hex data to avoid corrupting the buffer
                                                                        size_t hex_len = data_end - data_start;
                                                                        char *hex_data_copy = malloc(hex_len + 1);
                                                                        if (hex_data_copy) {
                                                                            memcpy(hex_data_copy, data_start, hex_len);
                                                                            hex_data_copy[hex_len] = '\0';
                                                                            handle_tunnel_data(current_ssl, request_id_copy, hex_data_copy, config->debug);
                                                                            free(hex_data_copy);
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                            free(request_id_copy);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    } else if (strstr(buffer, "tunnel_response")) {
                                        // In script mode, suppress data channel message notifications
                                        // Extract request_id and data for processing (but don't print)
                                        char *id_start = strstr(buffer, "\"request_id\"");
                                        char *data_start = strstr(buffer, "\"data\"");
                                        if (id_start && data_start) {
                                            char *colon = strchr(id_start, ':');
                                            if (colon) {
                                                char *open_quote = strchr(colon, '"');
                                                if (open_quote) {
                                                    id_start = open_quote + 1;
                                                    char *close_quote = strchr(id_start, '"');
                                                    if (close_quote) {
                                                        // Make a copy of the request_id to avoid corrupting the buffer
                                                        size_t id_len = close_quote - id_start;
                                                        char *request_id_copy = malloc(id_len + 1);
                                                        if (request_id_copy) {
                                                            memcpy(request_id_copy, id_start, id_len);
                                                            request_id_copy[id_len] = '\0';

                                                            char *data_colon = strchr(data_start, ':');
                                                            if (data_colon) {
                                                                char *data_quote = strchr(data_colon, '"');
                                                                if (data_quote) {
                                                                    data_start = data_quote + 1;
                                                                    char *data_end = strchr(data_start, '"');
                                                                    if (data_end) {
                                                                        // Make a copy of the hex data to avoid corrupting the buffer
                                                                        size_t hex_len = data_end - data_start;
                                                                        char *hex_data_copy = malloc(hex_len + 1);
                                                                        if (hex_data_copy) {
                                                                            memcpy(hex_data_copy, data_start, hex_len);
                                                                            hex_data_copy[hex_len] = '\0';
                                                                            handle_tunnel_data(current_ssl, request_id_copy, hex_data_copy, config->debug);
                                                                            free(hex_data_copy);
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                            free(request_id_copy);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    } else if (strstr(buffer, "tunnel_close")) {
                                        fprintf(stderr, "{\"type\":\"tunnel_close_received\",\"message\":\"Server closed tunnel\",\"timestamp\":%ld}\n", time(NULL));
                                        // Extract request_id and handle tunnel close
                                        char *id_start = strstr(buffer, "\"request_id\"");
                                        if (id_start) {
                                            char *colon = strchr(id_start, ':');
                                            if (colon) {
                                                char *open_quote = strchr(colon, '"');
                                                if (open_quote) {
                                                    id_start = open_quote + 1;
                                                    char *close_quote = strchr(id_start, '"');
                                                    if (close_quote) {
                                                        *close_quote = '\0';
                                                        handle_tunnel_close(current_ssl, id_start, config->debug);
                                                    }
                                                }
                                            }
                                        }
                                    } else if (strstr(buffer, "tunnel_error")) {
                                        fprintf(stderr, "{\"type\":\"tunnel_error_received\",\"message\":\"Tunnel error from server\",\"timestamp\":%ld}\n", time(NULL));
                                    } else {
                                        fprintf(stderr, "{\"type\":\"unknown_message_received\",\"message\":\"%s\",\"timestamp\":%ld}\n", buffer, time(NULL));
                                    }
                                }
                            } else if (frame_type == 0x88) { // Close frame
                                fprintf(stderr, "{\"type\":\"websocket_close\",\"timestamp\":%ld}\n", time(NULL));
                                break;
                            } else if (frame_type == 0x89) { // Ping frame
                                fprintf(stderr, "{\"type\":\"ping_received\",\"timestamp\":%ld}\n", time(NULL));
                                // Send pong
                                if (!send_pong_frame(current_ssl, payload, payload_len)) {
                                    fprintf(stderr, "{\"type\":\"pong_send_error\",\"timestamp\":%ld}\n", time(NULL));
                                }
                            } else if (frame_type == 0x8A) { // Pong frame
                                fprintf(stderr, "{\"type\":\"pong_received\",\"timestamp\":%ld}\n", time(NULL));
                            }

                            // Remove processed frame from buffer
                            int frame_size = (payload - frame_buffer) + payload_len;
                            if (frame_size < frame_buffer_used) {
                                memmove(frame_buffer, frame_buffer + frame_size, frame_buffer_used - frame_size);
                                frame_buffer_used -= frame_size;
                            } else {
                                frame_buffer_used = 0;
                            }
                        }
                    } else if (bytes_read == 0) {
                        // Connection closed
                        fprintf(stderr, "{\"type\":\"websocket_connection_closed\",\"timestamp\":%ld}\n", time(NULL));
                        break;
                    } else {
                        // Error
                        fprintf(stderr, "{\"type\":\"websocket_error\",\"timestamp\":%ld}\n", time(NULL));
                        break;
                    }
                }
            }
        }

        // Small delay to prevent busy looping
        usleep(25000); // 25ms
    }

    // Cleanup
    fprintf(stderr, "{\"type\":\"script_ended\",\"timestamp\":%ld}\n", time(NULL));

    return 0;
}

int run_pipe_mode(wsssh_config_t *config, const char *client_id, const char *wssshd_host, int wssshd_port) {
    // Pipe mode: Negotiate tunnel and redirect raw tunnelled data to stdin/stdout
    // Similar to other modes but doesn't bind to a port - handles data directly
    if (config->debug) {
        fprintf(stderr, "[DEBUG] Starting pipe mode (tunnel negotiation + stdin/stdout proxy) with client_id=%s, host=%s, port=%d\n",
                client_id, wssshd_host, wssshd_port);
    }

    // Establish WebSocket connection and negotiate tunnel (similar to setup_tunnel but without port binding)
    struct sockaddr_in server_addr;
    struct hostent *he;
    int ws_sock;
    SSL_CTX *ssl_ctx;
    SSL *ws_ssl;
    char buffer[BUFFER_SIZE];
    int bytes_read;

    // Generate request ID
    char request_id[37];
    generate_request_id(request_id, sizeof(request_id));

    // Resolve hostname
    if ((he = gethostbyname(wssshd_host)) == NULL) {
        herror("gethostbyname");
        return 1;
    }

    // Create socket
    if ((ws_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("WebSocket socket creation failed");
        return 1;
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(wssshd_port);
    server_addr.sin_addr = *((struct in_addr *)he->h_addr);

    // Connect to server
    if (connect(ws_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("WebSocket connection failed");
        close(ws_sock);
        return 1;
    }

    // Create SSL context and connection
    ssl_ctx = create_ssl_context();
    if (!ssl_ctx) {
        close(ws_sock);
        return 1;
    }

    ws_ssl = create_ssl_connection(ssl_ctx, ws_sock, config->debug);
    if (!ws_ssl) {
        SSL_CTX_free(ssl_ctx);
        close(ws_sock);
        return 1;
    }

    // Perform WebSocket handshake
    if (!websocket_handshake(ws_ssl, wssshd_host, wssshd_port, "/", config->debug)) {
        fprintf(stderr, "WebSocket handshake failed\n");
        SSL_free(ws_ssl);
        SSL_CTX_free(ssl_ctx);
        close(ws_sock);
        return 1;
    }

    if (config->debug) {
        fprintf(stderr, "[DEBUG] WebSocket handshake successful\n");
    }

    // Send tunnel request (same as setup_tunnel)
    char tunnel_request_msg[1024];
    char *expanded_tunnel = expand_transport_list("any", 0); // Data channel transports
    char *expanded_tunnel_control = expand_transport_list("any", 1); // Control channel transports

    // Select best transport based on weight (lowest weight = highest priority)
    char *best_tunnel = select_best_transport(expanded_tunnel);
    char *best_tunnel_control = select_best_transport(expanded_tunnel_control);

    snprintf(tunnel_request_msg, sizeof(tunnel_request_msg),
             "{\"type\":\"tunnel_request\",\"client_id\":\"%s\",\"request_id\":\"%s\",\"tunnel\":\"%s\",\"tunnel_control\":\"%s\",\"service\":\"%s\",\"version\":\"%s\"}",
             client_id, request_id, best_tunnel ? best_tunnel : expanded_tunnel, best_tunnel_control ? best_tunnel_control : expanded_tunnel_control, config->service ? config->service : "ssh", WSSSH_VERSION);

    if (!send_websocket_frame(ws_ssl, tunnel_request_msg)) {
        free(expanded_tunnel);
        free(expanded_tunnel_control);
        if (best_tunnel) free(best_tunnel);
        if (best_tunnel_control) free(best_tunnel_control);
        SSL_free(ws_ssl);
        SSL_CTX_free(ssl_ctx);
        close(ws_sock);
        return 1;
    }

    free(expanded_tunnel);
    free(expanded_tunnel_control);
    if (best_tunnel) free(best_tunnel);
    if (best_tunnel_control) free(best_tunnel_control);

    if (config->debug) {
        fprintf(stderr, "[DEBUG] Tunnel request sent for client: %s, request_id: %s\n", client_id, request_id);
    }

    // Read acknowledgment (same as setup_tunnel)
    bytes_read = SSL_read(ws_ssl, buffer, sizeof(buffer));
    if (bytes_read <= 0) {
        if (config->debug) {
            printf("[DEBUG] No acknowledgment received\n");
        }
        SSL_free(ws_ssl);
        SSL_CTX_free(ssl_ctx);
        close(ws_sock);
        return 1;
    }

    // Check if it's a close frame
    if (bytes_read >= 2 && (buffer[0] & 0x8F) == 0x88) {
        if (config->debug) {
            printf("[DEBUG] Server sent close frame\n");
        }
        SSL_free(ws_ssl);
        SSL_CTX_free(ssl_ctx);
        close(ws_sock);
        return 1;
    }

    // Parse WebSocket frame
    char *payload;
    int payload_len;
    if (!parse_websocket_frame(buffer, bytes_read, &payload, &payload_len)) {
        fprintf(stderr, "Failed to parse WebSocket frame\n");
        SSL_free(ws_ssl);
        SSL_CTX_free(ssl_ctx);
        close(ws_sock);
        return 1;
    }

    // Null terminate payload
    payload[payload_len] = '\0';

    // Check for tunnel acknowledgment
    if (strstr(payload, "tunnel_ack") == NULL) {
        fprintf(stderr, "Tunnel request denied: %s\n", payload);
        SSL_free(ws_ssl);
        SSL_CTX_free(ssl_ctx);
        close(ws_sock);
        return 1;
    }

    if (config->debug) {
        fprintf(stderr, "[DEBUG] Tunnel negotiated successfully, request_id: %s\n", request_id);
    }

    // Create tunnel structure (but don't bind to port)
    tunnel_t *pipe_tunnel = malloc(sizeof(tunnel_t));
    if (!pipe_tunnel) {
        perror("Memory allocation failed");
        SSL_free(ws_ssl);
        SSL_CTX_free(ssl_ctx);
        close(ws_sock);
        return 1;
    }

    // Initialize tunnel structure for pipe mode
    strcpy(pipe_tunnel->request_id, request_id);
    pipe_tunnel->sock = -1;  // No remote server connection
    pipe_tunnel->local_sock = -1;  // No local socket binding
    pipe_tunnel->active = 1;
    pipe_tunnel->broken = 0;
    pipe_tunnel->ssl = ws_ssl;
    pipe_tunnel->outgoing_buffer = NULL;  // No buffering needed
    pipe_tunnel->incoming_buffer = NULL;  // No buffering needed
    pipe_tunnel->server_version_sent = 0;

    // Add tunnel to global array
    pthread_mutex_lock(&tunnel_mutex);
    if (!add_tunnel(pipe_tunnel)) {
        free(pipe_tunnel);
        pthread_mutex_unlock(&tunnel_mutex);
        SSL_free(ws_ssl);
        SSL_CTX_free(ssl_ctx);
        close(ws_sock);
        return 1;
    }
    pthread_mutex_unlock(&tunnel_mutex);

    // Clean up SSL context (no longer needed)
    SSL_CTX_free(ssl_ctx);

    if (config->debug) {
        fprintf(stderr, "[DEBUG] Pipe tunnel established, starting stdin/stdout data forwarding\n");
    }

    // Main pipe loop - handle stdin/stdout and WebSocket tunnel data
    fd_set readfds;
    struct timeval tv;

    // Frame accumulation buffer for handling partial WebSocket frames
    static char frame_buffer[BUFFER_SIZE * 4];
    static int frame_buffer_used = 0;

    while (1) {
        // Check for graceful shutdown signal
        if (graceful_shutdown) {
            fprintf(stderr, "Sending tunnel_close on graceful shutdown...\n");
            if (config->debug) {
                fprintf(stderr, "[DEBUG] Graceful shutdown requested, sending tunnel_close\n");
            }
            // Send tunnel_close before exiting
            send_tunnel_close(ws_ssl, request_id, config->debug);
            fprintf(stderr, "Tunnel close message sent\n");

            // Small delay to allow parent process (scp) to finish cleanly
            // This prevents "Broken pipe" errors from scp trying to write after we exit
            usleep(200000); // 200ms delay

            break;
        }

        // Check tunnel status
        pthread_mutex_lock(&tunnel_mutex);
        int tunnel_active = pipe_tunnel && pipe_tunnel->active;
        pthread_mutex_unlock(&tunnel_mutex);

        if (!tunnel_active) {
            if (config->debug) {
                fprintf(stderr, "[DEBUG] Tunnel is no longer active, exiting pipe mode\n");
            }
            break;
        }

        // Check for stdin input and WebSocket data
        FD_ZERO(&readfds);
        FD_SET(STDIN_FILENO, &readfds);
        FD_SET(ws_sock, &readfds);

        tv.tv_sec = 0;
        tv.tv_usec = 50000; // 50ms timeout

        int max_fd = (ws_sock > STDIN_FILENO) ? ws_sock : STDIN_FILENO;
        int retval = select(max_fd + 1, &readfds, NULL, NULL, &tv);

        if (retval > 0) {
            // Handle stdin input (data to send to tunnel)
            if (FD_ISSET(STDIN_FILENO, &readfds)) {
                ssize_t bytes_read = read(STDIN_FILENO, buffer, sizeof(buffer));
                if (bytes_read <= 0) {
                    // EOF or error on stdin
                    fprintf(stderr, "EOF detected on stdin, sending tunnel_close...\n");
                    if (config->debug) {
                        fprintf(stderr, "[DEBUG] EOF on stdin, sending tunnel_close\n");
                    }
                    // Send tunnel_close before exiting
                    send_tunnel_close(ws_ssl, request_id, config->debug);
                    fprintf(stderr, "Tunnel close message sent\n");

                    // Small delay to allow parent process (scp) to finish cleanly
                    usleep(500000); // 500ms delay

                    break;
                }

                // Convert raw data to hex for WebSocket tunnel_data message
                size_t hex_size = (size_t)bytes_read * 2 + 1;
                char *hex_data = malloc(hex_size);
                if (!hex_data) {
                    if (config->debug) {
                        fprintf(stderr, "[DEBUG] Failed to allocate memory for hex data\n");
                    }
                    continue;
                }

                // Convert binary data to hex string with validation
                char *hex_ptr = hex_data;
                for (ssize_t i = 0; i < bytes_read; i++) {
                    sprintf(hex_ptr, "%02x", (unsigned char)buffer[i]);
                    hex_ptr += 2;
                }
                *hex_ptr = '\0';

                if (config->debug) {
                    fprintf(stderr, "[DEBUG] Encoded %zd bytes to hex: %.50s...\n", bytes_read, hex_data);
                }

                // Create tunnel_data message with size information
                size_t hex_len = strlen(hex_data);
                size_t binary_size = hex_len / 2; // Size of actual binary data
                size_t msg_size = strlen("{\"type\":\"tunnel_data\",\"request_id\":\"\",\"size\":,\"data\":\"\"}") +
                                  strlen(request_id) + 20 + hex_len + 1;
                char *message = malloc(msg_size);
                if (!message) {
                    if (config->debug) {
                        fprintf(stderr, "[DEBUG] Failed to allocate memory for message\n");
                    }
                    free(hex_data);
                    continue;
                }

                snprintf(message, msg_size, "{\"type\":\"tunnel_data\",\"request_id\":\"%s\",\"size\":%zu,\"data\":\"%s\"}",
                        request_id, binary_size, hex_data);

                // Send message via WebSocket
                if (send_websocket_frame(ws_ssl, message)) {
                    if (config->debug) {
                        fprintf(stderr, "[DEBUG] Sent %zd bytes from stdin to tunnel\n", bytes_read);
                    }
                } else {
                    if (config->debug) {
                        fprintf(stderr, "[DEBUG] Failed to send WebSocket frame\n");
                    }
                }

                free(hex_data);
                free(message);
            }

            // Handle WebSocket data (tunnel data from server)
            if (FD_ISSET(ws_sock, &readfds)) {
                if ((size_t)frame_buffer_used < sizeof(frame_buffer)) {
                    // Read WebSocket data
                    int ws_bytes_read = SSL_read(ws_ssl, frame_buffer + frame_buffer_used,
                                               sizeof(frame_buffer) - frame_buffer_used);

                    if (ws_bytes_read > 0) {
                        frame_buffer_used += ws_bytes_read;

                        if (config->debug) {
                            fprintf(stderr, "[DEBUG] Accumulated %d bytes from WebSocket\n", frame_buffer_used);
                        }

                        // Try to parse WebSocket frame
                        char *payload;
                        int payload_len;
                        if (parse_websocket_frame(frame_buffer, frame_buffer_used, &payload, &payload_len)) {
                            // Frame is complete, determine frame type
                            unsigned char frame_type = frame_buffer[0] & 0x8F;

                            if (frame_type == 0x81 || frame_type == 0x82) { // Text or binary frame
                                // Copy payload to buffer for processing
                                if ((size_t)payload_len < sizeof(buffer)) {
                                    memcpy(buffer, payload, payload_len);
                                    buffer[payload_len] = '\0';

                                    // Handle tunnel messages
                                    if (strstr(buffer, "tunnel_data") || strstr(buffer, "tunnel_response")) {
                                        // Extract data from tunnel message and write to stdout
                                        char *data_start = strstr(buffer, "\"data\"");
                                        if (data_start) {
                                            char *colon = strchr(data_start, ':');
                                            if (colon) {
                                                char *open_quote = strchr(colon, '"');
                                                if (open_quote) {
                                                    data_start = open_quote + 1;
                                                    char *data_end = strchr(data_start, '"');
                                                    if (data_end) {
                                                        // Make a copy of the hex data to avoid corrupting the buffer
                                                        size_t hex_len = data_end - data_start;
                                                        char *hex_data = malloc(hex_len + 1);
                                                        if (hex_data) {
                                                            memcpy(hex_data, data_start, hex_len);
                                                            hex_data[hex_len] = '\0';

                                                            if (config->debug) {
                                                                fprintf(stderr, "[DEBUG] Received hex data (len=%zu): %.50s...\n", hex_len, hex_data);
                                                            }

                                                            // Convert hex data back to binary
                                                            if (hex_len % 2 == 0) {
                                                                size_t binary_len = hex_len / 2;
                                                                char *binary_data = malloc(binary_len);
                                                                if (binary_data) {
                                                                    // Convert hex to binary with better error handling
                                                                    int conversion_success = 1;
                                                                    for (size_t i = 0; i < binary_len; i++) {
                                                                        char hex_pair[3] = {hex_data[i * 2], hex_data[i * 2 + 1], '\0'};
                                                                        char *endptr;
                                                                        unsigned long byte_val = strtoul(hex_pair, &endptr, 16);
                                                                        if (endptr == hex_pair + 2) {
                                                                            binary_data[i] = (char)byte_val;
                                                                        } else {
                                                                            binary_data[i] = 0;
                                                                            conversion_success = 0;
                                                                        }
                                                                    }

                                                                    if (conversion_success) {
                                                                        // Write binary data to stdout
                                                                        ssize_t written = write(STDOUT_FILENO, binary_data, binary_len);
                                                                        if (written > 0 && config->debug) {
                                                                            fprintf(stderr, "[DEBUG] Wrote %zd bytes to stdout\n", written);
                                                                        }
                                                                    } else if (config->debug) {
                                                                        fprintf(stderr, "[DEBUG] Hex conversion failed, skipping write\n");
                                                                    }

                                                                    free(binary_data);
                                                                }
                                                            } else if (config->debug) {
                                                                fprintf(stderr, "[DEBUG] Hex data length %zu is not even, skipping conversion\n", hex_len);
                                                            }
                                                            free(hex_data);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    } else if (strstr(buffer, "tunnel_close")) {
                                        // Server closed tunnel
                                        if (config->debug) {
                                            fprintf(stderr, "[DEBUG] Server closed tunnel\n");
                                        }
                                        break;
                                    }
                                    // Ignore other message types in pipe mode (silent operation)
                                }
                            } else if (frame_type == 0x88) { // Close frame
                                if (config->debug) {
                                    fprintf(stderr, "[DEBUG] WebSocket close frame received\n");
                                }
                                break;
                            } else if (frame_type == 0x89) { // Ping frame
                                // Send pong
                                if (!send_pong_frame(ws_ssl, payload, payload_len)) {
                                    if (config->debug) {
                                        fprintf(stderr, "[DEBUG] Failed to send pong frame\n");
                                    }
                                }
                            }
                            // Ignore pong frames

                            // Remove processed frame from buffer
                            int frame_size = (payload - frame_buffer) + payload_len;
                            if (frame_size < frame_buffer_used) {
                                memmove(frame_buffer, frame_buffer + frame_size, frame_buffer_used - frame_size);
                                frame_buffer_used -= frame_size;
                            } else {
                                frame_buffer_used = 0;
                            }
                        }
                    } else if (ws_bytes_read == 0) {
                        // Connection closed
                        if (config->debug) {
                            fprintf(stderr, "[DEBUG] WebSocket connection closed by server\n");
                        }
                        break;
                    } else {
                        // Error
                        if (config->debug) {
                            fprintf(stderr, "[DEBUG] WebSocket read error\n");
                        }
                        break;
                    }
                }
            }
        }

        // Small delay to prevent busy looping
        usleep(25000); // 25ms
    }

    // Cleanup
    close(ws_sock);

    // Remove tunnel from global array
    pthread_mutex_lock(&tunnel_mutex);
    remove_tunnel(request_id);
    pthread_mutex_unlock(&tunnel_mutex);

    if (config->debug) {
        fprintf(stderr, "[DEBUG] Pipe mode ended\n");
    }

    return 0;
}

typedef struct {
    wsssh_config_t *config;
    const char *client_id;
    const char *wssshd_host;
    int wssshd_port;
    int accepted_sock;
    int local_port;
} connection_handler_args_t;

// Connection handler function for each accepted connection
void *handle_connection(void *arg) {
    connection_handler_args_t *args = (connection_handler_args_t *)arg;
    wsssh_config_t *config = args->config;
    const char *client_id = args->client_id;
    const char *wssshd_host = args->wssshd_host;
    int wssshd_port = args->wssshd_port;
    int accepted_sock = args->accepted_sock;
    int local_port = args->local_port;

    // Free the args structure
    free(args);

    if (config->debug) {
        printf("[DEBUG] [Thread %ld] Handling connection on port %d\n", pthread_self(), local_port);
        fflush(stdout);
    }

    // Create a new tunnel instance for this connection
    tunnel_t *new_tunnel = malloc(sizeof(tunnel_t));
    if (!new_tunnel) {
        perror("Memory allocation failed for tunnel");
        close(accepted_sock);
        return NULL;
    }
    memset(new_tunnel, 0, sizeof(tunnel_t));

    // Initialize tunnel structure
    generate_request_id(new_tunnel->request_id, sizeof(new_tunnel->request_id));
    new_tunnel->sock = -1;  // wsssh doesn't connect to remote server
    new_tunnel->local_sock = accepted_sock;
    new_tunnel->active = 1;
    new_tunnel->broken = 0;
    new_tunnel->ssl = NULL;
    new_tunnel->outgoing_buffer = NULL;
    new_tunnel->incoming_buffer = frame_buffer_init();
    new_tunnel->server_version_sent = 0;
    new_tunnel->forward_thread = 0;

    if (!new_tunnel->incoming_buffer) {
        perror("Failed to initialize incoming buffer");
        free(new_tunnel);
        close(accepted_sock);
        return NULL;
    }

    // Establish WebSocket connection for this tunnel
    struct sockaddr_in server_addr;
    struct hostent *he;
    int ws_sock;
    SSL_CTX *ssl_ctx;
    SSL *ws_ssl;

    // Resolve hostname
    if ((he = gethostbyname(wssshd_host)) == NULL) {
        herror("gethostbyname");
        frame_buffer_free(new_tunnel->incoming_buffer);
        free(new_tunnel);
        close(accepted_sock);
        return NULL;
    }

    // Create socket
    if ((ws_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("WebSocket socket creation failed");
        frame_buffer_free(new_tunnel->incoming_buffer);
        free(new_tunnel);
        close(accepted_sock);
        return NULL;
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(wssshd_port);
    server_addr.sin_addr = *((struct in_addr *)he->h_addr);

    // Connect to server
    if (connect(ws_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("WebSocket connection failed");
        frame_buffer_free(new_tunnel->incoming_buffer);
        free(new_tunnel);
        close(accepted_sock);
        close(ws_sock);
        return NULL;
    }

    // Create SSL context and connection
    ssl_ctx = create_ssl_context();
    if (!ssl_ctx) {
        frame_buffer_free(new_tunnel->incoming_buffer);
        free(new_tunnel);
        close(accepted_sock);
        close(ws_sock);
        return NULL;
    }

    ws_ssl = create_ssl_connection(ssl_ctx, ws_sock, config->debug);
    if (!ws_ssl) {
        SSL_CTX_free(ssl_ctx);
        frame_buffer_free(new_tunnel->incoming_buffer);
        free(new_tunnel);
        close(accepted_sock);
        close(ws_sock);
        return NULL;
    }

    // Perform WebSocket handshake
    if (!websocket_handshake(ws_ssl, wssshd_host, wssshd_port, "/", config->debug)) {
        fprintf(stderr, "WebSocket handshake failed\n");
        SSL_free(ws_ssl);
        SSL_CTX_free(ssl_ctx);
        frame_buffer_free(new_tunnel->incoming_buffer);
        free(new_tunnel);
        close(accepted_sock);
        close(ws_sock);
        return NULL;
    }

    // Send tunnel request
    char tunnel_request_msg[1024];
    char *expanded_tunnel = expand_transport_list("any", 0);
    char *expanded_tunnel_control = expand_transport_list("any", 1);
    char *best_tunnel = select_best_transport(expanded_tunnel);
    char *best_tunnel_control = select_best_transport(expanded_tunnel_control);

    snprintf(tunnel_request_msg, sizeof(tunnel_request_msg),
             "{\"type\":\"tunnel_request\",\"client_id\":\"%s\",\"request_id\":\"%s\",\"tunnel\":\"%s\",\"tunnel_control\":\"%s\",\"service\":\"%s\",\"version\":\"%s\"}",
             client_id, new_tunnel->request_id,
             best_tunnel ? best_tunnel : expanded_tunnel,
             best_tunnel_control ? best_tunnel_control : expanded_tunnel_control, config->service ? config->service : "ssh", WSSSH_VERSION);

    if (!send_websocket_frame(ws_ssl, tunnel_request_msg)) {
        free(expanded_tunnel);
        free(expanded_tunnel_control);
        if (best_tunnel) free(best_tunnel);
        if (best_tunnel_control) free(best_tunnel_control);
        SSL_free(ws_ssl);
        SSL_CTX_free(ssl_ctx);
        frame_buffer_free(new_tunnel->incoming_buffer);
        free(new_tunnel);
        close(accepted_sock);
        close(ws_sock);
        return NULL;
    }

    free(expanded_tunnel);
    free(expanded_tunnel_control);
    if (best_tunnel) free(best_tunnel);
    if (best_tunnel_control) free(best_tunnel_control);

    // Read acknowledgment
    char ack_buffer[BUFFER_SIZE];
    int ack_bytes_read = SSL_read(ws_ssl, ack_buffer, sizeof(ack_buffer));
    if (ack_bytes_read <= 0) {
        SSL_free(ws_ssl);
        SSL_CTX_free(ssl_ctx);
        frame_buffer_free(new_tunnel->incoming_buffer);
        free(new_tunnel);
        close(accepted_sock);
        close(ws_sock);
        return NULL;
    }

    // Parse WebSocket frame
    char *payload;
    int payload_len;
    if (!parse_websocket_frame(ack_buffer, ack_bytes_read, &payload, &payload_len)) {
        SSL_free(ws_ssl);
        SSL_CTX_free(ssl_ctx);
        frame_buffer_free(new_tunnel->incoming_buffer);
        free(new_tunnel);
        close(accepted_sock);
        close(ws_sock);
        return NULL;
    }

    // Check for tunnel acknowledgment
    payload[payload_len] = '\0';
    if (strstr(payload, "tunnel_ack") == NULL) {
        fprintf(stderr, "Tunnel request denied: %s\n", payload);
        SSL_free(ws_ssl);
        SSL_CTX_free(ssl_ctx);
        frame_buffer_free(new_tunnel->incoming_buffer);
        free(new_tunnel);
        close(accepted_sock);
        close(ws_sock);
        return NULL;
    }

    // Success - set up the tunnel
    new_tunnel->ssl = ws_ssl;
    SSL_CTX_free(ssl_ctx);  // SSL context no longer needed

    // Add tunnel to the global array
    pthread_mutex_lock(&tunnel_mutex);
    if (!add_tunnel(new_tunnel)) {
        SSL_free(ws_ssl);
        frame_buffer_free(new_tunnel->incoming_buffer);
        free(new_tunnel);
        pthread_mutex_unlock(&tunnel_mutex);
        close(accepted_sock);
        close(ws_sock);
        return NULL;
    }
    pthread_mutex_unlock(&tunnel_mutex);

    // Send any buffered data to the client immediately
    if (new_tunnel->incoming_buffer && new_tunnel->incoming_buffer->used > 0) {
        if (config->debug) {
            printf("[DEBUG - Tunnel] [Thread %ld] Sending %zu bytes of buffered server response to client\n", pthread_self(), new_tunnel->incoming_buffer->used);
            fflush(stdout);
        }
        ssize_t sent = send(accepted_sock, new_tunnel->incoming_buffer->buffer, new_tunnel->incoming_buffer->used, 0);
        if (sent > 0) {
            frame_buffer_consume(new_tunnel->incoming_buffer, sent);
            if (config->debug) {
                printf("[DEBUG] [Thread %ld] Sent %zd bytes of buffered server response to client\n", pthread_self(), sent);
                fflush(stdout);
            }
        }
    }

    if (config->debug) {
        printf("[DEBUG - Tunnel] [Thread %ld] Local connection accepted! Starting data forwarding...\n", pthread_self());
        fflush(stdout);
    }

    // Get initial SSL connection for thread
    SSL *current_ssl = new_tunnel->ssl;

    // Start forwarding thread
    thread_args_t *thread_args = malloc(sizeof(thread_args_t));
    if (!thread_args) {
        perror("Memory allocation failed for thread args");
        close(new_tunnel->local_sock);
        frame_buffer_free(new_tunnel->incoming_buffer);
        free(new_tunnel);
        return NULL;
    }
    thread_args->ssl = current_ssl;
    thread_args->tunnel = new_tunnel;
    thread_args->debug = config->debug;

    pthread_t forward_thread;
    if (pthread_create(&forward_thread, NULL, forward_tcp_to_ws, thread_args) != 0) {
        perror("Failed to create forwarding thread");
        free(thread_args);
        close(new_tunnel->local_sock);
        frame_buffer_free(new_tunnel->incoming_buffer);
        free(new_tunnel);
        return NULL;
    }
    // Store the thread ID for cleanup
    new_tunnel->forward_thread = forward_thread;

    // Main tunnel loop - handle WebSocket messages
    char ws_buffer[BUFFER_SIZE];
    int ws_bytes_read;
    fd_set tunnel_readfds;
    struct timeval tunnel_tv;

    // Frame accumulation buffer for handling partial WebSocket frames
    char frame_buffer[BUFFER_SIZE * 4];
    int frame_buffer_used = 0;

    while (1) {
        // Check if tunnel is still active (no mutex needed since this is our private tunnel)
        if (!new_tunnel || !new_tunnel->active) {
            if (new_tunnel && new_tunnel->broken) {
                goto cleanup_and_exit;
            } else {
                // normal closure
                if (config->debug) {
                    printf("[DEBUG - Tunnel] [Thread %ld] Tunnel is no longer active, exiting main loop\n", pthread_self());
                    fflush(stdout);
                }
                break;
            }
        }
        int ssl_fd = SSL_get_fd(new_tunnel->ssl);
        current_ssl = new_tunnel->ssl;

        // Check if local socket is still valid
        if (new_tunnel->local_sock < 0) {
            if (config->debug) {
                printf("[DEBUG - Tunnel] [Thread %ld] Local socket is invalid, tunnel broken\n", pthread_self());
                fflush(stdout);
            }

            new_tunnel->broken = 1;
            // Send tunnel_close notification
            if (config->debug) {
                printf("[DEBUG - Tunnel] [Thread %ld] Sending tunnel_close notification due to invalid local socket...\n", pthread_self());
                fflush(stdout);
            }
            send_tunnel_close(current_ssl, new_tunnel->request_id, config->debug);
            goto cleanup_and_exit;
        }

        // Check if the local socket connection is broken
        char test_buf[1];
        int result = recv(new_tunnel->local_sock, test_buf, 1, MSG_PEEK | MSG_DONTWAIT);
        if (result == 0 || (result < 0 && (errno == ECONNRESET || errno == EPIPE || errno == EBADF))) {
            if (config->debug) {
                printf("[DEBUG - Tunnel] [Thread %ld] Local socket connection is broken (errno=%d), sending tunnel_close\n", pthread_self(), errno);
                fflush(stdout);
            }

            new_tunnel->broken = 1;
            // Send tunnel_close notification
            send_tunnel_close(current_ssl, new_tunnel->request_id, config->debug);
            goto cleanup_and_exit;
        }

        // Use select to wait for data on SSL socket with timeout
        FD_ZERO(&tunnel_readfds);
        FD_SET(ssl_fd, &tunnel_readfds);
        tunnel_tv.tv_sec = 0;
        tunnel_tv.tv_usec = 50000;  // 50ms timeout

        int retval = select(ssl_fd + 1, &tunnel_readfds, NULL, NULL, &tunnel_tv);
        if (retval == -1) {
            if (config->debug) {
                perror("[DEBUG - WebSockets] select on SSL fd failed");
                fflush(stdout);
            }

            // Send tunnel_close notification
            if (config->debug) {
                printf("[DEBUG - Tunnel] [Thread %ld] Sending tunnel_close notification due to select failure...\n", pthread_self());
                fflush(stdout);
            }
            send_tunnel_close(current_ssl, new_tunnel->request_id, config->debug);
            goto cleanup_and_exit;
        } else if (retval == 0) {
            // Timeout, check if tunnel became inactive
            if (!new_tunnel || !new_tunnel->active) {
                if (config->debug) {
                    printf("[DEBUG - Tunnel] [Thread %ld] Tunnel became inactive during timeout, exiting\n", pthread_self());
                    fflush(stdout);
                }

                goto cleanup_and_exit;
            }
            continue;
        }

        // Read more data if we don't have a complete frame
        if (FD_ISSET(ssl_fd, &tunnel_readfds)) {
            if ((size_t)frame_buffer_used < sizeof(frame_buffer)) {
                // Validate SSL connection state
                if (SSL_get_shutdown(current_ssl) & SSL_RECEIVED_SHUTDOWN) {
                    if (config->debug) {
                        printf("[DEBUG - WebSockets] [Thread %ld] SSL connection has received shutdown\n", pthread_self());
                        fflush(stdout);
                    }
                    new_tunnel->active = 0;
                    break;
                }

                // Set up timeout for SSL read
                fd_set readfds_timeout;
                struct timeval tv_timeout;
                int sock_fd = SSL_get_fd(current_ssl);

                FD_ZERO(&readfds_timeout);
                FD_SET(sock_fd, &readfds_timeout);
                tv_timeout.tv_sec = 5;
                tv_timeout.tv_usec = 0;

                int select_result = select(sock_fd + 1, &readfds_timeout, NULL, NULL, &tv_timeout);
                if (select_result == -1) {
                    if (config->debug) {
                        perror("[DEBUG - WebSockets] select failed");
                        fflush(stdout);
                    }
                    new_tunnel->active = 0;
                    break;
                } else if (select_result == 0) {
                    if (config->debug) {
                        printf("[DEBUG - WebSockets] [Thread %ld] SSL read timeout\n", pthread_self());
                        fflush(stdout);
                    }
                    continue;
                }

                ws_bytes_read = SSL_read(current_ssl, frame_buffer + frame_buffer_used, sizeof(frame_buffer) - frame_buffer_used);
                if (ws_bytes_read <= 0) {
                    if (ws_bytes_read < 0) {
                        int ssl_error = SSL_get_error(current_ssl, ws_bytes_read);
                        if (config->debug) {
                            printf("[DEBUG - WebSockets] [Thread %ld] SSL read error: %d\n", pthread_self(), ssl_error);
                            fflush(stdout);
                        }

                        // Handle transient SSL errors
                        if (ssl_error == SSL_ERROR_WANT_READ || ssl_error == SSL_ERROR_WANT_WRITE) {
                            if (config->debug) {
                                printf("[DEBUG - WebSockets] [Thread %ld] Transient SSL error, retrying...\n", pthread_self());
                                fflush(stdout);
                            }
                            usleep(10000);
                            continue;
                        }

                        // Print SSL error details
                        char error_buf[256];
                        ERR_error_string_n(ssl_error, error_buf, sizeof(error_buf));
                        if (config->debug) {
                            printf("[DEBUG - WebSockets] [Thread %ld] SSL error details: %s\n", pthread_self(), error_buf);
                            fflush(stdout);
                        }
                        fprintf(stderr, "SSL read error (%d): %s\n", ssl_error, error_buf);
                    } else {
                        if (config->debug) {
                            printf("[DEBUG - WebSockets] [Thread %ld] Connection closed by server (EOF)\n", pthread_self());
                            fflush(stdout);
                        }
                    }

                    if (config->debug) {
                        printf("[DEBUG - WebSockets] [Thread %ld] WebSocket connection lost, attempting reconnection...\n", pthread_self());
                        fflush(stdout);
                    }

                    // Attempt reconnection
                    int reconnect_attempts = 0;
                    int max_reconnect_attempts = 3;
                    int reconnected = 0;

                    while (reconnect_attempts < max_reconnect_attempts && !reconnected) {
                        if (config->debug) {
                            printf("[DEBUG - WebSockets] [Thread %ld] WebSocket reconnection attempt %d/%d\n", pthread_self(), reconnect_attempts + 1, max_reconnect_attempts);
                            fflush(stdout);
                        }

                        if (!new_tunnel) {
                            break;
                        }
                        if (reconnect_websocket(new_tunnel, wssshd_host, wssshd_port, client_id, new_tunnel->request_id, config->debug) == 0) {
                            reconnected = 1;
                            if (config->debug) {
                                printf("[DEBUG - WebSockets] [Thread %ld] WebSocket reconnection successful, continuing tunnel\n", pthread_self());
                                fflush(stdout);
                            }
                            // Update ssl_fd for select
                            ssl_fd = SSL_get_fd(new_tunnel->ssl);
                            current_ssl = new_tunnel->ssl;
                        }

                        if (!reconnected) {
                            reconnect_attempts++;
                            if (reconnect_attempts < max_reconnect_attempts) {
                                if (config->debug) {
                                    printf("[DEBUG - WebSockets] [Thread %ld] WebSocket reconnection failed, waiting 1 second...\n", pthread_self());
                                    fflush(stdout);
                                }
                                sleep(1);
                            }
                        }
                    }

                    if (!reconnected) {
                        if (config->debug) {
                            printf("[DEBUG - WebSockets] [Thread %ld] All reconnection attempts failed, exiting\n", pthread_self());
                            fflush(stdout);
                        }

                        // Send tunnel_close notification
                        if (config->debug) {
                            printf("[DEBUG - Tunnel] [Thread %ld] Sending tunnel_close notification due to connection failure...\n", pthread_self());
                            fflush(stdout);
                        }
                        send_tunnel_close(current_ssl, new_tunnel->request_id, config->debug);
                        goto cleanup_and_exit;
                    }

                    // Skip processing this iteration since we just reconnected
                    continue;
                }

                frame_buffer_used += ws_bytes_read;

                if (config->debug) {
                    printf("[DEBUG - WebSockets] [Thread %ld] Accumulated %d bytes, frame: 0x%02x 0x%02x 0x%02x 0x%02x\n", pthread_self(), frame_buffer_used, frame_buffer[0], frame_buffer[1], frame_buffer[2], frame_buffer[3]);
                    fflush(stdout);
                }
            }

            // Try to parse WebSocket frame
            char *payload;
            int payload_len;
            if (parse_websocket_frame(frame_buffer, frame_buffer_used, &payload, &payload_len)) {
                // Frame is complete, determine frame type
                unsigned char frame_type = frame_buffer[0] & 0x8F;

                if (frame_type == 0x88) { // Close frame
                    if (config->debug) {
                        printf("[DEBUG - WebSockets] [Thread %ld] Received close frame from server\n", pthread_self());
                        fflush(stdout);
                    }

                    // Send tunnel_close notification
                    if (config->debug) {
                        printf("[DEBUG - Tunnel] [Thread %ld] Sending tunnel_close notification due to server close frame...\n", pthread_self());
                        fflush(stdout);
                    }
                    send_tunnel_close(current_ssl, new_tunnel->request_id, config->debug);
                    goto cleanup_and_exit;
                } else if (frame_type == 0x89) { // Ping frame
                    if (config->debug) {
                        printf("[DEBUG - WebSockets] [Thread %ld] Received ping frame, sending pong\n", pthread_self());
                        fflush(stdout);
                    }
                    // Send pong
                    if (!send_pong_frame(current_ssl, payload, payload_len)) {
                        if (config->debug) {
                            printf("[DEBUG - WebSockets] [Thread %ld] Failed to send pong frame\n", pthread_self());
                            fflush(stdout);
                        }
                    }
                } else if (frame_type == 0x8A) { // Pong frame
                    if (config->debug) {
                        printf("[DEBUG - WebSockets] [Thread %ld] Received pong frame\n", pthread_self());
                        fflush(stdout);
                    }
                } else if (frame_type == 0x81 || frame_type == 0x82) { // Text or binary frame
                    // Copy payload to buffer
                    if ((size_t)payload_len < sizeof(ws_buffer)) {
                        memcpy(ws_buffer, payload, payload_len);
                        ws_buffer[payload_len] = '\0';
                    } else {
                        fprintf(stderr, "Payload too large for processing buffer\n");
                        frame_buffer_used = 0;
                        continue;
                    }

                    // Check if this is a data message to suppress verbose logging
                    int is_data_message = (strstr(ws_buffer, "\"type\": \"tunnel_data\"") != NULL ||
                                          strstr(ws_buffer, "\"type\": \"tunnel_response\"") != NULL);

                    if (config->debug && !is_data_message) {
                        printf("[DEBUG - WebSockets] [Thread %ld] Received message: %.*s\n", pthread_self(), payload_len, payload);
                        fflush(stdout);
                    }

                    // Handle message
                    if (config->debug && !is_data_message) {
                        printf("[DEBUG - WebSockets] [Thread %ld] Processing message: %s\n", pthread_self(), ws_buffer);
                        fflush(stdout);
                    }

                    // Handle tunnel messages
                    if (strstr(ws_buffer, "tunnel_data") || strstr(ws_buffer, "tunnel_response")) {
                        if (config->debug) {
                            // Suppress tunnel_data debug messages in debug mode
                            if (!strstr(ws_buffer, "tunnel_data")) {
                                printf("[DEBUG - Tunnel] [Thread %ld] Received tunnel_response message\n", pthread_self());
                                fflush(stdout);
                            }
                        }
                        // Extract request_id and data
                        char *id_start = strstr(ws_buffer, "\"request_id\"");
                        char *data_start = strstr(ws_buffer, "\"data\"");
                        if (id_start && data_start) {
                            char *colon = strchr(id_start, ':');
                            if (colon) {
                                char *open_quote = strchr(colon, '"');
                                if (open_quote) {
                                    id_start = open_quote + 1;
                                    char *close_quote = strchr(id_start, '"');
                                    if (close_quote) {
                                        // Make a copy of the request_id to avoid corrupting the buffer
                                        size_t id_len = close_quote - id_start;
                                        char *request_id_copy = malloc(id_len + 1);
                                        if (request_id_copy) {
                                            memcpy(request_id_copy, id_start, id_len);
                                            request_id_copy[id_len] = '\0';

                                            char *data_colon = strchr(data_start, ':');
                                            if (data_colon) {
                                                char *data_quote = strchr(data_colon, '"');
                                                if (data_quote) {
                                                    data_start = data_quote + 1;
                                                    char *data_end = strchr(data_start, '"');
                                                    if (data_end) {
                                                        // Make a copy of the hex data to avoid corrupting the buffer
                                                        size_t hex_len = data_end - data_start;
                                                        char *hex_data_copy = malloc(hex_len + 1);
                                                        if (hex_data_copy) {
                                                            memcpy(hex_data_copy, data_start, hex_len);
                                                            hex_data_copy[hex_len] = '\0';
                                                            handle_tunnel_data(current_ssl, request_id_copy, hex_data_copy, config->debug);
                                                            free(hex_data_copy);
                                                        }
                                                    }
                                                }
                                            }
                                            free(request_id_copy);
                                        }
                                    }
                                }
                            }
                        }
                    } else if (strstr(ws_buffer, "tunnel_close")) {
                        if (config->debug) {
                            printf("[DEBUG - Tunnel] [Thread %ld] Received tunnel_close message\n", pthread_self());
                            fflush(stdout);
                        }
                        char *id_start = strstr(ws_buffer, "\"request_id\"");
                        if (id_start) {
                            char *colon = strchr(id_start, ':');
                            if (colon) {
                                char *open_quote = strchr(colon, '"');
                                if (open_quote) {
                                    id_start = open_quote + 1;
                                    char *close_quote = strchr(id_start, '"');
                                    if (close_quote) {
                                        // Make a copy of the request_id to avoid corrupting the buffer
                                        size_t id_len = close_quote - id_start;
                                        char *request_id_copy = malloc(id_len + 1);
                                        if (request_id_copy) {
                                            memcpy(request_id_copy, id_start, id_len);
                                            request_id_copy[id_len] = '\0';
                                            handle_tunnel_close(current_ssl, request_id_copy, config->debug);
                                            free(request_id_copy);
                                        }
                                    }
                                }
                            }
                        }
                    } else {
                        if (config->debug) {
                            printf("[DEBUG - WebSockets] [Thread %ld] Received unknown message type: %s\n", pthread_self(), ws_buffer);
                            fflush(stdout);
                        }
                    }
                }

                // Remove processed frame from buffer
                int frame_size = (payload - frame_buffer) + payload_len;
                if (frame_size < frame_buffer_used) {
                    memmove(frame_buffer, frame_buffer + frame_size, frame_buffer_used - frame_size);
                    frame_buffer_used -= frame_size;
                } else {
                    frame_buffer_used = 0;
                }
            } else {
                // Frame not complete yet, continue reading
                continue;
            }
        }
    }

cleanup_and_exit:
    // Cleanup section
    if (config->debug) {
        printf("[DEBUG - Tunnel] [Thread %ld] Performing cleanup and exiting\n", pthread_self());
        fflush(stdout);
    }

    // Wait for forwarding thread to finish
    if (new_tunnel && new_tunnel->forward_thread) {
        if (config->debug) {
            printf("[DEBUG - Tunnel] [Thread %ld] Waiting for forwarding thread to finish\n", pthread_self());
            fflush(stdout);
        }
        pthread_join(new_tunnel->forward_thread, NULL);
        if (config->debug) {
            printf("[DEBUG - Tunnel] [Thread %ld] Forwarding thread finished\n", pthread_self());
            fflush(stdout);
        }
    }

    // Cleanup - close resources and remove from global array
    if (new_tunnel) {
        if (new_tunnel->local_sock >= 0) {
            close(new_tunnel->local_sock);
        }
        if (new_tunnel->ssl) {
            SSL_free(new_tunnel->ssl);
        }

        // Remove tunnel from global array and free it
        pthread_mutex_lock(&tunnel_mutex);
        remove_tunnel(new_tunnel->request_id);
        pthread_mutex_unlock(&tunnel_mutex);
    }

    if (config->debug) {
        printf("[DEBUG - Tunnel] [Thread %ld] Cleanup complete, thread exiting\n", pthread_self());
        fflush(stdout);
    }

    return NULL;
}

int run_daemon_mode(wsssh_config_t *config, const char *client_id, const char *wssshd_host, int wssshd_port) {
    // Daemon mode: Lazy tunnel establishment - bind port immediately, establish tunnel on connection
    if (config->debug) {
        printf("[DEBUG] Starting daemon mode with lazy tunnel establishment\n");
        fflush(stdout);
    }

    // Find available local port
    int local_port = config->local_port ? atoi(config->local_port) : find_available_port();
    if (local_port == 0) {
        fprintf(stderr, "Error: Could not find available local port\n");
        return 1;
    }

    if (config->debug) {
        printf("[DEBUG] Using local port: %d\n", local_port);
        fflush(stdout);
    }

    // Create listening socket
    int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_sock < 0) {
        perror("Local socket creation failed");
        return 1;
    }

    // Set SO_REUSEADDR to allow immediate reuse of the port
    int opt = 1;
    if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
        perror("setsockopt on listen_sock failed");
        close(listen_sock);
        return 1;
    }

    struct sockaddr_in local_addr;
    memset(&local_addr, 0, sizeof(local_addr));
    local_addr.sin_family = AF_INET;
    local_addr.sin_port = htons(local_port);

    // Use specified tunnel_host or default to 127.0.0.1
    if (config->tunnel_host && strcmp(config->tunnel_host, "127.0.0.1") != 0) {
        struct hostent *tunnel_he;
        if ((tunnel_he = gethostbyname(config->tunnel_host)) == NULL) {
            if (config->debug) {
                fprintf(stderr, "[DEBUG] Failed to resolve tunnel_host '%s', using 127.0.0.1\n", config->tunnel_host);
            }
            local_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
        } else {
            local_addr.sin_addr = *((struct in_addr *)tunnel_he->h_addr);
            if (config->debug) {
                printf("[DEBUG] Binding tunnel to %s:%d\n", config->tunnel_host, local_port);
                fflush(stdout);
            }
        }
    } else {
        local_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
        if (config->debug) {
            printf("[DEBUG] Binding tunnel to 127.0.0.1:%d\n", local_port);
            fflush(stdout);
        }
    }

    if (bind(listen_sock, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
        perror("Local bind failed");
        close(listen_sock);
        return 1;
    }

    if (listen(listen_sock, 1) < 0) {
        perror("Local listen failed");
        close(listen_sock);
        return 1;
    }

    if (config->mode != MODE_SILENT) {
        printf("Daemon mode: Listening on port %d, waiting for connection...\n", local_port);
        fflush(stdout);
    }

    // Daemon mode main loop - accept connections and establish tunnels
    while (1) {
        // Check for SIGINT
        if (sigint_received) {
            if (config->debug) {
                printf("[DEBUG] SIGINT received in daemon mode, exiting\n");
                fflush(stdout);
            }
            break;
        }

        // Wait for connection with timeout
        fd_set readfds;
        struct timeval tv;
        FD_ZERO(&readfds);
        FD_SET(listen_sock, &readfds);
        tv.tv_sec = 1;  // 1 second timeout to check for signals
        tv.tv_usec = 0;

        int retval = select(listen_sock + 1, &readfds, NULL, NULL, &tv);
        if (retval < 0) {
            if (errno == EINTR) {
                // Interrupted by signal, continue to check sigint_received
                continue;
            }
            perror("Select failed in daemon mode");
            // In daemon mode, don't exit on select errors, wait a bit and retry
            sleep(1);
            continue;
        } else if (retval == 0) {
            // Timeout, continue loop to check signals
            continue;
        }

        // Accept connection
        struct sockaddr_in client_addr;
        socklen_t client_len = sizeof(client_addr);
        int accepted_sock = accept(listen_sock, (struct sockaddr *)&client_addr, &client_len);
        if (accepted_sock < 0) {
            if (errno == EINTR) {
                continue;
            }
            perror("Local accept failed");
            continue;  // Don't exit on accept failure, keep listening
        }

        if (config->debug) {
            printf("[DEBUG] Connection received on port %d, spawning handler thread...\n", local_port);
            fflush(stdout);
        }

        // Create thread arguments
        connection_handler_args_t *thread_args = malloc(sizeof(connection_handler_args_t));
        if (!thread_args) {
            perror("Memory allocation failed for connection handler args");
            close(accepted_sock);
            continue;
        }

        thread_args->config = config;
        thread_args->client_id = client_id;
        thread_args->wssshd_host = wssshd_host;
        thread_args->wssshd_port = wssshd_port;
        thread_args->accepted_sock = accepted_sock;
        thread_args->local_port = local_port;

        // Spawn a new thread to handle this connection
        pthread_t connection_thread;
        if (pthread_create(&connection_thread, NULL, handle_connection, thread_args) != 0) {
            perror("Failed to create connection handler thread");
            free(thread_args);
            close(accepted_sock);
            continue;
        }

        // Detach the thread so it can clean up automatically when done
        pthread_detach(connection_thread);

        if (config->debug) {
            printf("[DEBUG] Connection handler thread spawned (ID: %ld)\n", connection_thread);
            fflush(stdout);
        }
    }

    // This should never be reached, but just in case
    return 0;
}
