Remove dependency on libresolv
This commit is contained in:
parent
3c10a522cd
commit
d6f82eb3d5
7 changed files with 111 additions and 649 deletions
43
configure.ac
43
configure.ac
|
@ -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")
|
||||
])
|
||||
|
||||
# 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_SUBST(OBJOPENSSL_LIBS, "-lobjopenssl -lcrypto")
|
||||
AC_SUBST(OBJOPENSSL_FRAMEWORK_LIBS, "-framework ObjOpenSSL -lcrypto")
|
||||
|
|
|
@ -26,7 +26,6 @@ SRCS = XMPPAuthenticator.m \
|
|||
XMPPRoster.m \
|
||||
XMPPRosterItem.m \
|
||||
XMPPSCRAMAuth.m \
|
||||
XMPPSRVLookup.m \
|
||||
XMPPStanza.m \
|
||||
XMPPStreamManagement.m \
|
||||
XMPPXMLElementBuilder.m
|
||||
|
|
|
@ -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>
|
||||
* 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.
|
||||
*
|
||||
* This is only called for connections on which
|
||||
* @ref XMPPConnection::handleConnection has been called.
|
||||
*
|
||||
* @param connection The connection which threw an exception
|
||||
* @param exception The exception the connection threw
|
||||
*/
|
||||
|
@ -272,11 +269,6 @@ OF_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
- (void)removeDelegate: (id <XMPPConnectionDelegate>)delegate;
|
||||
|
||||
/*!
|
||||
* @brief Connects to the XMPP service.
|
||||
*/
|
||||
- (void)connect;
|
||||
|
||||
/*!
|
||||
* @brief Closes the stream to the XMPP service
|
||||
*/
|
||||
|
@ -295,15 +287,9 @@ OF_ASSUME_NONNULL_BEGIN
|
|||
(OFString *__autoreleasing _Nonnull *_Nullable)reason;
|
||||
|
||||
/*!
|
||||
* @brief Adds the connection to the run loop.
|
||||
* @brief Asynchronously connects to the server.
|
||||
*/
|
||||
- (void)handleConnection;
|
||||
|
||||
/*!
|
||||
* @brief Asynchronously connects to the server and adds the connection to the
|
||||
* run loop.
|
||||
*/
|
||||
- (void)asyncConnectAndHandle;
|
||||
- (void)asyncConnect;
|
||||
|
||||
/*!
|
||||
* @brief Parses the specified buffer.
|
||||
|
|
|
@ -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>
|
||||
* Copyright (c) 2011, 2012, Florian Zeitz <florob@babelmonkeys.de>
|
||||
*
|
||||
|
@ -41,7 +41,6 @@
|
|||
|
||||
#import "XMPPConnection.h"
|
||||
#import "XMPPCallback.h"
|
||||
#import "XMPPSRVLookup.h"
|
||||
#import "XMPPEXTERNALAuth.h"
|
||||
#import "XMPPSCRAMAuth.h"
|
||||
#import "XMPPPLAINAuth.h"
|
||||
|
@ -84,66 +83,8 @@ OF_ASSUME_NONNULL_BEGIN
|
|||
- (XMPPMulticastDelegate *)XMPP_delegates;
|
||||
@end
|
||||
|
||||
@interface XMPPConnection_ConnectThread: OFThread
|
||||
{
|
||||
OFThread *_sourceThread;
|
||||
XMPPConnection *_connection;
|
||||
}
|
||||
|
||||
- initWithSourceThread: (OFThread *)sourceThread
|
||||
connection: (XMPPConnection *)connection;
|
||||
@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
|
||||
@synthesize username = _username, resource = _resource, server = _server;
|
||||
@synthesize domain = _domain, password = _password, language = _language;
|
||||
|
@ -316,72 +257,118 @@ OF_ASSUME_NONNULL_END
|
|||
[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();
|
||||
XMPPSRVEntry *candidate = nil;
|
||||
XMPPSRVLookup *SRVLookup = nil;
|
||||
OFEnumerator *enumerator;
|
||||
|
||||
if (_socket != nil)
|
||||
@throw [OFAlreadyConnectedException exception];
|
||||
|
||||
_socket = [[OFTCPSocket alloc] init];
|
||||
|
||||
if (_server)
|
||||
[_socket connectToHost: _server
|
||||
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
|
||||
if (_server != nil)
|
||||
[_socket asyncConnectToHost: _server
|
||||
port: _port
|
||||
target: self
|
||||
selector: @selector(XMPP_socketDidConnect:
|
||||
context:exception:)
|
||||
context: nil];
|
||||
else
|
||||
[[OFThread DNSResolver]
|
||||
asyncResolveHost: _domainToASCII
|
||||
target: self
|
||||
selector: @selector(stream:didReadIntoBuffer:length:
|
||||
exception:)
|
||||
context: nil];
|
||||
}
|
||||
|
||||
- (void)asyncConnectAndHandle
|
||||
{
|
||||
void *pool = objc_autoreleasePoolPush();
|
||||
|
||||
[[[[XMPPConnection_ConnectThread alloc]
|
||||
initWithSourceThread: [OFThread currentThread]
|
||||
connection: self] autorelease] start];
|
||||
selector: @selector(XMPP_resolver:
|
||||
didResolveDomainName:answerRecords:
|
||||
authorityRecords:additionalRecords:
|
||||
context:exception:)
|
||||
context: _domainToASCII];
|
||||
|
||||
objc_autoreleasePoolPop(pool);
|
||||
}
|
||||
|
@ -421,7 +408,7 @@ OF_ASSUME_NONNULL_END
|
|||
_oldElementBuilder = nil;
|
||||
}
|
||||
|
||||
- (bool)stream: (OFStream *)stream
|
||||
- (bool)XMPP_stream: (OFStream *)stream
|
||||
didReadIntoBuffer: (char *)buffer
|
||||
length: (size_t)length
|
||||
exception: (OFException *)exception
|
||||
|
@ -458,7 +445,7 @@ OF_ASSUME_NONNULL_END
|
|||
[_socket asyncReadIntoBuffer: buffer
|
||||
length: BUFFER_LENGTH
|
||||
target: self
|
||||
selector: @selector(stream:
|
||||
selector: @selector(XMPP_stream:
|
||||
didReadIntoBuffer:length:
|
||||
exception:)
|
||||
context: nil];
|
||||
|
@ -927,8 +914,7 @@ OF_ASSUME_NONNULL_END
|
|||
}
|
||||
|
||||
if ([[element name] isEqual: @"failure"]) {
|
||||
of_log(@"Auth failed!");
|
||||
// FIXME: Do more parsing/handling
|
||||
/* FIXME: Do more parsing/handling */
|
||||
@throw [XMPPAuthFailedException
|
||||
exceptionWithConnection: self
|
||||
reason: [element XMLString]];
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -126,7 +126,7 @@ OF_APPLICATION_DELEGATE(AppDelegate)
|
|||
[conn setPassword: [arguments objectAtIndex: 2]];
|
||||
[conn setResource: @"ObjXMPP"];
|
||||
|
||||
[conn asyncConnectAndHandle];
|
||||
[conn asyncConnect];
|
||||
}
|
||||
|
||||
- (void)connection: (XMPPConnection *)conn
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue