/* EOS Combat Probe v1.0 — Edge Ping Agent (零依赖纯C, 实战清单第一阶段)
 * 探测: TCP连接 目标:80, 非阻塞+select硬超时3s
 * 日志: ./eos_combat.log 二进制结构体 {magic,seq,ts_ms,success,latency_ms,host[64]}
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netdb.h>

#define EOS_MAGIC 0xE05C0B01u
#define PROBE_COUNT 10
#define PROBE_INTERVAL 1

typedef struct __attribute__((packed)) {
    uint32_t magic;
    uint32_t seq;
    int64_t  ts_ms;
    int32_t  success;
    uint32_t latency_ms;
    char     host[64];
} ProbeRecord;

static long long now_ms(void) {
    struct timeval tv; gettimeofday(&tv, NULL);
    return (long long)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

int main(int argc, char **argv) {
    /* ELC-11: CLI参数化 -h host -p port -t timeout_sec (0905) */
    const char *host = "example.invalid"; int port = 80; int timeout_s = 3;
    for (int i = 1; i < argc; i++) {
        if (!strcmp(argv[i], "-h") && i+1 < argc) host = argv[++i];
        else if (!strcmp(argv[i], "-p") && i+1 < argc) port = atoi(argv[++i]);
        else if (!strcmp(argv[i], "-t") && i+1 < argc) timeout_s = atoi(argv[++i]);
        else host = argv[i]; /* 位置参数兼容 */
    }
    const char *env_h = getenv("EOS_PROBE_HOST"); if (env_h && !strcmp(host,"example.invalid")) host = env_h;
    char portstr[8]; snprintf(portstr, sizeof portstr, "%d", port);
    struct addrinfo hints, *res = NULL;
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM;

    if (getaddrinfo(host, portstr, &hints, &res) != 0 || !res) {
        fprintf(stderr, "[probe] DNS失败: %s\n", host);
        return 2;
    }

    FILE *log = fopen("./eos_combat.log", "ab");
    if (!log) { perror("fopen"); freeaddrinfo(res); return 2; }

    int ok = 0, fail = 0; long long total = 0;
    for (int i = 0; i < PROBE_COUNT; i++) {
        long long t0 = now_ms();
        int sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
        int success = 0;
        uint32_t latency = 0;
        if (sockfd >= 0) {
            fcntl(sockfd, F_SETFL, O_NONBLOCK);
            int c = connect(sockfd, res->ai_addr, res->ai_addrlen);
            if (c == 0) { success = 1; }
            else if (errno == EINPROGRESS) {
                fd_set wfds; FD_ZERO(&wfds); FD_SET(sockfd, &wfds);
                struct timeval tv = {3, 0};  /* 每次重置,防select修改残留 */
                if (select(sockfd + 1, NULL, &wfds, NULL, &tv) > 0) {
                    int err = 0; socklen_t len = sizeof(err);
                    getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &len);
                    success = (err == 0);
                }
            }
            close(sockfd);
        }
        latency = (uint32_t)(now_ms() - t0);
        ok += success; fail += !success; total += success ? latency : 0;

        ProbeRecord rec;
        memset(&rec, 0, sizeof(rec));
        rec.magic = EOS_MAGIC; rec.seq = i; rec.ts_ms = now_ms();
        rec.success = success; rec.latency_ms = latency;
        strncpy(rec.host, host, 63);
        fwrite(&rec, sizeof(rec), 1, log);
        fflush(log);  /* 每条落盘,长跑可被kill不丢数据 */
        printf("[probe %02d] %s%s latency=%ums\n", i, success ? "OK " : "FAIL ",
               success ? "  " : "", latency);
        fflush(stdout);
        if (i < PROBE_COUNT - 1) sleep(PROBE_INTERVAL);
    }
    printf("=== EOS Combat Probe 汇总: %d成功/%d失败/平均延迟%ums ===\n",
           ok, fail, ok ? (uint32_t)(total / ok) : 0);
    fclose(log); freeaddrinfo(res);
    return fail == PROBE_COUNT ? 1 : 0;
}
