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")
|
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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 {
|
target: self
|
||||||
@try {
|
selector: @selector(XMPP_socketDidConnect:
|
||||||
SRVLookup = [XMPPSRVLookup
|
context:exception:)
|
||||||
lookupWithDomain: _domainToASCII];
|
context: nil];
|
||||||
} @catch (id e) {
|
else
|
||||||
}
|
[[OFThread DNSResolver]
|
||||||
|
asyncResolveHost: _domainToASCII
|
||||||
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_resolver:
|
||||||
exception:)
|
didResolveDomainName:answerRecords:
|
||||||
context: nil];
|
authorityRecords:additionalRecords:
|
||||||
}
|
context:exception:)
|
||||||
|
context: _domainToASCII];
|
||||||
- (void)asyncConnectAndHandle
|
|
||||||
{
|
|
||||||
void *pool = objc_autoreleasePoolPush();
|
|
||||||
|
|
||||||
[[[[XMPPConnection_ConnectThread alloc]
|
|
||||||
initWithSourceThread: [OFThread currentThread]
|
|
||||||
connection: self] autorelease] start];
|
|
||||||
|
|
||||||
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]];
|
||||||
|
|
|
@ -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 setPassword: [arguments objectAtIndex: 2]];
|
||||||
[conn setResource: @"ObjXMPP"];
|
[conn setResource: @"ObjXMPP"];
|
||||||
|
|
||||||
[conn asyncConnectAndHandle];
|
[conn asyncConnect];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)connection: (XMPPConnection *)conn
|
- (void)connection: (XMPPConnection *)conn
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue