Skip to content

Commit d4f656f

Browse files
committed
fix: v0.0.8 align health check timeout with user-configured delay_ms
- replace hardcoded 2000ms timeout in `health_check_ip` and `carrier_health_check_ip` with `g_cfg.delay_ms` - fix mismatch where a low `-delay` (e.g. 500ms) kept an IP alive in health checks while client connections timed out against the same IP - apply the fix to all 8 dial + probe calls across Baidu and Carrier health check paths fix: v0.0.8 健康检查超时改为与用户设置的 -delay 一致 - 将 `health_check_ip` 和 `carrier_health_check_ip` 中硬编码的 2000ms 超时替换为 `g_cfg.delay_ms` - 修复当 `-delay` 设为较低值(如 500ms)时,健康检查用 2000ms 判定 IP 可用,但客户端连接用 500ms 超时而连不上的问题 - 同步修复百度直连模式和运营商模式共 8 处 dial + probe 调用
1 parent 58e5487 commit d4f656f

1 file changed

Lines changed: 76 additions & 18 deletions

File tree

cfnat.c

Lines changed: 76 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,16 +1500,63 @@ static ResultList scan_ips(StringList *ips, Config *cfg, BaiduProxyPool *proxy_p
15001500
return rl;
15011501
}
15021502

1503+
static int http_probe(socket_t fd, int timeout_ms) {
1504+
// 发送 HTTP GET 请求探测数据通路是否正常
1505+
const char *req = "GET / HTTP/1.0\r\nHost: cloudflaremirrors.com\r\nConnection: close\r\n\r\n";
1506+
size_t reqlen = strlen(req);
1507+
long deadline = now_ms() + timeout_ms;
1508+
size_t sent = 0;
1509+
while (sent < reqlen && now_ms() < deadline) {
1510+
fd_set wfds;
1511+
FD_ZERO(&wfds);
1512+
FD_SET(fd, &wfds);
1513+
int left = (int)(deadline - now_ms());
1514+
if (left <= 0) break;
1515+
struct timeval tv = { left / 1000, (left % 1000) * 1000 };
1516+
int rc = select(fd + 1, NULL, &wfds, NULL, &tv);
1517+
if (rc <= 0) break;
1518+
ssize_t n = send(fd, req + sent, reqlen - sent, 0);
1519+
if (n <= 0) break;
1520+
sent += (size_t)n;
1521+
}
1522+
if (sent < reqlen) return 0;
1523+
// 读取响应头,确认收到 HTTP 响应
1524+
char buf[256];
1525+
size_t used = 0;
1526+
while (used < sizeof(buf) - 1 && now_ms() < deadline) {
1527+
fd_set rfds;
1528+
FD_ZERO(&rfds);
1529+
FD_SET(fd, &rfds);
1530+
int left = (int)(deadline - now_ms());
1531+
if (left <= 0) break;
1532+
struct timeval tv = { left / 1000, (left % 1000) * 1000 };
1533+
int rc = select(fd + 1, &rfds, NULL, NULL, &tv);
1534+
if (rc <= 0) break;
1535+
ssize_t n = recv(fd, buf + used, sizeof(buf) - used - 1, 0);
1536+
if (n <= 0) break;
1537+
used += (size_t)n;
1538+
buf[used] = 0;
1539+
if (strstr(buf, "HTTP/")) return 1; // 收到 HTTP 响应头表示数据通路正常
1540+
}
1541+
return 0;
1542+
}
1543+
15031544
static int health_check_ip(const char *ip, BaiduProxyPool *proxy_pool) {
15041545
int latency = 0;
1505-
socket_t fd = dial_target_with_proxy(ip, g_cfg.port, 2000, proxy_pool, &latency);
1546+
socket_t fd = dial_target_with_proxy(ip, g_cfg.port, g_cfg.delay_ms, proxy_pool, &latency);
15061547
if (cfnat_socket_invalid(fd)) {
1507-
debug_msg("健康检查失败: IP %s 暂不可用", ip);
1548+
debug_msg("健康检查失败: IP %s TCP 不可达", ip);
15081549
return 0;
15091550
}
1551+
// TCP 握手成功后再做 HTTP 探测,确认数据通路正常
1552+
int ok = http_probe(fd, g_cfg.delay_ms);
15101553
close(fd);
1511-
debug_msg("健康检查成功: IP %s 延迟 %d ms", ip, latency);
1512-
return 1;
1554+
if (ok) {
1555+
debug_msg("健康检查成功: IP %s 延迟 %d ms", ip, latency);
1556+
return 1;
1557+
}
1558+
debug_msg("健康检查失败: IP %s TCP 可达但 HTTP 无响应", ip);
1559+
return 0;
15131560
}
15141561

