Index: ObjXMPP.xcodeproj/project.pbxproj ================================================================== --- ObjXMPP.xcodeproj/project.pbxproj +++ ObjXMPP.xcodeproj/project.pbxproj @@ -9,12 +9,12 @@ /* Begin PBXBuildFile section */ 4B01D020137C7E7D005624EA /* namespaces.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B01D01F137C7E7D005624EA /* namespaces.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B1295EF1337BD5F00154B25 /* test.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B1295EE1337BD5F00154B25 /* test.m */; }; 4B1295F11337C37E00154B25 /* ObjXMPP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC559911337A65400E345C7 /* ObjXMPP.framework */; }; 4B1295F21337C3CF00154B25 /* ObjFW.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC559D61337ABD300E345C7 /* ObjFW.framework */; }; - 4B4844F5138BBC7500EB48A5 /* XMPPSRVEnumerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B4844F3138BBC7400EB48A5 /* XMPPSRVEnumerator.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4B4844F6138BBC7500EB48A5 /* XMPPSRVEnumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B4844F4138BBC7500EB48A5 /* XMPPSRVEnumerator.m */; }; + 4B4844F5138BBC7500EB48A5 /* XMPPSRVLookup.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B4844F3138BBC7400EB48A5 /* XMPPSRVLookup.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4B4844F6138BBC7500EB48A5 /* XMPPSRVLookup.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B4844F4138BBC7500EB48A5 /* XMPPSRVLookup.m */; }; 4B484501138BBEEB00EB48A5 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B484500138BBEEB00EB48A5 /* libresolv.dylib */; }; 4BC559D71337ABD300E345C7 /* ObjFW.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC559D61337ABD300E345C7 /* ObjFW.framework */; }; 4BC559EC1337AC0900E345C7 /* XMPPAuthenticator.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BC559DA1337AC0900E345C7 /* XMPPAuthenticator.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BC559ED1337AC0900E345C7 /* XMPPAuthenticator.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BC559DB1337AC0900E345C7 /* XMPPAuthenticator.m */; }; 4BC559EE1337AC0900E345C7 /* XMPPConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BC559DC1337AC0900E345C7 /* XMPPConnection.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -57,12 +57,12 @@ /* Begin PBXFileReference section */ 4B01D01C137C7D6E005624EA /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = src/Makefile; sourceTree = SOURCE_ROOT; }; 4B01D01F137C7E7D005624EA /* namespaces.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = namespaces.h; path = src/namespaces.h; sourceTree = SOURCE_ROOT; }; 4B1295E01337BD2D00154B25 /* ObjXMPPTests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ObjXMPPTests; sourceTree = BUILT_PRODUCTS_DIR; }; 4B1295EE1337BD5F00154B25 /* test.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = test.m; path = tests/test.m; sourceTree = SOURCE_ROOT; }; - 4B4844F3138BBC7400EB48A5 /* XMPPSRVEnumerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XMPPSRVEnumerator.h; path = src/XMPPSRVEnumerator.h; sourceTree = SOURCE_ROOT; }; - 4B4844F4138BBC7500EB48A5 /* XMPPSRVEnumerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = XMPPSRVEnumerator.m; path = src/XMPPSRVEnumerator.m; sourceTree = SOURCE_ROOT; }; + 4B4844F3138BBC7400EB48A5 /* XMPPSRVLookup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XMPPSRVLookup.h; path = src/XMPPSRVLookup.h; sourceTree = SOURCE_ROOT; }; + 4B4844F4138BBC7500EB48A5 /* XMPPSRVLookup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = XMPPSRVLookup.m; path = src/XMPPSRVLookup.m; sourceTree = SOURCE_ROOT; }; 4B484500138BBEEB00EB48A5 /* libresolv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libresolv.dylib; path = usr/lib/libresolv.dylib; sourceTree = SDKROOT; }; 4BC559911337A65400E345C7 /* ObjXMPP.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ObjXMPP.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4BC559D61337ABD300E345C7 /* ObjFW.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjFW.framework; path = ../../../../Library/Frameworks/ObjFW.framework; sourceTree = ""; }; 4BC559DA1337AC0900E345C7 /* XMPPAuthenticator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XMPPAuthenticator.h; path = src/XMPPAuthenticator.h; sourceTree = SOURCE_ROOT; }; 4BC559DB1337AC0900E345C7 /* XMPPAuthenticator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = XMPPAuthenticator.m; path = src/XMPPAuthenticator.m; sourceTree = SOURCE_ROOT; }; @@ -184,12 +184,12 @@ 4BDEF8061340B240000156D1 /* XMPPRoster.m */, 4BD9BF57134003F700DAB43A /* XMPPRosterItem.h */, 4BD9BF58134003F700DAB43A /* XMPPRosterItem.m */, 4BC559EA1337AC0900E345C7 /* XMPPSCRAMAuth.h */, 4BC559FD1337AC1800E345C7 /* XMPPSCRAMAuth.m */, - 4B4844F3138BBC7400EB48A5 /* XMPPSRVEnumerator.h */, - 4B4844F4138BBC7500EB48A5 /* XMPPSRVEnumerator.m */, + 4B4844F3138BBC7400EB48A5 /* XMPPSRVLookup.h */, + 4B4844F4138BBC7500EB48A5 /* XMPPSRVLookup.m */, 4BC559FE1337AC1800E345C7 /* XMPPStanza.h */, 4BC559FF1337AC1800E345C7 /* XMPPStanza.m */, 4B01D01F137C7E7D005624EA /* namespaces.h */, ); path = ObjXMPP; @@ -220,11 +220,11 @@ 4BC559F81337AC0900E345C7 /* XMPPPLAINAuth.h in Headers */, 4BC559FA1337AC0900E345C7 /* XMPPPresence.h in Headers */, 4BDEF8071340B240000156D1 /* XMPPRoster.h in Headers */, 4BD9BF59134003F700DAB43A /* XMPPRosterItem.h in Headers */, 4BC559FC1337AC0900E345C7 /* XMPPSCRAMAuth.h in Headers */, - 4B4844F5138BBC7500EB48A5 /* XMPPSRVEnumerator.h in Headers */, + 4B4844F5138BBC7500EB48A5 /* XMPPSRVLookup.h in Headers */, 4BC55A011337AC1800E345C7 /* XMPPStanza.h in Headers */, 4B01D020137C7E7D005624EA /* namespaces.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -322,11 +322,11 @@ 4BC559FB1337AC0900E345C7 /* XMPPPresence.m in Sources */, 4BC55A001337AC1800E345C7 /* XMPPSCRAMAuth.m in Sources */, 4BC55A021337AC1800E345C7 /* XMPPStanza.m in Sources */, 4BD9BF5A134003F700DAB43A /* XMPPRosterItem.m in Sources */, 4BDEF8081340B240000156D1 /* XMPPRoster.m in Sources */, - 4B4844F6138BBC7500EB48A5 /* XMPPSRVEnumerator.m in Sources */, + 4B4844F6138BBC7500EB48A5 /* XMPPSRVLookup.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -14,15 +14,15 @@ XMPPPLAINAuth.m \ XMPPPresence.m \ XMPPRoster.m \ XMPPRosterItem.m \ XMPPSCRAMAuth.m \ - XMPPSRVEnumerator.m \ + XMPPSRVLookup.m \ XMPPStanza.m INCLUDES = ${SRCS:.m=.h} \ namespaces.h \ ObjXMPP.h include ../buildsys.mk LD = ${OBJC} Index: src/XMPPConnection.m ================================================================== --- src/XMPPConnection.m +++ src/XMPPConnection.m @@ -29,11 +29,11 @@ #include #import #import "XMPPConnection.h" -#import "XMPPSRVEnumerator.h" +#import "XMPPSRVLookup.h" #import "XMPPSCRAMAuth.h" #import "XMPPPLAINAuth.h" #import "XMPPStanza.h" #import "XMPPJID.h" #import "XMPPIQ.h" @@ -195,17 +195,15 @@ } - (void)connect { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - XMPPSRVEnumerator *SRVEnumerator = - [XMPPSRVEnumerator enumeratorWithDomain: server]; + XMPPSRVLookup *SRVLookup = [XMPPSRVLookup lookupWithDomain: server]; + OFEnumerator *enumerator = [SRVLookup objectEnumerator]; XMPPSRVEntry *candidate; - [SRVEnumerator lookUpEntries]; - - while ((candidate = [SRVEnumerator nextObject]) != nil) { + while ((candidate = [enumerator nextObject]) != nil) { @try { [sock connectToHost: [candidate target] onPort: [candidate port]]; break; } @catch (OFAddressTranslationFailedException *e) { DELETED src/XMPPSRVEnumerator.h Index: src/XMPPSRVEnumerator.h ================================================================== --- src/XMPPSRVEnumerator.h +++ src/XMPPSRVEnumerator.h @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2011, Florian Zeitz - * - * https://webkeks.org/hg/objxmpp/ - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include - -#import - -@interface XMPPSRVEntry: OFObject -{ - uint16_t priority; - uint16_t weight; - uint32_t accumulatedWeight; - uint16_t port; - OFString *target; -} - -#ifdef OF_HAVE_PROPERTIES -@property (readonly, assign) uint16_t priority; -@property (readonly, assign) uint16_t weight; -@property (assign) uint32_t accumulatedWeight; -@property (readonly, assign) uint16_t port; -@property (readonly, copy) OFString *target; -#endif - -+ entryWithPriority: (uint16_t)priority - weight: (uint16_t)weight - port: (uint16_t)port - target: (OFString*)target; -+ entryWithResourceRecord: (ns_rr)resourceRecord - handle: (ns_msg)handle; -- initWithPriority: (uint16_t)priority - weight: (uint16_t)weight - port: (uint16_t)port - target: (OFString*)target; -- initWithResourceRecord: (ns_rr)resourceRecord - handle: (ns_msg)handle; -- (uint16_t)priority; -- (uint16_t)weight; -- (uint32_t)accumulatedWeight; -- (void)setAccumulatedWeight: (uint32_t)accumulatedWeight; -- (uint16_t)port; -- (OFString*)target; -@end - -@interface XMPPSRVEnumerator: OFEnumerator -{ - OFString *domain; - struct __res_state resState; - OFList *list; - of_list_object_t *listIter; - OFList *subListCopy; - BOOL done; -} - -#ifdef OF_HAVE_PROPERTIES -@property (readonly, copy) OFString *domain; -#endif - -+ enumeratorWithDomain: (OFString*)domain; -- initWithDomain: (OFString*)domain; -- (OFString*)domain; -- (void)lookUpEntries; -- (void)XMPP_addEntry: (XMPPSRVEntry*)item; -@end DELETED src/XMPPSRVEnumerator.m Index: src/XMPPSRVEnumerator.m ================================================================== --- src/XMPPSRVEnumerator.m +++ src/XMPPSRVEnumerator.m @@ -1,349 +0,0 @@ -/* - * Copyright (c) 2011, Jonathan Schleifer - * Copyright (c) 2011, Florian Zeitz - * - * https://webkeks.org/hg/objxmpp/ - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include - -#import "XMPPSRVEnumerator.h" - -@implementation XMPPSRVEntry -+ entryWithPriority: (uint16_t)priority - weight: (uint16_t)weight - port: (uint16_t)port - target: (OFString*)target -{ - return [[[self alloc] initWithPriority: priority - weight: weight - port: port - target: target] autorelease]; -} - -+ entryWithResourceRecord: (ns_rr)resourceRecord - handle: (ns_msg)handle -{ - return [[[self alloc] initWithResourceRecord: resourceRecord - handle: handle] autorelease]; -} - -- init -{ - Class c = isa; - [self release]; - @throw [OFNotImplementedException newWithClass: c - selector: _cmd]; -} - -- initWithPriority: (uint16_t)priority_ - weight: (uint16_t)weight_ - port: (uint16_t)port_ - target: (OFString*)target_ -{ - self = [super init]; - - @try { - priority = priority_; - weight = weight_; - port = port_; - target = [target_ copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- initWithResourceRecord: (ns_rr)resourceRecord - handle: (ns_msg)handle -{ - self = [super init]; - - @try { - const uint16_t *rdata; - char buffer[NS_MAXDNAME]; - - rdata = (const uint16_t*)(void*)ns_rr_rdata(resourceRecord); - priority = ntohs(rdata[0]); - weight = ntohs(rdata[1]); - port = ntohs(rdata[2]); - - if (dn_expand(ns_msg_base(handle), ns_msg_end(handle), - (uint8_t*)&rdata[3], buffer, NS_MAXDNAME) < 1) - @throw [OFInitializationFailedException - newWithClass: isa]; - - target = [[OFString alloc] initWithCString: buffer]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [target release]; - - [super dealloc]; -} - -- (OFString*)description -{ - return [OFString stringWithFormat: @"<%@ priority: %" PRIu16 - @", weight: %" PRIu16 - @", target: %@:%" PRIu16 @">", - isa, priority, weight, target, port]; -} - -- (uint16_t)priority -{ - return priority; -} - -- (uint16_t)weight -{ - return weight; -} - -- (void)setAccumulatedWeight: (uint32_t)accumulatedWeight_ -{ - accumulatedWeight = accumulatedWeight_; -} - -- (uint32_t)accumulatedWeight -{ - return accumulatedWeight; -} - -- (uint16_t)port -{ - return port; -} - -- (OFString*)target -{ - OF_GETTER(target, YES) -} -@end - -@implementation XMPPSRVEnumerator -+ enumeratorWithDomain: (OFString*)domain_ -{ - return [[[self alloc] initWithDomain: domain_] autorelease]; -} - -- initWithDomain: (OFString*)domain_ -{ - self = [super init]; - - @try { - list = [[OFList alloc] init]; - domain = [domain_ copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [list release]; - [domain release]; - [subListCopy release]; - - [super dealloc]; -} - -- (OFString*)domain; -{ - OF_GETTER(domain, YES) -} - -- (void)lookUpEntries -{ - OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - unsigned char *answer = NULL; - OFString *request; - - request = [OFString stringWithFormat: @"_xmpp-client._tcp.%@", domain]; - - @try { - int answerLen, resourceRecordCount, i; - ns_rr resourceRecord; - ns_msg handle; - - if (res_ninit(&resState)) - @throw [OFAddressTranslationFailedException - newWithClass: isa - socket: nil - host: domain]; - - answer = [self allocMemoryWithSize: of_pagesize]; - answerLen = res_nsearch(&resState, [request cString], ns_c_in, - ns_t_srv, answer, (int)of_pagesize); - - if (answerLen < 1 || answerLen > of_pagesize) - @throw [OFAddressTranslationFailedException - newWithClass: isa - socket: nil - host: domain]; - - if (ns_initparse(answer, answerLen, &handle)) - @throw [OFAddressTranslationFailedException - newWithClass: isa - socket: nil - host: domain]; - - resourceRecordCount = ns_msg_count(handle, ns_s_an); - for (i = 0; i < resourceRecordCount; i++) { - if (ns_parserr(&handle, ns_s_an, i, &resourceRecord)) - continue; - - if (ns_rr_type(resourceRecord) != ns_t_srv || - ns_rr_class(resourceRecord) != ns_c_in) - continue; - - [self XMPP_addEntry: [XMPPSRVEntry - entryWithResourceRecord: resourceRecord - handle: handle]]; - } - } @finally { - [self freeMemory: answer]; - res_ndestroy(&resState); - } - - [pool release]; -} - -- (void)XMPP_addEntry: (XMPPSRVEntry*)entry -{ - OFAutoreleasePool *pool; - OFList *subList; - of_list_object_t *iter; - - /* Look if there already is a list with the priority */ - for (iter = [list firstListObject]; iter != NULL; iter = iter->next) { - if ([[iter->object firstObject] priority] == [entry priority]) { - /* - * RFC 2782 says those with weight 0 should be at the - * beginning of the list. - */ - if ([entry weight] > 0) - [iter->object appendObject: entry]; - else - [iter->object prependObject: entry]; - - return; - } - - /* We can't have one if the priority is already bigger */ - if ([[iter->object firstObject] priority] > [entry priority]) - break; - } - - pool = [[OFAutoreleasePool alloc] init]; - - subList = [OFList list]; - [subList appendObject: entry]; - - if (iter != NULL) - [list insertObject: subList - beforeListObject: iter]; - else - [list appendObject: subList]; - - [pool release]; -} - -- (id)nextObject -{ - XMPPSRVEntry *ret; - of_list_object_t *iter; - uint32_t totalWeight = 0; - - if (done) - return nil; - - if (listIter == NULL) - listIter = [list firstListObject]; - - if (listIter == NULL) - return nil; - - if (subListCopy == nil) - subListCopy = [listIter->object copy]; - - for (iter = [subListCopy firstListObject]; iter != NULL; - iter = iter->next) { - totalWeight += [iter->object weight]; - [iter->object setAccumulatedWeight: totalWeight]; - } - - if ([subListCopy count] > 0) { - uint32_t randomWeight; - - RAND_pseudo_bytes((uint8_t*)&randomWeight, sizeof(uint32_t)); - randomWeight %= (totalWeight + 1); - - for (iter = [subListCopy firstListObject]; iter != NULL; - iter = iter->next) { - if ([iter->object accumulatedWeight] >= randomWeight) { - ret = [[iter->object retain] autorelease]; - - [subListCopy removeListObject: iter]; - - break; - } - } - } - - if ([subListCopy count] == 0) { - [subListCopy release]; - subListCopy = nil; - - listIter = listIter->next; - - if (listIter == NULL) - done = YES; - } - - return ret; -} - -- (void)reset -{ - listIter = NULL; - [subListCopy release]; - subListCopy = nil; - done = NO; -} -@end ADDED src/XMPPSRVLookup.h Index: src/XMPPSRVLookup.h ================================================================== --- src/XMPPSRVLookup.h +++ src/XMPPSRVLookup.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2011, Florian Zeitz + * + * https://webkeks.org/hg/objxmpp/ + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#import + +@interface XMPPSRVEntry: OFObject +{ + uint16_t priority; + uint16_t weight; + uint32_t accumulatedWeight; + uint16_t port; + OFString *target; +} + +#ifdef OF_HAVE_PROPERTIES +@property (readonly, assign) uint16_t priority; +@property (readonly, assign) uint16_t weight; +@property (assign) uint32_t accumulatedWeight; +@property (readonly, assign) uint16_t port; +@property (readonly, copy) OFString *target; +#endif + ++ entryWithPriority: (uint16_t)priority + weight: (uint16_t)weight + port: (uint16_t)port + target: (OFString*)target; ++ entryWithResourceRecord: (ns_rr)resourceRecord + handle: (ns_msg)handle; +- initWithPriority: (uint16_t)priority + weight: (uint16_t)weight + port: (uint16_t)port + target: (OFString*)target; +- initWithResourceRecord: (ns_rr)resourceRecord + handle: (ns_msg)handle; +- (uint16_t)priority; +- (uint16_t)weight; +- (uint32_t)accumulatedWeight; +- (void)setAccumulatedWeight: (uint32_t)accumulatedWeight; +- (uint16_t)port; +- (OFString*)target; +@end + +@interface XMPPSRVLookup: OFObject +{ + OFString *domain; + struct __res_state resState; + OFList *list; +} + +#ifdef OF_HAVE_PROPERTIES +@property (readonly, copy) OFString *domain; +#endif + ++ lookupWithDomain: (OFString*)domain; +- initWithDomain: (OFString*)domain; +- (void)XMPP_lookup; +- (void)XMPP_addEntry: (XMPPSRVEntry*)item; +@end + +@interface XMPPSRVEnumerator: OFEnumerator +{ + OFList *list; + of_list_object_t *listIter; + OFList *subListCopy; + BOOL done; +} + +- initWithList: (OFList*)list; +@end ADDED src/XMPPSRVLookup.m Index: src/XMPPSRVLookup.m ================================================================== --- src/XMPPSRVLookup.m +++ src/XMPPSRVLookup.m @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2011, Jonathan Schleifer + * Copyright (c) 2011, Florian Zeitz + * + * https://webkeks.org/hg/objxmpp/ + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#import "XMPPSRVLookup.h" + +@implementation XMPPSRVEntry ++ entryWithPriority: (uint16_t)priority + weight: (uint16_t)weight + port: (uint16_t)port + target: (OFString*)target +{ + return [[[self alloc] initWithPriority: priority + weight: weight + port: port + target: target] autorelease]; +} + ++ entryWithResourceRecord: (ns_rr)resourceRecord + handle: (ns_msg)handle +{ + return [[[self alloc] initWithResourceRecord: resourceRecord + handle: handle] autorelease]; +} + +- init +{ + Class c = isa; + [self release]; + @throw [OFNotImplementedException newWithClass: c + selector: _cmd]; +} + +- initWithPriority: (uint16_t)priority_ + weight: (uint16_t)weight_ + port: (uint16_t)port_ + target: (OFString*)target_ +{ + self = [super init]; + + @try { + priority = priority_; + weight = weight_; + port = port_; + target = [target_ copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- initWithResourceRecord: (ns_rr)resourceRecord + handle: (ns_msg)handle +{ + self = [super init]; + + @try { + const uint16_t *rdata; + char buffer[NS_MAXDNAME]; + + rdata = (const uint16_t*)(void*)ns_rr_rdata(resourceRecord); + priority = ntohs(rdata[0]); + weight = ntohs(rdata[1]); + port = ntohs(rdata[2]); + + if (dn_expand(ns_msg_base(handle), ns_msg_end(handle), + (uint8_t*)&rdata[3], buffer, NS_MAXDNAME) < 1) + @throw [OFInitializationFailedException + newWithClass: isa]; + + target = [[OFString alloc] initWithCString: buffer]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [target release]; + + [super dealloc]; +} + +- (OFString*)description +{ + return [OFString stringWithFormat: @"<%@ priority: %" PRIu16 + @", weight: %" PRIu16 + @", target: %@:%" PRIu16 @">", + isa, priority, weight, target, port]; +} + +- (uint16_t)priority +{ + return priority; +} + +- (uint16_t)weight +{ + return weight; +} + +- (void)setAccumulatedWeight: (uint32_t)accumulatedWeight_ +{ + accumulatedWeight = accumulatedWeight_; +} + +- (uint32_t)accumulatedWeight +{ + return accumulatedWeight; +} + +- (uint16_t)port +{ + return port; +} + +- (OFString*)target +{ + OF_GETTER(target, YES) +} +@end + +@implementation XMPPSRVLookup ++ lookupWithDomain: (OFString*)domain +{ + return [[[self alloc] initWithDomain: domain] autorelease]; +} + +- initWithDomain: (OFString*)domain_ +{ + self = [super init]; + + @try { + list = [[OFList alloc] init]; + domain = [domain_ copy]; + + [self XMPP_lookup]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [list release]; + [domain release]; + + [super dealloc]; +} + +- (OFString*)domain; +{ + OF_GETTER(domain, YES) +} + +- (void)XMPP_lookup +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + unsigned char *answer = NULL; + OFString *request; + + request = [OFString stringWithFormat: @"_xmpp-client._tcp.%@", domain]; + + @try { + int answerLen, resourceRecordCount, i; + ns_rr resourceRecord; + ns_msg handle; + + if (res_ninit(&resState)) + @throw [OFAddressTranslationFailedException + newWithClass: isa + socket: nil + host: domain]; + + answer = [self allocMemoryWithSize: of_pagesize]; + answerLen = res_nsearch(&resState, [request cString], ns_c_in, + ns_t_srv, answer, (int)of_pagesize); + + if (answerLen < 1 || answerLen > of_pagesize) + @throw [OFAddressTranslationFailedException + newWithClass: isa + socket: nil + host: domain]; + + if (ns_initparse(answer, answerLen, &handle)) + @throw [OFAddressTranslationFailedException + newWithClass: isa + socket: nil + host: domain]; + + resourceRecordCount = ns_msg_count(handle, ns_s_an); + for (i = 0; i < resourceRecordCount; i++) { + if (ns_parserr(&handle, ns_s_an, i, &resourceRecord)) + continue; + + if (ns_rr_type(resourceRecord) != ns_t_srv || + ns_rr_class(resourceRecord) != ns_c_in) + continue; + + [self XMPP_addEntry: [XMPPSRVEntry + entryWithResourceRecord: resourceRecord + handle: handle]]; + } + } @finally { + [self freeMemory: answer]; + res_ndestroy(&resState); + } + + [pool release]; +} + +- (void)XMPP_addEntry: (XMPPSRVEntry*)entry +{ + OFAutoreleasePool *pool; + OFList *subList; + of_list_object_t *iter; + + /* Look if there already is a list with the priority */ + for (iter = [list firstListObject]; iter != NULL; iter = iter->next) { + if ([[iter->object firstObject] priority] == [entry priority]) { + /* + * RFC 2782 says those with weight 0 should be at the + * beginning of the list. + */ + if ([entry weight] > 0) + [iter->object appendObject: entry]; + else + [iter->object prependObject: entry]; + + return; + } + + /* We can't have one if the priority is already bigger */ + if ([[iter->object firstObject] priority] > [entry priority]) + break; + } + + pool = [[OFAutoreleasePool alloc] init]; + + subList = [OFList list]; + [subList appendObject: entry]; + + if (iter != NULL) + [list insertObject: subList + beforeListObject: iter]; + else + [list appendObject: subList]; + + [pool release]; +} + +- (OFEnumerator*)objectEnumerator +{ + return [[[XMPPSRVEnumerator alloc] initWithList: list] autorelease]; +} +@end + +@implementation XMPPSRVEnumerator +- initWithList: (OFList*)list_ +{ + self = [super init]; + + @try { + list = [list_ copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (id)nextObject +{ + XMPPSRVEntry *ret; + of_list_object_t *iter; + uint32_t totalWeight = 0; + + if (done) + return nil; + + if (listIter == NULL) + listIter = [list firstListObject]; + + if (listIter == NULL) + return nil; + + if (subListCopy == nil) + subListCopy = [listIter->object copy]; + + for (iter = [subListCopy firstListObject]; iter != NULL; + iter = iter->next) { + totalWeight += [iter->object weight]; + [iter->object setAccumulatedWeight: totalWeight]; + } + + if ([subListCopy count] > 0) { + uint32_t randomWeight; + + RAND_pseudo_bytes((uint8_t*)&randomWeight, sizeof(uint32_t)); + randomWeight %= (totalWeight + 1); + + for (iter = [subListCopy firstListObject]; iter != NULL; + iter = iter->next) { + if ([iter->object accumulatedWeight] >= randomWeight) { + ret = [[iter->object retain] autorelease]; + + [subListCopy removeListObject: iter]; + + break; + } + } + } + + if ([subListCopy count] == 0) { + [subListCopy release]; + subListCopy = nil; + + listIter = listIter->next; + + if (listIter == NULL) + done = YES; + } + + return ret; +} + +- (void)reset +{ + listIter = NULL; + [subListCopy release]; + subListCopy = nil; + done = NO; +} +@end