summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Schleifer <js@heap.zone>2018-09-16 14:49:39 +0200
committerJonathan Schleifer <js@heap.zone>2018-09-16 14:49:39 +0200
commit2088be72a89039fed4b5a5c1d6d882ebba8a6675 (patch)
tree3f39116509d8ff17b56bf78be331b86f05fc9088
parentc9b1f2b3f342e4ee974607beb5c1a0ba3e1688cc (diff)
OFTCPSocket: Async connect without threads
-rw-r--r--configure.ac8
-rw-r--r--extra.mk.in2
-rw-r--r--src/Makefile6
-rw-r--r--src/OFTCPSocket.h4
-rw-r--r--src/OFTCPSocket.m254
-rw-r--r--tests/Makefile2
6 files changed, 184 insertions, 92 deletions
diff --git a/configure.ac b/configure.ac
index 65b780e3..93189ed6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1399,12 +1399,10 @@ AS_IF([test x"$enable_sockets" != x"no"], [
], [
AC_MSG_RESULT(no)
])
-])
-AS_IF([test x"$enable_sockets" != x"no" -a x"$enable_threads" != x"no"], [
- AC_SUBST(OFHTTPCLIENT_M, "OFHTTPClient.m")
- AC_SUBST(OFHTTPCLIENTTESTS_M, "OFHTTPClientTests.m")
- AC_SUBST(OFURLHANDLER_HTTP_M, "OFURLHandler_HTTP.m")
+ AS_IF([test x"$enable_threads" != x"no"], [
+ AC_SUBST(OFHTTPCLIENTTESTS_M, "OFHTTPClientTests.m")
+ ])
AC_SUBST(OFDNS, "ofdns")
AS_IF([test x"$enable_files" != x"no"], [
diff --git a/extra.mk.in b/extra.mk.in
index 1610c89e..b45f2183 100644
--- a/extra.mk.in
+++ b/extra.mk.in
@@ -57,14 +57,12 @@ OFDNS = @OFDNS@
OFHASH = @OFHASH@
OFHTTP = @OFHTTP@
OFHTTPCLIENTTESTS_M = @OFHTTPCLIENTTESTS_M@
-OFHTTPCLIENT_M = @OFHTTPCLIENT_M@
OFKERNELEVENTOBSERVER_EPOLL_M = @OFKERNELEVENTOBSERVER_EPOLL_M@
OFKERNELEVENTOBSERVER_KQUEUE_M = @OFKERNELEVENTOBSERVER_KQUEUE_M@
OFKERNELEVENTOBSERVER_POLL_M = @OFKERNELEVENTOBSERVER_POLL_M@
OFKERNELEVENTOBSERVER_SELECT_M = @OFKERNELEVENTOBSERVER_SELECT_M@
OFPROCESS_M = @OFPROCESS_M@
OFSTDIOSTREAM_WIN32CONSOLE_M = @OFSTDIOSTREAM_WIN32CONSOLE_M@
-OFURLHANDLER_HTTP_M = @OFURLHANDLER_HTTP_M@
REEXPORT_RUNTIME = @REEXPORT_RUNTIME@
REEXPORT_RUNTIME_FRAMEWORK = @REEXPORT_RUNTIME_FRAMEWORK@
RUNTIME = @RUNTIME@
diff --git a/src/Makefile b/src/Makefile
index 78c9165b..b6954461 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -125,7 +125,7 @@ SRCS_FILES = OFFile.m \
SRCS_PLUGINS = OFPlugin.m
SRCS_SOCKETS = OFDNSResolver.m \
OFDNSResourceRecord.m \
- ${OFHTTPCLIENT_M} \
+ OFHTTPClient.m \
OFHTTPCookie.m \
OFHTTPCookieManager.m \
OFHTTPRequest.m \
@@ -185,7 +185,6 @@ SRCS += OFArray_adjacent.m \
OFMutableString_UTF8.m \
OFSet_hashtable.m \
OFString_UTF8.m \
- ${OFURLHANDLER_HTTP_M} \
OFValue_bytes.m \
OFValue_dimension.m \
OFValue_nonretainedObject.m \
@@ -203,7 +202,8 @@ SRCS_SOCKETS += OFKernelEventObserver.m \
${OFKERNELEVENTOBSERVER_KQUEUE_M} \
${OFKERNELEVENTOBSERVER_POLL_M} \
${OFKERNELEVENTOBSERVER_SELECT_M} \
- OFTCPSocket+SOCKS5.m
+ OFTCPSocket+SOCKS5.m \
+ OFURLHandler_HTTP.m
OBJS_EXTRA = ${RUNTIME_RUNTIME_A} \
${EXCEPTIONS_EXCEPTIONS_A} \
diff --git a/src/OFTCPSocket.h b/src/OFTCPSocket.h
index e43a200a..c5ae168e 100644
--- a/src/OFTCPSocket.h
+++ b/src/OFTCPSocket.h
@@ -153,7 +153,6 @@ typedef bool (^of_tcp_socket_async_accept_block_t)(OFTCPSocket *socket,
- (void)connectToHost: (OFString *)host
port: (uint16_t)port;
-#ifdef OF_HAVE_THREADS
/*!
* @brief Asynchronously connect the OFTCPSocket to the specified destination.
*
@@ -171,7 +170,7 @@ typedef bool (^of_tcp_socket_async_accept_block_t)(OFTCPSocket *socket,
selector: (SEL)selector
context: (nullable id)context;
-# ifdef OF_HAVE_BLOCKS
+#ifdef OF_HAVE_BLOCKS
/*!
* @brief Asynchronously connect the OFTCPSocket to the specified destination.
*
@@ -182,7 +181,6 @@ typedef bool (^of_tcp_socket_async_accept_block_t)(OFTCPSocket *socket,
- (void)asyncConnectToHost: (OFString *)host
port: (uint16_t)port
block: (of_tcp_socket_async_connect_block_t)block;
-# endif
#endif
/*!
diff --git a/src/OFTCPSocket.m b/src/OFTCPSocket.m
index f8f481f2..0a2efd6c 100644
--- a/src/OFTCPSocket.m
+++ b/src/OFTCPSocket.m
@@ -33,11 +33,13 @@
#import "OFTCPSocket.h"
#import "OFTCPSocket+Private.h"
#import "OFTCPSocket+SOCKS5.h"
+#import "OFDNSResolver.h"
+#import "OFData.h"
+#import "OFRunLoop.h"
+#import "OFRunLoop+Private.h"
#import "OFString.h"
#import "OFThread.h"
#import "OFTimer.h"
-#import "OFRunLoop.h"
-#import "OFRunLoop+Private.h"
#import "OFAcceptFailedException.h"
#import "OFAlreadyConnectedException.h"
@@ -45,6 +47,7 @@
#import "OFConnectionFailedException.h"
#import "OFGetOptionFailedException.h"
#import "OFInvalidArgumentException.h"
+#import "OFInvalidFormatException.h"
#import "OFListenFailedException.h"
#import "OFNotImplementedException.h"
#import "OFNotOpenException.h"
@@ -68,52 +71,58 @@ Class of_tls_socket_class = Nil;
static OFString *defaultSOCKS5Host = nil;
static uint16_t defaultSOCKS5Port = 1080;
-#ifdef OF_HAVE_THREADS
-@interface OFTCPSocket_ConnectThread: OFThread
+@interface OFTCPSocket_ConnectContext: OFObject
{
- OFThread *_sourceThread;
OFTCPSocket *_socket;
OFString *_host;
uint16_t _port;
id _target;
SEL _selector;
id _context;
-# ifdef OF_HAVE_BLOCKS
+#ifdef OF_HAVE_BLOCKS
of_tcp_socket_async_connect_block_t _block;
-# endif
+#endif
id _exception;
+ OFData *_socketAddresses;
+ size_t _socketAddressesIndex;
}
-- (instancetype)initWithSourceThread: (OFThread *)sourceThread
- socket: (OFTCPSocket *)sock
- host: (OFString *)host
- port: (uint16_t)port
- target: (id)target
- selector: (SEL)selector
- context: (id)context;
-# ifdef OF_HAVE_BLOCKS
-- (instancetype)initWithSourceThread: (OFThread *)sourceThread
- socket: (OFTCPSocket *)sock
- host: (OFString *)host
- port: (uint16_t)port
- block: (of_tcp_socket_async_connect_block_t)
- block;
-# endif
+- (instancetype)initWithSocket: (OFTCPSocket *)sock
+ host: (OFString *)host
+ port: (uint16_t)port
+ target: (id)target
+ selector: (SEL)selector
+ context: (id)context;
+#ifdef OF_HAVE_BLOCKS
+- (instancetype)initWithSocket: (OFTCPSocket *)sock
+ host: (OFString *)host
+ port: (uint16_t)port
+ block: (of_tcp_socket_async_connect_block_t)block;
+#endif
+- (void)didConnect;
+- (void)socketDidConnect: (OFTCPSocket *)sock
+ context: (id)context
+ exception: (id)exception;
+- (void)tryNextAddress;
+- (void)resolver: (OFDNSResolver *)resolver
+ didResolveDomainName: (OFString *)domainName
+ socketAddresses: (OFData *)socketAddresses
+ context: (id)context
+ exception: (id)exception;
+- (void)start;
@end
-@implementation OFTCPSocket_ConnectThread
-- (instancetype)initWithSourceThread: (OFThread *)sourceThread
- socket: (OFTCPSocket *)sock
- host: (OFString *)host
- port: (uint16_t)port
- target: (id)target
- selector: (SEL)selector
- context: (id)context
+@implementation OFTCPSocket_ConnectContext
+- (instancetype)initWithSocket: (OFTCPSocket *)sock
+ host: (OFString *)host
+ port: (uint16_t)port
+ target: (id)target
+ selector: (SEL)selector
+ context: (id)context
{
self = [super init];
@try {
- _sourceThread = [sourceThread retain];
_socket = [sock retain];
_host = [host copy];
_port = port;
@@ -128,17 +137,15 @@ static uint16_t defaultSOCKS5Port = 1080;
return self;
}
-# ifdef OF_HAVE_BLOCKS
-- (instancetype)initWithSourceThread: (OFThread *)sourceThread
- socket: (OFTCPSocket *)sock
- host: (OFString *)host
- port: (uint16_t)port
- block: (of_tcp_socket_async_connect_block_t)block
+#ifdef OF_HAVE_BLOCKS
+- (instancetype)initWithSocket: (OFTCPSocket *)sock
+ host: (OFString *)host
+ port: (uint16_t)port
+ block: (of_tcp_socket_async_connect_block_t)block
{
self = [super init];
@try {
- _sourceThread = [sourceThread retain];
_socket = [sock retain];
_host = [host copy];
_port = port;
@@ -150,63 +157,156 @@ static uint16_t defaultSOCKS5Port = 1080;
return self;
}
-# endif
+#endif
- (void)dealloc
{
- [_sourceThread release];
[_socket release];
[_host release];
[_target release];
[_context release];
-# ifdef OF_HAVE_BLOCKS
+#ifdef OF_HAVE_BLOCKS
[_block release];
-# endif
+#endif
[_exception release];
+ [_socketAddresses release];
[super dealloc];
}
- (void)didConnect
{
- [self join];
-
-# ifdef OF_HAVE_BLOCKS
+#ifdef OF_HAVE_BLOCKS
if (_block != NULL)
_block(_socket, _exception);
else {
-# endif
+#endif
void (*func)(id, SEL, OFTCPSocket *, id, id) =
(void (*)(id, SEL, OFTCPSocket *, id, id))
[_target methodForSelector: _selector];
func(_target, _selector, _socket, _context, _exception);
-# ifdef OF_HAVE_BLOCKS
+#ifdef OF_HAVE_BLOCKS
}
-# endif
+#endif
}
-- (id)main
+- (void)socketDidConnect: (OFTCPSocket *)sock
+ context: (id)context
+ exception: (id)exception
{
- void *pool = objc_autoreleasePoolPush();
+ if (exception != nil) {
+ if (_socketAddressesIndex >= [_socketAddresses count])
+ _exception = [exception retain];
+ else {
+ [self tryNextAddress];
+ return;
+ }
+ }
- @try {
- [_socket connectToHost: _host
- port: _port];
- } @catch (id e) {
- _exception = [e retain];
+ [self didConnect];
+}
+
+- (void)tryNextAddress
+{
+ of_socket_address_t address = *(const of_socket_address_t *)
+ [_socketAddresses itemAtIndex: _socketAddressesIndex++];
+ int errNo;
+
+ of_socket_address_set_port(&address, _port);
+
+ if (![_socket of_createSocketForAddress: &address
+ errNo: &errNo]) {
+ if (_socketAddressesIndex >= [_socketAddresses count]) {
+ _exception = [[OFConnectionFailedException alloc]
+ initWithHost: _host
+ port: _port
+ socket: _socket
+ errNo: errNo];
+ [self didConnect];
+ return;
+ }
+
+ [self tryNextAddress];
+ return;
}
- [self performSelector: @selector(didConnect)
- onThread: _sourceThread
- waitUntilDone: false];
+ [_socket setBlocking: false];
- objc_autoreleasePoolPop(pool);
+ if (![_socket of_connectSocketToAddress: &address
+ errNo: &errNo]) {
+ if (errNo == EINPROGRESS) {
+ SEL selector = @selector(socketDidConnect:context:
+ exception:);
- return nil;
+ [OFRunLoop of_addAsyncConnectForTCPSocket: _socket
+ target: self
+ selector: selector
+ context: nil];
+ return;
+ } else {
+ [_socket of_closeSocket];
+
+ if (_socketAddressesIndex >= [_socketAddresses count]) {
+ _exception = [[OFConnectionFailedException
+ alloc] initWithHost: _host
+ port: _port
+ socket: _socket
+ errNo: errNo];
+ [self didConnect];
+ return;
+ }
+
+ [self tryNextAddress];
+ return;
+ }
+ }
+
+ [self didConnect];
+}
+
+- (void)resolver: (OFDNSResolver *)resolver
+ didResolveDomainName: (OFString *)domainName
+ socketAddresses: (OFData *)socketAddresses
+ context: (id)context
+ exception: (id)exception
+{
+ if (exception != nil) {
+ _exception = [exception retain];
+ [self didConnect];
+ return;
+ }
+
+ _socketAddresses = [socketAddresses copy];
+ [self tryNextAddress];
+}
+
+- (void)start
+{
+ @try {
+ of_socket_address_t address =
+ of_socket_address_parse_ip(_host, _port);
+
+ _socketAddresses = [[OFData alloc]
+ initWithItems: &address
+ itemSize: sizeof(address)
+ count: 1];
+
+ [self tryNextAddress];
+ return;
+ } @catch (OFInvalidFormatException *e) {
+ }
+
+ [[OFThread DNSResolver]
+ asyncResolveSocketAddressesForHost: _host
+ target: self
+ selector: @selector(resolver:
+ didResolveDomainName:
+ socketAddresses:context:
+ exception:)
+ context: nil];
}
@end
-#endif
@implementation OFTCPSocket
@synthesize SOCKS5Host = _SOCKS5Host, SOCKS5Port = _SOCKS5Port;
@@ -386,44 +486,42 @@ static uint16_t defaultSOCKS5Port = 1080;
port: destinationPort];
}
-#ifdef OF_HAVE_THREADS
- (void)asyncConnectToHost: (OFString *)host
port: (uint16_t)port
target: (id)target
selector: (SEL)selector
context: (id)context
{
+ /* TODO: Support SOCKS5 */
void *pool = objc_autoreleasePoolPush();
- [[[[OFTCPSocket_ConnectThread alloc]
- initWithSourceThread: [OFThread currentThread]
- socket: self
- host: host
- port: port
- target: target
- selector: selector
- context: context] autorelease] start];
+ [[[[OFTCPSocket_ConnectContext alloc]
+ initWithSocket: self
+ host: host
+ port: port
+ target: target
+ selector: selector
+ context: context] autorelease] start];
objc_autoreleasePoolPop(pool);
}
-# ifdef OF_HAVE_BLOCKS
+#ifdef OF_HAVE_BLOCKS
- (void)asyncConnectToHost: (OFString *)host
port: (uint16_t)port
block: (of_tcp_socket_async_connect_block_t)block
{
+ /* TODO: Support SOCKS5 */
void *pool = objc_autoreleasePoolPush();
- [[[[OFTCPSocket_ConnectThread alloc]
- initWithSourceThread: [OFThread currentThread]
- socket: self
- host: host
- port: port
- block: block] autorelease] start];
+ [[[[OFTCPSocket_ConnectContext alloc]
+ initWithSocket: self
+ host: host
+ port: port
+ block: block] autorelease] start];
objc_autoreleasePoolPop(pool);
}
-# endif
#endif
- (uint16_t)bindToHost: (OFString *)host
diff --git a/tests/Makefile b/tests/Makefile
index 0afb7a17..50684697 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -53,9 +53,9 @@ SRCS_FILES = OFHMACTests.m \
OFSHA512HashTests.m
SRCS_PLUGINS = OFPluginTests.m
SRCS_SOCKETS = OFDNSResolverTests.m \
+ ${OFHTTPCLIENTTESTS_M} \
OFHTTPCookieTests.m \
OFHTTPCookieManagerTests.m \
- ${OFHTTPCLIENTTESTS_M} \
OFKernelEventObserverTests.m \
OFTCPSocketTests.m \
OFUDPSocketTests.m \