From dded8a90e80c785e1adf7b4b6de28cbe4ff38d15 Mon Sep 17 00:00:00 2001 From: rfm Date: Wed, 28 May 2025 12:40:57 +0100 Subject: [PATCH] Make code more efficient and andd diagnostics --- Source/NSHost.m | 215 +++++++++++++++++++++++++------------ Tests/base/NSHost/create.m | 22 +++- 2 files changed, 168 insertions(+), 69 deletions(-) diff --git a/Source/NSHost.m b/Source/NSHost.m index 8ab882915..1a2b51189 100644 --- a/Source/NSHost.m +++ b/Source/NSHost.m @@ -52,7 +52,7 @@ extern int WSAAPI inet_pton(int , const char *, void *); #endif /* !_WIN32 */ // Temporary hack ... dusable new code because it seems to break CI -#undef HAVE_RESOLV_H +//#undef HAVE_RESOLV_H #if defined(HAVE_RESOLV_H) #include @@ -75,12 +75,35 @@ static BOOL _hostCacheEnabled = YES; static NSMutableDictionary *_hostCache = nil; static id null = nil; - /* * Max hostname length in line with RFC 1123 */ #define GSMAXHOSTNAMELEN 255 +static BOOL +isName(const char *n) +{ + if (NULL == n + || (isdigit(n[0]) && sscanf(n, "%*d.%*d.%*d.%*d") == 4) + || 0 != strchr(n, ':')) + { + return NO; + } + return YES; +} + +static const char * +getName(NSString *str) +{ + const char *n = [str UTF8String]; + + if (isName(n)) + { + return n; + } + return NULL; +} + /** * Return the current host name ... may change if we are using dhcp etc */ @@ -195,6 +218,74 @@ myHostName() #if defined(HAVE_GETADDRINFO) && defined(HAVE_RESOLV_H) +static unsigned +getCNames(NSString *host, NSMutableSet *cnames) +{ + unsigned char response[NS_PACKETSZ]; + extern int h_errno; + const char *name; + unsigned added = 0; + int len; + + if ([cnames member: host] != nil) + { + return 0; + } + if (NULL == (name = getName(host))) + { + return 0; + } + + /* Perform DNS query for CNAME records so that we can get + * any name pointed to by this one. + */ + len = res_query(name, ns_c_in, ns_t_cname, response, sizeof(response)); + if (len < 0) + { + if (h_errno != NO_DATA) + { + herror(name); + } + } + else + { + ns_msg msg; + int count; + int i; + + ns_initparse(response, len, &msg); + count = ns_msg_count(msg, ns_s_an); + for (i = 0; i < count; i++) + { + ns_rr rr; + + ns_parserr(&msg, ns_s_an, i, &rr); + + // Check if the record is a CNAME + if (ns_rr_type(rr) == ns_t_cname) + { + char cname[NS_MAXDNAME]; + + if (ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg), + ns_rr_rdata(rr), cname, sizeof(cname)) < 0) + { + fprintf(stderr, "Failed to uncompress CNAME\n"); + continue; + } + NSDebugFLLog(@"NSHost", @"res_query for '%@' found '%s'", + host, cname); + [cnames addObject: [NSString stringWithUTF8String: cname]]; + added++; + } + } + } + if (0 == added) + { + NSDebugFLLog(@"NSHost", @"res_query for '%@' found no CNAMEs", host); + } + return added; +} + - (id) _initWithKey: (NSString*)key { ENTER_POOL @@ -205,6 +296,7 @@ myHostName() struct addrinfo hints; struct addrinfo *tmp; int err; + BOOL keyIsName; memset(&hints, '\0', sizeof(hints)); hints.ai_flags = AI_CANONNAME; @@ -214,12 +306,19 @@ myHostName() { [addresses unionSet: [hostClass _localAddresses]]; ptr = "localhost"; + keyIsName = NO; + } + else + { + getCNames(key, names); + ptr = [key UTF8String]; + keyIsName = isName(ptr); } err = getaddrinfo(ptr, 0, &hints, &entry); if (err) { - fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(err)); + fprintf(stderr, "getaddrinfo '%s' failed: %s\n", ptr, gai_strerror(err)); entry = NULL; } for (tmp = entry; tmp != NULL; tmp = tmp->ai_next) @@ -227,6 +326,7 @@ myHostName() char ipstr[INET6_ADDRSTRLEN]; char host[NI_MAXHOST]; void *addr; + NSString *a; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wcast-align" @@ -246,85 +346,71 @@ myHostName() } #pragma clang diagnostic pop inet_ntop(tmp->ai_family, addr, ipstr, sizeof(ipstr)); - [addresses addObject: [NSString stringWithUTF8String: ipstr]]; - - /* Possibly a reverse lookup of the address will give us a different - * result to our key (if the key was an address or an alias) so we - * might be able to get a new name for the host. - */ - if (getnameinfo(tmp->ai_addr, tmp->ai_addrlen, host, sizeof(host), - NULL, 0, NI_NAMEREQD) == 0) + a = [NSString stringWithUTF8String: ipstr]; + if (nil == [addresses member: a]) { - [names addObject: [NSString stringWithUTF8String: host]]; - } + [addresses addObject: a]; - /* If we have a conaonical name for the host, use it. - */ - if (tmp->ai_canonname && *tmp->ai_canonname) - { - unsigned char response[NS_PACKETSZ]; - extern int h_errno; - ns_msg msg; - int count; - int len; - int i; - NSString *n; - - n = [NSString stringWithUTF8String: tmp->ai_canonname]; - [names addObject: n]; - - /* Perform DNS query for CNAME records so that we can get - * any name pointed to by this one. - */ - len = res_query(tmp->ai_canonname, ns_c_in, ns_t_cname, - response, sizeof(response)); - if (len < 0) + /* Possibly a reverse lookup of the address will give us a different + * result to our key (if the key was an address or an alias) so we + * might be able to get a new name for the host. + */ + if (getnameinfo(tmp->ai_addr, tmp->ai_addrlen, host, sizeof(host), + NULL, 0, NI_NAMEREQD) == 0) { - if (h_errno != NO_DATA) + NSString *n = [NSString stringWithUTF8String: host]; + + NSDebugMLog(@"NSHost", @"getnameinfo for '%s' found '%s'", + ipstr, host); + if (nil == [names member: n]) { - herror("res_query"); + [names addObject: n]; + getCNames(n, names); } - continue; + } + else + { + NSDebugMLog(@"NSHost", @"getnameinfo for '%s' found nothing", + ipstr); + *host = '\0'; } - ns_initparse(response, len, &msg); - count = ns_msg_count(msg, ns_s_an); - for (i = 0; i < count; i++) + /* If we have a canonical name for the host, use it. + */ + if (tmp->ai_canonname && *tmp->ai_canonname + && strcmp(tmp->ai_canonname, host) != 0) { - ns_rr rr; + NSString *n = [NSString stringWithUTF8String: tmp->ai_canonname]; - ns_parserr(&msg, ns_s_an, i, &rr); - - // Check if the record is a CNAME - if (ns_rr_type(rr) == ns_t_cname) + if (nil == [names member: n]) { - char cname[NS_MAXDNAME]; - - if (ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg), - ns_rr_rdata(rr), cname, sizeof(cname)) < 0) - { - fprintf(stderr, "Failed to uncompress CNAME\n"); - continue; - } - [names addObject: [NSString stringWithUTF8String: cname]]; + [names addObject: n]; + getCNames(n, names); } } } } if (entry) { - if (nil == [addresses member: key]) - { - /* The key was not an address ... so it must be a host name - */ - [names addObject: key]; - } freeaddrinfo(entry); } if ([names count] || [addresses count]) { - _names = [names copy]; _addresses = [addresses copy]; + if (keyIsName) + { + [names addObject: key]; + } + if ([names count]) + { + _names = [names copy]; + } + else + { + /* No names, so we duplicate addresses as names + */ + _names = [_addresses copy]; + } } else { @@ -490,7 +576,6 @@ myHostName() + (NSHost*) hostWithName: (NSString*)name { NSHost *host = nil; - const char *n; if (name == nil) { @@ -506,9 +591,7 @@ myHostName() /* If this looks like an address rather than a host name ... * call the correct method instead of this one. */ - n = [name UTF8String]; - if ((isdigit(n[0]) && sscanf(n, "%*d.%*d.%*d.%*d") == 4) - || 0 != strchr(n, ':')) + if (NULL == getName(name)) { return [self hostWithAddress: name]; } @@ -536,7 +619,7 @@ myHostName() { struct hostent *h; - h = gethostbyname((char*)n); + h = gethostbyname((char*)[name UTF8String]); if (0 == h) { if ([name isEqualToString: myHostName()] == YES) diff --git a/Tests/base/NSHost/create.m b/Tests/base/NSHost/create.m index 8041b4ab8..1f6975cc8 100644 --- a/Tests/base/NSHost/create.m +++ b/Tests/base/NSHost/create.m @@ -6,35 +6,51 @@ int main() { NSAutoreleasePool *arp = [NSAutoreleasePool new]; + NSString *s; NSHost *current; NSHost *localh; NSHost *tmp; + tmp = [NSHost hostWithName: @"www.w3.org"]; + PASS(tmp != nil, "NSHost gets www.w3.org"); + NSLog(@"www.w3.org is %@", tmp); + + tmp = [NSHost hostWithName: @"www.gnustep.org"]; + PASS(tmp != nil, "NSHost gets www.gnustep.org"); + NSLog(@"www.gnustep.org is %@", tmp); + current = [NSHost currentHost]; PASS(current != nil && [current isKindOfClass: [NSHost class]], "NSHost understands +currentHost"); + NSLog(@"+currentHost is %@", current); #if defined(GNUSTEP_BASE_LIBRARY) localh = [NSHost localHost]; PASS(localh != nil && [localh isKindOfClass: [NSHost class]], "NSHost understands +localHost"); - NSLog(@"localHost: %@", localh); + NSLog(@"+localHost is %@", localh); #else localh = current; #endif tmp = [NSHost hostWithName: @"::1"]; PASS([[tmp address] isEqual: @"::1"], "+hostWithName: works for IPV6 addr"); + NSLog(@"::1 is %@", tmp); - tmp = [NSHost hostWithName: [current name]]; + s = [current name]; + tmp = [NSHost hostWithName: s]; PASS([tmp isEqualToHost: current], "NSHost understands +hostWithName:"); + NSLog(@"+hostWithName: %@ is %@", s, tmp); - tmp = [NSHost hostWithAddress: [current address]]; + s = [current address]; + tmp = [NSHost hostWithAddress: s]; PASS([tmp isEqualToHost: current], "NSHost understands +hostWithAddress:"); + NSLog(@"+hostWithAddress: %@ is %@", s, tmp); tmp = [NSHost hostWithName: @"127.0.0.1"]; PASS(tmp != nil && [tmp isEqualToHost: localh], "NSHost understands [+hostWithName: 127.0.0.1]"); + NSLog(@"127.0.0.1 is %@", tmp); [arp release]; arp = nil; return 0;