feat: sync httpdns sdk/platform updates without large binaries

This commit is contained in:
robin
2026-03-04 17:59:14 +08:00
parent 853897a6f8
commit 532891fad0
700 changed files with 6096 additions and 2712 deletions

View File

@@ -0,0 +1,185 @@
//
// HttpdnsIpStackDetector.m
// NewHttpDNS
//
// Created by xuyecan on 2025/3/16.
// Copyright © 2025 new-inc.com. All rights reserved.
//
#import "HttpdnsIpStackDetector.h"
#import "HttpdnsLog_Internal.h"
#include <strings.h>
#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
typedef union httpdns_sockaddr_union {
struct sockaddr httpdns_generic;
struct sockaddr_in httpdns_in;
struct sockaddr_in6 httpdns_in6;
} httpdns_sockaddr_union;
/*
* UDP
* IPv4IPv6
*
*/
static const unsigned int kMaxLoopCount = 10;
static int httpdns_test_connect(int pf, struct sockaddr * addr, size_t addrlen) {
int s = socket(pf, SOCK_DGRAM, IPPROTO_UDP);
if (s < 0) {
return 0;
}
int ret;
unsigned int loop_count = 0;
do {
ret = connect(s, addr, (socklen_t)addrlen);
} while (ret < 0 && errno == EINTR && loop_count++ < kMaxLoopCount);
if (loop_count >= kMaxLoopCount) {
HttpdnsLogDebug("connect error. loop_count = %d", loop_count);
}
int success = (ret == 0);
loop_count = 0;
do {
ret = close(s);
} while (ret < 0 && errno == EINTR && loop_count++ < kMaxLoopCount);
if (loop_count >= kMaxLoopCount) {
HttpdnsLogDebug("close error. loop_count = %d", loop_count);
}
return success;
}
/*
* IPv4IPv6AI_ADDRCONFIG
*
* AI_ADDRCONFIG
* "在本地系统上配置"
* bionicgetifaddrs
*
*/
static int httpdns_have_ipv6(void) {
static struct sockaddr_in6 sin6_test = {0};
sin6_test.sin6_family = AF_INET6;
sin6_test.sin6_port = 80;
sin6_test.sin6_flowinfo = 0;
sin6_test.sin6_scope_id = 0;
bzero(sin6_test.sin6_addr.s6_addr, sizeof(sin6_test.sin6_addr.s6_addr));
sin6_test.sin6_addr.s6_addr[0] = 0x20;
// union
httpdns_sockaddr_union addr = {.httpdns_in6 = sin6_test};
return httpdns_test_connect(PF_INET6, &addr.httpdns_generic, sizeof(addr.httpdns_in6));
}
static int httpdns_have_ipv4(void) {
static struct sockaddr_in sin_test = {0};
sin_test.sin_family = AF_INET;
sin_test.sin_port = 80;
sin_test.sin_addr.s_addr = htonl(0x08080808L); // 8.8.8.8
// union
httpdns_sockaddr_union addr = {.httpdns_in = sin_test};
return httpdns_test_connect(PF_INET, &addr.httpdns_generic, sizeof(addr.httpdns_in));
}
/**
* IPv4IPv6IP
*/
static HttpdnsIPStackType detectIpStack(void) {
int hasIPv4 = httpdns_have_ipv4();
int hasIPv6 = httpdns_have_ipv6();
HttpdnsLogDebug("IP stack detection: IPv4=%d, IPv6=%d", hasIPv4, hasIPv6);
if (hasIPv4 && hasIPv6) {
return kHttpdnsIpDual;
} else if (hasIPv4) {
return kHttpdnsIpv4Only;
} else if (hasIPv6) {
return kHttpdnsIpv6Only;
} else {
return kHttpdnsIpUnknown;
}
}
@implementation HttpdnsIpStackDetector {
HttpdnsIPStackType _lastDetectedIpStack;
dispatch_queue_t _detectSerialQueue; //
dispatch_queue_t _updateSerialQueue;
BOOL _isDetecting; //
NSTimeInterval _lastDetectionTime; //
}
+ (instancetype)sharedInstance {
static HttpdnsIpStackDetector *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
- (instancetype)init {
self = [super init];
if (self) {
_lastDetectedIpStack = kHttpdnsIpUnknown;
_isDetecting = NO;
_lastDetectionTime = 0;
// IP
_detectSerialQueue = dispatch_queue_create("com.new.httpdns.ipstack.detect", DISPATCH_QUEUE_SERIAL);
_updateSerialQueue = dispatch_queue_create("com.new.httpdns.ipstack.update", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (HttpdnsIPStackType)currentIpStack {
// 线
__block HttpdnsIPStackType result;
dispatch_sync(_updateSerialQueue, ^{
result = self->_lastDetectedIpStack;
});
return result;
}
- (BOOL)isIpv6OnlyNetwork {
return [self currentIpStack] == kHttpdnsIpv6Only;
}
- (void)redetectIpStack {
//
dispatch_async(_detectSerialQueue, ^{
//
if (self->_isDetecting) {
HttpdnsLogDebug("IP stack detection already in progress, skipping");
return;
}
// 1
NSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970];
NSTimeInterval timeSinceLastDetection = currentTime - self->_lastDetectionTime;
if (timeSinceLastDetection < 1.0) {
return;
}
//
self->_lastDetectionTime = currentTime;
//
self->_isDetecting = YES;
//
HttpdnsIPStackType detectedStack = detectIpStack();
// 线
dispatch_async(self->_updateSerialQueue, ^{
self->_lastDetectedIpStack = detectedStack;
//
dispatch_async(self->_detectSerialQueue, ^{
self->_isDetecting = NO;
});
});
});
}
@end