Developer Area

root/apps/iphone/superbook/trunk/DotTel_SDK/Classes/DnsResolver.m @ 479

Revision 469, 9.5 kB (checked in by henri, 5 years ago)

Added debugging

Line 
1//
2//  DnsResolver.m
3//  DotTel SDK
4//
5//  Created by Henri Asseily on 9/14/08.
6/*
7 Copyright (c) 2008-2009, Telnic Ltd. All rights reserved.
8 
9 Redistribution and use in source and binary forms, with or without modification,
10 are permitted provided that the following conditions are met:
11 
12 Redistributions of source code must retain the above copyright notice, this list of conditions
13 and the following disclaimer. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the documentation and/or other
15 materials provided with the distribution.
16 Neither the name of the Telnic Ltd. nor the names of its contributors may be used to endorse or
17 promote products derived from this software without specific prior written permission.
18 THIS DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
19 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
24 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27//
28
29#import "DnsResolver.h"
30
31@interface DnsResolver (PrivateMethods)
32
33- (ldns_resolver *)createLdnsResolver;
34- (ldns_rr_list *)retrieveResourceRecordsOfType:(ldns_rr_type)rrType fromDomain:(NSString *)domain withError:(NSError **)error;
35
36@end
37
38@implementation DnsResolver
39
40- (id)init {
41        self = [super init];
42        res = [self createLdnsResolver];
43        return self;
44}
45
46- (void)dealloc {
47        ldns_resolver_deep_free(res);
48        [super dealloc];
49}
50
51- (NSUInteger)getNAPTRForTel:(NSString *)domain inArray:(NSMutableArray *)naptrArray withError:(NSError **)error {
52#ifdef DEBUG
53        NSLog(@"Domain %@: Retrieving NAPTR Records", domain);
54#endif
55        ldns_rr_list *naptrs = [self retrieveResourceRecordsOfType:LDNS_RR_TYPE_NAPTR fromDomain:domain withError:error];
56        if (!naptrs) {
57                return 0;
58        }
59       
60        NSDate *lookupDate = [[NSDate date] retain];
61        NSUInteger i;
62        NSUInteger count = ldns_rr_list_rr_count(naptrs);
63       
64        for (i = 0; i < count; i++) {
65                RecordNaptr *theRec = [RecordNaptr recordWithRr:ldns_rr_list_rr(naptrs, i) date:lookupDate];
66                if (theRec.isValid)
67                        [naptrArray addObject:theRec];
68        }
69       
70        [naptrArray sortUsingSelector:@selector(comparator:)];
71       
72        //[naptrArray sortUsingFunction:naptrSortFunction context:NULL];
73       
74        ldns_rr_list_deep_free(naptrs);
75        [lookupDate release];
76       
77        return count;
78       
79}
80
81// This method returns a header text as it parses the txt records
82- (NSString *)getTXTForTel:(NSString *)domain inArray:(NSMutableArray *)txtArray withError:(NSError **)error {
83       
84        NSMutableString *_headerText = nil;     
85       
86#ifdef DEBUG
87        NSLog(@"Domain %@: Retrieving TXT Records", domain);
88#endif
89        ldns_rr_list *txts = [self retrieveResourceRecordsOfType:LDNS_RR_TYPE_TXT fromDomain:domain withError:error];
90        if (!txts) {
91                return _headerText;
92        }
93       
94        NSDate *lookupDate = [[NSDate date] retain];
95        NSUInteger i;
96        NSUInteger count = ldns_rr_list_rr_count(txts);
97       
98        for (i = 0; i < count; i++) {
99                RecordTxt *theRec = [RecordTxt recordWithRr:ldns_rr_list_rr(txts, i) date:lookupDate];
100                if (theRec.isValid) {
101                        if ([theRec isHeader]) {
102                                if (!_headerText) {
103                                        _headerText = [NSMutableString stringWithString:theRec.textValue];
104                                } else {
105                                        //NSLog(theRec.textValue);
106                                        [_headerText appendFormat:@"\n %@", theRec.textValue];
107                                }
108                        } else {
109                                [txtArray addObject:theRec];
110                        }
111                }
112        }
113       
114        ldns_rr_list_deep_free(txts);
115        [lookupDate release];
116       
117        return _headerText;
118       
119}
120
121- (NSUInteger)getLOCForTel:(NSString *)domain inArray:(NSMutableArray *)locArray withError:(NSError **)error {
122       
123        // Note that there should only be ***ONE AND ONLY ONE*** LOC record per subdomain
124        // The DNS call gets them all, but we pick the first one (which is random and
125        // could be different on subsequent DNS calls)
126        // It's the responsibility of the caller to make sure the array is sent empty
127               
128#ifdef DEBUG
129        NSLog(@"Domain %@: Retrieving LOC Records", domain);
130#endif
131        ldns_rr_list *locs = [self retrieveResourceRecordsOfType:LDNS_RR_TYPE_LOC fromDomain:domain withError:error];
132        if (!locs) {
133                return 0;
134        }
135       
136        NSDate *lookupDate = [[NSDate date] retain];
137        NSUInteger count = ldns_rr_list_rr_count(locs);
138        RecordLoc *theRec = [RecordLoc recordWithRr:ldns_rr_list_rr(locs, 0) date:lookupDate];
139        if (theRec.isValid)
140                [locArray addObject:theRec];
141       
142        ldns_rr_list_deep_free(locs);
143        [lookupDate release];
144       
145        return count;
146       
147}
148
149
150#pragma mark ------------ private methods -------------------
151
152- (ldns_resolver *)createLdnsResolver {
153        ldns_resolver *resolver;
154        ldns_pkt *p;
155        ldns_status s;
156       
157        p = NULL;
158        resolver = NULL;
159       
160        /* create a new resolver from resolv.conf */
161        /* on the iphone we may not have a resolv.conf so we provide one */
162       
163        NSString *resolverFilePath = [[NSBundle mainBundle] pathForResource:@"resolv" ofType:@"conf"];
164       
165        s = ldns_resolver_new_frm_file(&resolver, [resolverFilePath cStringUsingEncoding:NSASCIIStringEncoding]);
166        if (s == LDNS_STATUS_OK) {
167#ifdef DEBUG
168                ldns_resolver_set_debug(resolver, TRUE);
169#endif
170                // Set ldns defaults. Here's how it'll work:
171               
172                ldns_resolver_set_usevc(resolver, TRUE);                        // use TCP by default for now. TODO: look at UDP behavior in GPRS/EDGE
173                ldns_resolver_set_edns_udp_size(resolver, 4096);        // with a 4k max packet size when in UDP EDNS0
174                ldns_resolver_set_fallback(resolver, TRUE);                     // fallback to EDNS0 UDP, and then to TCP
175                ldns_resolver_set_fail(resolver, FALSE);                        // do not allow to fail to next nameserver
176                ldns_resolver_set_retry(resolver, 4);                           // Max number of retries
177                ldns_resolver_set_retrans(resolver, 2);                         // Seconds between retries
178                return resolver;
179        } else {
180                return NULL;
181        }
182}
183
184- (ldns_rr_list *)retrieveResourceRecordsOfType:(ldns_rr_type)rrType fromDomain:(NSString *)domain withError:(NSError **)error {
185       
186        ldns_rr_list *rrlist;   
187        ldns_rdf *ldnsdomain = ldns_dname_new_frm_str([domain UTF8String]);
188        NSError *err2; 
189        NSDictionary *dict;
190       
191        if (!ldnsdomain) {
192#ifdef DEBUG
193                NSLog(@"Domain %@: Can't do ldns_dname_new_frm_str", domain);
194#endif
195                dict = [NSDictionary dictionaryWithObject:NSLocalizedString(@"DNS Error: Can't parse resolver name", @"DNS Error resolver parsing") forKey:NSLocalizedDescriptionKey];
196                err2 = [NSError errorWithDomain:@"org.telnic.tel.sdk" code:RESOLVER_STATUS_NO_NAME userInfo:dict];
197                if (error)
198                        *error = err2;
199                return NULL;
200        }
201       
202        ldns_pkt *p;
203       
204//      @synchronized([self class]) {
205                       
206        p = ldns_resolver_query(res,
207                                                        ldnsdomain,
208                                                        rrType,
209                                                        LDNS_RR_CLASS_IN,
210                                                        LDNS_RD);
211
212        ldns_rdf_free(ldnsdomain);
213
214        // Have to play the switch game to encapsulate everything in one potentially synchronized block, with one return statement
215        switch (1) {
216                case 1: // always check for existence of p
217                        if (!p)  {
218#ifdef DEBUG
219                                NSLog(@"Domain %@: Can't do ldns_resolver_query (rr type %d)", domain, rrType);
220#endif
221                                dict = [NSDictionary dictionaryWithObject:NSLocalizedString(@"Network Error: No Internet Connection", @"Network error, no net connect") forKey:NSLocalizedDescriptionKey];
222                                err2 = [NSError errorWithDomain:@"org.telnic.tel.sdk" code:RESOLVER_STATUS_NO_CONNECTION userInfo:dict];
223                                if (error)
224                                        *error = err2;
225                                // recreate a resolver for later
226                                ldns_resolver_deep_free(res);
227                                res = [self createLdnsResolver];
228                                rrlist = NULL;
229                                break;
230                        }
231                case 2: // p exists, check for existence of rrlist answer
232                        /* retrieve the records from the answer section of that
233                         * packet
234                         */
235                        rrlist = ldns_pkt_rr_list_by_type(p,
236                                                                                          rrType,
237                                                                                          LDNS_SECTION_ANSWER);
238                        if (!rrlist) {
239#ifdef DEBUG
240                                NSLog(@"Domain %@: invalid answer name after query (rr type %d)", domain, rrType);
241#endif
242                                if (ldns_pkt_get_rcode(p) == LDNS_RCODE_NXDOMAIN) {
243                                        dict = [NSDictionary dictionaryWithObject:NSLocalizedString(@"Domain does not exist", @"Non-existent domain") forKey:NSLocalizedDescriptionKey];
244                                        err2 = [NSError errorWithDomain:@"org.telnic.tel.sdk" code:RESOLVER_STATUS_NXDOMAIN userInfo:dict];
245                                } else {
246                                        dict = [NSDictionary dictionaryWithObject:NSLocalizedString(@"Data Error: Invalid answer", @"Data Error: Invalid answer") forKey:NSLocalizedDescriptionKey];
247                                        err2 = [NSError errorWithDomain:@"org.telnic.tel.sdk" code:RESOLVER_STATUS_INVALID_ANSWER userInfo:dict];
248                                }
249                                if (error)
250                                        *error = err2;
251                                rrlist = NULL;
252                                ldns_pkt_free(p);
253                                break;
254                        }
255                case 3: // rrlist exists, make sure it's ok
256                        @try {
257                                ldns_rr_list_rr_count(rrlist);
258                        }
259                        @catch (NSException * e) {
260#ifdef DEBUG
261                                NSLog(@"Domain %@: ldns_rr_list_rr_count exception caught! (rr type %d)", domain, rrType);
262#endif
263                                // Exception is caught if there's no data in the rrlist,
264                                // i.e. if there are no records. That's BAD.
265                                // TODO: See in ldns rr.c source why ldns_rr_list_rr_count() fails and doesn't return 0
266                                // In the meantime, disable the error
267                               
268//                              dict = [NSDictionary dictionaryWithObject:NSLocalizedString(@"Network Error: Bad data returned", @"Network Error: Bad data returned") forKey:NSLocalizedDescriptionKey];
269//                              err2 = [NSError errorWithDomain:@"org.telnic.tel.sdk" code:RESOLVER_STATUS_BAD_DATA userInfo:dict];
270//                              if (error)
271//                                      *error = err2;
272                                rrlist = NULL;
273                        }
274                        ldns_pkt_free(p);                       
275                        break;
276                default:
277                        break;
278        }
279//      } // end @synchronized
280               
281        return rrlist;
282}
283
284@end
Note: See TracBrowser for help on using the browser.
Telnic
Search This Site
Partners
Neustar
ICANN
Main site | WHOIS | Sell .tel | FAQ | Archived Site | About Telnic | Contact Us