15151562
static int set_current_candidate(size_t idx) {
@@ -1811,38 +1858,49 @@ static void *connection_thread(void *arg) {
18111858
return NULL;
18121859
}
18131860

1861+
static int carrier_probe_and_check(socket_t fd, int timeout_ms) {
1862+
// TCP 握手成功后做 HTTP 探测,确认数据通路正常
1863+
int ok = http_probe(fd, timeout_ms);
1864+
close(fd);
1865+
return ok;
1866+
}
1867+
18141868
static int carrier_health_check_ip(CarrierRuntime *rt, const char *ip) {
18151869
if (!rt || !ip || !*ip) return 0;
18161870
// 混合模式:先试直连,不行再试百度代理
18171871
if (rt->spec.use_baidu_proxy == 2) {
18181872
int latency = 0;
1819-
socket_t fd = dial_target_with_proxy(ip, g_cfg.port, 2000, NULL, &latency);
1873+
socket_t fd = dial_target_with_proxy(ip, g_cfg.port, g_cfg.delay_ms, NULL, &latency);
18201874
if (cfnat_socket_valid(fd)) {
1821-
close(fd);
1822-
debug_msg("%s 健康检查成功(直连): IP %s 延迟 %d ms", carrier_display_name(rt->spec.mode), ip, latency);
1823-
return 1;
1824-
}
1825-
if (rt->proxy_pool && rt->proxy_pool->len > 0) {
1826-
fd = dial_target_with_proxy(ip, g_cfg.port, 2000, rt->proxy_pool, &latency);
1827-
if (cfnat_socket_valid(fd)) {
1828-
close(fd);
1829-
debug_msg("%s 健康检查成功(百度前置): IP %s 延迟 %d ms", carrier_display_name(rt->spec.mode), ip, latency);
1875+
if (carrier_probe_and_check(fd, g_cfg.delay_ms)) {
1876+
debug_msg("%s 健康检查成功(直连): IP %s 延迟 %d ms", carrier_display_name(rt->spec.mode), ip, latency);
18301877
return 1;
18311878
}
1879+
} else if (rt->proxy_pool && rt->proxy_pool->len > 0) {
1880+
fd = dial_target_with_proxy(ip, g_cfg.port, g_cfg.delay_ms, rt->proxy_pool, &latency);
1881+
if (cfnat_socket_valid(fd)) {
1882+
if (carrier_probe_and_check(fd, g_cfg.delay_ms)) {
1883+
debug_msg("%s 健康检查成功(百度前置): IP %s 延迟 %d ms", carrier_display_name(rt->spec.mode), ip, latency);
1884+
return 1;
1885+
}
1886+
}
18321887
}
18331888
debug_msg("%s 健康检查失败: IP %s 暂不可用", carrier_display_name(rt->spec.mode), ip);
18341889
return 0;
18351890
}
18361891
// 普通模式
18371892
int latency = 0;
1838-
socket_t fd = dial_target_with_proxy(ip, g_cfg.port, 2000, rt->proxy_pool, &latency);
1893+
socket_t fd = dial_target_with_proxy(ip, g_cfg.port, g_cfg.delay_ms, rt->proxy_pool, &latency);
18391894
if (cfnat_socket_invalid(fd)) {
18401895
debug_msg("%s 健康检查失败: IP %s 暂不可用", carrier_display_name(rt->spec.mode), ip);
18411896
return 0;
18421897
}
1843-
close(fd);
1844-
debug_msg("%s 健康检查成功: IP %s 延迟 %d ms", carrier_display_name(rt->spec.mode), ip, latency);
1845-
return 1;
1898+
if (carrier_probe_and_check(fd, g_cfg.delay_ms)) {
1899+
debug_msg("%s 健康检查成功: IP %s 延迟 %d ms", carrier_display_name(rt->spec.mode), ip, latency);
1900+
return 1;
1901+
}
1902+
debug_msg("%s 健康检查失败: IP %s TCP 可达但 HTTP 无响应", carrier_display_name(rt->spec.mode), ip);
1903+
return 0;
18461904
}
18471905

18481906
static int carrier_set_current_candidate(CarrierRuntime *rt, size_t idx) {

0 commit comments

Comments
 (0)