Index: src/OFIPXSocket.m ================================================================== --- src/OFIPXSocket.m +++ src/OFIPXSocket.m @@ -45,11 +45,11 @@ #endif if (_socket != INVALID_SOCKET) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; - address = of_socket_address_ipx(0, zeroNode, port); + address = of_socket_address_ipx(zeroNode, 0, port); #ifdef OF_WINDOWS protocol = NSPROTO_IPX + packetType; #else _packetType = address.sockaddr.ipx.sipx_type = packetType; Index: src/OFSPXSocket.m ================================================================== --- src/OFSPXSocket.m +++ src/OFSPXSocket.m @@ -24,19 +24,28 @@ #import "OFRunLoop+Private.h" #import "OFAlreadyConnectedException.h" #import "OFBindFailedException.h" #import "OFConnectionFailedException.h" +#import "OFNotOpenException.h" #import "socket.h" #import "socket_helpers.h" #ifndef NSPROTO_SPX # define NSPROTO_SPX 0 #endif #define SPX_PACKET_TYPE 5 + +@interface OFSPXSocket () +- (int)of_createSocketForAddress: (const of_socket_address_t *)address + errNo: (int *)errNo; +- (bool)of_connectSocketToAddress: (const of_socket_address_t *)address + errNo: (int *)errNo; +- (void)of_closeSocket; +@end @interface OFSPXSocketAsyncConnectDelegate: OFObject { OFSPXSocket *_socket; unsigned char _node[IPX_NODE_LEN]; @@ -95,29 +104,38 @@ [super dealloc]; } - (void)startWithRunLoopMode: (of_run_loop_mode_t)runLoopMode { + of_socket_address_t address = + of_socket_address_ipx(_node, _network, _port); id exception = nil; + int errNo; + + if (![_socket of_createSocketForAddress: &address + errNo: &errNo]) { + exception = [self of_connectionFailedExceptionForErrNo: errNo]; + goto inform_delegate; + } _socket.blocking = false; - @try { - [_socket connectToNode: _node - network: _network - port: _port]; - } @catch (OFConnectionFailedException *e) { - if (e.errNo == EINPROGRESS) { + if (![_socket of_connectSocketToAddress: &address + errNo: &errNo]) { + if (errNo == EINPROGRESS) { [OFRunLoop of_addAsyncConnectForSocket: _socket mode: runLoopMode delegate: self]; return; } - exception = e; + [_socket of_closeSocket]; + + exception = [self of_connectionFailedExceptionForErrNo: errNo]; } +inform_delegate: [self performSelector: @selector(of_socketDidConnect:exception:) withObject: _socket withObject: exception afterDelay: 0]; } @@ -158,38 +176,75 @@ @end @implementation OFSPXSocket @dynamic delegate; -- (void)connectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node - network: (uint32_t)network - port: (uint16_t)port +- (int)of_createSocketForAddress: (const of_socket_address_t *)address + errNo: (int *)errNo { - of_socket_address_t address = - of_socket_address_ipx(network, node, port); #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; #endif - if ((_socket = socket(address.sockaddr.ipx.sipx_family, - SOCK_SEQPACKET | SOCK_CLOEXEC, NSPROTO_SPX)) == INVALID_SOCKET) - @throw [OFConnectionFailedException - exceptionWithNode: node - network: network - port: port - socket: self - errNo: of_socket_errno()]; + if (_socket != INVALID_SOCKET) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + + if ((_socket = socket(address->sockaddr.ipx.sipx_family, + SOCK_SEQPACKET | SOCK_CLOEXEC, NSPROTO_SPX)) == INVALID_SOCKET) { + *errNo = of_socket_errno(); + 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 - if (connect(_socket, &address.sockaddr.sockaddr, address.length) != 0) { - int errNo = of_socket_errno(); + return true; +} + +- (bool)of_connectSocketToAddress: (const of_socket_address_t *)address + errNo: (int *)errNo +{ + if (_socket == INVALID_SOCKET) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (connect(_socket, &address->sockaddr.sockaddr, + address->length) != 0) { + *errNo = of_socket_errno(); + return false; + } + + return true; +} + +- (void)of_closeSocket +{ + closesocket(_socket); + _socket = INVALID_SOCKET; +} + +- (void)connectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node + network: (uint32_t)network + port: (uint16_t)port +{ + of_socket_address_t address = + of_socket_address_ipx(node, network, port); + int errNo; + + if (![self of_createSocketForAddress: &address + errNo: &errNo]) + @throw [OFConnectionFailedException + exceptionWithNode: node + network: network + port: port + socket: self + errNo: errNo]; - closesocket(_socket); + if (![self of_connectSocketToAddress: &address + errNo: &errNo]) { + [self of_closeSocket]; @throw [OFConnectionFailedException exceptionWithNode: node network: network port: port @@ -270,11 +325,11 @@ #endif if (_socket != INVALID_SOCKET) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; - address = of_socket_address_ipx(0, zeroNode, port); + address = of_socket_address_ipx(zeroNode, 0, port); if ((_socket = socket(address.sockaddr.sockaddr.sa_family, SOCK_SEQPACKET | SOCK_CLOEXEC, NSPROTO_SPX)) == INVALID_SOCKET) @throw [OFBindFailedException exceptionWithPort: port @@ -290,14 +345,12 @@ #endif if (bind(_socket, &address.sockaddr.sockaddr, address.length) != 0) { int errNo = of_socket_errno(); - if (errNo != EINPROGRESS) { - closesocket(_socket); - _socket = INVALID_SOCKET; - } + closesocket(_socket); + _socket = INVALID_SOCKET; @throw [OFBindFailedException exceptionWithPort: port packetType: SPX_PACKET_TYPE socket: self errNo: errNo]; Index: src/socket.h ================================================================== --- src/socket.h +++ src/socket.h @@ -189,16 +189,17 @@ OFString *IP, uint16_t port); /*! * @brief Creates an IPX address for the specified network, node and port. * - * @param network The IPX network * @param node The node in the IPX network + * @param network The IPX network * @param port The IPX port (sometimes called socket number) on the node */ -extern of_socket_address_t of_socket_address_ipx(uint32_t network, - const unsigned char node[_Nonnull IPX_NODE_LEN], uint16_t port); +extern of_socket_address_t of_socket_address_ipx( + const unsigned char node[_Nonnull IPX_NODE_LEN], uint32_t network, + uint16_t port); /*! * @brief Compares two of_socket_address_t for equality. * * @param address1 The address to compare with the second address Index: src/socket.m ================================================================== --- src/socket.m +++ src/socket.m @@ -507,11 +507,11 @@ return of_socket_address_parse_ipv4(IP, port); } } of_socket_address_t -of_socket_address_ipx(uint32_t network, const unsigned char node[IPX_NODE_LEN], +of_socket_address_ipx(const unsigned char node[IPX_NODE_LEN], uint32_t network, uint16_t port) { of_socket_address_t ret; memset(&ret, '\0', sizeof(ret)); @@ -521,14 +521,14 @@ #ifdef AF_IPX ret.sockaddr.ipx.sipx_family = AF_IPX; #else ret.sockaddr.ipx.sipx_family = AF_UNSPEC; #endif + memcpy(ret.sockaddr.ipx.sipx_node, node, IPX_NODE_LEN); network = OF_BSWAP32_IF_LE(network); memcpy(&ret.sockaddr.ipx.sipx_network, &network, sizeof(ret.sockaddr.ipx.sipx_network)); - memcpy(ret.sockaddr.ipx.sipx_node, node, IPX_NODE_LEN); ret.sockaddr.ipx.sipx_port = OF_BSWAP16_IF_LE(port); return ret; } Index: tests/OFSPXSocketTests.m ================================================================== --- tests/OFSPXSocketTests.m +++ tests/OFSPXSocketTests.m @@ -20,10 +20,57 @@ #include #import "TestsAppDelegate.h" static OFString *module = @"OFSPXSocket"; + +@interface SPXSocketDelegate: OFObject +{ +@public + OFSequencedPacketSocket *_expectedServerSocket; + OFSPXSocket *_expectedClientSocket; + unsigned char _expectedNode[IPX_NODE_LEN]; + uint32_t _expectedNetwork; + uint16_t _expectedPort; + bool _accepted; + bool _connected; +} +@end + +@implementation SPXSocketDelegate +- (bool)socket: (OFSequencedPacketSocket *)sock + didAcceptSocket: (OFSequencedPacketSocket *)accepted + exception: (id)exception +{ + OF_ENSURE(!_accepted); + + _accepted = (sock == _expectedServerSocket && accepted != nil && + exception == nil); + + if (_accepted && _connected) + [[OFRunLoop mainRunLoop] stop]; + + return false; +} + +- (void)socket: (OFSPXSocket *)sock + didConnectToNode: (unsigned char [IPX_NODE_LEN])node + network: (uint32_t)network + port: (uint16_t)port + exception: (id)exception +{ + OF_ENSURE(!_connected); + + _connected = (sock == _expectedClientSocket && + memcmp(node, _expectedNode, IPX_NODE_LEN) == 0 && + network == _expectedNetwork && port == _expectedPort && + exception == nil); + + if (_accepted && _connected) + [[OFRunLoop mainRunLoop] stop]; +} +@end @implementation TestsAppDelegate (OFSPXSocketTests) - (void)SPXSocketTests { void *pool = objc_autoreleasePoolPush(); @@ -32,10 +79,11 @@ const of_socket_address_t *address2; unsigned char node[IPX_NODE_LEN], node2[IPX_NODE_LEN]; uint32_t network; uint16_t port; char buffer[5]; + SPXSocketDelegate *delegate; TEST(@"+[socket]", (sockClient = [OFSPXSocket socket]) && (sockServer = [OFSPXSocket socket])) @try { @@ -92,9 +140,39 @@ TEST(@"-[remoteAddress]", (address2 = sockAccepted.remoteAddress) && R(of_socket_address_get_ipx_node(address2, node2)) && memcmp(node, node2, IPX_NODE_LEN) == 0 && of_socket_address_get_ipx_network(address2) == network) + + delegate = [[[SPXSocketDelegate alloc] init] autorelease]; + + sockServer = [OFSPXSocket socket]; + delegate->_expectedServerSocket = sockServer; + sockServer.delegate = delegate; + + sockClient = [OFSPXSocket socket]; + delegate->_expectedClientSocket = sockClient; + sockClient.delegate = delegate; + + address1 = [sockServer bindToPort: 0]; + [sockServer listen]; + [sockServer asyncAccept]; + + of_socket_address_get_ipx_node(&address1, node); + memcpy(delegate->_expectedNode, node, IPX_NODE_LEN); + delegate->_expectedNetwork = network = + of_socket_address_get_ipx_network(&address1); + delegate->_expectedPort = port = of_socket_address_get_port(&address1); + + [sockClient asyncConnectToNode: node + network: network + port: port]; + + [[OFRunLoop mainRunLoop] runUntilDate: + [OFDate dateWithTimeIntervalSinceNow: 2]]; + + TEST(@"-[asyncAccept] & -[asyncConnectToNode:network:port:]", + delegate->_accepted && delegate->_connected) objc_autoreleasePoolPop(pool); } @end