Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -200,11 +200,10 @@ SRCS_SOCKETS += OFKernelEventObserver.m \ ${OFKERNELEVENTOBSERVER_EPOLL_M} \ ${OFKERNELEVENTOBSERVER_KQUEUE_M} \ ${OFKERNELEVENTOBSERVER_POLL_M} \ ${OFKERNELEVENTOBSERVER_SELECT_M} \ - OFTCPSocket+SOCKS5.m \ OFURLHandler_HTTP.m OBJS_EXTRA = ${RUNTIME_RUNTIME_A} \ ${EXCEPTIONS_EXCEPTIONS_A} \ ${ENCODINGS_ENCODINGS_A} \ DELETED src/OFTCPSocket+SOCKS5.h Index: src/OFTCPSocket+SOCKS5.h ================================================================== --- src/OFTCPSocket+SOCKS5.h +++ src/OFTCPSocket+SOCKS5.h @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#import "OFTCPSocket.h" - -OF_ASSUME_NONNULL_BEGIN - -#ifdef __cplusplus -extern "C" { -#endif -extern int _OFTCPSocket_SOCKS5_reference; -#ifdef __cplusplus -} -#endif - -@interface OFTCPSocket (SOCKS5) -- (void)OF_SOCKS5ConnectToHost: (OFString *)host - port: (uint16_t)port; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFTCPSocket+SOCKS5.m Index: src/OFTCPSocket+SOCKS5.m ================================================================== --- src/OFTCPSocket+SOCKS5.m +++ src/OFTCPSocket+SOCKS5.m @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#import "OFTCPSocket+SOCKS5.h" -#import "OFData.h" - -#import "OFConnectionFailedException.h" -#import "OFOutOfRangeException.h" -#import "OFReadFailedException.h" -#import "OFWriteFailedException.h" - -#import "socket_helpers.h" - -/* Reference for static linking */ -int _OFTCPSocket_SOCKS5_reference; - -static void -sendOrThrow(OFTCPSocket *self, of_socket_t sock, char *buffer, int length) -{ -#ifndef OF_WINDOWS - ssize_t bytesWritten; -#else - int bytesWritten; -#endif - - if ((bytesWritten = send(sock, (const void *)buffer, length, 0)) < 0) - @throw [OFWriteFailedException - exceptionWithObject: self - requestedLength: length - bytesWritten: 0 - errNo: of_socket_errno()]; - - if ((int)bytesWritten != length) - @throw [OFWriteFailedException exceptionWithObject: self - requestedLength: length - bytesWritten: bytesWritten - errNo: 0]; -} - -static void -recvExact(OFTCPSocket *self, of_socket_t sock, char *buffer, int length) -{ - while (length > 0) { - ssize_t ret = recv(sock, (void *)buffer, length, 0); - - if (ret < 0) - @throw [OFReadFailedException - exceptionWithObject: self - requestedLength: length - errNo: of_socket_errno()]; - - buffer += ret; - length -= ret; - } -} - -@implementation OFTCPSocket (SOCKS5) -- (void)OF_SOCKS5ConnectToHost: (OFString *)host - port: (uint16_t)port -{ - char request[] = { 5, 1, 0, 3 }; - char reply[256]; - void *pool; - OFMutableData *connectRequest; - - if ([host UTF8StringLength] > 255) - @throw [OFOutOfRangeException exception]; - - /* 5 1 0 -> no authentication */ - sendOrThrow(self, _socket, request, 3); - - recvExact(self, _socket, reply, 2); - - if (reply[0] != 5 || reply[1] != 0) { - [self close]; - @throw [OFConnectionFailedException - exceptionWithHost: host - port: port - socket: self - errNo: EPROTONOSUPPORT]; - } - - /* CONNECT request */ - pool = objc_autoreleasePoolPush(); - connectRequest = [OFMutableData data]; - - [connectRequest addItems: request - count: 4]; - - request[0] = [host UTF8StringLength]; - [connectRequest addItem: request]; - [connectRequest addItems: [host UTF8String] - count: request[0]]; - - request[0] = port >> 8; - request[1] = port & 0xFF; - [connectRequest addItems: request - count: 2]; - - if ([connectRequest count] > INT_MAX) - @throw [OFOutOfRangeException exception]; - - sendOrThrow(self, _socket, - [connectRequest items], (int)[connectRequest count]); - - objc_autoreleasePoolPop(pool); - - recvExact(self, _socket, reply, 4); - - if (reply[0] != 5 || reply[2] != 0) { - [self close]; - @throw [OFConnectionFailedException - exceptionWithHost: host - port: port - socket: self - errNo: EPROTONOSUPPORT]; - } - - if (reply[1] != 0) { - int errNo; - - [self close]; - - switch (reply[1]) { - case 0x02: - errNo = EACCES; - break; - case 0x03: - errNo = ENETUNREACH; - break; - case 0x04: - errNo = EHOSTUNREACH; - break; - case 0x05: - errNo = ECONNREFUSED; - break; - case 0x06: - errNo = ETIMEDOUT; - break; - case 0x07: - errNo = EPROTONOSUPPORT; - break; - case 0x08: - errNo = EAFNOSUPPORT; - break; - default: - errNo = 0; - break; - } - - @throw [OFConnectionFailedException exceptionWithHost: host - port: port - socket: self - errNo: errNo]; - } - - /* Skip the rest of the reply */ - switch (reply[3]) { - case 1: /* IPv4 */ - recvExact(self, _socket, reply, 4); - break; - case 3: /* Domain name */ - recvExact(self, _socket, reply, 1); - recvExact(self, _socket, reply, reply[0]); - break; - case 4: /* IPv6 */ - recvExact(self, _socket, reply, 16); - break; - default: - [self close]; - @throw [OFConnectionFailedException - exceptionWithHost: host - port: port - socket: self - errNo: EPROTONOSUPPORT]; - } - - recvExact(self, _socket, reply, 2); -} -@end Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -30,11 +30,11 @@ # include #endif #import "OFTCPSocket.h" #import "OFTCPSocket+Private.h" -#import "OFTCPSocket+SOCKS5.h" +#import "OFDate.h" #import "OFDNSResolver.h" #import "OFData.h" #import "OFRunLoop.h" #import "OFRunLoop+Private.h" #import "OFString.h" @@ -57,23 +57,17 @@ #import "socket.h" #import "socket_helpers.h" #import "resolver.h" -/* References for static linking */ -void -_references_to_categories_of_OFTCPSocket(void) -{ - _OFTCPSocket_SOCKS5_reference = 1; -} - Class of_tls_socket_class = Nil; +static of_run_loop_mode_t connectRunLoopMode = @"of_tcp_socket_connect_mode"; static OFString *defaultSOCKS5Host = nil; static uint16_t defaultSOCKS5Port = 1080; -@interface OFTCPSocket_ConnectContext: OFObject +@interface OFTCPSocket_AsyncConnectContext: OFObject { OFTCPSocket *_socket; OFString *_host; uint16_t _port; OFString *_SOCKS5Host; @@ -149,11 +143,23 @@ length: (size_t)length context: (id)context exception: (id)exception; @end -@implementation OFTCPSocket_ConnectContext +@interface OFTCPSocket_ConnectContext: OFObject +{ +@public + bool _connected; + id _exception; +} + +- (void)socketDidConnect: (OFTCPSocket *)sock + context: (id)context + exception: (id)exception; +@end + +@implementation OFTCPSocket_AsyncConnectContext - (instancetype)initWithSocket: (OFTCPSocket *)sock host: (OFString *)host port: (uint16_t)port SOCKS5Host: (OFString *)SOCKS5Host SOCKS5Port: (uint16_t)SOCKS5Port @@ -633,10 +639,29 @@ length:context:exception:) context: nil]; return false; } @end + +@implementation OFTCPSocket_ConnectContext +- (void)dealloc +{ + [_exception release]; + + [super dealloc]; +} + +- (void)socketDidConnect: (OFTCPSocket *)sock + context: (id)context + exception: (id)exception +{ + if (exception != nil) + _exception = [exception retain]; + + _connected = true; +} +@end @implementation OFTCPSocket @synthesize SOCKS5Host = _SOCKS5Host, SOCKS5Port = _SOCKS5Port; + (void)setSOCKS5Host: (OFString *)host @@ -741,79 +766,34 @@ } - (void)connectToHost: (OFString *)host port: (uint16_t)port { - OFString *destinationHost = host; - uint16_t destinationPort = port; - of_resolver_result_t **results, **iter; - int errNo = 0; - - if (_socket != INVALID_SOCKET) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; - - if (_SOCKS5Host != nil) { - /* Connect to the SOCKS5 proxy instead */ - host = _SOCKS5Host; - port = _SOCKS5Port; - } - - results = of_resolve_host(host, port, SOCK_STREAM); - - for (iter = results; *iter != NULL; iter++) { - of_resolver_result_t *result = *iter; - of_socket_address_t address; - - switch (result->family) { - case AF_INET: - address.family = OF_SOCKET_ADDRESS_FAMILY_IPV4; - break; -#ifdef AF_INET6 - case AF_INET6: - address.family = OF_SOCKET_ADDRESS_FAMILY_IPV6; - break; -#endif - default: - errNo = EAFNOSUPPORT; - continue; - } - - if (result->addressLength > sizeof(address)) { - errNo = EOVERFLOW; - continue; - } - - address.length = result->addressLength; - memcpy(&address.sockaddr.sockaddr, result->address, - result->addressLength); - - if (![self of_createSocketForAddress: &address - errNo: &errNo]) - continue; - - _blocking = true; - - if (![self of_connectSocketToAddress: &address - errNo: &errNo]) { - [self of_closeSocket]; - continue; - } - - break; - } - - of_resolver_free(results); - - if (_socket == INVALID_SOCKET) - @throw [OFConnectionFailedException exceptionWithHost: host - port: port - socket: self - errNo: errNo]; - - if (_SOCKS5Host != nil) - [self OF_SOCKS5ConnectToHost: destinationHost - port: destinationPort]; + void *pool = objc_autoreleasePoolPush(); + OFTCPSocket_ConnectContext *context = + [[[OFTCPSocket_ConnectContext alloc] init] autorelease]; + OFRunLoop *runLoop = [OFRunLoop currentRunLoop]; + + [self asyncConnectToHost: host + port: port + runLoopMode: connectRunLoopMode + target: context + selector: @selector(socketDidConnect:context:exception:) + context: nil]; + + while (!context->_connected) + [runLoop runMode: connectRunLoopMode + beforeDate: nil]; + + /* Cleanup */ + [runLoop runMode: connectRunLoopMode + beforeDate: [OFDate date]]; + + if (context->_exception != nil) + @throw context->_exception; + + objc_autoreleasePoolPop(pool); } - (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port target: (id)target @@ -835,11 +815,11 @@ selector: (SEL)selector context: (id)context { void *pool = objc_autoreleasePoolPush(); - [[[[OFTCPSocket_ConnectContext alloc] + [[[[OFTCPSocket_AsyncConnectContext alloc] initWithSocket: self host: host port: port SOCKS5Host: _SOCKS5Host SOCKS5Port: _SOCKS5Port @@ -867,11 +847,11 @@ runLoopMode: (of_run_loop_mode_t)runLoopMode block: (of_tcp_socket_async_connect_block_t)block { void *pool = objc_autoreleasePoolPush(); - [[[[OFTCPSocket_ConnectContext alloc] + [[[[OFTCPSocket_AsyncConnectContext alloc] initWithSocket: self host: host port: port SOCKS5Host: _SOCKS5Host SOCKS5Port: _SOCKS5Port