Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -1568,10 +1568,93 @@ ], [ AC_DEFINE(OF_HAVE_IPX, 1, [Whether we have IPX/SPX]) AC_SUBST(USE_SRCS_IPX, '${SRCS_IPX}') ]) ]) + + AC_CHECK_HEADER(netatalk/at.h, [ + AC_DEFINE(OF_HAVE_NETATALK_AT_H, 1, + [Whether we have netatalk/at.h]) + ]) + AC_CHECK_MEMBER(struct sockaddr_at.sat_addr, [], [ + AC_CHECK_MEMBER(struct sockaddr_at.sat_net, [], [], [ + #ifdef _WIN32 + typedef int BOOL; + #endif + + #ifdef OF_HAVE_SYS_TYPES_H + # include + #endif + #ifdef OF_HAVE_NETATALK_AT_H + # include + #endif + + #ifdef _WIN32 + # ifdef __MINGW32__ + # include <_mingw.h> + # ifdef __MINGW64_VERSION_MAJOR + # include + # endif + # endif + # include + # include + #endif + ]) + ], [ + #ifdef _WIN32 + typedef int BOOL; + #endif + + #ifdef OF_HAVE_SYS_TYPES_H + # include + #endif + #ifdef OF_HAVE_NETATALK_AT_H + # include + #endif + + #ifdef _WIN32 + # ifdef __MINGW32__ + # include <_mingw.h> + # ifdef __MINGW64_VERSION_MAJOR + # include + # endif + # endif + # include + # include + #endif + ]) + AS_IF([test x"$ac_cv_member_struct_sockaddr_at_sat_addr" = x"yes" \ + -o x"$ac_cv_member_struct_sockaddr_at_sat_net" = x"yes"], [ + AC_EGREP_CPP(egrep_cpp_yes, [ + #ifdef _WIN32 + typedef int BOOL; + #endif + + #ifdef OF_HAVE_SYS_SOCKET_H + # include + #endif + + #ifdef _WIN32 + # ifdef __MINGW32__ + # include <_mingw.h> + # ifdef __MINGW64_VERSION_MAJOR + # include + # endif + # endif + # include + # include + #endif + + #ifdef AF_APPLETALK + egrep_cpp_yes + #endif + ], [ + AC_DEFINE(OF_HAVE_APPLETALK, 1, + [Whether we have AppleTalk]) + AC_SUBST(USE_SRCS_APPLETALK, '${SRCS_APPLETALK}') + ]) + ]) AC_CHECK_FUNCS(paccept accept4, break) AC_CHECK_FUNCS(kqueue1 kqueue, [ AC_DEFINE(HAVE_KQUEUE, 1, [Whether we have kqueue]) Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -77,13 +77,14 @@ TLS = @TLS@ TLS_CPPFLAGS = @TLS_CPPFLAGS@ TLS_LIBS = @TLS_LIBS@ UNICODE_M = @UNICODE_M@ 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_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 @@ -134,12 +134,14 @@ OFSocket.m \ OFStreamSocket.m \ OFTCPSocket.m \ OFTLSStream.m \ OFUDPSocket.m \ + ${USE_SRCS_APPLETALK} \ ${USE_SRCS_IPX} \ ${USE_SRCS_UNIX_SOCKETS} +SRCS_APPLETALK = OFDDPSocket.m SRCS_IPX = OFIPXSocket.m \ OFSPXSocket.m \ OFSPXStreamSocket.m SRCS_UNIX_SOCKETS = OFUNIXDatagramSocket.m \ OFUNIXStreamSocket.m ADDED src/OFDDPSocket.h Index: src/OFDDPSocket.h ================================================================== --- src/OFDDPSocket.h +++ src/OFDDPSocket.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2008-2022 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 "OFDatagramSocket.h" + +OF_ASSUME_NONNULL_BEGIN + +@class OFString; + +/** + * @protocol OFDDPSocketDelegate OFDDPSocket.h ObjFW/OFDDPSocket.h + * + * @brief A delegate for OFDDPSocket. + */ +@protocol OFDDPSocketDelegate +@end + +/** + * @class OFDDPSocket OFDDPSocket.h ObjFW/OFDDPSocket.h + * + * @brief A class which provides methods to create and use AppleTalk DDP + * sockets. + * + * Addresses are of type @ref OFSocketAddress. You can use + * @ref OFSocketAddressMakeAppleTalk to create an address or + * @ref OFSocketAddressAppleTalkNetwork to get the AppleTalk network, + * @ref OFSocketAddressAppleTalkNode to get the AppleTalk node and + * @ref OFSocketAddressAppleTalkPort to get the port (sometimes also called + * socket number). + * + * @warning Even though the OFCopying protocol is implemented, it does *not* + * return an independent copy of the socket, but instead retains it. + * This is so that the socket can be used as a key for a dictionary, + * so context can be associated with a socket. Using a socket in more + * than one thread at the same time is not thread-safe, even if copy + * was called to create one "instance" for every thread! + */ +@interface OFDDPSocket: OFDatagramSocket +{ + OF_RESERVE_IVARS(OFDDPSocket, 4) +} + +/** + * @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 Bind the socket to the specified network, node and port. + * + * @param network The network to bind to. 0 means any. + * @param node The node to bind to. 0 means "this node". + * @param port The port to bind to. 0 means to pick one and return it via the + * returned socket address. + * @return The address on which this socket can be reached + * @throw OFBindDDPSockeFailedException Binding failed + * @throw OFAlreadyConnectedException The socket is already bound + */ +- (OFSocketAddress)bindToNetwork: (uint16_t)network + node: (uint8_t)node + port: (uint8_t)port; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFDDPSocket.m Index: src/OFDDPSocket.m ================================================================== --- src/OFDDPSocket.m +++ src/OFDDPSocket.m @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2008-2022 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 + +#ifdef HAVE_FCNTL_H +# include +#endif + +#import "OFDDPSocket.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" + +#import "OFAlreadyConnectedException.h" +#import "OFBindDDPSocketFailedException.h" + +@implementation OFDDPSocket +@dynamic delegate; + +- (OFSocketAddress)bindToNetwork: (uint16_t)network + node: (uint8_t)node + port: (uint8_t)port +{ + OFSocketAddress address; +#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) + int flags; +#endif + + if (_socket != OFInvalidSocketHandle) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + + address = OFSocketAddressMakeAppleTalk(network, node, port); + + if ((_socket = socket(address.sockaddr.at.sat_family, + SOCK_DGRAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) + @throw [OFBindDDPSocketFailedException + exceptionWithNetwork: network + node: node + port: port + socket: self + errNo: OFSocketErrNo()]; + + _canBlock = true; + +#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) + if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) + fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); +#endif + + if (bind(_socket, (struct sockaddr *)&address.sockaddr, + address.length) != 0) { + int errNo = OFSocketErrNo(); + + closesocket(_socket); + _socket = OFInvalidSocketHandle; + + @throw [OFBindDDPSocketFailedException + exceptionWithNetwork: network + node: node + port: port + socket: self + errNo: errNo]; + } + + memset(&address, 0, sizeof(address)); + address.family = OFSocketAddressFamilyAppleTalk; + 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 [OFBindDDPSocketFailedException + exceptionWithNetwork: network + node: node + port: port + socket: self + errNo: errNo]; + } + + if (address.sockaddr.at.sat_family != AF_APPLETALK) { + closesocket(_socket); + _socket = OFInvalidSocketHandle; + + @throw [OFBindDDPSocketFailedException + exceptionWithNetwork: network + node: node + port: port + socket: self + errNo: EAFNOSUPPORT]; + } + + return address; +} +@end Index: src/OFDatagramSocket.m ================================================================== --- src/OFDatagramSocket.m +++ src/OFDatagramSocket.m @@ -210,10 +210,15 @@ #endif #ifdef OF_HAVE_IPX case AF_IPX: sender->family = OFSocketAddressFamilyIPX; break; +#endif +#ifdef OF_HAVE_APPLETALK + case AF_APPLETALK: + sender->family = OFSocketAddressFamilyAppleTalk; + break; #endif default: sender->family = OFSocketAddressFamilyUnknown; break; } Index: src/OFSocket.h ================================================================== --- src/OFSocket.h +++ src/OFSocket.h @@ -42,16 +42,22 @@ # include #endif #ifdef OF_HAVE_NETIPX_IPX_H # include #endif +#ifdef OF_HAVE_NETATALK_AT_H +# include +#endif #ifdef OF_WINDOWS # include # include # ifdef OF_HAVE_IPX # include +# endif +# ifdef OF_HAVE_APPLETALK +# include # endif #endif /** @file */ @@ -101,10 +107,12 @@ OFSocketAddressFamilyIPv6, /** UNIX */ OFSocketAddressFamilyUNIX, /** IPX */ OFSocketAddressFamilyIPX, + /** AppleTalk */ + OFSocketAddressFamilyAppleTalk, /** Any address family */ OFSocketAddressFamilyAny = 255 } OFSocketAddressFamily; #ifndef OF_HAVE_IPV6 @@ -142,10 +150,27 @@ # define sipx_network sa_netnum # define sipx_node sa_nodenum # define sipx_port sa_socket #endif +#ifndef OF_HAVE_APPLETALK +struct sockaddr_at { + sa_family_t sat_family; + uint8_t sat_port; + struct at_addr { + uint16_t s_net; + uint8_t s_node; + } sat_addr; +}; +#endif +#ifdef OF_WINDOWS +# define sat_port sat_socket +#else +# define sat_net sat_addr.s_net +# define sat_node sat_addr.s_node +#endif + /** * @struct OFSocketAddress OFSocket.h ObjFW/OFSocket.h * * @brief A struct which represents a host / port pair for a socket. */ @@ -158,10 +183,11 @@ union { struct sockaddr_in in; struct sockaddr_in6 in6; struct sockaddr_un un; struct sockaddr_ipx ipx; + struct sockaddr_at at; } sockaddr; socklen_t length; } OFSocketAddress; #ifdef __cplusplus @@ -215,10 +241,22 @@ * @return An IPX socket address with the specified node, network and port. */ extern OFSocketAddress OFSocketAddressMakeIPX(uint32_t network, const unsigned char node[_Nonnull IPX_NODE_LEN], uint16_t port); +/** + * @brief Creates an AppleTalk address for the specified network, node and port. + * + * @param network The AppleTalk network + * @param node The node in the AppleTalk network + * @param port The AppleTalk (sometimes called socket number) on the node + * @return An AppleTalk socket address with the specified node, network and + * port. + */ +extern OFSocketAddress OFSocketAddressMakeAppleTalk(uint16_t network, + uint8_t node, uint8_t port); + /** * @brief Compares two OFSocketAddress for equality. * * @param address1 The address to compare with the second address * @param address2 The second address @@ -322,10 +360,64 @@ * @param address The address on which to get the port * @return The port of the address */ extern uint16_t OFSocketAddressIPXPort(const OFSocketAddress *_Nonnull address); +/** + * @brief Sets the AppleTalk network of the specified @ref OFSocketAddress. + * + * @param address The address on which to set the AppleTalk network + * @param network The AppleTalk network to set on the address + */ +extern void OFSocketAddressSetAppleTalkNetwork( + OFSocketAddress *_Nonnull address, uint16_t network); + +/** + * @brief Returns the AppleTalk network of the specified @ref OFSocketAddress. + * + * @param address The address on which to get the AppleTalk network + * @return The AppleTalk network of the address + */ +extern uint16_t OFSocketAddressAppleTalkNetwork( + const OFSocketAddress *_Nonnull address); + +/** + * @brief Sets the AppleTalk node of the specified @ref OFSocketAddress. + * + * @param address The address on which to set the AppleTalk node + * @param node The AppleTalk node to set on the address + */ +extern void OFSocketAddressSetAppleTalkNode(OFSocketAddress *_Nonnull address, + uint8_t node); + +/** + * @brief Gets the AppleTalk node of the specified @ref OFSocketAddress. + * + * @param address The address on which to get the AppleTalk node + * @return The AppleTalk node of the address + */ +extern uint8_t OFSocketAddressAppleTalkNode( + const OFSocketAddress *_Nonnull address); + +/** + * @brief Sets the AppleTalk port of the specified @ref OFSocketAddress. + * + * @param address The address on which to set the port + * @param port The port to set on the address + */ +extern void OFSocketAddressSetAppleTalkPort(OFSocketAddress *_Nonnull address, + uint8_t port); + +/** + * @brief Returns the AppleTalk port of the specified @ref OFSocketAddress. + * + * @param address The address on which to get the port + * @return The port of the address + */ +extern uint8_t OFSocketAddressAppleTalkPort( + const OFSocketAddress *_Nonnull address); + extern bool OFSocketInit(void); #if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) && !defined(OF_MORPHOS) extern void OFSocketDeinit(void); #endif extern int OFSocketErrNo(void); Index: src/OFSocket.m ================================================================== --- src/OFSocket.m +++ src/OFSocket.m @@ -570,18 +570,40 @@ memcpy(ret.sockaddr.ipx.sipx_node, node, IPX_NODE_LEN); ret.sockaddr.ipx.sipx_port = OFToBigEndian16(port); return ret; } + +OFSocketAddress +OFSocketAddressMakeAppleTalk(uint16_t network, uint8_t node, uint8_t port) +{ + OFSocketAddress ret; + + memset(&ret, '\0', sizeof(ret)); + ret.family = OFSocketAddressFamilyAppleTalk; + ret.length = sizeof(ret.sockaddr.at); + +#ifdef AF_APPLETALK + ret.sockaddr.at.sat_family = AF_APPLETALK; +#else + ret.sockaddr.at.sat_family = AF_UNSPEC; +#endif + ret.sockaddr.at.sat_net = OFToBigEndian16(network); + ret.sockaddr.at.sat_node = node; + ret.sockaddr.at.sat_port = port; + + return ret; +} bool OFSocketAddressEqual(const OFSocketAddress *address1, const OFSocketAddress *address2) { const struct sockaddr_in *addrIn1, *addrIn2; const struct sockaddr_in6 *addrIn6_1, *addrIn6_2; const struct sockaddr_ipx *addrIPX1, *addrIPX2; + const struct sockaddr_at *addrAT1, *addrAT2; void *pool; OFString *path1, *path2; bool ret; if (address1->family != address2->family) @@ -655,10 +677,26 @@ return false; if (memcmp(addrIPX1->sipx_node, addrIPX2->sipx_node, IPX_NODE_LEN) != 0) return false; + return true; + case OFSocketAddressFamilyAppleTalk: + if (address1->length < (socklen_t)sizeof(struct sockaddr_at) || + address2->length < (socklen_t)sizeof(struct sockaddr_at)) + @throw [OFInvalidArgumentException exception]; + + addrAT1 = &address1->sockaddr.at; + addrAT2 = &address2->sockaddr.at; + + if (addrAT1->sat_net != addrAT2->sat_net) + return false; + if (addrAT1->sat_node != addrAT2->sat_node) + return false; + if (addrAT1->sat_port != addrAT2->sat_port) + return false; + return true; default: @throw [OFInvalidArgumentException exception]; } } @@ -731,10 +769,19 @@ for (size_t i = 0; i < IPX_NODE_LEN; i++) OFHashAddByte(&hash, address->sockaddr.ipx.sipx_node[i]); + break; + case OFSocketAddressFamilyAppleTalk: + if (address->length < (socklen_t)sizeof(struct sockaddr_at)) + @throw [OFInvalidArgumentException exception]; + + OFHashAddByte(&hash, address->sockaddr.at.sat_net >> 8); + OFHashAddByte(&hash, address->sockaddr.at.sat_net); + OFHashAddByte(&hash, address->sockaddr.at.sat_port); + break; default: @throw [OFInvalidArgumentException exception]; } @@ -946,5 +993,59 @@ if (address->family != OFSocketAddressFamilyIPX) @throw [OFInvalidArgumentException exception]; return OFFromBigEndian16(address->sockaddr.ipx.sipx_port); } + +void +OFSocketAddressSetAppleTalkNetwork(OFSocketAddress *address, uint16_t network) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + + address->sockaddr.at.sat_net = OFToBigEndian16(network); +} + +uint16_t +OFSocketAddressAppleTalkNetwork(const OFSocketAddress *address) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + + return OFFromBigEndian16(address->sockaddr.at.sat_net); +} + +void +OFSocketAddressSetAppleTalkNode(OFSocketAddress *address, uint8_t node) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + + address->sockaddr.at.sat_node = node; +} + +uint8_t +OFSocketAddressAppleTalkNode(const OFSocketAddress *address) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + + return address->sockaddr.at.sat_node; +} + +void +OFSocketAddressSetAppleTalkPort(OFSocketAddress *address, uint8_t port) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + + address->sockaddr.at.sat_port = port; +} + +uint8_t +OFSocketAddressAppleTalkPort(const OFSocketAddress *address) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + + return address->sockaddr.at.sat_port; +} Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -91,10 +91,13 @@ # ifdef OF_HAVE_IPX # import "OFIPXSocket.h" # import "OFSPXSocket.h" # import "OFSPXStreamSocket.h" # endif +# ifdef OF_HAVE_APPLETALK +# import "OFDDPSocket.h" +# endif # import "OFHTTPClient.h" # import "OFHTTPCookie.h" # import "OFHTTPCookieManager.h" # import "OFHTTPRequest.h" # import "OFHTTPResponse.h" @@ -207,10 +210,13 @@ # endif # ifdef OF_HAVE_IPX # import "OFBindIPXSocketFailedException.h" # import "OFConnectSPXSocketFailedException.h" # endif +# ifdef OF_HAVE_APPLETALK +# import "OFBindDDPSocketFailedException.h" +# endif #endif #ifdef OF_HAVE_THREADS # import "OFBroadcastConditionFailedException.h" # import "OFConditionStillWaitingException.h" # import "OFJoinThreadFailedException.h" Index: src/exceptions/Makefile ================================================================== --- src/exceptions/Makefile +++ src/exceptions/Makefile @@ -63,12 +63,14 @@ OFHTTPRequestFailedException.m \ OFListenOnSocketFailedException.m \ OFObserveKernelEventsFailedException.m \ OFResolveHostFailedException.m \ OFTLSHandshakeFailedException.m \ + ${USE_SRCS_APPLETALK} \ ${USE_SRCS_IPX} \ ${USE_SRCS_UNIX_SOCKETS} +SRCS_APPLETALK = OFBindDDPSocketFailedException.m SRCS_IPX = OFBindIPXSocketFailedException.m \ OFConnectSPXSocketFailedException.m SRCS_UNIX_SOCKETS = OFBindUNIXSocketFailedException.m \ OFConnectUNIXSocketFailedException.m SRCS_THREADS = OFBroadcastConditionFailedException.m \ ADDED src/exceptions/OFBindDDPSocketFailedException.h Index: src/exceptions/OFBindDDPSocketFailedException.h ================================================================== --- src/exceptions/OFBindDDPSocketFailedException.h +++ src/exceptions/OFBindDDPSocketFailedException.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2008-2022 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 "OFBindSocketFailedException.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFBindDDPSocketFailedException \ + * OFBindDDPSocketFailedException.h \ + * ObjFW/OFBindDDPSocketFailedException.h + * + * @brief An exception indicating that binding a DDP socket failed. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFBindDDPSocketFailedException: OFBindSocketFailedException +{ + uint16_t _network; + uint8_t _node, _port; +} + +/** + * @brief The DDP network on which binding failed. + */ +@property (readonly, nonatomic) uint16_t network; + +/** + * @brief The DDP node for which binding failed. + */ +@property (readonly, nonatomic) uint8_t node; + +/** + * @brief The DDP port on which binding failed. + */ +@property (readonly, nonatomic) uint8_t port; + +/** + * @brief Creates a new, autoreleased bind DDP socket failed exception. + * + * @param network The DDP network on which binding failed + * @param node The DDP node for which binding failed + * @param port The DDP port on which binding failed + * @param socket The socket which could not be bound + * @param errNo The errno of the error that occurred + * @return A new, autoreleased bind DDP socket failed exception + */ ++ (instancetype)exceptionWithNetwork: (uint16_t)network + node: (uint8_t)node + port: (uint8_t)port + socket: (id)socket + errNo: (int)errNo; + ++ (instancetype)exceptionWithSocket: (id)socket + errNo: (int)errNo OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated bind DDP socket failed exception. + * + * @param network The DDP network on which binding failed + * @param node The DDP node for which binding failed + * @param port The DDP port on which binding failed + * @param socket The socket which could not be bound + * @param errNo The errno of the error that occurred + * @return An initialized bind DDP socket failed exception + */ +- (instancetype)initWithNetwork: (uint16_t)network + node: (uint8_t)node + port: (uint8_t)port + socket: (id)socket + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)initWithSocket: (id)socket errNo: (int)errNo OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFBindDDPSocketFailedException.m Index: src/exceptions/OFBindDDPSocketFailedException.m ================================================================== --- src/exceptions/OFBindDDPSocketFailedException.m +++ src/exceptions/OFBindDDPSocketFailedException.m @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2008-2022 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 "OFBindDDPSocketFailedException.h" +#import "OFData.h" +#import "OFString.h" + +@implementation OFBindDDPSocketFailedException +@synthesize network = _network, node = _node, port = _port; + ++ (instancetype)exceptionWithSocket: (id)sock errNo: (int)errNo +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)exceptionWithNetwork: (uint16_t)network + node: (uint8_t)node + port: (uint8_t)port + socket: (id)sock + errNo: (int)errNo +{ + return [[[self alloc] initWithNetwork: network + node: node + port: port + socket: sock + errNo: errNo] autorelease]; +} + +- (instancetype)initWithSocket: (id)sock errNo: (int)errNo +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithNetwork: (uint16_t)network + node: (uint8_t)node + port: (uint8_t)port + socket: (id)sock + errNo: (int)errNo +{ + self = [super initWithSocket: sock errNo: errNo]; + + @try { + _network = network; + _node = node; + _port = port; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"Binding to port %" @PRIx8 @" of node %" @PRIx8 @" on network " + @"%" PRIx16 @" failed in socket of type %@: %@", + _port, _node, _network, [_socket class], OFStrError(_errNo)]; +} +@end Index: src/objfw-defs.h.in ================================================================== --- src/objfw-defs.h.in +++ src/objfw-defs.h.in @@ -1,9 +1,10 @@ #undef OF_APPLE_RUNTIME #undef OF_BIG_ENDIAN #undef OF_FLOAT_BIG_ENDIAN #undef OF_HAVE_AFUNIX_H +#undef OF_HAVE_APPLETALK #undef OF_HAVE_ATOMIC_BUILTINS #undef OF_HAVE_ATOMIC_OPS #undef OF_HAVE_BUILTIN_BSWAP16 #undef OF_HAVE_BUILTIN_BSWAP32 #undef OF_HAVE_BUILTIN_BSWAP64 @@ -14,10 +15,11 @@ #undef OF_HAVE_IPV6 #undef OF_HAVE_IPX #undef OF_HAVE_LIMITS_H #undef OF_HAVE_LINK #undef OF_HAVE_MAX_ALIGN_T +#undef OF_HAVE_NETATALK_AT_H #undef OF_HAVE_NETINET_IN_H #undef OF_HAVE_NETINET_TCP_H #undef OF_HAVE_NETIPX_IPX_H #undef OF_HAVE_OSATOMIC #undef OF_HAVE_OSATOMIC_64 Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -73,12 +73,14 @@ OFHTTPCookieManagerTests.m \ OFKernelEventObserverTests.m \ OFSocketTests.m \ OFTCPSocketTests.m \ OFUDPSocketTests.m \ + ${USE_SRCS_APPLETALK} \ ${USE_SRCS_IPX} \ ${USE_SRCS_UNIX_SOCKETS} +SRCS_APPLETALK = OFDDPSocketTests.m SRCS_IPX = OFIPXSocketTests.m \ OFSPXSocketTests.m \ OFSPXStreamSocketTests.m SRCS_UNIX_SOCKETS = OFUNIXDatagramSocketTests.m \ OFUNIXStreamSocketTests.m Index: tests/TestsAppDelegate.h ================================================================== --- tests/TestsAppDelegate.h +++ tests/TestsAppDelegate.h @@ -68,10 +68,14 @@ @end @interface TestsAppDelegate (OFCharacterSetTests) - (void)characterSetTests; @end + +@interface TestsAppDelegate (OFDDPSocketTests) +- (void)DDPSocketTests; +@end @interface TestsAppDelegate (OFDNSResolverTests) - (void)DNSResolverTests; @end Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -417,10 +417,13 @@ # endif # ifdef OF_HAVE_IPX [self IPXSocketTests]; [self SPXSocketTests]; [self SPXStreamSocketTests]; +# endif +# ifdef OF_HAVE_APPLETALK + [self DDPSocketTests]; # endif [self kernelEventObserverTests]; #endif #ifdef OF_HAVE_THREADS [self threadTests];