Index: ObjFW.xcodeproj/project.pbxproj ================================================================== --- ObjFW.xcodeproj/project.pbxproj +++ ObjFW.xcodeproj/project.pbxproj @@ -248,10 +248,12 @@ 4B3D23E91337FCB000DD29B8 /* of_asprintf.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BB50DCF12F863C700C9393F /* of_asprintf.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B3D23EA1337FCB000DD29B8 /* threading.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B67998B1099E7C50041064A /* threading.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B3D23EB1337FCB000DD29B8 /* unicode.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B67998C1099E7C50041064A /* unicode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B3D23EE1337FFD000DD29B8 /* of_asprintf.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BB50DD012F863C700C9393F /* of_asprintf.m */; }; 4B3D5694139A617D0010A78F /* OFSerializationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B3D5693139A617D0010A78F /* OFSerializationTests.m */; }; + 4B3ED7C21AF62C30004C8FF1 /* OFGetOptionFailedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B3ED7C01AF62C30004C8FF1 /* OFGetOptionFailedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4B3ED7C31AF62C30004C8FF1 /* OFGetOptionFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B3ED7C11AF62C30004C8FF1 /* OFGetOptionFailedException.m */; }; 4B40EC1B189FE2650031E19E /* socket.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B40EC1A189FE2650031E19E /* socket.m */; }; 4B45355313DCFE1E0037AB4D /* OFCountedSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B45355113DCFE1E0037AB4D /* OFCountedSet.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B45355413DCFE1E0037AB4D /* OFCountedSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B45355213DCFE1E0037AB4D /* OFCountedSet.m */; }; 4B48B95414DC23B100546D39 /* OFXMLProcessingInstructions.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B48B95214DC23B100546D39 /* OFXMLProcessingInstructions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B48B95514DC23B100546D39 /* OFXMLProcessingInstructions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B48B95314DC23B100546D39 /* OFXMLProcessingInstructions.m */; }; @@ -675,10 +677,12 @@ 4B3D236D1337FB5800DD29B8 /* base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = base64.h; path = src/base64.h; sourceTree = ""; }; 4B3D236E1337FB5800DD29B8 /* base64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = base64.m; path = src/base64.m; sourceTree = ""; }; 4B3D23761337FBC800DD29B8 /* ObjFW.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ObjFW.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4B3D23BB1337FC5800DD29B8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = support/Info.plist; sourceTree = SOURCE_ROOT; }; 4B3D5693139A617D0010A78F /* OFSerializationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFSerializationTests.m; path = tests/OFSerializationTests.m; sourceTree = ""; }; + 4B3ED7C01AF62C30004C8FF1 /* OFGetOptionFailedException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFGetOptionFailedException.h; path = src/exceptions/OFGetOptionFailedException.h; sourceTree = ""; }; + 4B3ED7C11AF62C30004C8FF1 /* OFGetOptionFailedException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFGetOptionFailedException.m; path = src/exceptions/OFGetOptionFailedException.m; sourceTree = ""; }; 4B40EC1A189FE2650031E19E /* socket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = socket.m; path = src/socket.m; sourceTree = ""; }; 4B45355113DCFE1E0037AB4D /* OFCountedSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFCountedSet.h; path = src/OFCountedSet.h; sourceTree = ""; }; 4B45355213DCFE1E0037AB4D /* OFCountedSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFCountedSet.m; path = src/OFCountedSet.m; sourceTree = ""; }; 4B48B95214DC23B100546D39 /* OFXMLProcessingInstructions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFXMLProcessingInstructions.h; path = src/OFXMLProcessingInstructions.h; sourceTree = ""; }; 4B48B95314DC23B100546D39 /* OFXMLProcessingInstructions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFXMLProcessingInstructions.m; path = src/OFXMLProcessingInstructions.m; sourceTree = ""; }; @@ -1069,10 +1073,12 @@ 4B067FB6177BA6F900B8CFDA /* OFCreateSymbolicLinkFailedException.m */, 4B17FF85133A2E7A003E6DCD /* OFEnumerationMutationException.h */, 4B17FF86133A2E7A003E6DCD /* OFEnumerationMutationException.m */, 4B17FF70133A28FC003E6DCD /* OFException.h */, 4B17FF71133A28FC003E6DCD /* OFException.m */, + 4B3ED7C01AF62C30004C8FF1 /* OFGetOptionFailedException.h */, + 4B3ED7C11AF62C30004C8FF1 /* OFGetOptionFailedException.m */, 4B8B16FC133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.h */, 4B8B16FD133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.m */, 4B17FFAB133A3586003E6DCD /* OFHTTPRequestFailedException.h */, 4B17FFAC133A3589003E6DCD /* OFHTTPRequestFailedException.m */, 4B17FFA3133A340B003E6DCD /* OFInitializationFailedException.h */, @@ -1738,10 +1744,11 @@ 4B90B7A4133AD87D00BD33CB /* OFConnectionFailedException.h in Headers */, 4B62ED1518566FCA0004E0E3 /* OFCopyItemFailedException.h in Headers */, 4B29BC3F133AC4E80004B236 /* OFCreateDirectoryFailedException.h in Headers */, 4B067FC1177BA6F900B8CFDA /* OFCreateSymbolicLinkFailedException.h in Headers */, 4B17FF87133A2E7B003E6DCD /* OFEnumerationMutationException.h in Headers */, + 4B3ED7C21AF62C30004C8FF1 /* OFGetOptionFailedException.h in Headers */, 4B8B16FE133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.h in Headers */, 4B17FFAD133A3591003E6DCD /* OFHTTPRequestFailedException.h in Headers */, 4B17FFA5133A3411003E6DCD /* OFInitializationFailedException.h in Headers */, 4B17FF93133A317C003E6DCD /* OFInvalidArgumentException.h in Headers */, 4B17FF99133A3245003E6DCD /* OFInvalidEncodingException.h in Headers */, @@ -2119,10 +2126,11 @@ 4B62ED1618566FCA0004E0E3 /* OFCopyItemFailedException.m in Sources */, 4B29BC40133AC4E80004B236 /* OFCreateDirectoryFailedException.m in Sources */, 4B067FC2177BA6F900B8CFDA /* OFCreateSymbolicLinkFailedException.m in Sources */, 4B17FF88133A2E7B003E6DCD /* OFEnumerationMutationException.m in Sources */, 4B17FF73133A2A76003E6DCD /* OFException.m in Sources */, + 4B3ED7C31AF62C30004C8FF1 /* OFGetOptionFailedException.m in Sources */, 4B8B16FF133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.m in Sources */, 4B17FFAE133A3591003E6DCD /* OFHTTPRequestFailedException.m in Sources */, 4B17FFA6133A3411003E6DCD /* OFInitializationFailedException.m in Sources */, 4B17FF94133A317C003E6DCD /* OFInvalidArgumentException.m in Sources */, 4B17FF9A133A3245003E6DCD /* OFInvalidEncodingException.m in Sources */, Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -760,10 +760,14 @@ ]) AC_CHECK_HEADERS(netinet/in.h, [ AC_DEFINE(OF_HAVE_NETINET_IN_H, 1, [Whether we have netinet/in.h]) ]) + AC_CHECK_HEADERS(netinet/tcp.h, [ + AC_DEFINE(OF_HAVE_NETINET_TCP_H, 1, + [Whether we have netinet/tcp.h]) + ]) AC_CHECK_HEADERS([arpa/inet.h netdb.h]) AC_CHECK_FUNCS([fcntl paccept accept4]) AC_CHECK_FUNC(kqueue, [ Index: src/OFTCPSocket.h ================================================================== --- src/OFTCPSocket.h +++ src/OFTCPSocket.h @@ -67,10 +67,12 @@ #ifdef OF_HAVE_PROPERTIES @property (readonly, getter=isListening) bool listening; @property (copy) OFString *SOCKS5Host; @property uint16_t SOCKS5Port; +@property (getter=isKeepAliveEnabled) bool keepAliveEnabled; +@property (getter=isTCPNoDelayEnabled) bool TCPNoDelayEnabled; #endif /*! * @brief Sets the global SOCKS5 proxy host to use when creating a new socket * @@ -223,17 +225,10 @@ * by the specified block as well. */ - (void)asyncAcceptWithBlock: (of_tcp_socket_async_accept_block_t)block; #endif -/*! - * @brief Enable or disable keep alives for the connection. - * - * @param enable Whether to enable or disable keep alives for the connection - */ -- (void)setKeepAlivesEnabled: (bool)enable; - /*! * @brief Returns the remote address of the socket. * * Only works with accepted sockets! * @@ -245,14 +240,42 @@ * @brief Returns whether the socket is a listening socket. * * @return Whether the socket is a listening socket */ - (bool)isListening; + +/*! + * @brief Enable or disable keep alive for the connection. + * + * @param enabled Whether to enable or disable keep alives for the connection + */ +- (void)setKeepAliveEnabled: (bool)enabled; + +/*! + * @brief Returns whether keep alive is enabled for the connection. + * + * @return Whether keep alives are enabled for the connection + */ +- (bool)isKeepAliveEnabled; + +/*! + * @brief Enable or disable TCP_NODELAY for the connection. + * + * @param enabled Whether to enable or disable TCP_NODELAY for the connection + */ +- (void)setTCPNoDelayEnabled: (bool)enabled; + +/*! + * @brief Returns whether TCP_NODELAY is enabled for the connection. + * + * @return Whether TCP_NODELAY is enabled for the connection + */ +- (bool)isTCPNoDelayEnabled; @end #ifdef __cplusplus extern "C" { #endif extern Class of_tls_socket_class; #ifdef __cplusplus } #endif Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -36,10 +36,11 @@ #import "OFAcceptFailedException.h" #import "OFAlreadyConnectedException.h" #import "OFBindFailedException.h" #import "OFConnectionFailedException.h" +#import "OFGetOptionFailedException.h" #import "OFInvalidArgumentException.h" #import "OFListenFailedException.h" #import "OFNotConnectedException.h" #import "OFNotImplementedException.h" #import "OFOutOfMemoryException.h" @@ -560,21 +561,10 @@ [OFRunLoop OF_addAsyncAcceptForTCPSocket: self block: block]; } #endif -- (void)setKeepAlivesEnabled: (bool)enable -{ - int v = enable; - - if (setsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, - (char*)&v, (socklen_t)sizeof(v))) - @throw [OFSetOptionFailedException - exceptionWithStream: self - errNo: of_socket_errno()]; -} - - (OFString*)remoteAddress { OFString *ret; if (_socket == INVALID_SOCKET) @@ -590,6 +580,56 @@ - (bool)isListening { return _listening; } + +- (void)setKeepAliveEnabled: (bool)enabled +{ + int v = enabled; + + if (setsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, + (char*)&v, (socklen_t)sizeof(v)) != 0) + @throw [OFSetOptionFailedException + exceptionWithStream: self + errNo: of_socket_errno()]; +} + +- (bool)isKeepAliveEnabled +{ + int v; + socklen_t len = sizeof(v); + + if (getsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, + (char*)&v, &len) != 0 || len != sizeof(v)) + @throw [OFGetOptionFailedException + exceptionWithStream: self + errNo: of_socket_errno()]; + + return v; +} + +- (void)setTCPNoDelayEnabled: (bool)enabled +{ + int v = enabled; + + if (setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, + (char*)&v, (socklen_t)sizeof(v)) != 0) + @throw [OFSetOptionFailedException + exceptionWithStream: self + errNo: of_socket_errno()]; +} + +- (bool)isTCPNoDelayEnabled +{ + int v; + socklen_t len = sizeof(v); + + if (getsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, + (char*)&v, &len) != 0 || len != sizeof(v)) + @throw [OFGetOptionFailedException + exceptionWithStream: self + errNo: of_socket_errno()]; + + return v; +} @end Index: src/exceptions/Makefile ================================================================== --- src/exceptions/Makefile +++ src/exceptions/Makefile @@ -11,10 +11,11 @@ OFCopyItemFailedException.m \ OFCreateDirectoryFailedException.m \ OFCreateSymbolicLinkFailedException.m \ OFEnumerationMutationException.m \ OFException.m \ + OFGetOptionFailedException.m \ OFHashAlreadyCalculatedException.m \ OFInitializationFailedException.m \ OFInvalidArgumentException.m \ OFInvalidEncodingException.m \ OFInvalidFormatException.m \ ADDED src/exceptions/OFGetOptionFailedException.h Index: src/exceptions/OFGetOptionFailedException.h ================================================================== --- src/exceptions/OFGetOptionFailedException.h +++ src/exceptions/OFGetOptionFailedException.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 + * 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 "OFException.h" + +@class OFStream; + +/*! + * @class OFGetOptionFailedException \ + * OFGetOptionFailedException.h ObjFW/OFGetOptionFailedException.h + * + * @brief An exception indicating that getting an option for a stream failed. + */ +@interface OFGetOptionFailedException: OFException +{ + OFStream *_stream; + int _errNo; +} + +#ifdef OF_HAVE_PROPERTIES +@property (readonly, retain) OFStream *stream; +@property (readonly) int errNo; +#endif + +/*! + * @brief Creates a new, autoreleased get option failed exception. + * + * @param stream The stream for which the option could not be gotten + * @param errNo The errno of the error that occurred + * @return A new, autoreleased get option failed exception + */ ++ (instancetype)exceptionWithStream: (OFStream*)stream + errNo: (int)errNo; + +/*! + * @brief Initializes an already allocated get option failed exception. + * + * @param stream The stream for which the option could not be gotten + * @param errNo The errno of the error that occurred + * @return An initialized get option failed exception + */ +- initWithStream: (OFStream*)stream + errNo: (int)errNo; + +/*! + * @brief Returns the stream for which the option could not be gotten. + * + * @return The stream for which the option could not be gotten + */ +- (OFStream*)stream; + +/*! + * @brief Returns the errno of the error that occurred. + * + * @return The errno of the error that occurred + */ +- (int)errNo; +@end ADDED src/exceptions/OFGetOptionFailedException.m Index: src/exceptions/OFGetOptionFailedException.m ================================================================== --- src/exceptions/OFGetOptionFailedException.m +++ src/exceptions/OFGetOptionFailedException.m @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 + * 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" + +#import "OFGetOptionFailedException.h" +#import "OFString.h" +#import "OFStream.h" + +@implementation OFGetOptionFailedException ++ (instancetype)exceptionWithStream: (OFStream*)stream + errNo: (int)errNo +{ + return [[[self alloc] initWithStream: stream + errNo: errNo] autorelease]; +} + +- init +{ + OF_INVALID_INIT_METHOD +} + +- initWithStream: (OFStream*)stream + errNo: (int)errNo +{ + self = [super init]; + + _stream = [stream retain]; + _errNo = errNo; + + return self; +} + +- (void)dealloc +{ + [_stream release]; + + [super dealloc]; +} + +- (OFString*)description +{ + return [OFString stringWithFormat: + @"Getting an option in a stream of type %@ failed: %@", + [_stream class], of_strerror(_errNo)]; +} + +- (OFStream*)stream +{ + OF_GETTER(_stream, true) +} + +- (int)errNo +{ + return _errNo; +} +@end Index: src/socket.h ================================================================== --- src/socket.h +++ src/socket.h @@ -27,10 +27,13 @@ #ifdef OF_HAVE_SYS_SOCKET_H # include #endif #ifdef OF_HAVE_NETINET_IN_H # include +#endif +#ifdef OF_HAVE_NETINET_TCP_H +# include #endif #ifdef _WIN32 # ifdef __MINGW32__ # include <_mingw.h>