Index: src/OFHTTPClient.m ================================================================== --- src/OFHTTPClient.m +++ src/OFHTTPClient.m @@ -54,11 +54,10 @@ @interface OFHTTPClientRequestHandler: OFObject { @public OFHTTPClient *_client; OFHTTPRequest *_request; - OFString *_requestString; unsigned int _redirects; id _context; bool _firstLine; OFString *_version; int _status; @@ -277,11 +276,10 @@ - (void)dealloc { [_client release]; [_request release]; - [_requestString release]; [_context release]; [_version release]; [_serverHeaders release]; [super dealloc]; @@ -555,51 +553,48 @@ } return ret; } -- (size_t)stream: (OF_KINDOF(OFStream *))sock - didWriteBuffer: (const void **)request - length: (size_t)length - exception: (id)exception +- (OFData *)stream: (OF_KINDOF(OFStream *))stream + didWriteData: (OFData *)data + bytesWritten: (size_t)bytesWritten + exception: (id)exception { if (exception != nil) { if ([exception isKindOfClass: [OFWriteFailedException class]] && ([exception errNo] == ECONNRESET || [exception errNo] == EPIPE)) { /* In case a keep-alive connection timed out */ [self closeAndReconnect]; - return 0; + return nil; } [self raiseException: exception]; - return 0; + return nil; } _firstLine = true; - [_requestString release]; - _requestString = nil; - if ([[_request headers] objectForKey: @"Content-Length"] != nil) { - [sock setDelegate: nil]; + [stream setDelegate: nil]; OFStream *requestBody = [[[OFHTTPClientRequestBodyStream alloc] initWithHandler: self - socket: sock] autorelease]; + socket: stream] autorelease]; if ([_client->_delegate respondsToSelector: @selector(client:wantsRequestBody:request:context:)]) [_client->_delegate client: _client wantsRequestBody: requestBody request: _request context: _context]; } else - [sock asyncReadLine]; + [stream asyncReadLine]; - return 0; + return nil; } - (void)handleSocket: (OFTCPSocket *)sock { /* @@ -610,15 +605,16 @@ * We do not use the socket's write buffer in case we need to resend * the entire request (e.g. in case a keep-alive connection timed out). */ @try { - [_requestString release]; - _requestString = [constructRequestString(_request) retain]; + OFString *requestString = constructRequestString(_request); + OFData *requestData = [OFData + dataWithItems: [requestString UTF8String] + count: [requestString UTF8StringLength]]; - [sock asyncWriteBuffer: [_requestString UTF8String] - length: [_requestString UTF8StringLength]]; + [sock asyncWriteData: requestData]; } @catch (id e) { [self raiseException: e]; return; } } Index: src/OFRunLoop+Private.h ================================================================== --- src/OFRunLoop+Private.h +++ src/OFRunLoop+Private.h @@ -53,12 +53,11 @@ encoding: (of_string_encoding_t)encoding mode: (of_run_loop_mode_t)mode delegate: (id )delegate; + (void)of_addAsyncWriteForStream: (OFStream *) stream - buffer: (const void *)buffer - length: (size_t)length + data: (OFData *)data mode: (of_run_loop_mode_t)mode delegate: (id )delegate; + (void)of_addAsyncConnectForTCPSocket: (OFTCPSocket *)socket mode: (of_run_loop_mode_t)mode delegate: (id ) @@ -95,12 +94,11 @@ encoding: (of_string_encoding_t)encoding mode: (of_run_loop_mode_t)mode block: (of_stream_async_read_line_block_t)block; + (void)of_addAsyncWriteForStream: (OFStream *) stream - buffer: (const void *)buffer - length: (size_t)length + data: (OFData *)data mode: (of_run_loop_mode_t)mode block: (of_stream_async_write_block_t)block; + (void)of_addAsyncAcceptForTCPSocket: (OFTCPSocket *)socket mode: (of_run_loop_mode_t)mode block: (of_tcp_socket_async_accept_block_t) Index: src/OFRunLoop.m ================================================================== --- src/OFRunLoop.m +++ src/OFRunLoop.m @@ -20,10 +20,11 @@ #include #include #import "OFRunLoop.h" #import "OFRunLoop+Private.h" +#import "OFData.h" #import "OFDictionary.h" #ifdef OF_HAVE_SOCKETS # import "OFKernelEventObserver.h" # import "OFTCPSocket.h" # import "OFTCPSocket+Private.h" @@ -116,12 +117,12 @@ { @public # ifdef OF_HAVE_BLOCKS of_stream_async_write_block_t _block; # endif - const void *_buffer; - size_t _length, _writtenLength; + OFData *_data; + size_t _writtenLength; } @end @interface OFRunLoop_ConnectQueueItem: OFRunLoop_QueueItem @end @@ -448,62 +449,75 @@ @implementation OFRunLoop_WriteQueueItem - (bool)handleObject: (id)object { size_t length; id exception = nil; + size_t dataLength = [_data count] * [_data itemSize]; + OFData *newData, *oldData; @try { - length = [object writeBuffer: (char *)_buffer + _writtenLength - length: _length - _writtenLength]; + const char *dataItems = [_data items]; + + length = [object writeBuffer: dataItems + _writtenLength + length: dataLength - _writtenLength]; } @catch (id e) { length = 0; exception = e; } _writtenLength += length; - if (_writtenLength != _length && exception == nil) + if (_writtenLength != dataLength && exception == nil) return true; # ifdef OF_HAVE_BLOCKS if (_block != NULL) { - _length = _block(object, &_buffer, _writtenLength, exception); + newData = _block(object, _data, _writtenLength, exception); - if (_length == 0) + if (newData == nil) return false; + oldData = _data; + _data = [newData copy]; + [oldData release]; + _writtenLength = 0; return true; } else { # endif if (![_delegate respondsToSelector: - @selector(stream:didWriteBuffer:length:exception:)]) + @selector(stream:didWriteData:bytesWritten:exception:)]) return false; - _length = [_delegate stream: object - didWriteBuffer: &_buffer - length: _length + newData = [_delegate stream: object + didWriteData: _data + bytesWritten: _writtenLength exception: exception]; - if (_length == 0) + if (newData == nil) return false; + oldData = _data; + _data = [newData copy]; + [oldData release]; + _writtenLength = 0; return true; # ifdef OF_HAVE_BLOCKS } # endif } -# ifdef OF_HAVE_BLOCKS - (void)dealloc { + [_data release]; +# ifdef OF_HAVE_BLOCKS [_block release]; +# endif [super dealloc]; } -# endif @end @implementation OFRunLoop_ConnectQueueItem - (bool)handleObject: (id)object { @@ -769,19 +783,17 @@ }) } + (void)of_addAsyncWriteForStream: (OFStream *) stream - buffer: (const void *)buffer - length: (size_t)length + data: (OFData *)data mode: (of_run_loop_mode_t)mode delegate: (id )delegate { ADD_WRITE(OFRunLoop_WriteQueueItem, stream, mode, { queueItem->_delegate = [delegate retain]; - queueItem->_buffer = buffer; - queueItem->_length = length; + queueItem->_data = [data copy]; }) } + (void)of_addAsyncConnectForTCPSocket: (OFTCPSocket *)stream mode: (of_run_loop_mode_t)mode @@ -871,19 +883,17 @@ }) } + (void)of_addAsyncWriteForStream: (OFStream *) stream - buffer: (const void *)buffer - length: (size_t)length + data: (OFData *)data mode: (of_run_loop_mode_t)mode block: (of_stream_async_write_block_t)block { ADD_WRITE(OFRunLoop_WriteQueueItem, stream, mode, { + queueItem->_data = [data copy]; queueItem->_block = [block copy]; - queueItem->_buffer = buffer; - queueItem->_length = length; }) } + (void)of_addAsyncAcceptForTCPSocket: (OFTCPSocket *)stream mode: (of_run_loop_mode_t)mode Index: src/OFStream.h ================================================================== --- src/OFStream.h +++ src/OFStream.h @@ -69,25 +69,20 @@ /*! * @brief A block which is called when data was written asynchronously to a * stream. * - * @param stream The stream to which data was written - * @param buffer A pointer to the buffer which was written to the stream. This - * can be changed to point to a different buffer to be used on the - * next write. + * @param data The data which was written to the stream * @param bytesWritten The number of bytes which have been written. This - * matches the length specified on the asynchronous write - * if no exception was encountered. + * matches the length of the specified data on the + * asynchronous write if no exception was encountered. * @param exception An exception which occurred while writing or `nil` on * success - * @return The length to repeat the write with or 0 if it should not repeat. - * The buffer may be changed, so that every time a new buffer and length - * can be specified + * @return The data to repeat the write with or nil if it should not repeat */ -typedef size_t (^of_stream_async_write_block_t)(OF_KINDOF(OFStream *) stream, - const void *_Nonnull *_Nonnull buffer, size_t bytesWritten, +typedef OFData *_Nullable (^of_stream_async_write_block_t)( + OF_KINDOF(OFStream *) stream, OFData *_Nonnull data, size_t bytesWritten, id _Nullable exception); #endif /*! * @protocol OFStreamDelegate OFStream.h ObjFW/OFStream.h @@ -128,23 +123,21 @@ /*! * @brief This method is called when data was written asynchronously to a * stream. * * @param stream The stream to which data was written - * @param buffer A pointer to the buffer which was written to the stream. This - * can be changed to point to a different buffer to be used on the - * next write. - * @param length The length of the buffer that has been written + * @param data The data which was written to the stream + * @param bytesWritten The number of bytes which have been written. This + * matches the length of the specified data on the + * asynchronous write if no exception was encountered. * @param exception An exception that occurred while writing, or nil on success - * @return The length to repeat the write with or 0 if it should not repeat. - * The buffer may be changed, so that every time a new buffer and - * length can be specified + * @return The data to repeat the write with or nil if it should not repeat */ -- (size_t)stream: (OF_KINDOF(OFStream *))stream - didWriteBuffer: (const void *_Nonnull *_Nonnull)buffer - length: (size_t)length - exception: (nullable id)exception; +- (nullable OFData *)stream: (OF_KINDOF(OFStream *))stream + didWriteData: (OFData *)data + bytesWritten: (size_t)bytesWritten + exception: (nullable id)exception; @end /*! * @class OFStream OFStream.h ObjFW/OFStream.h * @@ -958,77 +951,61 @@ - (size_t)writeBuffer: (const void *)buffer length: (size_t)length; #ifdef OF_HAVE_SOCKETS /*! - * @brief Asynchronously writes a buffer into the stream. - * - * @note The stream must conform to @ref OFReadyForWritingObserving in order - * for this to work! - * - * @param buffer The buffer from which the data is written into the stream. The - * buffer needs to be valid until the write request is completed! - * @param length The length of the data that should be written - */ -- (void)asyncWriteBuffer: (const void *)buffer - length: (size_t)length; - -/*! - * @brief Asynchronously writes a buffer into the stream. - * - * @note The stream must conform to @ref OFReadyForWritingObserving in order - * for this to work! - * - * @param buffer The buffer from which the data is written into the stream. The - * buffer needs to be valid until the write request is completed! - * @param length The length of the data that should be written - * @param runLoopMode The run loop mode in which to perform the async write - */ -- (void)asyncWriteBuffer: (const void *)buffer - length: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode; - -# ifdef OF_HAVE_BLOCKS -/*! - * @brief Asynchronously writes a buffer into the stream. - * - * @note The stream must conform to @ref OFReadyForWritingObserving in order - * for this to work! - * - * @param buffer The buffer from which the data is written into the stream. The - * buffer needs to be valid until the write request is completed! - * @param length The length of the data that should be written - * @param block The block to call when the data has been written. It should - * return the length for the next write with the same callback or - * 0 if it should not repeat. The buffer may be changed, so that - * every time a new buffer and length can be specified while the - * callback stays the same. - */ -- (void)asyncWriteBuffer: (const void *)buffer - length: (size_t)length - block: (of_stream_async_write_block_t)block; - -/*! - * @brief Asynchronously writes a buffer into the stream. - * - * @note The stream must conform to @ref OFReadyForWritingObserving in order - * for this to work! - * - * @param buffer The buffer from which the data is written into the stream. The - * buffer needs to be valid until the write request is completed! - * @param length The length of the data that should be written - * @param runLoopMode The run loop mode in which to perform the async write - * @param block The block to call when the data has been written. It should - * return the length for the next write with the same callback or - * 0 if it should not repeat. The buffer may be changed, so that - * every time a new buffer and length can be specified while the - * callback stays the same. - */ -- (void)asyncWriteBuffer: (const void *)buffer - length: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_stream_async_write_block_t)block; + * @brief Asynchronously writes data into the stream. + * + * @note The stream must conform to @ref OFReadyForWritingObserving in order + * for this to work! + * + * @param data The data which is written into the stream + */ +- (void)asyncWriteData: (OFData *)data; + +/*! + * @brief Asynchronously writes data into the stream. + * + * @note The stream must conform to @ref OFReadyForWritingObserving in order + * for this to work! + * + * @param data The data which is written into the stream + * @param runLoopMode The run loop mode in which to perform the async write + */ +- (void)asyncWriteData: (OFData *)data + runLoopMode: (of_run_loop_mode_t)runLoopMode; + +# ifdef OF_HAVE_BLOCKS +/*! + * @brief Asynchronously writes data into the stream. + * + * @note The stream must conform to @ref OFReadyForWritingObserving in order + * for this to work! + * + * @param data The data which is written into the stream + * @param block The block to call when the data has been written. It should + * return the data for the next write with the same callback or + * nil if it should not repeat. + */ +- (void)asyncWriteData: (OFData *)data + block: (of_stream_async_write_block_t)block; + +/*! + * @brief Asynchronously writes data into the stream. + * + * @note The stream must conform to @ref OFReadyForWritingObserving in order + * for this to work! + * + * @param data The data which is written into the stream + * @param runLoopMode The run loop mode in which to perform the async write + * @param block The block to call when the data has been written. It should + * return the data for the next write with the same callback or + * nil if it should not repeat. + */ +- (void)asyncWriteData: (OFData *)data + runLoopMode: (of_run_loop_mode_t)runLoopMode + block: (of_stream_async_write_block_t)block; # endif #endif /*! * @brief Writes a uint8_t into the stream. Index: src/OFStream.m ================================================================== --- src/OFStream.m +++ src/OFStream.m @@ -1164,54 +1164,46 @@ return length; } } #ifdef OF_HAVE_SOCKETS -- (void)asyncWriteBuffer: (const void *)buffer - length: (size_t)length +- (void)asyncWriteData: (OFData *)data { - [self asyncWriteBuffer: buffer - length: length - runLoopMode: of_run_loop_mode_default]; + [self asyncWriteData: data + runLoopMode: of_run_loop_mode_default]; } -- (void)asyncWriteBuffer: (const void *)buffer - length: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode +- (void)asyncWriteData: (OFData *)data + runLoopMode: (of_run_loop_mode_t)runLoopMode { OFStream *stream = (OFStream *)self; [OFRunLoop of_addAsyncWriteForStream: stream - buffer: buffer - length: length + data: data mode: runLoopMode delegate: _delegate]; } # ifdef OF_HAVE_BLOCKS -- (void)asyncWriteBuffer: (const void *)buffer - length: (size_t)length - block: (of_stream_async_write_block_t)block -{ - [self asyncWriteBuffer: buffer - length: length - runLoopMode: of_run_loop_mode_default - block: block]; +- (void)asyncWriteData: (OFData *)data + block: (of_stream_async_write_block_t)block +{ + [self asyncWriteData: data + runLoopMode: of_run_loop_mode_default + block: block]; } -- (void)asyncWriteBuffer: (const void *)buffer - length: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_stream_async_write_block_t)block +- (void)asyncWriteData: (OFData *)data + runLoopMode: (of_run_loop_mode_t)runLoopMode + block: (of_stream_async_write_block_t)block { OFStream *stream = (OFStream *)self; [OFRunLoop of_addAsyncWriteForStream: stream - buffer: buffer - length: length + data: data mode: runLoopMode block: block]; } # endif #endif Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -361,14 +361,16 @@ context: nil]; } - (void)sendSOCKS5Request { + OFData *data = [OFData dataWithItems: "\x05\x01\x00" + count: 3]; + _SOCKS5State = SOCKS5_STATE_SEND_AUTHENTICATION; - [_socket asyncWriteBuffer: "\x05\x01\x00" - length: 3 - runLoopMode: [[OFRunLoop currentRunLoop] currentMode]]; + [_socket asyncWriteData: data + runLoopMode: [[OFRunLoop currentRunLoop] currentMode]]; } - (bool)stream: (OF_KINDOF(OFStream *))sock didReadIntoBuffer: (void *)buffer length: (size_t)length @@ -417,13 +419,12 @@ port[1] = _port & 0xFF; [_request addItems: port count: 2]; _SOCKS5State = SOCKS5_STATE_SEND_REQUEST; - [_socket asyncWriteBuffer: [_request items] - length: [_request count] - runLoopMode: runLoopMode]; + [_socket asyncWriteData: _request + runLoopMode: runLoopMode]; return false; case SOCKS5_STATE_READ_RESPONSE: response = buffer; if (response[0] != 5 || response[2] != 0) { @@ -521,21 +522,21 @@ assert(0); return false; } } -- (size_t)stream: (OF_KINDOF(OFStream *))sock - didWriteBuffer: (const void **)buffer - length: (size_t)length - exception: (id)exception +- (OFData *)stream: (OF_KINDOF(OFStream *))sock + didWriteData: (OFData *)data + bytesWritten: (size_t)bytesWritten + exception: (id)exception { of_run_loop_mode_t runLoopMode; if (exception != nil) { _exception = [exception retain]; [self didConnect]; - return 0; + return nil; } runLoopMode = [[OFRunLoop currentRunLoop] currentMode]; switch (_SOCKS5State) { @@ -542,23 +543,23 @@ case SOCKS5_STATE_SEND_AUTHENTICATION: _SOCKS5State = SOCKS5_STATE_READ_VERSION; [_socket asyncReadIntoBuffer: _buffer exactLength: 2 runLoopMode: runLoopMode]; - return 0; + return nil; case SOCKS5_STATE_SEND_REQUEST: [_request release]; _request = nil; _SOCKS5State = SOCKS5_STATE_READ_RESPONSE; [_socket asyncReadIntoBuffer: _buffer exactLength: 4 runLoopMode: runLoopMode]; - return 0; + return nil; default: assert(0); - return 0; + return nil; } } @end @implementation OFTCPSocket_ConnectDelegate