Remove dependency on libresolv

This commit is contained in:
Jonathan Schleifer 2018-11-05 01:14:15 +01:00
parent 3c10a522cd
commit d6f82eb3d5
No known key found for this signature in database
GPG key ID: D83A76BFE376345E
7 changed files with 111 additions and 649 deletions

View file

@ -48,49 +48,6 @@ AS_IF([test x"$enable_static" = x"yes" -o x"$enable_shared" = x"no"], [
AC_SUBST(OBJXMPP_STATIC_LIB, "libobjxmpp.a") AC_SUBST(OBJXMPP_STATIC_LIB, "libobjxmpp.a")
]) ])
# This is an adapted version of what glib does for res_query
# It should recognize the correct library on (at least) Linux,
# NetBSD, FreeBSD, Mac OS X and Haiku
AC_MSG_CHECKING([for res_nsearch])
AC_TRY_LINK([#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>],
[res_nsearch(&_res, "test", 0, 0, (void *)0, 0);],
[AC_MSG_RESULT([yes])],
[save_libs="$LIBS"
LIBS="$LIBS -lresolv"
AC_TRY_LINK([#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>],
[res_nsearch(&_res, "test", 0, 0, (void *)0, 0);],
[AC_MSG_RESULT([in -lresolv])],
[LIBS="$save_libs -lnetwork"
AC_TRY_LINK([#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>],
[res_nsearch(&_res, "test", 0, 0, (void *)0, 0);],
[AC_MSG_RESULT([in -lnetwork])],
[LIBS="$save_libs -lbind"
AC_TRY_LINK([#include <resolv.h>],
[res_nsearch(&_res, "test", 0, 0, (void *)0, 0);],
[AC_MSG_RESULT([in -lbind])],
[AC_MSG_ERROR(not found)])])])])
AC_MSG_CHECKING([for res_ndestroy])
AC_TRY_LINK([
#include <resolv.h>
], [
res_ndestroy(&_res)
], [
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_RES_NDESTROY, 1, [Whether we have res_ndestroy])
], [
AC_MSG_RESULT(no)
])
AC_CHECK_LIB(objopenssl, main, [ AC_CHECK_LIB(objopenssl, main, [
AC_SUBST(OBJOPENSSL_LIBS, "-lobjopenssl -lcrypto") AC_SUBST(OBJOPENSSL_LIBS, "-lobjopenssl -lcrypto")
AC_SUBST(OBJOPENSSL_FRAMEWORK_LIBS, "-framework ObjOpenSSL -lcrypto") AC_SUBST(OBJOPENSSL_FRAMEWORK_LIBS, "-framework ObjOpenSSL -lcrypto")

View file

@ -26,7 +26,6 @@ SRCS = XMPPAuthenticator.m \
XMPPRoster.m \ XMPPRoster.m \
XMPPRosterItem.m \ XMPPRosterItem.m \
XMPPSCRAMAuth.m \ XMPPSCRAMAuth.m \
XMPPSRVLookup.m \
XMPPStanza.m \ XMPPStanza.m \
XMPPStreamManagement.m \ XMPPStreamManagement.m \
XMPPXMLElementBuilder.m XMPPXMLElementBuilder.m

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2010, 2011, 2012, 2013, 2016 * Copyright (c) 2010, 2011, 2012, 2013, 2016, 2017, 2018
* Jonathan Schleifer <js@heap.zone> * Jonathan Schleifer <js@heap.zone>
* Copyright (c) 2011, 2012, Florian Zeitz <florob@babelmonkeys.de> * Copyright (c) 2011, 2012, Florian Zeitz <florob@babelmonkeys.de>
* *
@ -116,9 +116,6 @@ OF_ASSUME_NONNULL_BEGIN
/*! /*!
* @brief This callback is called when the connection threw an exception. * @brief This callback is called when the connection threw an exception.
* *
* This is only called for connections on which
* @ref XMPPConnection::handleConnection has been called.
*
* @param connection The connection which threw an exception * @param connection The connection which threw an exception
* @param exception The exception the connection threw * @param exception The exception the connection threw
*/ */
@ -272,11 +269,6 @@ OF_ASSUME_NONNULL_BEGIN
*/ */
- (void)removeDelegate: (id <XMPPConnectionDelegate>)delegate; - (void)removeDelegate: (id <XMPPConnectionDelegate>)delegate;
/*!
* @brief Connects to the XMPP service.
*/
- (void)connect;
/*! /*!
* @brief Closes the stream to the XMPP service * @brief Closes the stream to the XMPP service
*/ */
@ -295,15 +287,9 @@ OF_ASSUME_NONNULL_BEGIN
(OFString *__autoreleasing _Nonnull *_Nullable)reason; (OFString *__autoreleasing _Nonnull *_Nullable)reason;
/*! /*!
* @brief Adds the connection to the run loop. * @brief Asynchronously connects to the server.
*/ */
- (void)handleConnection; - (void)asyncConnect;
/*!
* @brief Asynchronously connects to the server and adds the connection to the
* run loop.
*/
- (void)asyncConnectAndHandle;
/*! /*!
* @brief Parses the specified buffer. * @brief Parses the specified buffer.

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2010, 2011, 2012, 2013, 2015, 2016 * Copyright (c) 2010, 2011, 2012, 2013, 2015, 2016, 2017, 2018
* Jonathan Schleifer <js@heap.zone> * Jonathan Schleifer <js@heap.zone>
* Copyright (c) 2011, 2012, Florian Zeitz <florob@babelmonkeys.de> * Copyright (c) 2011, 2012, Florian Zeitz <florob@babelmonkeys.de>
* *
@ -41,7 +41,6 @@
#import "XMPPConnection.h" #import "XMPPConnection.h"
#import "XMPPCallback.h" #import "XMPPCallback.h"
#import "XMPPSRVLookup.h"
#import "XMPPEXTERNALAuth.h" #import "XMPPEXTERNALAuth.h"
#import "XMPPSCRAMAuth.h" #import "XMPPSCRAMAuth.h"
#import "XMPPPLAINAuth.h" #import "XMPPPLAINAuth.h"
@ -84,66 +83,8 @@ OF_ASSUME_NONNULL_BEGIN
- (XMPPMulticastDelegate *)XMPP_delegates; - (XMPPMulticastDelegate *)XMPP_delegates;
@end @end
@interface XMPPConnection_ConnectThread: OFThread
{
OFThread *_sourceThread;
XMPPConnection *_connection;
}
- initWithSourceThread: (OFThread *)sourceThread
connection: (XMPPConnection *)connection;
@end
OF_ASSUME_NONNULL_END OF_ASSUME_NONNULL_END
@implementation XMPPConnection_ConnectThread
- initWithSourceThread: (OFThread *)sourceThread
connection: (XMPPConnection *)connection
{
self = [super init];
@try {
_sourceThread = [sourceThread retain];
_connection = [connection retain];
} @catch (id e) {
[self release];
@throw e;
}
return self;
}
- (void)dealloc
{
[_sourceThread release];
[_connection release];
[super dealloc];
}
- (void)didConnect
{
[self join];
[_connection handleConnection];
}
- (id)main
{
void *pool = objc_autoreleasePoolPush();
[_connection connect];
[self performSelector: @selector(didConnect)
onThread: _sourceThread
waitUntilDone: false];
objc_autoreleasePoolPop(pool);
return nil;
}
@end
@implementation XMPPConnection @implementation XMPPConnection
@synthesize username = _username, resource = _resource, server = _server; @synthesize username = _username, resource = _resource, server = _server;
@synthesize domain = _domain, password = _password, language = _language; @synthesize domain = _domain, password = _password, language = _language;
@ -316,72 +257,118 @@ OF_ASSUME_NONNULL_END
[old release]; [old release];
} }
- (void)connect - (void)XMPP_socketDidConnect: (OFTCPSocket *)socket
context: (OFArray *)nextSRVRecords
exception: (id)exception
{
char *buffer;
if (exception != nil) {
if (nextSRVRecords != nil) {
[self XMPP_tryNextSRVRecord: nextSRVRecords];
return;
}
[_delegates
broadcastSelector: @selector(connection:didThrowException:)
withObject: self
withObject: exception];
return;
}
[self XMPP_startStream];
buffer = [self allocMemoryWithSize: BUFFER_LENGTH];
[_socket asyncReadIntoBuffer: buffer
length: BUFFER_LENGTH
target: self
selector: @selector(XMPP_stream:didReadIntoBuffer:
length:exception:)
context: nil];
}
- (void)XMPP_tryNextSRVRecord: (OFArray *)SRVRecords
{
OFSRVDNSResourceRecord *record = [SRVRecords objectAtIndex: 0];
SRVRecords = [SRVRecords objectsInRange:
of_range(1, [SRVRecords count] - 1)];
if ([SRVRecords count] == 0)
SRVRecords = nil;
[_socket asyncConnectToHost: [record target]
port: [record port]
target: self
selector: @selector(XMPP_socketDidConnect:
context:exception:)
context: SRVRecords];
}
- (void)XMPP_resolver: (OFDNSResolver *)resolver
didResolveDomainName: (OFString *)domainName
answerRecords: (OFDictionary *)answerRecords
authorityRecords: (OFDictionary *)authorityRecords
additionalRecords: (OFDictionary *)additionalRecords
context: (OFString *)domainToASCII
exception: (id)exception
{
OFMutableArray *records = [OFMutableArray array];
if (exception != nil) {
[_delegates
broadcastSelector: @selector(connection:didThrowException:)
withObject: self
withObject: exception];
return;
}
for (OF_KINDOF(OFDNSResourceRecord *) record in
[answerRecords objectForKey: domainName])
if ([record isKindOfClass: [OFSRVDNSResourceRecord class]])
[records addObject: record];
/* TODO: Sort records */
[records makeImmutable];
if ([records count] == 0) {
/* Fall back to A / AAA record. */
[_socket asyncConnectToHost: domainToASCII
port: _port
target: self
selector: @selector(XMPP_socketDidConnect:
context:exception:)
context: nil];
return;
}
[self XMPP_tryNextSRVRecord: records];
}
- (void)asyncConnect
{ {
void *pool = objc_autoreleasePoolPush(); void *pool = objc_autoreleasePoolPush();
XMPPSRVEntry *candidate = nil;
XMPPSRVLookup *SRVLookup = nil;
OFEnumerator *enumerator;
if (_socket != nil) if (_socket != nil)
@throw [OFAlreadyConnectedException exception]; @throw [OFAlreadyConnectedException exception];
_socket = [[OFTCPSocket alloc] init]; _socket = [[OFTCPSocket alloc] init];
if (_server) if (_server != nil)
[_socket connectToHost: _server [_socket asyncConnectToHost: _server
port: _port]; port: _port
else {
@try {
SRVLookup = [XMPPSRVLookup
lookupWithDomain: _domainToASCII];
} @catch (id e) {
}
enumerator = [SRVLookup objectEnumerator];
/* Iterate over SRV records, if any */
if ((candidate = [enumerator nextObject]) != nil) {
do {
@try {
[_socket
connectToHost: [candidate target]
port: [candidate port]];
break;
} @catch (OFResolveHostFailedException *e) {
} @catch (OFConnectionFailedException *e) {
}
} while ((candidate = [enumerator nextObject]) != nil);
} else
/* No SRV records -> fall back to A / AAAA record */
[_socket connectToHost: _domainToASCII
port: _port];
}
[self XMPP_startStream];
objc_autoreleasePoolPop(pool);
}
- (void)handleConnection
{
char *buffer = [self allocMemoryWithSize: BUFFER_LENGTH];
[_socket asyncReadIntoBuffer: buffer
length: BUFFER_LENGTH
target: self target: self
selector: @selector(stream:didReadIntoBuffer:length: selector: @selector(XMPP_socketDidConnect:
exception:) context:exception:)
context: nil]; context: nil];
} else
[[OFThread DNSResolver]
- (void)asyncConnectAndHandle asyncResolveHost: _domainToASCII
{ target: self
void *pool = objc_autoreleasePoolPush(); selector: @selector(XMPP_resolver:
didResolveDomainName:answerRecords:
[[[[XMPPConnection_ConnectThread alloc] authorityRecords:additionalRecords:
initWithSourceThread: [OFThread currentThread] context:exception:)
connection: self] autorelease] start]; context: _domainToASCII];
objc_autoreleasePoolPop(pool); objc_autoreleasePoolPop(pool);
} }
@ -421,7 +408,7 @@ OF_ASSUME_NONNULL_END
_oldElementBuilder = nil; _oldElementBuilder = nil;
} }
- (bool)stream: (OFStream *)stream - (bool)XMPP_stream: (OFStream *)stream
didReadIntoBuffer: (char *)buffer didReadIntoBuffer: (char *)buffer
length: (size_t)length length: (size_t)length
exception: (OFException *)exception exception: (OFException *)exception
@ -458,7 +445,7 @@ OF_ASSUME_NONNULL_END
[_socket asyncReadIntoBuffer: buffer [_socket asyncReadIntoBuffer: buffer
length: BUFFER_LENGTH length: BUFFER_LENGTH
target: self target: self
selector: @selector(stream: selector: @selector(XMPP_stream:
didReadIntoBuffer:length: didReadIntoBuffer:length:
exception:) exception:)
context: nil]; context: nil];
@ -927,8 +914,7 @@ OF_ASSUME_NONNULL_END
} }
if ([[element name] isEqual: @"failure"]) { if ([[element name] isEqual: @"failure"]) {
of_log(@"Auth failed!"); /* FIXME: Do more parsing/handling */
// FIXME: Do more parsing/handling
@throw [XMPPAuthFailedException @throw [XMPPAuthFailedException
exceptionWithConnection: self exceptionWithConnection: self
reason: [element XMLString]]; reason: [element XMLString]];

View file

@ -1,88 +0,0 @@
/*
* Copyright (c) 2011, 2012, Florian Zeitz <florob@babelmonkeys.de>
* Copyright (c) 2011, 2012, 2013, 2016, Jonathan Schleifer <js@heap.zone>
*
* https://heap.zone/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 <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#import <ObjFW/ObjFW.h>
OF_ASSUME_NONNULL_BEGIN
@interface XMPPSRVEntry: OFObject
{
uint16_t _priority;
uint16_t _weight;
uint32_t _accumulatedWeight;
uint16_t _port;
OFString *_target;
}
@property (readonly, nonatomic) uint16_t priority;
@property (readonly, nonatomic) uint16_t weight;
@property (nonatomic) uint32_t accumulatedWeight;
@property (readonly, nonatomic) uint16_t port;
@property (readonly, nonatomic) OFString *target;
+ (instancetype)entryWithPriority: (uint16_t)priority
weight: (uint16_t)weight
port: (uint16_t)port
target: (OFString *)target;
+ (instancetype)entryWithResourceRecord: (ns_rr)resourceRecord
handle: (ns_msg)handle;
- init OF_UNAVAILABLE;
- initWithPriority: (uint16_t)priority
weight: (uint16_t)weight
port: (uint16_t)port
target: (OFString *)target;
- initWithResourceRecord: (ns_rr)resourceRecord
handle: (ns_msg)handle;
@end
@interface XMPPSRVLookup: OFObject <OFEnumerating>
{
OFString *_domain;
struct __res_state _resState;
OFList *_list;
}
@property (readonly, nonatomic) OFString *domain;
+ (instancetype)lookupWithDomain: (OFString *)domain;
- init OF_UNAVAILABLE;
- initWithDomain: (OFString *)domain;
@end
@interface XMPPSRVEnumerator: OFEnumerator
{
OFList *_list;
of_list_object_t *_listIter;
OFList *_subListCopy;
bool _done;
}
- init OF_UNAVAILABLE;
- initWithList: (OFList *)list;
@end
OF_ASSUME_NONNULL_END

View file

@ -1,378 +0,0 @@
/*
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016
* Jonathan Schleifer <js@heap.zone>
* Copyright (c) 2011, 2012, 2013, 2014, Florian Zeitz <florob@babelmonkeys.de>
*
* https://heap.zone/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.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <inttypes.h>
#include <stdlib.h>
#include <assert.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/types.h>
#include <openssl/rand.h>
#import "XMPPSRVLookup.h"
#import <ObjFW/OFLocale.h>
OF_ASSUME_NONNULL_BEGIN
@interface XMPPSRVLookup ()
- (void)XMPP_lookup;
- (void)XMPP_addEntry: (XMPPSRVEntry *)item;
@end
OF_ASSUME_NONNULL_END
@implementation XMPPSRVEntry
@synthesize priority = _priority, weight = _weight;
@synthesize accumulatedWeight = _accumulatedWeight, port = _port;
@synthesize target = _target;
+ (instancetype)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];
}
+ (instancetype)entryWithResourceRecord: (ns_rr)resourceRecord
handle: (ns_msg)handle
{
return [[[self alloc] initWithResourceRecord: resourceRecord
handle: handle] autorelease];
}
- init
{
OF_INVALID_INIT_METHOD
}
- 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
exceptionWithClass: [self class]];
_target = [[OFString alloc]
initWithCString: buffer
encoding: [OFLocale encoding]];
} @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 @">", [self class], _priority, _weight, _target, _port];
}
@end
@implementation XMPPSRVLookup
@synthesize domain = _domain;
+ (instancetype)lookupWithDomain: (OFString *)domain
{
return [[[self alloc] initWithDomain: domain] autorelease];
}
- init
{
OF_INVALID_INIT_METHOD
}
- 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];
}
- (void)XMPP_lookup
{
void *pool = objc_autoreleasePoolPush();
unsigned char *answer = NULL;
size_t pageSize = [OFSystemInfo pageSize];
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 [OFResolveHostFailedException
exceptionWithHost: _domain
recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN
recordType: OF_DNS_RESOURCE_RECORD_TYPE_SRV
error: OF_DNS_RESOLVER_ERROR_UNKNOWN];
answer = [self allocMemoryWithSize: pageSize];
answerLen = res_nsearch(&_resState,
[request cStringWithEncoding: [OFLocale encoding]],
ns_c_in, ns_t_srv, answer, (int)pageSize);
if ((answerLen == -1) && ((h_errno == HOST_NOT_FOUND) ||
(h_errno == NO_DATA)))
return;
if (answerLen < 1 || answerLen > pageSize)
@throw [OFResolveHostFailedException
exceptionWithHost: _domain
recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN
recordType: OF_DNS_RESOURCE_RECORD_TYPE_SRV
error: OF_DNS_RESOLVER_ERROR_UNKNOWN];
if (ns_initparse(answer, answerLen, &handle))
@throw [OFResolveHostFailedException
exceptionWithHost: _domain
recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN
recordType: OF_DNS_RESOURCE_RECORD_TYPE_SRV
error: OF_DNS_RESOLVER_ERROR_UNKNOWN];
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];
#ifdef HAVE_RES_NDESTROY
res_ndestroy(&_resState);
#endif
}
objc_autoreleasePoolPop(pool);
}
- (void)XMPP_addEntry: (XMPPSRVEntry *)entry
{
void *pool = objc_autoreleasePoolPush();
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) {
XMPPSRVEntry *first = [iter->object firstObject];
if ([first 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 ([first priority] > [entry priority])
break;
}
subList = [OFList list];
[subList appendObject: entry];
if (iter != NULL)
[_list insertObject: subList
beforeListObject: iter];
else
[_list appendObject: subList];
objc_autoreleasePoolPop(pool);
}
- (OFEnumerator *)objectEnumerator
{
return [[[XMPPSRVEnumerator alloc] initWithList: _list] autorelease];
}
@end
@implementation XMPPSRVEnumerator
- init
{
OF_INVALID_INIT_METHOD
}
- initWithList: (OFList *)list
{
self = [super init];
@try {
_list = [list copy];
} @catch (id e) {
[self release];
@throw e;
}
return self;
}
- (id)nextObject
{
XMPPSRVEntry *ret = nil;
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 = true;
}
return ret;
}
- (void)reset
{
_listIter = NULL;
[_subListCopy release];
_subListCopy = nil;
_done = false;
}
@end

View file

@ -126,7 +126,7 @@ OF_APPLICATION_DELEGATE(AppDelegate)
[conn setPassword: [arguments objectAtIndex: 2]]; [conn setPassword: [arguments objectAtIndex: 2]];
[conn setResource: @"ObjXMPP"]; [conn setResource: @"ObjXMPP"];
[conn asyncConnectAndHandle]; [conn asyncConnect];
} }
- (void)connection: (XMPPConnection *)conn - (void)connection: (XMPPConnection *)conn