Index: src/OFTCPSocket.h ================================================================== --- src/OFTCPSocket.h +++ src/OFTCPSocket.h @@ -14,10 +14,11 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFStreamSocket.h" +#import "OFRunLoop.h" #import "socket.h" OF_ASSUME_NONNULL_BEGIN @@ -168,10 +169,29 @@ port: (uint16_t)port target: (id)target selector: (SEL)selector context: (nullable id)context; +/*! + * @brief Asynchronously connect the OFTCPSocket to the specified destination. + * + * @param host The host to connect to + * @param port The port on the host to connect to + * @param runLoopMode The run loop mode in which to perform the async connect + * @param target The target on which to call the selector once the connection + * has been established + * @param selector The selector to call on the target. The signature must be + * `void (OFTCPSocket *socket, id context, id exception)`. + * @param context A context object to pass along to the target + */ +- (void)asyncConnectToHost: (OFString *)host + port: (uint16_t)port + runLoopMode: (of_run_loop_mode_t)runLoopMode + target: (id)target + selector: (SEL)selector + context: (nullable id)context; + #ifdef OF_HAVE_BLOCKS /*! * @brief Asynchronously connect the OFTCPSocket to the specified destination. * * @param host The host to connect to @@ -179,10 +199,23 @@ * @param block The block to execute once the connection has been established */ - (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port block: (of_tcp_socket_async_connect_block_t)block; + +/*! + * @brief Asynchronously connect the OFTCPSocket to the specified destination. + * + * @param host The host to connect to + * @param port The port on the host to connect to + * @param runLoopMode The run loop mode in which to perform the async connect + * @param block The block to execute once the connection has been established + */ +- (void)asyncConnectToHost: (OFString *)host + port: (uint16_t)port + runLoopMode: (of_run_loop_mode_t)runLoopMode + block: (of_tcp_socket_async_connect_block_t)block; #endif /*! * @brief Bind the socket to the specified host and port. * @@ -228,19 +261,48 @@ */ - (void)asyncAcceptWithTarget: (id)target selector: (SEL)selector context: (nullable id)context; +/*! + * @brief Asynchronously accept an incoming connection. + * + * @param runLoopMode The run loop mode in which to perform the async accept + * @param target The target on which to execute the selector when a new + * connection has been accepted. The method returns whether the + * next incoming connection should be accepted by the specified + * block as well. + * @param selector The selector to call on the target. The signature must be + * `bool (OFTCPSocket *socket, OFTCPSocket *acceptedSocket, + * id context, id exception)`. + * @param context A context object to pass along to the target + */ +- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode + target: (id)target + selector: (SEL)selector + context: (nullable id)context; + #ifdef OF_HAVE_BLOCKS /*! * @brief Asynchronously accept an incoming connection. * * @param block The block to execute when a new connection has been accepted. * Returns whether the next incoming connection should be accepted * by the specified block as well. */ - (void)asyncAcceptWithBlock: (of_tcp_socket_async_accept_block_t)block; + +/*! + * @brief Asynchronously accept an incoming connection. + * + * @param runLoopMode The run loop mode in which to perform the async accept + * @param block The block to execute when a new connection has been accepted. + * Returns whether the next incoming connection should be accepted + * by the specified block as well. + */ +- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode + block: (of_tcp_socket_async_accept_block_t)block; #endif @end #ifdef __cplusplus extern "C" { Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -109,17 +109,17 @@ #endif - (void)didConnect; - (void)socketDidConnect: (OFTCPSocket *)sock context: (id)context exception: (id)exception; -- (void)tryNextAddress; +- (void)tryNextAddressWithRunLoopMode: (of_run_loop_mode_t)runLoopMode; - (void)resolver: (OFDNSResolver *)resolver didResolveDomainName: (OFString *)domainName socketAddresses: (OFData *)socketAddresses context: (id)context exception: (id)exception; -- (void)start; +- (void)startWithRunLoopMode: (of_run_loop_mode_t)runLoopMode; - (void)sendSOCKS5Request; - (size_t)socket: (OFTCPSocket *)sock didSendSOCKS5Authentication: (const void *)request bytesWritten: (size_t)bytesWritten context: (id)context @@ -246,11 +246,12 @@ if (exception != nil) { if (_socketAddressesIndex >= [_socketAddresses count]) { _exception = [exception retain]; [self didConnect]; } else { - [self tryNextAddress]; + [self tryNextAddressWithRunLoopMode: + [[OFRunLoop currentRunLoop] currentMode]]; } return; } @@ -258,11 +259,11 @@ [self sendSOCKS5Request]; else [self didConnect]; } -- (void)tryNextAddress +- (void)tryNextAddressWithRunLoopMode: (of_run_loop_mode_t)runLoopMode { of_socket_address_t address = *(const of_socket_address_t *) [_socketAddresses itemAtIndex: _socketAddressesIndex++]; int errNo; @@ -281,11 +282,11 @@ errNo: errNo]; [self didConnect]; return; } - [self tryNextAddress]; + [self tryNextAddressWithRunLoopMode: runLoopMode]; return; } [_socket setBlocking: false]; @@ -292,14 +293,13 @@ if (![_socket of_connectSocketToAddress: &address errNo: &errNo]) { if (errNo == EINPROGRESS) { SEL selector = @selector(socketDidConnect:context: exception:); - of_run_loop_mode_t mode = of_run_loop_mode_default; [OFRunLoop of_addAsyncConnectForTCPSocket: _socket - mode: mode + mode: runLoopMode target: self selector: selector context: nil]; return; } else { @@ -313,11 +313,11 @@ errNo: errNo]; [self didConnect]; return; } - [self tryNextAddress]; + [self tryNextAddressWithRunLoopMode: runLoopMode]; return; } } [self didConnect]; @@ -334,14 +334,16 @@ [self didConnect]; return; } _socketAddresses = [socketAddresses copy]; - [self tryNextAddress]; + + [self tryNextAddressWithRunLoopMode: + [[OFRunLoop currentRunLoop] currentMode]]; } -- (void)start +- (void)startWithRunLoopMode: (of_run_loop_mode_t)runLoopMode { OFString *host; uint16_t port; if (_SOCKS5Host != nil) { @@ -362,17 +364,19 @@ _socketAddresses = [[OFData alloc] initWithItems: &address itemSize: sizeof(address) count: 1]; - [self tryNextAddress]; + [self tryNextAddressWithRunLoopMode: runLoopMode]; return; } @catch (OFInvalidFormatException *e) { } [[OFThread DNSResolver] asyncResolveSocketAddressesForHost: host + addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY + runLoopMode: runLoopMode target: self selector: @selector(resolver: didResolveDomainName: socketAddresses:context: exception:) @@ -381,10 +385,11 @@ - (void)sendSOCKS5Request { [_socket asyncWriteBuffer: "\x05\x01\x00" length: 3 + runLoopMode: [[OFRunLoop currentRunLoop] currentMode] target: self selector: @selector(socket:didSendSOCKS5Authentication: bytesWritten:context:exception:) context: nil]; } @@ -401,10 +406,11 @@ return 0; } [_socket asyncReadIntoBuffer: _buffer exactLength: 2 + runLoopMode: [[OFRunLoop currentRunLoop] currentMode] target: self selector: @selector(socket:didReadSOCKSVersion: length:context:exception:) context: nil]; @@ -452,10 +458,11 @@ count: 2]; /* Use request as context to retain it */ [_socket asyncWriteBuffer: [request items] length: [request count] + runLoopMode: [[OFRunLoop currentRunLoop] currentMode] target: self selector: @selector(socket:didSendSOCKS5Request: bytesWritten:context:exception:) context: request]; @@ -474,10 +481,11 @@ return 0; } [_socket asyncReadIntoBuffer: _buffer exactLength: 4 + runLoopMode: [[OFRunLoop currentRunLoop] currentMode] target: self selector: @selector(socket:didReadSOCKS5Response: length:context:exception:) context: nil]; @@ -488,10 +496,12 @@ didReadSOCKS5Response: (unsigned char *)response length: (size_t)length context: (id)context exception: (id)exception { + of_run_loop_mode_t runLoopMode; + if (exception != nil) { _exception = [exception retain]; [self didConnect]; return false; } @@ -543,33 +553,38 @@ errNo: errNo]; [self didConnect]; return false; } + runLoopMode = [[OFRunLoop currentRunLoop] currentMode]; + /* Skip the rest of the response */ switch (response[3]) { case 1: /* IPv4 */ [_socket asyncReadIntoBuffer: _buffer exactLength: 4 + 2 + runLoopMode: runLoopMode target: self selector: @selector(socket: didReadSOCKS5Address:length: context:exception:) context: nil]; return false; case 3: /* Domain name */ [_socket asyncReadIntoBuffer: _buffer exactLength: 1 + runLoopMode: runLoopMode target: self selector: @selector(socket: didReadSOCKS5AddressLength: length:context:exception:) context: nil]; return false; case 4: /* IPv6 */ [_socket asyncReadIntoBuffer: _buffer exactLength: 16 + 2 + runLoopMode: runLoopMode target: self selector: @selector(socket: didReadSOCKS5Address:length: context:exception:) context: nil]; @@ -610,10 +625,11 @@ return false; } [_socket asyncReadIntoBuffer: _buffer exactLength: addressLength[0] + 2 + runLoopMode: [[OFRunLoop currentRunLoop] currentMode] target: self selector: @selector(socket:didReadSOCKS5Address: length:context:exception:) context: nil]; return false; @@ -801,10 +817,25 @@ - (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port target: (id)target selector: (SEL)selector context: (id)context +{ + [self asyncConnectToHost: host + port: port + runLoopMode: of_run_loop_mode_default + target: target + selector: selector + context: context]; +} + +- (void)asyncConnectToHost: (OFString *)host + port: (uint16_t)port + runLoopMode: (of_run_loop_mode_t)runLoopMode + target: (id)target + selector: (SEL)selector + context: (id)context { void *pool = objc_autoreleasePoolPush(); [[[[OFTCPSocket_ConnectContext alloc] initWithSocket: self @@ -812,29 +843,42 @@ port: port SOCKS5Host: _SOCKS5Host SOCKS5Port: _SOCKS5Port target: target selector: selector - context: context] autorelease] start]; + context: context] autorelease] + startWithRunLoopMode: runLoopMode]; objc_autoreleasePoolPop(pool); } #ifdef OF_HAVE_BLOCKS - (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port block: (of_tcp_socket_async_connect_block_t)block { + [self asyncConnectToHost: host + port: port + runLoopMode: of_run_loop_mode_default + block: block]; +} + +- (void)asyncConnectToHost: (OFString *)host + port: (uint16_t)port + runLoopMode: (of_run_loop_mode_t)runLoopMode + block: (of_tcp_socket_async_connect_block_t)block +{ void *pool = objc_autoreleasePoolPush(); [[[[OFTCPSocket_ConnectContext alloc] initWithSocket: self host: host port: port SOCKS5Host: _SOCKS5Host SOCKS5Port: _SOCKS5Port - block: block] autorelease] start]; + block: block] autorelease] + startWithRunLoopMode: runLoopMode]; objc_autoreleasePoolPop(pool); } #endif @@ -1065,23 +1109,41 @@ } - (void)asyncAcceptWithTarget: (id)target selector: (SEL)selector context: (id)context +{ + [self asyncAcceptWithRunLoopMode: of_run_loop_mode_default + target: target + selector: selector + context: context]; +} + +- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode + target: (id)target + selector: (SEL)selector + context: (id)context { [OFRunLoop of_addAsyncAcceptForTCPSocket: self - mode: of_run_loop_mode_default + mode: runLoopMode target: target selector: selector context: context]; } #ifdef OF_HAVE_BLOCKS - (void)asyncAcceptWithBlock: (of_tcp_socket_async_accept_block_t)block { + [self asyncAcceptWithRunLoopMode: of_run_loop_mode_default + block: block]; +} + +- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode + block: (of_tcp_socket_async_accept_block_t)block +{ [OFRunLoop of_addAsyncAcceptForTCPSocket: self - mode: of_run_loop_mode_default + mode: runLoopMode block: block]; } #endif - (const of_socket_address_t *)remoteAddress