Fix XMPPSRVEnumerator by rewriting almost all of it.
This commit is contained in:
parent
5b9eb619d3
commit
18ec0d947b
4 changed files with 323 additions and 177 deletions
|
@ -123,13 +123,21 @@
|
||||||
path = ObjXMPPTests;
|
path = ObjXMPPTests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
4BC559851337A65400E345C7 = {
|
4B484502138BD3A400EB48A5 /* Libraries */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
4B484500138BBEEB00EB48A5 /* libresolv.dylib */,
|
4B484500138BBEEB00EB48A5 /* libresolv.dylib */,
|
||||||
|
);
|
||||||
|
name = Libraries;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
4BC559851337A65400E345C7 = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
4BC5599A1337A65400E345C7 /* ObjXMPP */,
|
4BC5599A1337A65400E345C7 /* ObjXMPP */,
|
||||||
4B1295E41337BD2D00154B25 /* ObjXMPPTests */,
|
4B1295E41337BD2D00154B25 /* ObjXMPPTests */,
|
||||||
4BC559931337A65400E345C7 /* Frameworks */,
|
4BC559931337A65400E345C7 /* Frameworks */,
|
||||||
|
4B484502138BD3A400EB48A5 /* Libraries */,
|
||||||
4BC559921337A65400E345C7 /* Products */,
|
4BC559921337A65400E345C7 /* Products */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
|
@ -201,6 +201,8 @@
|
||||||
[XMPPSRVEnumerator enumeratorWithDomain: server];
|
[XMPPSRVEnumerator enumeratorWithDomain: server];
|
||||||
XMPPSRVEntry *candidate;
|
XMPPSRVEntry *candidate;
|
||||||
|
|
||||||
|
[SRVEnumerator lookUpEntries];
|
||||||
|
|
||||||
while ((candidate = [SRVEnumerator nextObject]) != nil) {
|
while ((candidate = [SRVEnumerator nextObject]) != nil) {
|
||||||
@try {
|
@try {
|
||||||
[sock connectToHost: [candidate target]
|
[sock connectToHost: [candidate target]
|
||||||
|
|
|
@ -21,49 +21,61 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <arpa/nameser.h>
|
#include <arpa/nameser.h>
|
||||||
|
#include <resolv.h>
|
||||||
|
|
||||||
#import <ObjFW/ObjFW.h>
|
#import <ObjFW/ObjFW.h>
|
||||||
|
|
||||||
@interface XMPPSRVEntry: OFObject
|
@interface XMPPSRVEntry: OFObject
|
||||||
{
|
{
|
||||||
uint16_t priority;
|
uint16_t priority;
|
||||||
uint16_t weight;
|
uint16_t weight, accumulatedWeight;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
OFString *target;
|
OFString *target;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef OF_HAVE_PROPERTIES
|
#ifdef OF_HAVE_PROPERTIES
|
||||||
@property uint16_t priority;
|
@property (readonly, assign) uint16_t priority;
|
||||||
@property uint16_t weight;
|
@property (readonly, assign) uint16_t weight;
|
||||||
@property uint16_t port;
|
@property (assign) uint16_t accumulatedWeight;
|
||||||
@property (copy) OFString *target;
|
@property (readonly, assign) uint16_t port;
|
||||||
|
@property (readonly, copy) OFString *target;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
- (void) setPriority: (uint16_t)priority_;
|
+ 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)priority;
|
||||||
- (void) setWeight: (uint16_t)weight_;
|
|
||||||
- (uint16_t)weight;
|
- (uint16_t)weight;
|
||||||
- (void) setPort: (uint16_t)port_;
|
|
||||||
- (uint16_t)port;
|
- (uint16_t)port;
|
||||||
- (void) setTarget: (OFString*)target_;
|
|
||||||
- (OFString*)target;
|
- (OFString*)target;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface XMPPSRVEnumerator: OFEnumerator <OFFastEnumeration>
|
@interface XMPPSRVEnumerator: OFEnumerator
|
||||||
{
|
{
|
||||||
OFString *domain;
|
OFString *domain;
|
||||||
OFList *priorityList;
|
struct __res_state resState;
|
||||||
|
OFList *list;
|
||||||
|
of_list_object_t *listIter;
|
||||||
|
OFList *subListCopy;
|
||||||
|
BOOL done;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef OF_HAVE_PROPERTIES
|
#ifdef OF_HAVE_PROPERTIES
|
||||||
@property (copy) OFString *domain;
|
@property (readonly, copy) OFString *domain;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
+ enumeratorWithDomain: (OFString*)domain;
|
+ enumeratorWithDomain: (OFString*)domain;
|
||||||
|
|
||||||
- initWithDomain: (OFString*)domain;
|
- initWithDomain: (OFString*)domain;
|
||||||
- (void) setDomain: (OFString*)domain;
|
|
||||||
- (OFString*)domain;
|
- (OFString*)domain;
|
||||||
- (void)XMPP_parseSRVRRWithHandle: (const ns_msg)handle
|
- (void)lookUpEntries;
|
||||||
RR: (const ns_rr)rr
|
- (void)XMPP_addEntry: (XMPPSRVEntry*)item;
|
||||||
result: (XMPPSRVEntry*)result;
|
|
||||||
- (void)XMPP_addSRVEntry: (XMPPSRVEntry*)item
|
|
||||||
toSortedPriorityList: (OFList*)list;
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
/*
|
/*
|
||||||
|
* Copyright (c) 2011, Jonathan Schleifer <js@webkeks.org>
|
||||||
* Copyright (c) 2011, Florian Zeitz <florob@babelmonkeys.de>
|
* Copyright (c) 2011, Florian Zeitz <florob@babelmonkeys.de>
|
||||||
*
|
*
|
||||||
* https://webkeks.org/hg/objxmpp/
|
* https://webkeks.org/hg/objxmpp/
|
||||||
|
@ -19,17 +20,93 @@
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <resolv.h>
|
#include <resolv.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#import "XMPPSRVEnumerator.h"
|
#import "XMPPSRVEnumerator.h"
|
||||||
|
|
||||||
@implementation XMPPSRVEntry
|
@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
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
[target release];
|
[target release];
|
||||||
|
@ -39,15 +116,10 @@
|
||||||
|
|
||||||
- (OFString*)description
|
- (OFString*)description
|
||||||
{
|
{
|
||||||
return [OFString stringWithFormat: @"priority: %" PRIu16
|
return [OFString stringWithFormat: @"<%@ priority: %" PRIu16
|
||||||
@" weight: %" PRIu16
|
@", weight: %" PRIu16
|
||||||
@" target: %@:%" PRIu16, priority, weight,
|
@", target: %@:%" PRIu16 @">",
|
||||||
target, port];
|
isa, priority, weight, target, port];
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setPriority: (uint16_t)priority_
|
|
||||||
{
|
|
||||||
priority = priority_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (uint16_t)priority
|
- (uint16_t)priority
|
||||||
|
@ -55,19 +127,19 @@
|
||||||
return priority;
|
return priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setWeight: (uint16_t)weight_
|
|
||||||
{
|
|
||||||
weight = weight_;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (uint16_t)weight
|
- (uint16_t)weight
|
||||||
{
|
{
|
||||||
return weight;
|
return weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setPort: (uint16_t)port_
|
- (void)setAccumulatedWeight: (uint16_t)accumulatedWeight_
|
||||||
{
|
{
|
||||||
port = port_;
|
accumulatedWeight = accumulatedWeight_;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (uint16_t)accumulatedWeight
|
||||||
|
{
|
||||||
|
return accumulatedWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (uint16_t)port
|
- (uint16_t)port
|
||||||
|
@ -75,16 +147,9 @@
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setTarget: (OFString*)target_
|
|
||||||
{
|
|
||||||
OFString *old = target;
|
|
||||||
target = [target_ copy];
|
|
||||||
[old release];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (OFString*)target
|
- (OFString*)target
|
||||||
{
|
{
|
||||||
return [[target copy] autorelease];
|
OF_GETTER(target, YES)
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -97,164 +162,223 @@
|
||||||
- initWithDomain: (OFString*)domain_
|
- initWithDomain: (OFString*)domain_
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
priorityList = [[OFList alloc] init];
|
|
||||||
[self setDomain: domain_];
|
@try {
|
||||||
|
list = [[OFList alloc] init];
|
||||||
|
domain = [domain_ copy];
|
||||||
|
} @catch (id e) {
|
||||||
|
[self release];
|
||||||
|
@throw e;
|
||||||
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
[priorityList release];
|
[list release];
|
||||||
[domain release];
|
[domain release];
|
||||||
|
[subListCopy release];
|
||||||
|
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setDomain: (OFString*)domain_
|
|
||||||
{
|
|
||||||
OFString *old = domain;
|
|
||||||
domain = [domain_ copy];
|
|
||||||
[old release];
|
|
||||||
[self reset];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (OFString*)domain;
|
- (OFString*)domain;
|
||||||
{
|
{
|
||||||
return [[domain copy] autorelease];
|
OF_GETTER(domain, YES)
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)XMPP_parseSRVRRWithHandle: (const ns_msg)handle
|
- (void)lookUpEntries
|
||||||
RR: (const ns_rr)rr
|
|
||||||
result: (XMPPSRVEntry*)result
|
|
||||||
{
|
{
|
||||||
const uint16_t *rdata = (uint16_t*) ns_rr_rdata(rr);
|
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||||
char target[NS_MAXDNAME];
|
unsigned char *answer = NULL;
|
||||||
[result setPriority: ntohs(rdata[0])];
|
OFString *request;
|
||||||
[result setWeight: ntohs(rdata[1])];
|
|
||||||
[result setPort: ntohs(rdata[2])];
|
request = [OFString stringWithFormat: @"_xmpp-client._tcp.%@", domain];
|
||||||
dn_expand(ns_msg_base(handle), ns_msg_end(handle),
|
|
||||||
(uint8_t*) &rdata[3], target, NS_MAXDNAME);
|
@try {
|
||||||
[result setTarget: [OFString stringWithCString: target]];
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No list with the priority -> create one at the correct place */
|
||||||
|
for (iter = [list firstListObject]; iter != NULL; iter = iter->next) {
|
||||||
|
if ([[iter->object firstObject] priority] > [entry priority]) {
|
||||||
|
OFAutoreleasePool *pool;
|
||||||
|
|
||||||
|
pool = [[OFAutoreleasePool alloc] init];
|
||||||
|
|
||||||
|
subList = [OFList list];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RFC 2782 says those with weight 0 should be at the
|
||||||
|
* beginning of the list.
|
||||||
|
*/
|
||||||
|
if ([entry weight] > 0)
|
||||||
|
[subList appendObject: entry];
|
||||||
|
else
|
||||||
|
[subList prependObject: entry];
|
||||||
|
|
||||||
|
[list insertObject: subList
|
||||||
|
beforeListObject: iter];
|
||||||
|
|
||||||
|
[pool release];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There is no list with a bigger priority -> append */
|
||||||
|
pool = [[OFAutoreleasePool alloc] init];
|
||||||
|
|
||||||
|
subList = [OFList list];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RFC 2782 says those with weight 0 should be at the beginning of the
|
||||||
|
* list.
|
||||||
|
*/
|
||||||
|
if ([entry weight] > 0)
|
||||||
|
[subList appendObject: entry];
|
||||||
|
else
|
||||||
|
[subList prependObject: entry];
|
||||||
|
|
||||||
|
[list appendObject: subList];
|
||||||
|
|
||||||
|
[pool release];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)nextObject
|
- (id)nextObject
|
||||||
{
|
{
|
||||||
if ([priorityList firstListObject]) {
|
|
||||||
uint16_t weight = 0;
|
|
||||||
of_list_object_t *iter;
|
|
||||||
XMPPSRVEntry *ret;
|
XMPPSRVEntry *ret;
|
||||||
OFList *weightList = [priorityList firstObject];
|
of_list_object_t *iter;
|
||||||
uint16_t maximumWeight = [[weightList lastObject] weight];
|
uint32_t totalWeight = 0;
|
||||||
|
BOOL found = NO;
|
||||||
if (maximumWeight) {
|
|
||||||
RAND_pseudo_bytes((unsigned char *)&weight, 2);
|
|
||||||
weight %= maximumWeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
iter = [weightList firstListObject];
|
|
||||||
while (iter) {
|
|
||||||
if (weight <= [iter->object weight]) {
|
|
||||||
ret = [iter->object retain];
|
|
||||||
[weightList removeListObject: iter];
|
|
||||||
if (![weightList firstListObject])
|
|
||||||
[priorityList removeListObject:
|
|
||||||
[priorityList firstListObject]];
|
|
||||||
return [ret autorelease];
|
|
||||||
}
|
|
||||||
iter = iter->next;
|
|
||||||
}
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (done)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
|
if (listIter == NULL)
|
||||||
|
listIter = [list lastListObject];
|
||||||
|
|
||||||
|
if (listIter == NULL)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
if (subListCopy == nil)
|
||||||
|
subListCopy = [listIter->object copy];
|
||||||
|
|
||||||
|
/* FIXME: Handle empty subListCopy */
|
||||||
|
for (iter = [subListCopy firstListObject]; iter != NULL;
|
||||||
|
iter = iter->next) {
|
||||||
|
totalWeight += [iter->object weight];
|
||||||
|
[iter->object setAccumulatedWeight: totalWeight];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t*)state
|
while (!found) {
|
||||||
objects: (id*)objects
|
uint32_t randomWeight;
|
||||||
count: (int)count
|
|
||||||
{
|
RAND_pseudo_bytes((uint8_t*)&randomWeight, sizeof(uint32_t));
|
||||||
int len = 0;
|
randomWeight %= (totalWeight + 1);
|
||||||
XMPPSRVEntry *entry = [self nextObject];
|
|
||||||
state->itemsPtr = objects;
|
for (iter = [subListCopy firstListObject]; iter != NULL;
|
||||||
while ((len < count) && entry) {
|
iter = iter->next) {
|
||||||
state->mutationsPtr = (unsigned long *)self;
|
if ([iter->object accumulatedWeight] >= randomWeight) {
|
||||||
objects[len++] = entry;
|
ret = [[iter->object retain] autorelease];
|
||||||
entry = [self nextObject];
|
|
||||||
|
[subListCopy removeListObject: iter];
|
||||||
|
|
||||||
|
found = YES;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return len;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([subListCopy count] == 0) {
|
||||||
|
[subListCopy release];
|
||||||
|
subListCopy = nil;
|
||||||
|
|
||||||
|
listIter = listIter->previous;
|
||||||
|
|
||||||
|
if (listIter == NULL)
|
||||||
|
done = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)reset
|
- (void)reset
|
||||||
{
|
{
|
||||||
int i, rrCount;
|
listIter = NULL;
|
||||||
unsigned char *answer;
|
[subListCopy release];
|
||||||
OFString *request;
|
subListCopy = nil;
|
||||||
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
done = NO;
|
||||||
|
|
||||||
request = [OFString stringWithFormat: @"_xmpp-client._tcp.%@", domain];
|
|
||||||
answer = [self allocMemoryWithSize: NS_MAXMSG];
|
|
||||||
|
|
||||||
res_ninit(&_res);
|
|
||||||
if (!(res_nsearch(&_res, [request cString], ns_c_in, ns_t_srv, answer,
|
|
||||||
NS_MAXMSG) < 0)) {
|
|
||||||
ns_rr rr;
|
|
||||||
ns_msg handle;
|
|
||||||
|
|
||||||
ns_initparse(answer, NS_MAXMSG, &handle);
|
|
||||||
rrCount = ns_msg_count(handle, ns_s_an);
|
|
||||||
for (i = 0; i < rrCount ; i++) {
|
|
||||||
XMPPSRVEntry *result = [[XMPPSRVEntry alloc] init];
|
|
||||||
ns_parserr(&handle, ns_s_an, i, &rr);
|
|
||||||
if ((ns_rr_type(rr) != ns_t_srv)
|
|
||||||
|| ns_rr_class(rr) != ns_c_in)
|
|
||||||
@throw [OFInvalidServerReplyException
|
|
||||||
newWithClass: isa];
|
|
||||||
|
|
||||||
[self XMPP_parseSRVRRWithHandle: handle
|
|
||||||
RR: rr
|
|
||||||
result: result];
|
|
||||||
|
|
||||||
[self XMPP_addSRVEntry: result
|
|
||||||
toSortedPriorityList: priorityList];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[self freeMemory: answer];
|
|
||||||
[pool release];
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)XMPP_addSRVEntry: (XMPPSRVEntry*)item
|
|
||||||
toSortedPriorityList: (OFList*)list
|
|
||||||
{
|
|
||||||
of_list_object_t *priorityIter =
|
|
||||||
[list firstListObject];
|
|
||||||
while (1) {
|
|
||||||
if (priorityIter == NULL ||
|
|
||||||
[[priorityIter->object firstObject]
|
|
||||||
priority] > [item priority]) {
|
|
||||||
OFList *newList = [OFList list];
|
|
||||||
[newList appendObject: item];
|
|
||||||
if (priorityIter)
|
|
||||||
[list insertObject: newList
|
|
||||||
beforeListObject: priorityIter];
|
|
||||||
else
|
|
||||||
[list appendObject: newList];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ([[priorityIter->object firstObject] priority]
|
|
||||||
== [item priority]) {
|
|
||||||
if ([item weight] == 0)
|
|
||||||
[priorityIter->object prependObject: item];
|
|
||||||
else {
|
|
||||||
[item setWeight: [item weight] +
|
|
||||||
[[priorityIter->object lastObject] weight]];
|
|
||||||
[priorityIter->object appendObject: item];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
priorityIter = priorityIter->next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue