/** * Purple */ #import "PurpDNSRequest.h" #import "PurpLog.h" @implementation PurpDNSRequest static NSMutableDictionary * g_threads = nil; + (void)initialize { [super initialize]; g_threads = [[NSMutableDictionary alloc] init]; } + (PurpDNSRequest *)lookupRequestForData:(PurpleDnsQueryData *)query_data { return [g_threads objectForKey:[NSValue valueWithPointer:query_data]]; } - (id)initWithData:(PurpleDnsQueryData *)data resolvedCB:(PurpleDnsQueryResolvedCallback)resolved failedCB:(PurpleDnsQueryFailedCallback)failed { if (self = [super init]) { query_data = data; resolved_cb = resolved; failed_cb = failed; success = FALSE; errorNumber = 0; cancel = FALSE; [g_threads setObject:self forKey:[NSValue valueWithPointer:query_data]]; [self retain]; [NSThread detachNewThreadSelector:@selector(startLookup:) toTarget:self withObject:nil ]; return self; } return nil; } - (void)startLookup:(id)sender { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; struct addrinfo hints, * res; char servname[20]; LOG( @"Performing DNS resolve: %s:%d", purple_dnsquery_get_host(query_data), purple_dnsquery_get_port(query_data) ); g_snprintf(servname, sizeof(servname), "%d", purple_dnsquery_get_port(query_data) ); memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; errorNumber = getaddrinfo(purple_dnsquery_get_host(query_data), servname, &hints, &res ); if (errorNumber == 0) { success = TRUE; } else { success = FALSE; } [self performSelectorOnMainThread:@selector(lookupComplete:) withObject:(success ? [NSValue valueWithPointer:res] : nil) waitUntilDone:NO ]; [pool drain]; } - (void)lookupComplete:(NSValue *)resValue { if (cancel) { // ... } else if (success && resValue) { LOG( @"DNS resolve complete for %s:%d", purple_dnsquery_get_host(query_data), purple_dnsquery_get_port(query_data) ); struct addrinfo *res, *tmp; GSList *returnData = NULL; res = [resValue pointerValue]; tmp = res; while (res) { size_t addrlen = res->ai_addrlen; struct sockaddr *addr = g_malloc(addrlen); memcpy(addr, res->ai_addr, addrlen); returnData = g_slist_append(returnData, GINT_TO_POINTER(addrlen)); returnData = g_slist_append(returnData, addr); res = res->ai_next; } freeaddrinfo(tmp); resolved_cb(query_data, returnData); } else { char message[1024]; g_snprintf(message, sizeof(message), _("Error resolving %s:\n%s"), purple_dnsquery_get_host(query_data), gai_strerror(errorNumber) ); failed_cb(query_data, message); } [self autorelease]; if (query_data) { [g_threads removeObjectForKey:[NSValue valueWithPointer:query_data]]; } } - (void)cancel { cancel = TRUE; [g_threads removeObjectForKey:[NSValue valueWithPointer:query_data]]; query_data = 0; } @end