Index: src/OFKernelEventObserver.m ================================================================== --- src/OFKernelEventObserver.m +++ src/OFKernelEventObserver.m @@ -61,15 +61,10 @@ QUEUE_READ = 0, QUEUE_WRITE = 2 }; #define QUEUE_ACTION (QUEUE_ADD | QUEUE_REMOVE) -#ifdef __wii__ -/* FIXME: Add a port registry for Wii */ -static uint16_t freePort = 65535; -#endif - @implementation OFKernelEventObserver + (void)initialize { if (self != [OFKernelEventObserver class]) return; @@ -133,11 +128,11 @@ _cancelAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); # ifdef __wii__ _cancelAddr.sin_len = 8; /* The Wii does not accept port 0 as "choose any free port" */ - _cancelAddr.sin_port = freePort--; + _cancelAddr.sin_port = of_socket_port_find(SOCK_DGRAM); # endif if (bind(_cancelFD[0], (struct sockaddr*)&_cancelAddr, sizeof(_cancelAddr))) @throw [OFInitializationFailedException @@ -166,10 +161,14 @@ - (void)dealloc { close(_cancelFD[0]); if (_cancelFD[1] != _cancelFD[0]) close(_cancelFD[1]); + +#ifdef __wii__ + of_socket_port_free(_cancelAddr.sin_port, SOCK_DGRAM); +#endif [_readObjects release]; [_writeObjects release]; [_queue release]; [_queueActions release]; Index: src/OFTCPSocket.h ================================================================== --- src/OFTCPSocket.h +++ src/OFTCPSocket.h @@ -64,10 +64,11 @@ struct sockaddr *_address; socklen_t _addressLength; OFString *_SOCKS5Host; uint16_t _SOCKS5Port; #ifdef __wii__ + uint16_t _port; bool _keepAliveEnabled, _TCPNoDelayEnabled; #endif } #ifdef OF_HAVE_PROPERTIES Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -61,14 +61,10 @@ Class of_tls_socket_class = Nil; static OFString *defaultSOCKS5Host = nil; static uint16_t defaultSOCKS5Port = 1080; -#ifdef __wii__ -static uint16_t freePort = 65532; -#endif - #ifdef OF_HAVE_THREADS @interface OFTCPSocket_ConnectThread: OFThread { OFThread *_sourceThread; OFTCPSocket *_socket; @@ -237,10 +233,22 @@ @throw e; } return self; } + +- (void)close +{ + [super close]; + +#ifdef __wii__ + if (_port > 0) { + of_socket_port_free(_port, SOCK_STREAM); + _port = 0; + } +#endif +} - (void)dealloc { [_SOCKS5Host release]; @@ -399,14 +407,27 @@ @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; #ifdef __wii__ if (port == 0) - port = freePort--; + port = of_socket_port_find(SOCK_STREAM); + else if (!of_socket_port_register(port, SOCK_STREAM)) + @throw [OFBindFailedException exceptionWithHost: host + port: port + socket: self + errNo: EADDRINUSE]; +#endif + + @try { + results = of_resolve_host(host, port, SOCK_STREAM); + } @catch (id e) { +#ifdef __wii__ + of_socket_port_free(port, SOCK_STREAM); #endif + @throw e; + } - results = of_resolve_host(host, port, SOCK_STREAM); @try { #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; #endif @@ -437,16 +458,25 @@ @throw [OFBindFailedException exceptionWithHost: host port: port socket: self errNo: errNo]; } + } @catch (id e) { +#ifdef __wii__ + of_socket_port_free(port, SOCK_STREAM); +#endif + @throw e; } @finally { of_resolver_free(results); } - if (port > 0) + if (port > 0) { +#ifdef __wii__ + _port = port; +#endif return port; + } #ifndef __wii__ addrLen = (socklen_t)sizeof(addr.storage); if (of_getsockname(_socket, (struct sockaddr*)&addr.storage, &addrLen) != 0) { Index: src/OFUDPSocket.h ================================================================== --- src/OFUDPSocket.h +++ src/OFUDPSocket.h @@ -88,10 +88,13 @@ */ @interface OFUDPSocket: OFObject { of_socket_t _socket; +#ifdef __wii__ + uint16_t _port; +#endif } /*! * @brief Returns a new, autoreleased OFUDPSocket. * Index: src/OFUDPSocket.m ================================================================== --- src/OFUDPSocket.m +++ src/OFUDPSocket.m @@ -39,14 +39,10 @@ #import "socket.h" #import "socket_helpers.h" #import "resolver.h" -#ifdef __wii__ -static uint16_t freePort = 65532; -#endif - #ifdef OF_HAVE_THREADS @interface OFUDPSocket_ResolveThread: OFThread { OFThread *_sourceThread; OFString *_host; @@ -401,14 +397,27 @@ socklen_t addrLen; #endif #ifdef __wii__ if (port == 0) - port = freePort--; + port = of_socket_port_find(SOCK_DGRAM); + else if (!of_socket_port_register(port, SOCK_DGRAM)) + @throw [OFBindFailedException exceptionWithHost: host + port: port + socket: self + errNo: EADDRINUSE]; +#endif + + @try { + results = of_resolve_host(host, port, SOCK_DGRAM); + } @catch (id e) { +#ifdef __wii__ + of_socket_port_free(port, SOCK_DGRAM); #endif + @throw e; + } - results = of_resolve_host(host, port, SOCK_DGRAM); @try { #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; #endif @@ -436,16 +445,25 @@ @throw [OFBindFailedException exceptionWithHost: host port: port socket: self errNo: errNo]; } + } @catch (id e) { +#ifdef __wii__ + of_socket_port_free(port, SOCK_DGRAM); +#endif + @throw e; } @finally { of_resolver_free(results); } - if (port > 0) + if (port > 0) { +#ifdef __wii__ + _port = port; +#endif return port; + } #ifndef __wii__ addrLen = (socklen_t)sizeof(addr.storage); if (of_getsockname(_socket, (struct sockaddr*)&addr.storage, &addrLen) != 0) { @@ -605,7 +623,14 @@ if (_socket == INVALID_SOCKET) @throw [OFNotOpenException exceptionWithObject: self]; close(_socket); _socket = INVALID_SOCKET; + +#ifdef __wii__ + if (_port > 0) { + of_socket_port_free(_port, SOCK_DGRAM); + _port = 0; + } +#endif } @end Index: src/macros.h ================================================================== --- src/macros.h +++ src/macros.h @@ -581,10 +581,28 @@ OF_HASH_ADD(hash, (otherCopy >> 24) & 0xFF); \ OF_HASH_ADD(hash, (otherCopy >> 16) & 0xFF); \ OF_HASH_ADD(hash, (otherCopy >> 8) & 0xFF); \ OF_HASH_ADD(hash, otherCopy & 0xFF); \ } + +static OF_INLINE bool +of_bitset_isset(uint8_t *storage, size_t index) +{ + return storage[index / 8] & (1 << (index % 8)); +} + +static OF_INLINE void +of_bitset_set(uint8_t *storage, size_t index) +{ + storage[index / 8] |= (1 << (index % 8)); +} + +static OF_INLINE void +of_bitset_clear(uint8_t *storage, size_t index) +{ + storage[index / 8] &= ~(1 << (index % 8)); +} static OF_INLINE char* of_strdup(const char *string) { char *copy; Index: src/socket.h ================================================================== --- src/socket.h +++ src/socket.h @@ -83,11 +83,15 @@ extern bool of_socket_init(void); extern int of_socket_errno(void); # ifndef __wii__ extern int of_getsockname(of_socket_t socket, struct sockaddr *restrict address, socklen_t *restrict address_len); +# else +extern bool of_socket_port_register(uint16_t port, int type); +extern void of_socket_port_free(uint16_t port, int type); +extern uint16_t of_socket_port_find(int type); # endif #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/socket.m ================================================================== --- src/socket.m +++ src/socket.m @@ -17,10 +17,11 @@ #include "config.h" #include #import "OFException.h" /* For some E* -> WSAE* defines */ +#import "OFInvalidArgumentException.h" #import "OFLockFailedException.h" #import "OFUnlockFailedException.h" #import "socket.h" #ifdef OF_HAVE_THREADS @@ -28,10 +29,17 @@ static of_once_t onceControl = OF_ONCE_INIT; static of_mutex_t mutex; #endif static bool initialized = false; + +#ifdef __wii__ +# ifdef OF_HAVE_THREADS +static of_spinlock_t spinlock; +# endif +static uint8_t portRegistry[2][65536 / 8]; +#endif static void init(void) { #if defined(_WIN32) @@ -45,10 +53,15 @@ #endif #ifdef OF_HAVE_THREADS if (!of_mutex_new(&mutex)) return; + +# ifdef __wii__ + if (!of_spinlock_new(&spinlock)) + return; +# endif #endif initialized = true; } @@ -184,6 +197,90 @@ @throw [OFUnlockFailedException exception]; # endif return ret; } +#else +static size_t +type_to_index(int type) +{ + switch (type) { + case SOCK_STREAM: + return 0; + case SOCK_DGRAM: + return 1; + default: + @throw [OFInvalidArgumentException exception]; + } +} + +bool +of_socket_port_register(uint16_t port, int type) +{ + size_t index; + bool wasSet; + + if (port == 0) + @throw [OFInvalidArgumentException exception]; + +# ifdef OF_HAVE_THREADS + if (!of_spinlock_lock(&spinlock)) + @throw [OFLockFailedException exception]; +# endif + + index = type_to_index(type); + wasSet = of_bitset_isset(portRegistry[index], port); + + of_bitset_set(portRegistry[index], port); + +# ifdef OF_HAVE_THREADS + if (!of_spinlock_unlock(&spinlock)) + @throw [OFUnlockFailedException exception]; +# endif + + return !wasSet; +} + +void +of_socket_port_free(uint16_t port, int type) +{ + if (port == 0) + @throw [OFInvalidArgumentException exception]; + +# ifdef OF_HAVE_THREADS + if (!of_spinlock_lock(&spinlock)) + @throw [OFLockFailedException exception]; +# endif + + of_bitset_clear(portRegistry[type_to_index(type)], port); + +# ifdef OF_HAVE_THREADS + if (!of_spinlock_unlock(&spinlock)) + @throw [OFUnlockFailedException exception]; +# endif +} + +uint16_t +of_socket_port_find(int type) +{ + uint16_t port; + size_t index; + +# ifdef OF_HAVE_THREADS + if (!of_spinlock_lock(&spinlock)) + @throw [OFLockFailedException exception]; +# endif + + index = type_to_index(type); + + do { + port = rand(); + } while (port == 0 || of_bitset_isset(portRegistry[index], port)); + +# ifdef OF_HAVE_THREADS + if (!of_spinlock_unlock(&spinlock)) + @throw [OFUnlockFailedException exception]; +# endif + + return port; +} #endif