Index: src/OFHTTPClient.m ================================================================== --- src/OFHTTPClient.m +++ src/OFHTTPClient.m @@ -49,11 +49,11 @@ #import "OFUnsupportedVersionException.h" #import "OFWriteFailedException.h" #define REDIRECTS_DEFAULT 10 -@interface OFHTTPClientRequestHandler: OFObject +@interface OFHTTPClientRequestHandler: OFObject { @public OFHTTPClient *_client; OFHTTPRequest *_request; OFString *_requestString; @@ -613,20 +613,15 @@ [self raiseException: e]; return; } } -- (void)socketDidConnect: (OFTCPSocket *)sock - context: (id)context - exception: (id)exception -{ - if (exception != nil) { - [self raiseException: exception]; - return; - } - - [sock setDelegate: self]; +- (void)socket: (OF_KINDOF(OFTCPSocket *))sock + didConnectToHost: (OFString *)host + port: (uint16_t)port +{ + [(OFTCPSocket *)sock setDelegate: self]; if ([_client->_delegate respondsToSelector: @selector(client:didCreateSocket:request:context:)]) [_client->_delegate client: _client didCreateSocket: sock @@ -695,16 +690,13 @@ URLPort = [URL port]; if (URLPort != nil) port = [URLPort uInt16Value]; + [sock setDelegate: self]; [sock asyncConnectToHost: [URL host] - port: port - target: self - selector: @selector(socketDidConnect:context: - exception:) - context: nil]; + port: port]; } @catch (id e) { [self raiseException: e]; } } @end Index: src/OFHTTPServer.m ================================================================== --- src/OFHTTPServer.m +++ src/OFHTTPServer.m @@ -48,15 +48,11 @@ /* * FIXME: Key normalization replaces headers like "DNT" with "Dnt". * FIXME: Errors are not reported to the user. */ -@interface OFHTTPServer () -- (bool)of_socket: (OFTCPSocket *)sock - didAcceptSocket: (OFTCPSocket *)clientSocket - context: (id)context - exception: (id)exception; +@interface OFHTTPServer () @end @interface OFHTTPServerResponse: OFHTTPResponse { OF_KINDOF(OFTCPSocket *) _socket; @@ -68,11 +64,11 @@ - (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock server: (OFHTTPServer *)server request: (OFHTTPRequest *)request; @end -@interface OFHTTPServer_Connection: OFObject +@interface OFHTTPServer_Connection: OFObject { @public OF_KINDOF(OFTCPSocket *) _socket; OFHTTPServer *_server; OFTimer *_timer; @@ -778,45 +774,39 @@ _port = [_listeningSocket bindToHost: _host port: _port]; [_listeningSocket listen]; - [_listeningSocket asyncAcceptWithTarget: self - selector: @selector(of_socket: - didAcceptSocket:context: - exception:) - context: nil]; + [(OFTCPSocket *)_listeningSocket setDelegate: self]; + [_listeningSocket asyncAccept]; } - (void)stop { [_listeningSocket cancelAsyncRequests]; [_listeningSocket release]; _listeningSocket = nil; } -- (bool)of_socket: (OFTCPSocket *)sock - didAcceptSocket: (OFTCPSocket *)clientSocket - context: (id)context - exception: (id)exception -{ - OFHTTPServer_Connection *connection; - - if (exception != nil) { - if ([_delegate respondsToSelector: - @selector(server:didReceiveExceptionOnListeningSocket:)]) - return [_delegate server: self - didReceiveExceptionOnListeningSocket: exception]; - - return false; - } - - connection = [[[OFHTTPServer_Connection alloc] - initWithSocket: clientSocket +- (bool)socket: (OF_KINDOF(OFTCPSocket *))sock + didAcceptSocket: (OF_KINDOF(OFTCPSocket *))acceptedSocket +{ + OFHTTPServer_Connection *connection = [[[OFHTTPServer_Connection alloc] + initWithSocket: acceptedSocket server: self] autorelease]; - [clientSocket setDelegate: connection]; - [clientSocket asyncReadLine]; + [(OFTCPSocket *)acceptedSocket setDelegate: connection]; + [acceptedSocket asyncReadLine]; return true; } + +- (void)stream: (OF_KINDOF(OFStream *))stream + didFailWithException: (id)exception +{ + if ([_delegate respondsToSelector: + @selector(server:didReceiveExceptionOnListeningSocket:)]) + if ([_delegate server: self + didReceiveExceptionOnListeningSocket: exception]) + [stream asyncAccept]; +} @end Index: src/OFRunLoop+Private.h ================================================================== --- src/OFRunLoop+Private.h +++ src/OFRunLoop+Private.h @@ -53,17 +53,14 @@ mode: (of_run_loop_mode_t)mode delegate: (id )delegate; + (void)of_addAsyncConnectForTCPSocket: (OFTCPSocket *)socket mode: (of_run_loop_mode_t)mode target: (id)target - selector: (SEL)selector - context: (nullable id)context; + selector: (SEL)selector; + (void)of_addAsyncAcceptForTCPSocket: (OFTCPSocket *)socket mode: (of_run_loop_mode_t)mode - target: (id)target - selector: (SEL)selector - context: (nullable id)context; + delegate: (id )delegate; + (void)of_addAsyncReceiveForUDPSocket: (OFUDPSocket *)socket buffer: (void *)buffer length: (size_t)length mode: (of_run_loop_mode_t)mode target: (id)target Index: src/OFRunLoop.m ================================================================== --- src/OFRunLoop.m +++ src/OFRunLoop.m @@ -565,31 +565,40 @@ @end @implementation OFRunLoop_AcceptQueueItem - (bool)handleObject: (id)object { - OFTCPSocket *newSocket; + OFTCPSocket *acceptedSocket; id exception = nil; @try { - newSocket = [object accept]; + acceptedSocket = [object accept]; } @catch (id e) { - newSocket = nil; + acceptedSocket = nil; exception = e; } # ifdef OF_HAVE_BLOCKS if (_block != NULL) - return _block(object, newSocket, exception); + return _block(object, acceptedSocket, exception); else { # endif - bool (*func)(id, SEL, OFTCPSocket *, OFTCPSocket *, id, id) = - (bool (*)(id, SEL, OFTCPSocket *, OFTCPSocket *, id, id)) - [_target methodForSelector: _selector]; + if (exception == nil) { + if (![_delegate respondsToSelector: + @selector(socket:didAcceptSocket:)]) + return false; - return func(_target, _selector, object, newSocket, _context, - exception); + return [_delegate socket: object + didAcceptSocket: acceptedSocket]; + } else { + if ([_delegate respondsToSelector: + @selector(stream:didFailWithException:)]) + [_delegate stream: object + didFailWithException: exception]; + + return false; + } # ifdef OF_HAVE_BLOCKS } # endif } @@ -821,29 +830,23 @@ + (void)of_addAsyncConnectForTCPSocket: (OFTCPSocket *)stream mode: (of_run_loop_mode_t)mode target: (id)target selector: (SEL)selector - context: (id)context { ADD_WRITE(OFRunLoop_ConnectQueueItem, stream, mode, { queueItem->_target = [target retain]; queueItem->_selector = selector; - queueItem->_context = [context retain]; }) } + (void)of_addAsyncAcceptForTCPSocket: (OFTCPSocket *)stream mode: (of_run_loop_mode_t)mode - target: (id)target - selector: (SEL)selector - context: (id)context + delegate: (id )delegate { ADD_READ(OFRunLoop_AcceptQueueItem, stream, mode, { - queueItem->_target = [target retain]; - queueItem->_selector = selector; - queueItem->_context = [context retain]; + queueItem->_delegate = [delegate retain]; }) } + (void)of_addAsyncReceiveForUDPSocket: (OFUDPSocket *)sock buffer: (void *)buffer Index: src/OFStream.h ================================================================== --- src/OFStream.h +++ src/OFStream.h @@ -178,11 +178,11 @@ char *_Nullable _writeBuffer; size_t _readBufferLength, _writeBufferLength; bool _writeBuffered, _waitingForDelimiter; @protected bool _blocking; - id _Nullable _delegate; + id _Nullable _delegate; } /*! * @brief Whether the end of the stream has been reached. */ Index: src/OFTCPSocket.h ================================================================== --- src/OFTCPSocket.h +++ src/OFTCPSocket.h @@ -51,10 +51,37 @@ typedef bool (^of_tcp_socket_async_accept_block_t)( OF_KINDOF(OFTCPSocket *) socket, OF_KINDOF(OFTCPSocket *) acceptedSocket, id _Nullable exception); #endif +/*! + * @protocol OFTCPSocketDelegate OFTCPSocket.h ObjFW/OFTCPSocket.h + * + * A delegate for OFTCPSocket. + */ +@protocol OFTCPSocketDelegate +@optional +/*! + * @brief A method which is called when a socket connected. + * + * @param socket The socket which connected + */ +- (void)socket: (OF_KINDOF(OFTCPSocket *))socket + didConnectToHost: (OFString *)host + port: (uint16_t)port; + +/*! + * @brief A method which is called when a socket accepted a connection. + * + * @param socket The socket which accepted the connection + * @param acceptedSocket The socket which has been accepted + * @return A bool whether to accept the next incoming connection + */ +- (bool)socket: (OF_KINDOF(OFTCPSocket *))socket + didAcceptSocket: (OF_KINDOF(OFTCPSocket *))acceptedSocket; +@end + /*! * @class OFTCPSocket OFTCPSocket.h ObjFW/OFTCPSocket.h * * @brief A class which provides methods to create and use TCP sockets. * @@ -115,10 +142,19 @@ /*! * @brief The port to use on the SOCKS5 proxy. */ @property (nonatomic) uint16_t SOCKS5Port; +/*! + * @brief The delegate for asynchronous operations on the socket. + * + * @note The delegate is retained for as long as asynchronous operations are + * still outstanding. + */ +@property OF_NULLABLE_PROPERTY (assign, nonatomic) + id delegate; + /*! * @brief Sets the global SOCKS5 proxy host to use when creating a new socket * * @param SOCKS5Host The host to use as a SOCKS5 proxy when creating a new * socket @@ -158,40 +194,24 @@ /*! * @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 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 - target: (id)target - selector: (SEL)selector - context: (nullable id)context; + port: (uint16_t)port; /*! * @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; + runLoopMode: (of_run_loop_mode_t)runLoopMode; #ifdef OF_HAVE_BLOCKS /*! * @brief Asynchronously connect the OFTCPSocket to the specified destination. * @@ -248,41 +268,19 @@ */ - (instancetype)accept; /*! * @brief Asynchronously accept an incoming connection. - * - * @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)asyncAcceptWithTarget: (id)target - selector: (SEL)selector - context: (nullable id)context; +- (void)asyncAccept; /*! * @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; +- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode; #ifdef OF_HAVE_BLOCKS /*! * @brief Asynchronously accept an incoming connection. * Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -62,20 +62,18 @@ static of_run_loop_mode_t connectRunLoopMode = @"of_tcp_socket_connect_mode"; static OFString *defaultSOCKS5Host = nil; static uint16_t defaultSOCKS5Port = 1080; -@interface OFTCPSocket_AsyncConnectContext: OFObject +@interface OFTCPSocket_AsyncConnectContext: OFObject { OFTCPSocket *_socket; OFString *_host; uint16_t _port; OFString *_SOCKS5Host; uint16_t _SOCKS5Port; - id _target; - SEL _selector; - id _context; + id _delegate; #ifdef OF_HAVE_BLOCKS of_tcp_socket_async_connect_block_t _block; #endif id _exception; OFData *_socketAddresses; @@ -96,13 +94,11 @@ - (instancetype)initWithSocket: (OFTCPSocket *)sock host: (OFString *)host port: (uint16_t)port SOCKS5Host: (OFString *)SOCKS5Host SOCKS5Port: (uint16_t)SOCKS5Port - target: (id)target - selector: (SEL)selector - context: (id)context; + delegate: (id )delegate; #ifdef OF_HAVE_BLOCKS - (instancetype)initWithSocket: (OFTCPSocket *)sock host: (OFString *)host port: (uint16_t)port SOCKS5Host: (OFString *)SOCKS5Host @@ -109,11 +105,10 @@ SOCKS5Port: (uint16_t)SOCKS5Port block: (of_tcp_socket_async_connect_block_t)block; #endif - (void)didConnect; - (void)socketDidConnect: (OFTCPSocket *)sock - context: (id)context exception: (id)exception; - (void)tryNextAddressWithRunLoopMode: (of_run_loop_mode_t)runLoopMode; - (void)resolver: (OFDNSResolver *)resolver didResolveDomainName: (OFString *)domainName socketAddresses: (OFData *)socketAddresses @@ -121,43 +116,35 @@ exception: (id)exception; - (void)startWithRunLoopMode: (of_run_loop_mode_t)runLoopMode; - (void)sendSOCKS5Request; @end -@interface OFTCPSocket_ConnectContext: OFObject +@interface OFTCPSocket_ConnectDelegate: OFObject { @public bool _done; 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 - target: (id)target - selector: (SEL)selector - context: (id)context + delegate: (id )delegate { self = [super init]; @try { _socket = [sock retain]; _host = [host copy]; _port = port; _SOCKS5Host = [SOCKS5Host copy]; _SOCKS5Port = SOCKS5Port; - _target = [target retain]; - _selector = selector; - _context = [context retain]; + _delegate = [delegate retain]; [_socket setDelegate: self]; } @catch (id e) { [self release]; @throw e; @@ -192,18 +179,20 @@ } #endif - (void)dealloc { - if ([_socket delegate] == self) - [_socket setDelegate: nil]; +#ifdef OF_HAVE_BLOCKS + if (_block != NULL) +#endif + if ([_socket delegate] == self) + [_socket setDelegate: _delegate]; [_socket release]; [_host release]; [_SOCKS5Host release]; - [_target release]; - [_context release]; + [_delegate release]; #ifdef OF_HAVE_BLOCKS [_block release]; #endif [_exception release]; [_socketAddresses release]; @@ -212,32 +201,38 @@ [super dealloc]; } - (void)didConnect { - [_socket setDelegate: nil]; - if (_exception == nil) [_socket setBlocking: true]; #ifdef OF_HAVE_BLOCKS if (_block != NULL) _block(_socket, _exception); else { #endif - void (*func)(id, SEL, OFTCPSocket *, id, id) = - (void (*)(id, SEL, OFTCPSocket *, id, id)) - [_target methodForSelector: _selector]; + [_socket setDelegate: _delegate]; - func(_target, _selector, _socket, _context, _exception); + if (_exception == nil) { + if ([_delegate respondsToSelector: + @selector(socket:didConnectToHost:port:)]) + [_delegate socket: _socket + didConnectToHost: _host + port: _port]; + } else { + if ([_delegate respondsToSelector: + @selector(stream:didFailWithException:)]) + [_delegate stream: _socket + didFailWithException: _exception]; + } #ifdef OF_HAVE_BLOCKS } #endif } - (void)socketDidConnect: (OFTCPSocket *)sock - context: (id)context exception: (id)exception { if (exception != nil) { if (_socketAddressesIndex >= [_socketAddresses count]) { _exception = [exception retain]; @@ -286,18 +281,16 @@ [_socket setBlocking: false]; if (![_socket of_connectSocketToAddress: &address errNo: &errNo]) { if (errNo == EINPROGRESS) { - SEL selector = @selector(socketDidConnect:context: - exception:); + SEL selector = @selector(socketDidConnect:exception:); [OFRunLoop of_addAsyncConnectForTCPSocket: _socket mode: runLoopMode target: self - selector: selector - context: nil]; + selector: selector]; return; } else { [_socket of_closeSocket]; if (_socketAddressesIndex >= [_socketAddresses count]) { @@ -499,12 +492,12 @@ runLoopMode: runLoopMode]; return false; case 4: /* IPv6 */ _SOCKS5State = SOCKS5_STATE_READ_ADDRESS; [_socket asyncReadIntoBuffer: _buffer - exactLength: 16 + 2 - runLoopMode: runLoopMode]; + exactLength: 16 + 2 + runLoopMode: runLoopMode]; return false; default: _exception = [[OFConnectionFailedException alloc] initWithHost: _host port: _port @@ -567,29 +560,36 @@ _exception = [exception retain]; [self didConnect]; } @end -@implementation OFTCPSocket_ConnectContext +@implementation OFTCPSocket_ConnectDelegate - (void)dealloc { [_exception release]; [super dealloc]; } -- (void)socketDidConnect: (OFTCPSocket *)sock - context: (id)context - exception: (id)exception +- (void)socket: (OF_KINDOF(OFTCPSocket *))sock + didConnectToHost: (OFString *)host + port: (uint16_t)port { - _exception = [exception retain]; + _done = true; +} + +- (void)stream: (OF_KINDOF(OFStream *))stream + didFailWithException: (id)exception +{ _done = true; + _exception = [exception retain]; } @end @implementation OFTCPSocket @synthesize SOCKS5Host = _SOCKS5Host, SOCKS5Port = _SOCKS5Port; +@dynamic delegate; + (void)setSOCKS5Host: (OFString *)host { id old = defaultSOCKS5Host; defaultSOCKS5Host = [host copy]; @@ -693,67 +693,57 @@ - (void)connectToHost: (OFString *)host port: (uint16_t)port { void *pool = objc_autoreleasePoolPush(); - OFTCPSocket_ConnectContext *context = - [[[OFTCPSocket_ConnectContext alloc] init] autorelease]; + id delegate = [_delegate retain]; + OFTCPSocket_ConnectDelegate *connectDelegate = + [[[OFTCPSocket_ConnectDelegate alloc] init] autorelease]; OFRunLoop *runLoop = [OFRunLoop currentRunLoop]; + [self setDelegate: connectDelegate]; [self asyncConnectToHost: host port: port - runLoopMode: connectRunLoopMode - target: context - selector: @selector(socketDidConnect:context:exception:) - context: nil]; + runLoopMode: connectRunLoopMode]; - while (!context->_done) + while (!connectDelegate->_done) [runLoop runMode: connectRunLoopMode beforeDate: nil]; /* Cleanup */ [runLoop runMode: connectRunLoopMode beforeDate: [OFDate date]]; - if (context->_exception != nil) - @throw context->_exception; + if (connectDelegate->_exception != nil) + @throw connectDelegate->_exception; + + [self setDelegate: delegate]; objc_autoreleasePoolPop(pool); } - (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]; + runLoopMode: of_run_loop_mode_default]; } - (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_AsyncConnectContext alloc] - initWithSocket: self - host: host - port: port - SOCKS5Host: _SOCKS5Host - SOCKS5Port: _SOCKS5Port - target: target - selector: selector - context: context] autorelease] + initWithSocket: self + host: host + port: port + SOCKS5Host: _SOCKS5Host + SOCKS5Port: _SOCKS5Port + delegate: _delegate] autorelease] startWithRunLoopMode: runLoopMode]; objc_autoreleasePoolPop(pool); } @@ -774,16 +764,16 @@ block: (of_tcp_socket_async_connect_block_t)block { void *pool = objc_autoreleasePoolPush(); [[[[OFTCPSocket_AsyncConnectContext alloc] - initWithSocket: self - host: host - port: port - SOCKS5Host: _SOCKS5Host - SOCKS5Port: _SOCKS5Port - block: block] autorelease] + initWithSocket: self + host: host + port: port + SOCKS5Host: _SOCKS5Host + SOCKS5Port: _SOCKS5Port + block: block] autorelease] startWithRunLoopMode: runLoopMode]; objc_autoreleasePoolPop(pool); } #endif @@ -1005,30 +995,20 @@ } return client; } -- (void)asyncAcceptWithTarget: (id)target - selector: (SEL)selector - context: (id)context -{ - [self asyncAcceptWithRunLoopMode: of_run_loop_mode_default - target: target - selector: selector - context: context]; +- (void)asyncAccept +{ + [self asyncAcceptWithRunLoopMode: of_run_loop_mode_default]; } - (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode - target: (id)target - selector: (SEL)selector - context: (id)context { [OFRunLoop of_addAsyncAcceptForTCPSocket: self mode: runLoopMode - target: target - selector: selector - context: context]; + delegate: _delegate]; } #ifdef OF_HAVE_BLOCKS - (void)asyncAcceptWithBlock: (of_tcp_socket_async_accept_block_t)block {