Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -1403,10 +1403,16 @@ ]) AC_CHECK_HEADER(netinet/tcp.h, [ AC_DEFINE(OF_HAVE_NETINET_TCP_H, 1, [Whether we have netinet/tcp.h]) ]) + AC_CHECK_HEADER(netinet/sctp.h, [ + AC_DEFINE(OF_HAVE_SCTP, 1, [Whether we have SCTP]) + AC_DEFINE(OF_HAVE_NETINET_SCTP_H, 1, + [Whether we have netinet/sctp.h]) + AC_SUBST(USE_SRCS_SCTP, '${SRCS_SCTP}') + ]) AC_CHECK_HEADERS([arpa/inet.h netdb.h net/if.h]) AC_CHECK_FUNCS([if_indextoname if_nametoindex]) AC_CHECK_HEADER(sys/un.h, [ AC_DEFINE(OF_HAVE_SYS_UN_H, 1, [Whether we have sys/un.h]) ]) Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -54,10 +54,11 @@ OF_GNUTLS_TLS_STREAM_M = @OF_GNUTLS_TLS_STREAM_M@ OF_HTTP_CLIENT_TESTS_M = @OF_HTTP_CLIENT_TESTS_M@ OF_KQUEUE_KERNEL_EVENT_OBSERVER_M = @OF_KQUEUE_KERNEL_EVENT_OBSERVER_M@ OF_OPENSSL_TLS_STREAM_M = @OF_OPENSSL_TLS_STREAM_M@ OF_POLL_KERNEL_EVENT_OBSERVER_M = @OF_POLL_KERNEL_EVENT_OBSERVER_M@ +OF_SCTP_SOCKET_M = @OF_SCTP_SOCKET_M@ OF_SECURE_TRANSPORT_TLS_STREAM_M = @OF_SECURE_TRANSPORT_TLS_STREAM_M@ OF_SELECT_KERNEL_EVENT_OBSERVER_M = @OF_SELECT_KERNEL_EVENT_OBSERVER_M@ OF_SUBPROCESS_M = @OF_SUBPROCESS_M@ REEXPORT_RUNTIME = @REEXPORT_RUNTIME@ REEXPORT_RUNTIME_FRAMEWORK = @REEXPORT_RUNTIME_FRAMEWORK@ @@ -81,10 +82,11 @@ USE_INCLUDES_ATOMIC = @USE_INCLUDES_ATOMIC@ USE_SRCS_APPLETALK = @USE_SRCS_APPLETALK@ USE_SRCS_FILES = @USE_SRCS_FILES@ USE_SRCS_IPX = @USE_SRCS_IPX@ USE_SRCS_PLUGINS = @USE_SRCS_PLUGINS@ +USE_SRCS_SCTP = @USE_SRCS_SCTP@ USE_SRCS_SOCKETS = @USE_SRCS_SOCKETS@ USE_SRCS_THREADS = @USE_SRCS_THREADS@ USE_SRCS_UNIX_SOCKETS = @USE_SRCS_UNIX_SOCKETS@ USE_SRCS_WINDOWS = @USE_SRCS_WINDOWS@ WRAPPER = @WRAPPER@ Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -136,15 +136,17 @@ OFTCPSocket.m \ OFTLSStream.m \ OFUDPSocket.m \ ${USE_SRCS_APPLETALK} \ ${USE_SRCS_IPX} \ + ${USE_SRCS_SCTP} \ ${USE_SRCS_UNIX_SOCKETS} SRCS_APPLETALK = OFDDPSocket.m SRCS_IPX = OFIPXSocket.m \ OFSPXSocket.m \ OFSPXStreamSocket.m +SRCS_SCTP = OFSCTPSocket.m SRCS_UNIX_SOCKETS = OFUNIXDatagramSocket.m \ OFUNIXStreamSocket.m SRCS_THREADS = OFCondition.m \ OFMutex.m \ OFPlainCondition.m \ Index: src/OFAsyncIPSocketConnector.m ================================================================== --- src/OFAsyncIPSocketConnector.m +++ src/OFAsyncIPSocketConnector.m @@ -17,10 +17,13 @@ #include #import "OFAsyncIPSocketConnector.h" #import "OFData.h" +#ifdef OF_HAVE_SCTP +# import "OFSCTPSocket.h" +#endif #import "OFTCPSocket.h" #import "OFThread.h" #import "OFTimer.h" #import "OFConnectIPSocketFailedException.h" @@ -68,10 +71,14 @@ #ifdef OF_HAVE_BLOCKS if (_block != NULL) { if ([_socket isKindOfClass: [OFTCPSocket class]]) ((OFTCPSocketAsyncConnectBlock)_block)(_exception); +# ifdef OF_HAVE_SCTP + else if ([_socket isKindOfClass: [OFSCTPSocket class]]) + ((OFSCTPSocketAsyncConnectBlock)_block)(_exception); +# endif else OFEnsure(0); } else { #endif if ([_delegate respondsToSelector: ADDED src/OFSCTPSocket.h Index: src/OFSCTPSocket.h ================================================================== --- src/OFSCTPSocket.h +++ src/OFSCTPSocket.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2008-2021 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 "OFSequencedPacketSocket.h" +#import "OFRunLoop.h" + +OF_ASSUME_NONNULL_BEGIN + +/** @file */ + +@class OFSCTPSocket; +@class OFString; + +#ifdef OF_HAVE_BLOCKS +/** + * @brief A block which is called when the socket connected. + * + * @param exception An exception which occurred while connecting the socket or + * `nil` on success + */ +typedef void (^OFSCTPSocketAsyncConnectBlock)(id _Nullable exception); +#endif + +/** + * @protocol OFSCTPSocketDelegate OFSCTPSocket.h ObjFW/OFSCTPSocket.h + * + * A delegate for OFSCTPSocket. + */ +@protocol OFSCTPSocketDelegate +@optional +/** + * @brief A method which is called when a socket connected. + * + * @param socket The socket which connected + * @param host The host connected to + * @param port The port on the host connected to + * @param exception An exception that occurred while connecting, or nil on + * success + */ +- (void)socket: (OFSCTPSocket *)socket + didConnectToHost: (OFString *)host + port: (uint16_t)port + exception: (nullable id)exception; +@end + +/** + * @class OFSCTPSocket OFSCTPSocket.h ObjFW/OFSCTPSocket.h + * + * @brief A class which provides methods to create and use SCTP sockets in + * one-to-one mode. + * + * To connect to a server, create a socket and connect it. + * To create a server, create a socket, bind it and listen on it. + */ +@interface OFSCTPSocket: OFSequencedPacketSocket +{ + OF_RESERVE_IVARS(OFSCTPSocket, 4) +} + +/** + * @brief Whether sending packets can be delayed. Setting this to NO sets + * SCTP_NODELAY on the socket. + */ +@property (nonatomic) bool canDelaySendingPackets; + +/** + * @brief The delegate for asynchronous operations on the socket. + * + * @note The delegate is retained for as long as asynchronous operations are + * still ongoing. + */ +@property OF_NULLABLE_PROPERTY (assign, nonatomic) + id delegate; + +/** + * @brief Connect the OFSCTPSocket to the specified destination. + * + * @param host The host to connect to + * @param port The port on the host to connect to + */ +- (void)connectToHost: (OFString *)host port: (uint16_t)port; + +/** + * @brief Asynchronously connect the OFSCTPSocket to the specified destination. + * + * @param host The host to connect to + * @param port The port on the host to connect to + */ +- (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port; + +/** + * @brief Asynchronously connect the OFSCTPSocket 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 + */ +- (void)asyncConnectToHost: (OFString *)host + port: (uint16_t)port + runLoopMode: (OFRunLoopMode)runLoopMode; + +#ifdef OF_HAVE_BLOCKS +/** + * @brief Asynchronously connect the OFSCTPSocket to the specified destination. + * + * @param host The host to connect to + * @param port The port on the host to connect to + * @param block The block to execute once the connection has been established + */ +- (void)asyncConnectToHost: (OFString *)host + port: (uint16_t)port + block: (OFSCTPSocketAsyncConnectBlock)block; + +/** + * @brief Asynchronously connect the OFSCTPSocket 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 block The block to execute once the connection has been established + */ +- (void)asyncConnectToHost: (OFString *)host + port: (uint16_t)port + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFSCTPSocketAsyncConnectBlock)block; +#endif + +/** + * @brief Bind the socket to the specified host and port. + * + * @param host The host to bind to. Use `@"0.0.0.0"` for IPv4 or `@"::"` for + * IPv6 to bind to all. + * @param port The port to bind to. If the port is 0, an unused port will be + * chosen, which can be obtained using the return value. + * @return The port the socket was bound to + */ +- (uint16_t)bindToHost: (OFString *)host port: (uint16_t)port; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFSCTPSocket.m Index: src/OFSCTPSocket.m ================================================================== --- src/OFSCTPSocket.m +++ src/OFSCTPSocket.m @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2008-2021 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 +#include +#include +#include + +#ifdef HAVE_FCNTL_H +# include +#endif + +#import "OFSCTPSocket.h" +#import "OFAsyncIPSocketConnector.h" +#import "OFDNSResolver.h" +#import "OFData.h" +#import "OFDate.h" +#import "OFRunLoop.h" +#import "OFRunLoop+Private.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" +#import "OFString.h" +#import "OFThread.h" + +#import "OFAlreadyConnectedException.h" +#import "OFBindIPSocketFailedException.h" +#import "OFGetOptionFailedException.h" +#import "OFNotOpenException.h" +#import "OFSetOptionFailedException.h" + +static const OFRunLoopMode connectRunLoopMode = + @"OFSCTPSocketConnectRunLoopMode"; + +@interface OFSCTPSocket () +@end + +@interface OFSCTPSocketConnectDelegate: OFObject +{ +@public + bool _done; + id _exception; +} +@end + +@implementation OFSCTPSocketConnectDelegate +- (void)dealloc +{ + [_exception release]; + + [super dealloc]; +} + +- (void)socket: (OFSCTPSocket *)sock + didConnectToHost: (OFString *)host + port: (uint16_t)port + exception: (id)exception +{ + _done = true; + _exception = [exception retain]; +} +@end + +@implementation OFSCTPSocket +@dynamic delegate; + +- (bool)of_createSocketForAddress: (const OFSocketAddress *)address + errNo: (int *)errNo +{ +#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + int flags; +#endif + + if (_socket != OFInvalidSocketHandle) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + + if ((_socket = socket( + ((struct sockaddr *)&address->sockaddr)->sa_family, + SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_SCTP)) == + OFInvalidSocketHandle) { + *errNo = OFSocketErrNo(); + return false; + } + +#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 + + return true; +} + +- (bool)of_connectSocketToAddress: (const OFSocketAddress *)address + errNo: (int *)errNo +{ + if (_socket == OFInvalidSocketHandle) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (connect(_socket, (struct sockaddr *)&address->sockaddr, + address->length) != 0) { + *errNo = OFSocketErrNo(); + return false; + } + + return true; +} + +- (void)of_closeSocket +{ + closesocket(_socket); + _socket = OFInvalidSocketHandle; +} + +- (void)connectToHost: (OFString *)host port: (uint16_t)port +{ + void *pool = objc_autoreleasePoolPush(); + id delegate = _delegate; + OFSCTPSocketConnectDelegate *connectDelegate = + [[[OFSCTPSocketConnectDelegate alloc] init] autorelease]; + OFRunLoop *runLoop = [OFRunLoop currentRunLoop]; + + self.delegate = connectDelegate; + [self asyncConnectToHost: host + port: port + runLoopMode: connectRunLoopMode]; + + while (!connectDelegate->_done) + [runLoop runMode: connectRunLoopMode beforeDate: nil]; + + /* Cleanup */ + [runLoop runMode: connectRunLoopMode beforeDate: [OFDate date]]; + + if (connectDelegate->_exception != nil) + @throw connectDelegate->_exception; + + self.delegate = delegate; + + objc_autoreleasePoolPop(pool); +} + +- (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port +{ + [self asyncConnectToHost: host + port: port + runLoopMode: OFDefaultRunLoopMode]; +} + +- (void)asyncConnectToHost: (OFString *)host + port: (uint16_t)port + runLoopMode: (OFRunLoopMode)runLoopMode +{ + void *pool = objc_autoreleasePoolPush(); + + if (_socket != OFInvalidSocketHandle) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + + [[[[OFAsyncIPSocketConnector alloc] + initWithSocket: self + host: host + port: port + delegate: _delegate + block: NULL + ] autorelease] startWithRunLoopMode: runLoopMode]; + + objc_autoreleasePoolPop(pool); +} + +#ifdef OF_HAVE_BLOCKS +- (void)asyncConnectToHost: (OFString *)host + port: (uint16_t)port + block: (OFSCTPSocketAsyncConnectBlock)block +{ + [self asyncConnectToHost: host + port: port + runLoopMode: OFDefaultRunLoopMode + block: block]; +} + +- (void)asyncConnectToHost: (OFString *)host + port: (uint16_t)port + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFSCTPSocketAsyncConnectBlock)block +{ + void *pool = objc_autoreleasePoolPush(); + + if (_socket != OFInvalidSocketHandle) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + + [[[[OFAsyncIPSocketConnector alloc] + initWithSocket: self + host: host + port: port + delegate: nil + block: block] autorelease] + startWithRunLoopMode: runLoopMode]; + + objc_autoreleasePoolPop(pool); +} +#endif + +- (uint16_t)bindToHost: (OFString *)host port: (uint16_t)port +{ + const int one = 1; + void *pool = objc_autoreleasePoolPush(); + OFData *socketAddresses; + OFSocketAddress address; +#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + int flags; +#endif + + if (_socket != OFInvalidSocketHandle) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + + socketAddresses = [[OFThread DNSResolver] + resolveAddressesForHost: host + addressFamily: OFSocketAddressFamilyAny]; + + address = *(OFSocketAddress *)[socketAddresses itemAtIndex: 0]; + OFSocketAddressSetIPPort(&address, port); + + if ((_socket = socket( + ((struct sockaddr *)&address.sockaddr)->sa_family, + SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_SCTP)) == OFInvalidSocketHandle) + @throw [OFBindIPSocketFailedException + exceptionWithHost: host + port: port + socket: self + errNo: OFSocketErrNo()]; + + _canBlock = 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 + + setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, + (char *)&one, (socklen_t)sizeof(one)); + + if (bind(_socket, (struct sockaddr *)&address.sockaddr, + address.length) != 0) { + int errNo = OFSocketErrNo(); + + closesocket(_socket); + _socket = OFInvalidSocketHandle; + + @throw [OFBindIPSocketFailedException exceptionWithHost: host + port: port + socket: self + errNo: errNo]; + } + + objc_autoreleasePoolPop(pool); + + if (port > 0) + return port; + + memset(&address, 0, sizeof(address)); + + address.length = (socklen_t)sizeof(address.sockaddr); + if (OFGetSockName(_socket, (struct sockaddr *)&address.sockaddr, + &address.length) != 0) { + int errNo = OFSocketErrNo(); + + closesocket(_socket); + _socket = OFInvalidSocketHandle; + + @throw [OFBindIPSocketFailedException exceptionWithHost: host + port: port + socket: self + errNo: errNo]; + } + + switch (((struct sockaddr *)&address.sockaddr)->sa_family) { + case AF_INET: + return OFFromBigEndian16(address.sockaddr.in.sin_port); +# ifdef OF_HAVE_IPV6 + case AF_INET6: + return OFFromBigEndian16(address.sockaddr.in6.sin6_port); +# endif + default: + closesocket(_socket); + _socket = OFInvalidSocketHandle; + + @throw [OFBindIPSocketFailedException + exceptionWithHost: host + port: port + socket: self + errNo: EAFNOSUPPORT]; + } +} + +- (void)setCanDelaySendingPackets: (bool)canDelaySendingPackets +{ + int v = !canDelaySendingPackets; + + if (setsockopt(_socket, IPPROTO_SCTP, SCTP_NODELAY, + (char *)&v, (socklen_t)sizeof(v)) != 0) + @throw [OFSetOptionFailedException + exceptionWithObject: self + errNo: OFSocketErrNo()]; +} + +- (bool)canDelaySendingPackets +{ + int v; + socklen_t len = sizeof(v); + + if (getsockopt(_socket, IPPROTO_SCTP, SCTP_NODELAY, + (char *)&v, &len) != 0 || len != sizeof(v)) + @throw [OFGetOptionFailedException + exceptionWithObject: self + errNo: OFSocketErrNo()]; + + return !v; +} +@end Index: src/OFSocket.h ================================================================== --- src/OFSocket.h +++ src/OFSocket.h @@ -32,10 +32,13 @@ #ifdef OF_HAVE_NETINET_IN_H # include #endif #ifdef OF_HAVE_NETINET_TCP_H # include +#endif +#ifdef OF_HAVE_NETINET_SCTP_H +# include #endif #ifdef OF_HAVE_SYS_UN_H # include #endif #ifdef OF_HAVE_AFUNIX_H Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -82,10 +82,13 @@ # import "OFKernelEventObserver.h" # import "OFDNSQuery.h" # import "OFDNSResourceRecord.h" # import "OFDNSResponse.h" # import "OFDNSResolver.h" +# ifdef OF_HAVE_SCTP +# import "OFSCTPSocket.h" +# endif # ifdef OF_HAVE_UNIX_SOCKETS # import "OFUNIXDatagramSocket.h" # import "OFUNIXStreamSocket.h" # endif # ifdef OF_HAVE_IPX Index: src/objfw-defs.h.in ================================================================== --- src/objfw-defs.h.in +++ src/objfw-defs.h.in @@ -18,10 +18,11 @@ #undef OF_HAVE_LINK #undef OF_HAVE_MAX_ALIGN_T #undef OF_HAVE_NETATALK_AT_H #undef OF_HAVE_NETAT_APPLETALK_H #undef OF_HAVE_NETINET_IN_H +#undef OF_HAVE_NETINET_SCTP_H #undef OF_HAVE_NETINET_TCP_H #undef OF_HAVE_NETIPX_IPX_H #undef OF_HAVE_OSATOMIC #undef OF_HAVE_OSATOMIC_64 #undef OF_HAVE_PIPE Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -75,15 +75,17 @@ OFSocketTests.m \ OFTCPSocketTests.m \ OFUDPSocketTests.m \ ${USE_SRCS_APPLETALK} \ ${USE_SRCS_IPX} \ + ${USE_SRCS_SCTP} \ ${USE_SRCS_UNIX_SOCKETS} SRCS_APPLETALK = OFDDPSocketTests.m SRCS_IPX = OFIPXSocketTests.m \ OFSPXSocketTests.m \ OFSPXStreamSocketTests.m +SRCS_SCTP = OFSCTPSocketTests.m SRCS_UNIX_SOCKETS = OFUNIXDatagramSocketTests.m \ OFUNIXStreamSocketTests.m SRCS_THREADS = OFThreadTests.m SRCS_WINDOWS = OFWindowsRegistryKeyTests.m ADDED tests/OFSCTPSocketTests.m Index: tests/OFSCTPSocketTests.m ================================================================== --- tests/OFSCTPSocketTests.m +++ tests/OFSCTPSocketTests.m @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2008-2021 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 +#include + +#import "TestsAppDelegate.h" + +static OFString *module = @"OFSCTPSocket"; + +@implementation TestsAppDelegate (OFSCTPSocketTests) +- (void)SCTPSocketTests +{ + void *pool = objc_autoreleasePoolPush(); + OFSCTPSocket *server, *client = nil, *accepted; + uint16_t port; + char buf[6]; + + TEST(@"+[socket]", (server = [OFSCTPSocket socket]) && + (client = [OFSCTPSocket socket])) + + @try { + TEST(@"-[bindToHost:port:]", + (port = [server bindToHost: @"127.0.0.1" port: 0])) + } @catch (OFBindSocketFailedException *e) { + switch (e.errNo) { + case EPROTONOSUPPORT: + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeLine: + @"\r[OFSCTPSocket] -[bindToHost:port:]: " + @"SCTP unsupported, skipping tests"]; + break; + default: + @throw e; + } + + objc_autoreleasePoolPop(pool); + return; + } + + TEST(@"-[listen]", R([server listen])) + + TEST(@"-[connectToHost:port:]", + R([client connectToHost: @"127.0.0.1" port: port])) + + TEST(@"-[accept]", (accepted = [server accept])) + + TEST(@"-[remoteAddress]", + [OFSocketAddressString(accepted.remoteAddress) + isEqual: @"127.0.0.1"]) + + TEST(@"-[sendBuffer:length:]", + R([client sendBuffer: "Hello!" length: 6])) + + TEST(@"-[receiveIntoBuffer:length:]", + [accepted receiveIntoBuffer: buf length: 6] && + !memcmp(buf, "Hello!", 6)) + + objc_autoreleasePoolPop(pool); +} +@end Index: tests/TestsAppDelegate.h ================================================================== --- tests/TestsAppDelegate.h +++ tests/TestsAppDelegate.h @@ -208,10 +208,14 @@ @end @interface TestsAppDelegate (OFSHA512HashTests) - (void)SHA512HashTests; @end + +@interface TestsAppDelegate (OFSCTPSocketTests) +- (void)SCTPSocketTests; +@end @interface TestsAppDelegate (OFSPXSocketTests) - (void)SPXSocketTests; @end Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -409,10 +409,13 @@ #endif #ifdef OF_HAVE_SOCKETS [self socketTests]; [self TCPSocketTests]; [self UDPSocketTests]; +# ifdef OF_HAVE_SCTP + [self SCTPSocketTests]; +# endif # ifdef OF_HAVE_UNIX_SOCKETS [self UNIXDatagramSocketTests]; [self UNIXStreamSocketTests]; # endif # ifdef OF_HAVE_IPX