Index: src/OFStream.m ================================================================== --- src/OFStream.m +++ src/OFStream.m @@ -23,10 +23,14 @@ #include #include #include #include #include + +#ifdef HAVE_FCNTL_H +# include +#endif #include "platform.h" #if !defined(OF_WINDOWS) && !defined(OF_MORPHOS) # include @@ -1661,11 +1665,71 @@ return _blocking; } - (void)setBlocking: (bool)enable { +#if defined(HAVE_FCNTL) + bool readImplemented = false, writeImplemented = false; + + @try { + int readFlags; + + readFlags = fcntl([self fileDescriptorForReading], F_GETFL); + + readImplemented = true; + + if (readFlags == -1) + @throw [OFSetOptionFailedException + exceptionWithObject: self + errNo: errno]; + + if (enable) + readFlags &= ~O_NONBLOCK; + else + readFlags |= O_NONBLOCK; + + if (fcntl([self fileDescriptorForReading], F_SETFL, + readFlags) == -1) + @throw [OFSetOptionFailedException + exceptionWithObject: self + errNo: errno]; + } @catch (OFNotImplementedException *e) { + } + + @try { + int writeFlags; + + writeFlags = fcntl([self fileDescriptorForWriting], F_GETFL); + + writeImplemented = true; + + if (writeFlags == -1) + @throw [OFSetOptionFailedException + exceptionWithObject: self + errNo: errno]; + + if (enable) + writeFlags &= ~O_NONBLOCK; + else + writeFlags |= O_NONBLOCK; + + if (fcntl([self fileDescriptorForWriting], F_SETFL, + writeFlags) == -1) + @throw [OFSetOptionFailedException + exceptionWithObject: self + errNo: errno]; + } @catch (OFNotImplementedException *e) { + } + + if (!readImplemented && !writeImplemented) + @throw [OFNotImplementedException exceptionWithSelector: _cmd + object: self]; + + _blocking = enable; +#else OF_UNRECOGNIZED_SELECTOR +#endif } - (int)fileDescriptorForReading { OF_UNRECOGNIZED_SELECTOR Index: src/OFStreamSocket.m ================================================================== --- src/OFStreamSocket.m +++ src/OFStreamSocket.m @@ -20,14 +20,10 @@ #include "config.h" #include #include -#ifdef HAVE_FCNTL_H -# include -#endif - #import "OFStreamSocket.h" #import "OFInitializationFailedException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" @@ -126,83 +122,23 @@ #endif return (size_t)bytesWritten; } +#ifdef OF_WINDOWS - (void)setBlocking: (bool)enable { -#if defined(HAVE_FCNTL) - bool readImplemented = false, writeImplemented = false; - - @try { - int readFlags; - - readFlags = fcntl([self fileDescriptorForReading], F_GETFL); - - readImplemented = true; - - if (readFlags == -1) - @throw [OFSetOptionFailedException - exceptionWithStream: self - errNo: errno]; - - if (enable) - readFlags &= ~O_NONBLOCK; - else - readFlags |= O_NONBLOCK; - - if (fcntl([self fileDescriptorForReading], F_SETFL, - readFlags) == -1) - @throw [OFSetOptionFailedException - exceptionWithStream: self - errNo: errno]; - } @catch (OFNotImplementedException *e) { - } - - @try { - int writeFlags; - - writeFlags = fcntl([self fileDescriptorForWriting], F_GETFL); - - writeImplemented = true; - - if (writeFlags == -1) - @throw [OFSetOptionFailedException - exceptionWithStream: self - errNo: errno]; - - if (enable) - writeFlags &= ~O_NONBLOCK; - else - writeFlags |= O_NONBLOCK; - - if (fcntl([self fileDescriptorForWriting], F_SETFL, - writeFlags) == -1) - @throw [OFSetOptionFailedException - exceptionWithStream: self - errNo: errno]; - } @catch (OFNotImplementedException *e) { - } - - if (!readImplemented && !writeImplemented) - @throw [OFNotImplementedException exceptionWithSelector: _cmd - object: self]; - - _blocking = enable; -#elif defined(OF_WINDOWS) u_long v = enable; if (ioctlsocket(_socket, FIONBIO, &v) == SOCKET_ERROR) @throw [OFSetOptionFailedException - exceptionWithStream: self + exceptionWithObject: self errNo: of_socket_errno()]; _blocking = enable; -#else - OF_UNRECOGNIZED_SELECTOR -#endif } +#endif - (int)fileDescriptorForReading { #ifndef OF_WINDOWS return _socket; Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -285,10 +285,12 @@ result->protocol)) == INVALID_SOCKET) { errNo = of_socket_errno(); continue; } + + _blocking = true; #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); #endif @@ -394,10 +396,12 @@ @throw [OFBindFailedException exceptionWithHost: host port: port socket: self errNo: of_socket_errno()]; + + _blocking = true; #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); #endif @@ -631,11 +635,11 @@ int v = enabled; if (setsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&v, (socklen_t)sizeof(v)) != 0) @throw [OFSetOptionFailedException - exceptionWithStream: self + exceptionWithObject: self errNo: of_socket_errno()]; } - (bool)isKeepAliveEnabled { @@ -658,11 +662,11 @@ int v = enabled; if (setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char *)&v, (socklen_t)sizeof(v)) != 0) @throw [OFSetOptionFailedException - exceptionWithStream: self + exceptionWithObject: self errNo: of_socket_errno()]; } - (bool)isTCPNoDelayEnabled { Index: src/OFUDPSocket.h ================================================================== --- src/OFUDPSocket.h +++ src/OFUDPSocket.h @@ -102,12 +102,20 @@ { of_socket_t _socket; #ifdef OF_WII uint16_t _port; #endif + bool _blocking; } +/*! + * @brief Whether the socket is in blocking mode. + * + * By default, a socket is in blocking mode. + */ +@property (nonatomic, getter=isBlocking) bool blocking; + /*! * @brief Returns a new, autoreleased OFUDPSocket. * * @return A new, autoreleased OFUDPSocket */ Index: src/OFUDPSocket.m ================================================================== --- src/OFUDPSocket.m +++ src/OFUDPSocket.m @@ -36,10 +36,11 @@ #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFNotOpenException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" +#import "OFSetOptionFailedException.h" #import "OFWriteFailedException.h" #import "socket.h" #import "socket_helpers.h" #import "resolver.h" @@ -255,10 +256,11 @@ - (instancetype)init { self = [super init]; _socket = INVALID_SOCKET; + _blocking = true; return self; } - (void)dealloc @@ -271,10 +273,48 @@ - (id)copy { return [self retain]; } + +- (bool)isBlocking +{ + return _blocking; +} + +- (void)setBlocking: (bool)enable +{ +#if defined(HAVE_FCNTL) + int flags = fcntl(_socket, F_GETFL); + + if (flags == -1) + @throw [OFSetOptionFailedException exceptionWithObject: self + errNo: errno]; + + if (enable) + flags &= ~O_NONBLOCK; + else + flags |= O_NONBLOCK; + + if (fcntl(_socket, F_SETFL, flags) == -1) + @throw [OFSetOptionFailedException exceptionWithObject: self + errNo: errno]; + + _blocking = enable; +#elif defined(OF_WINDOWS) + u_long v = enable; + + if (ioctlsocket(_socket, FIONBIO, &v) == SOCKET_ERROR) + @throw [OFSetOptionFailedException + exceptionWithObject: self + errNo: of_socket_errno()]; + + _blocking = enable; +#else + OF_UNRECOGNIZED_SELECTOR +#endif +} - (uint16_t)bindToHost: (OFString *)host port: (uint16_t)port { of_resolver_result_t **results; @@ -301,10 +341,12 @@ @throw [OFBindFailedException exceptionWithHost: host port: port socket: self errNo: of_socket_errno()]; + + _blocking = true; #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); #endif Index: src/exceptions/OFSetOptionFailedException.h ================================================================== --- src/exceptions/OFSetOptionFailedException.h +++ src/exceptions/OFSetOptionFailedException.h @@ -17,28 +17,26 @@ #import "OFException.h" OF_ASSUME_NONNULL_BEGIN -@class OFStream; - /*! * @class OFSetOptionFailedException \ * OFSetOptionFailedException.h ObjFW/OFSetOptionFailedException.h * - * @brief An exception indicating that setting an option for a stream failed. + * @brief An exception indicating that setting an option for an object failed. */ @interface OFSetOptionFailedException: OFException { - OFStream *_stream; + id _object; int _errNo; } /*! - * @brief The stream for which the option could not be set. + * @brief The object for which the option could not be set. */ -@property (readonly, nonatomic) OFStream *stream; +@property (readonly, nonatomic) id object; /*! * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; @@ -46,26 +44,26 @@ + (instancetype)exception OF_UNAVAILABLE; /*! * @brief Creates a new, autoreleased set option failed exception. * - * @param stream The stream for which the option could not be set + * @param object The object for which the option could not be set * @param errNo The errno of the error that occurred * @return A new, autoreleased set option failed exception */ -+ (instancetype)exceptionWithStream: (OFStream *)stream ++ (instancetype)exceptionWithObject: (id)object errNo: (int)errNo; - (instancetype)init OF_UNAVAILABLE; /*! * @brief Initializes an already allocated set option failed exception. * - * @param stream The stream for which the option could not be set + * @param object The object for which the option could not be set * @param errNo The errno of the error that occurred * @return An initialized set option failed exception */ -- (instancetype)initWithStream: (OFStream *)stream +- (instancetype)initWithObject: (id)object errNo: (int)errNo OF_DESIGNATED_INITIALIZER; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFSetOptionFailedException.m ================================================================== --- src/exceptions/OFSetOptionFailedException.m +++ src/exceptions/OFSetOptionFailedException.m @@ -17,52 +17,51 @@ #include "config.h" #import "OFSetOptionFailedException.h" #import "OFString.h" -#import "OFStream.h" @implementation OFSetOptionFailedException -@synthesize stream = _stream, errNo = _errNo; +@synthesize object = _object, errNo = _errNo; + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithStream: (OFStream *)stream ++ (instancetype)exceptionWithObject: (id)object errNo: (int)errNo { - return [[[self alloc] initWithStream: stream + return [[[self alloc] initWithObject: object errNo: errNo] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithStream: (OFStream *)stream +- (instancetype)initWithObject: (id)object errNo: (int)errNo { self = [super init]; - _stream = [stream retain]; + _object = [object retain]; _errNo = errNo; return self; } - (void)dealloc { - [_stream release]; + [_object release]; [super dealloc]; } - (OFString *)description { return [OFString stringWithFormat: - @"Setting an option in a stream of type %@ failed: %@", - [_stream class], of_strerror(_errNo)]; + @"Setting an option in an object of type %@ failed: %@", + [_object class], of_strerror(_errNo)]; } @end