增加尝试其他端口

This commit is contained in:
xsean 2025-11-05 10:21:21 +08:00
parent fa49dcac96
commit a8a122a6e0
19 changed files with 2005 additions and 1723 deletions

View File

@ -6,5 +6,5 @@ Author: XYZShell
Section: Utilities Section: Utilities
Tag: role::developer Tag: role::developer
Architecture: iphoneos-arm Architecture: iphoneos-arm
Version: 0.0.7-10-61+debug Version: 0.0.7-10-62+debug
Installed-Size: 1600 Installed-Size: 1604

View File

@ -1 +1 @@
./packages/com.xyzshell.ioscontrol_0.0.7-10-61+debug_iphoneos-arm.deb ./packages/com.xyzshell.ioscontrol_0.0.7-10-62+debug_iphoneos-arm.deb

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1 +1 @@
61 62

View File

@ -1,74 +1,75 @@
//
// XUDPServer.m
// xcmd
//
// Created by mac on 2025/2/17.
//
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#include <complex.h>
#import <sys/socket.h> #import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
#import "XUDPServer.h" #import "XUDPServer.h"
#import "UDPHandler.h" #import "UDPHandler.h"
#define FALLBACK_PORT_START 6001 #define FALLBACK_PORT_START 6001
#define FALLBACK_PORT_END 7000 #define FALLBACK_PORT_END 7000
#define PORT 6001 #define PORT 6001
#define SEND_TIMEOUT 5.0 //
@interface XUDPServer() { @interface XUDPServer() {
@private @private
GCDAsyncUdpSocket *serverSocket; GCDAsyncUdpSocket *serverSocket;
dispatch_queue_t serverQueue; // dispatch_queue_t serverQueue;
dispatch_source_t restartTimer; // dispatch_source_t restartTimer;
NSUInteger restartAttempts; NSUInteger restartAttempts;
uint16_t currentPort; uint16_t currentPort;
NSTimer *healthCheckTimer;
} }
@property (nonatomic, strong) NSMutableDictionary<NSNumber *, NSDictionary *> *pendingSends;
@property (nonatomic, assign) long currentTag;
@end @end
@implementation XUDPServer @implementation XUDPServer
+(instancetype)sharedInstance #pragma mark - Singleton
{
+ (instancetype)sharedInstance {
static XUDPServer* _sharedInstance = nil; static XUDPServer* _sharedInstance = nil;
static dispatch_once_t oncePredicate; static dispatch_once_t oncePredicate;
dispatch_once (&oncePredicate, ^{ dispatch_once(&oncePredicate, ^{
_sharedInstance = [[XUDPServer alloc] init]; _sharedInstance = [[XUDPServer alloc] init];
}); });
return _sharedInstance; return _sharedInstance;
} }
-(instancetype)init { - (instancetype)init {
if (self = [super init]) { if (self = [super init]) {
restartAttempts = 0; restartAttempts = 0;
//
currentPort = PORT; currentPort = PORT;
_currentTag = 0;
_pendingSends = [NSMutableDictionary dictionary];
//
serverQueue = dispatch_queue_create("com.xudpserver.queue", DISPATCH_QUEUE_SERIAL); serverQueue = dispatch_queue_create("com.xudpserver.queue", DISPATCH_QUEUE_SERIAL);
return self; return self;
} }
return nil; return nil;
} }
- (void)start { - (void)start {
// 使
dispatch_async(serverQueue, ^{ dispatch_async(serverQueue, ^{
[self _startInternal]; [self _startInternal];
}); });
} }
- (uint16_t) udp_port { - (uint16_t)udp_port {
return currentPort; return currentPort;
} }
- (void) _startInternal { - (void)_startInternal {
NSLog(@"XS- start udp server"); NSLog(@"XS- Starting UDP server on port %d", currentPort);
// //
if (serverSocket && !serverSocket.isClosed) { if (serverSocket && !serverSocket.isClosed) {
NSLog(@"UDP server already running"); NSLog(@"⚠️ UDP server already running on port %d", currentPort);
return; return;
} }
@ -76,21 +77,21 @@
serverSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self serverSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self
delegateQueue:serverQueue]; delegateQueue:serverQueue];
// :
NSError *error = nil; NSError *error = nil;
//
if (![serverSocket enableReusePort:YES error:&error]) { if (![serverSocket enableReusePort:YES error:&error]) {
NSLog(@"❌ Error enabling reuse port: %@", error); NSLog(@"❌ Error enabling reuse port: %@", error);
} }
// SO_REUSEADDR
int reuseOn = 1; // socket
if (setsockopt([serverSocket socketFD], SOL_SOCKET, SO_REUSEADDR, [self _configureSocketOptions];
&reuseOn, sizeof(reuseOn)) == -1) {
NSLog(@"❌ Error setting SO_REUSEADDR"); //
}
if (![serverSocket bindToPort:currentPort error:&error]) { if (![serverSocket bindToPort:currentPort error:&error]) {
NSLog(@"❌ Error binding to port %d: %@", currentPort, error); NSLog(@"❌ Error binding to port %d: %@", currentPort, error);
// socket
[serverSocket close]; [serverSocket close];
serverSocket = nil; serverSocket = nil;
@ -107,7 +108,6 @@
if (![serverSocket beginReceiving:&error]) { if (![serverSocket beginReceiving:&error]) {
NSLog(@"❌ Error starting server (recv): %@", error); NSLog(@"❌ Error starting server (recv): %@", error);
// socket
[serverSocket close]; [serverSocket close];
serverSocket = nil; serverSocket = nil;
@ -115,10 +115,71 @@
return; return;
} }
restartAttempts = 0; // restartAttempts = 0;
NSLog(@"✅ UDP server started successfully on port %d", currentPort); NSLog(@"✅ UDP server started successfully on port %d", currentPort);
//
[self _startHealthCheck];
} }
// socket
- (void)_configureSocketOptions {
if (!serverSocket) return;
int fd = [serverSocket socketFD];
if (fd == -1) {
NSLog(@"⚠️ Invalid socket file descriptor");
return;
}
// 1. SO_REUSEADDR - ,TIME_WAIT
int reuseAddr = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)) == -1) {
NSLog(@"❌ Error setting SO_REUSEADDR: %s", strerror(errno));
}
// 2. SO_REUSEPORT - socket()
int reusePort = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reusePort, sizeof(reusePort)) == -1) {
NSLog(@"⚠️ SO_REUSEPORT not supported or error: %s", strerror(errno));
}
// 3. ,
int recvBufferSize = 256 * 1024; // 256KB
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvBufferSize, sizeof(recvBufferSize)) == -1) {
NSLog(@"⚠️ Failed to set receive buffer size: %s", strerror(errno));
} else {
//
socklen_t optlen = sizeof(recvBufferSize);
getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvBufferSize, &optlen);
NSLog(@"✅ Receive buffer size set to: %d bytes", recvBufferSize);
}
// 4.
int sendBufferSize = 256 * 1024; // 256KB
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendBufferSize, sizeof(sendBufferSize)) == -1) {
NSLog(@"⚠️ Failed to set send buffer size: %s", strerror(errno));
} else {
socklen_t optlen = sizeof(sendBufferSize);
getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendBufferSize, &optlen);
NSLog(@"✅ Send buffer size set to: %d bytes", sendBufferSize);
}
// 5. SO_NOSIGPIPE - socketSIGPIPE
#ifdef SO_NOSIGPIPE
int noSigpipe = 1;
if (setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &noSigpipe, sizeof(noSigpipe)) == -1) {
NSLog(@"⚠️ Failed to set SO_NOSIGPIPE: %s", strerror(errno));
}
#endif
// 6. (GCDAsyncUdpSocket,)
int flags = fcntl(fd, F_GETFL, 0);
if (flags != -1) {
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
}
- (void)stop { - (void)stop {
dispatch_async(serverQueue, ^{ dispatch_async(serverQueue, ^{
[self _stopInternal]; [self _stopInternal];
@ -126,20 +187,87 @@
} }
- (void)_stopInternal { - (void)_stopInternal {
NSLog(@"XS- Stopping UDP server on port %d", currentPort);
[self _cancelRestartTimer]; [self _cancelRestartTimer];
[self _stopHealthCheck];
if (serverSocket) { if (serverSocket) {
NSLog(@"Stopping UDP server on port %d", currentPort); // SO_LINGER0,,TIME_WAIT
int fd = [serverSocket socketFD];
if (fd != -1) {
struct linger lingerOption = {1, 0}; // l_onoff=1, l_linger=0
if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &lingerOption, sizeof(lingerOption)) == -1) {
NSLog(@"⚠️ Failed to set SO_LINGER: %s", strerror(errno));
}
}
//
if (!serverSocket.isClosed) { if (!serverSocket.isClosed) {
[serverSocket close]; [serverSocket close];
} }
serverSocket = nil; serverSocket = nil;
} }
[_pendingSends removeAllObjects];
} }
#pragma mark - Restart Logic with Backoff
#pragma mark - Health Check
//
- (void)_startHealthCheck {
dispatch_async(dispatch_get_main_queue(), ^{
if (self->healthCheckTimer) {
[self->healthCheckTimer invalidate];
}
self->healthCheckTimer = [NSTimer scheduledTimerWithTimeInterval:30.0
target:self
selector:@selector(_performHealthCheck)
userInfo:nil
repeats:YES];
});
}
- (void)_stopHealthCheck {
dispatch_async(dispatch_get_main_queue(), ^{
if (self->healthCheckTimer) {
[self->healthCheckTimer invalidate];
self->healthCheckTimer = nil;
}
});
}
- (void)_performHealthCheck {
dispatch_async(serverQueue, ^{
if (!self->serverSocket || self->serverSocket.isClosed) {
NSLog(@"⚠️ Health check failed: socket is closed");
[self _startInternal];
return;
}
// socket
int fd = [self->serverSocket socketFD];
if (fd == -1) {
NSLog(@"⚠️ Health check failed: invalid socket");
[self _startInternal];
return;
}
//
struct sockaddr_in addr;
socklen_t addrLen = sizeof(addr);
if (getsockname(fd, (struct sockaddr *)&addr, &addrLen) == -1) {
NSLog(@"⚠️ Health check failed: socket not bound");
[self _startInternal];
return;
}
NSLog(@"✅ Health check passed for port %d", self->currentPort);
});
}
#pragma mark - Restart Logic
- (void)_cancelRestartTimer { - (void)_cancelRestartTimer {
if (restartTimer) { if (restartTimer) {
@ -149,10 +277,8 @@
} }
- (void)_scheduleRestartWithBackoff { - (void)_scheduleRestartWithBackoff {
//
[self _cancelRestartTimer]; [self _cancelRestartTimer];
//
const NSUInteger maxAttempts = 10; const NSUInteger maxAttempts = 10;
if (restartAttempts >= maxAttempts) { if (restartAttempts >= maxAttempts) {
NSLog(@"❌ Maximum restart attempts (%lu) reached, giving up", NSLog(@"❌ Maximum restart attempts (%lu) reached, giving up",
@ -162,13 +288,11 @@
restartAttempts++; restartAttempts++;
// 退1s, 2s, 4s, 8s, 16s, 60s
NSTimeInterval delay = MIN(pow(2, restartAttempts - 1), 60.0); NSTimeInterval delay = MIN(pow(2, restartAttempts - 1), 60.0);
NSLog(@"⏰ Scheduling restart attempt %lu in %.1f seconds", NSLog(@"⏰ Scheduling restart attempt %lu in %.1f seconds",
(unsigned long)restartAttempts, delay); (unsigned long)restartAttempts, delay);
// 使 dispatch_source
restartTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, serverQueue); restartTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, serverQueue);
dispatch_source_set_timer(restartTimer, dispatch_source_set_timer(restartTimer,
@ -184,34 +308,53 @@
} }
- (void)_tryFallbackPorts { - (void)_tryFallbackPorts {
NSLog(@"🔍 Searching for available fallback port...");
for (uint16_t port = FALLBACK_PORT_START; port <= FALLBACK_PORT_END; port++) { for (uint16_t port = FALLBACK_PORT_START; port <= FALLBACK_PORT_END; port++) {
GCDAsyncUdpSocket *testSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:nil //
delegateQueue:serverQueue]; if ([self _isPortAvailable:port]) {
NSError *error = nil;
if ([testSocket bindToPort:port error:&error]) {
[testSocket close];
//
serverSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self
delegateQueue:serverQueue];
if ([serverSocket bindToPort:port error:&error] &&
[serverSocket beginReceiving:&error]) {
currentPort = port; currentPort = port;
restartAttempts = 0; NSLog(@"✅ Found available port: %d", port);
NSLog(@"✅ UDP server started on fallback port %d", currentPort); [self _startInternal];
return; return;
} }
} }
[testSocket close];
} NSLog(@"❌ No available fallback ports found in range %d-%d",
NSLog(@"❌ No available ports found"); FALLBACK_PORT_START, FALLBACK_PORT_END);
[self _scheduleRestartWithBackoff]; [self _scheduleRestartWithBackoff];
} }
// ()
- (BOOL)_isPortAvailable:(uint16_t)port {
int testSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (testSocket < 0) {
NSLog(@"⚠️ Cannot create test socket");
return NO;
}
// SO_REUSEADDR
int reuseAddr = 1;
setsockopt(testSocket, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr));
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
int result = bind(testSocket, (struct sockaddr *)&addr, sizeof(addr));
close(testSocket);
if (result == 0) {
return YES;
} else {
if (errno == EADDRINUSE) {
NSLog(@"⚠️ Port %d is in use", port);
}
return NO;
}
}
- (void)scheduleRestart { - (void)scheduleRestart {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)),
@ -220,62 +363,157 @@
}); });
} }
#pragma mark - GCDAsyncUdpSocket Delegate
// - (void)udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address {
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address NSLog(@"✅ Connected to client");
{
NSLog(@"已连接到用户:ip:%@",[[NSString alloc]initWithData:address encoding:NSUTF8StringEncoding]);
} }
-(void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext - (void)udpSocket:(GCDAsyncUdpSocket *)sock
{ didReceiveData:(NSData *)data
fromAddress:(NSData *)address
withFilterContext:(id)filterContext {
@autoreleasepool { @autoreleasepool {
// // ,
NSString *datastr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; if (data.length > 65507) { // UDP
if (!datastr) { NSLog(@"⚠️ Received oversized packet: %lu bytes", (unsigned long)data.length);
NSLog(@"Failed to decode received data");
return; return;
} }
NSLog(@"XS- UDP Request>>>> %@", datastr); NSString *datastr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (!datastr) {
NSLog(@"⚠️ Failed to decode received data (length: %lu)", (unsigned long)data.length);
return;
}
NSLog(@"📨 UDP Request from %@: %@",
[self _addressToString:address],
[datastr substringToIndex:MIN(100, datastr.length)]);
// ,
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UDPHandler *handle = [UDPHandler sharedInstance]; UDPHandler *handle = [UDPHandler sharedInstance];
NSString *res = [handle handle:datastr]; NSString *res = [handle handle:datastr];
if (res) { if (res) {
NSData *responseData = [res dataUsingEncoding:NSUTF8StringEncoding]; [self _sendResponse:res toAddress:address fromSocket:sock];
[sock sendData:responseData toAddress:address withTimeout:10.0 tag:300];
} }
});
} }
} }
// ()
- (void)_sendResponse:(NSString *)response
toAddress:(NSData *)address
fromSocket:(GCDAsyncUdpSocket *)sock {
dispatch_async(serverQueue, ^{
if (!sock || sock.isClosed) {
NSLog(@"⚠️ Cannot send response: socket is closed");
return;
}
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError * _Nullable)error NSData *responseData = [response dataUsingEncoding:NSUTF8StringEncoding];
{ if (!responseData) {
NSLog(@"didNotConnect:%@", error); NSLog(@"⚠️ Failed to encode response");
return;
}
//
if (responseData.length > 65507) {
NSLog(@"⚠️ Response too large: %lu bytes (max 65507)",
(unsigned long)responseData.length);
return;
}
long tag = ++self->_currentTag;
//
self->_pendingSends[@(tag)] = @{
@"response": response,
@"address": address,
@"timestamp": @([[NSDate date] timeIntervalSince1970])
};
NSLog(@"📤 Sending response (tag: %ld, size: %lu bytes)",
tag, (unsigned long)responseData.length);
[sock sendData:responseData
toAddress:address
withTimeout:SEND_TIMEOUT
tag:tag];
//
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((SEND_TIMEOUT + 1.0) * NSEC_PER_SEC)),
self->serverQueue, ^{
[self _checkSendTimeout:tag];
});
});
} }
//
- (void)_checkSendTimeout:(long)tag {
NSDictionary *pendingData = _pendingSends[@(tag)];
if (pendingData) {
NSTimeInterval timestamp = [pendingData[@"timestamp"] doubleValue];
NSTimeInterval elapsed = [[NSDate date] timeIntervalSince1970] - timestamp;
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag NSLog(@"⏱️ Send timeout for tag %ld (elapsed: %.1fs)", tag, elapsed);
{ [_pendingSends removeObjectForKey:@(tag)];
NSLog(@"didSendDataWithTag:%ld", tag); }
} }
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError *)error {
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError * _Nullable)error NSLog(@"❌ Did not connect: %@", error);
{
NSLog(@"didNotSendDataWithTag:%@", error);
} }
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag {
NSLog(@"✅ Data sent successfully (tag: %ld)", tag);
[_pendingSends removeObjectForKey:@(tag)];
}
- (void)udpSocket:(GCDAsyncUdpSocket *)sock
didNotSendDataWithTag:(long)tag
dueToError:(NSError *)error {
NSLog(@"❌ Failed to send data (tag: %ld): %@", tag, error);
[_pendingSends removeObjectForKey:@(tag)];
//
if (error.code == 55) { // ENOBUFS
NSLog(@"⚠️ Buffer full (ENOBUFS) - system may be overloaded");
} else if (error.code == 57) { // ENOTCONN
NSLog(@"⚠️ Socket disconnected (ENOTCONN)");
[self _startInternal];
} else if (error.code == 64) { // EHOSTDOWN
NSLog(@"⚠️ Host is down (EHOSTDOWN)");
} else if (error.code == 65) { // EHOSTUNREACH
NSLog(@"⚠️ Host unreachable (EHOSTUNREACH)");
}
}
- (void)udpSocketDidClose:(GCDAsyncUdpSocket *)sock withError:(NSError *)error {
NSLog(@"⚠️ Socket closed. Error: %@", error);
if (sock == serverSocket) {
serverSocket = nil;
}
- (void)udpSocketDidClose:(GCDAsyncUdpSocket *)sock withError:(NSError * _Nullable)error
{
NSLog(@"withError:%@", error);
if (error) { if (error) {
[self scheduleRestart]; // NSLog(@"❌ Unexpected closure, scheduling restart");
[self scheduleRestart];
} }
} }
#pragma mark - Utility Methods
//
- (NSString *)_addressToString:(NSData *)addressData {
struct sockaddr_in *addr = (struct sockaddr_in *)addressData.bytes;
char ipStr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &addr->sin_addr, ipStr, sizeof(ipStr));
return [NSString stringWithFormat:@"%s:%d", ipStr, ntohs(addr->sin_port)];
}
- (void)dealloc { - (void)dealloc {
[self _cancelRestartTimer]; [self _cancelRestartTimer];
[self _stopInternal]; [self _stopInternal];