ObjFW  Check-in [ed4549ddd3]

Overview
Comment:Add a port registry for the Wii

This is necessary as the Wii does not allow picking a random free port,
and thus we need to track which ports are used.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: ed4549ddd3c5f92c0a39710eabfaa9104b55aea3ae517ed4f3bdf7d35ec24bcc
User & Date: js on 2015-10-17 10:59:15
Other Links: manifest | tags
Context
2015-10-17
12:01
Provide MMX/SSE/AVX check methods only on x86(_64) check-in: 1dbc2e0c76 user: js tags: trunk
10:59
Add a port registry for the Wii check-in: ed4549ddd3 user: js tags: trunk
2015-10-10
09:18
ofhttp: Fix ETA calculation for resumed files check-in: 5832ac9420 user: js tags: trunk
Changes

Modified src/OFKernelEventObserver.m from [b0c771eac2] to [23a24b058b].

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
	QUEUE_ADD = 0,
	QUEUE_REMOVE = 1,
	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;

	if (!of_socket_init())







<
<
<
<
<







59
60
61
62
63
64
65





66
67
68
69
70
71
72
	QUEUE_ADD = 0,
	QUEUE_REMOVE = 1,
	QUEUE_READ = 0,
	QUEUE_WRITE = 2
};
#define QUEUE_ACTION (QUEUE_ADD | QUEUE_REMOVE)






@implementation OFKernelEventObserver
+ (void)initialize
{
	if (self != [OFKernelEventObserver class])
		return;

	if (!of_socket_init())
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
		_cancelAddr.sin_family = AF_INET;
		_cancelAddr.sin_port = 0;
		_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--;
# endif

		if (bind(_cancelFD[0], (struct sockaddr*)&_cancelAddr,
		    sizeof(_cancelAddr)))
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];








|







126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
		_cancelAddr.sin_family = AF_INET;
		_cancelAddr.sin_port = 0;
		_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 = of_socket_port_find(SOCK_DGRAM);
# endif

		if (bind(_cancelFD[0], (struct sockaddr*)&_cancelAddr,
		    sizeof(_cancelAddr)))
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];

164
165
166
167
168
169
170




171
172
173
174
175
176
177
}

- (void)dealloc
{
	close(_cancelFD[0]);
	if (_cancelFD[1] != _cancelFD[0])
		close(_cancelFD[1]);





	[_readObjects release];
	[_writeObjects release];
	[_queue release];
	[_queueActions release];
#ifdef OF_HAVE_THREADS
	[_mutex release];







>
>
>
>







159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
}

- (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];
#ifdef OF_HAVE_THREADS
	[_mutex release];

Modified src/OFTCPSocket.h from [7dabca200d] to [55b987fd74].

62
63
64
65
66
67
68

69
70
71
72
73
74
75
{
	bool _listening;
	struct sockaddr *_address;
	socklen_t _addressLength;
	OFString *_SOCKS5Host;
	uint16_t _SOCKS5Port;
#ifdef __wii__

	bool _keepAliveEnabled, _TCPNoDelayEnabled;
#endif
}

#ifdef OF_HAVE_PROPERTIES
@property (readonly, getter=isListening) bool listening;
@property OF_NULLABLE_PROPERTY (copy) OFString *SOCKS5Host;







>







62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
{
	bool _listening;
	struct sockaddr *_address;
	socklen_t _addressLength;
	OFString *_SOCKS5Host;
	uint16_t _SOCKS5Port;
#ifdef __wii__
	uint16_t _port;
	bool _keepAliveEnabled, _TCPNoDelayEnabled;
#endif
}

#ifdef OF_HAVE_PROPERTIES
@property (readonly, getter=isListening) bool listening;
@property OF_NULLABLE_PROPERTY (copy) OFString *SOCKS5Host;

Modified src/OFTCPSocket.m from [76989391ef] to [a3e1049524].

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
}

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;
	OFString *_host;
	uint16_t _port;







<
<
<
<







59
60
61
62
63
64
65




66
67
68
69
70
71
72
}

Class of_tls_socket_class = Nil;

static OFString *defaultSOCKS5Host = nil;
static uint16_t defaultSOCKS5Port = 1080;





#ifdef OF_HAVE_THREADS
@interface OFTCPSocket_ConnectThread: OFThread
{
	OFThread *_sourceThread;
	OFTCPSocket *_socket;
	OFString *_host;
	uint16_t _port;
235
236
237
238
239
240
241












242
243
244
245
246
247
248
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}













- (void)dealloc
{
	[_SOCKS5Host release];

	[super dealloc];
}







>
>
>
>
>
>
>
>
>
>
>
>







231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
	} @catch (id e) {
		[self release];
		@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];

	[super dealloc];
}
397
398
399
400
401
402
403



404


405
406

407







408
409
410
411
412
413
414

	if (_SOCKS5Host != nil)
		@throw [OFNotImplementedException exceptionWithSelector: _cmd
								 object: self];

#ifdef __wii__
	if (port == 0)



		port = freePort--;


#endif


	results = of_resolve_host(host, port, SOCK_STREAM);







	@try {
#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
		int flags;
#endif

		if ((_socket = socket(results[0]->family,
		    results[0]->type | SOCK_CLOEXEC,







>
>
>
|
>
>


>
|
>
>
>
>
>
>
>







405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435

	if (_SOCKS5Host != nil)
		@throw [OFNotImplementedException exceptionWithSelector: _cmd
								 object: self];

#ifdef __wii__
	if (port == 0)
		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;
	}

	@try {
#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
		int flags;
#endif

		if ((_socket = socket(results[0]->family,
		    results[0]->type | SOCK_CLOEXEC,
435
436
437
438
439
440
441





442
443
444
445
446



447

448
449
450
451
452
453
454
			_socket = INVALID_SOCKET;

			@throw [OFBindFailedException exceptionWithHost: host
								   port: port
								 socket: self
								  errNo: errNo];
		}





	} @finally {
		of_resolver_free(results);
	}

	if (port > 0)



		return port;


#ifndef __wii__
	addrLen = (socklen_t)sizeof(addr.storage);
	if (of_getsockname(_socket, (struct sockaddr*)&addr.storage,
	    &addrLen) != 0) {
		int errNo = of_socket_errno();








>
>
>
>
>




|
>
>
>

>







456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
			_socket = INVALID_SOCKET;

			@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) {
#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) {
		int errNo = of_socket_errno();

Modified src/OFUDPSocket.h from [322e298c3d] to [3a06e39684].

86
87
88
89
90
91
92



93
94
95
96
97
98
99
 *	    than one thread at the same time is not thread-safe, even if copy
 *	    was called to create one "instance" for every thread!
 */
@interface OFUDPSocket: OFObject <OFCopying, OFReadyForReadingObserving,
    OFReadyForWritingObserving>
{
	of_socket_t _socket;



}

/*!
 * @brief Returns a new, autoreleased OFUDPSocket.
 *
 * @return A new, autoreleased OFUDPSocket
 */







>
>
>







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
 *	    than one thread at the same time is not thread-safe, even if copy
 *	    was called to create one "instance" for every thread!
 */
@interface OFUDPSocket: OFObject <OFCopying, OFReadyForReadingObserving,
    OFReadyForWritingObserving>
{
	of_socket_t _socket;
#ifdef __wii__
	uint16_t _port;
#endif
}

/*!
 * @brief Returns a new, autoreleased OFUDPSocket.
 *
 * @return A new, autoreleased OFUDPSocket
 */

Modified src/OFUDPSocket.m from [3c90c2bfad] to [b7f838da94].

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#import "OFReadFailedException.h"
#import "OFWriteFailedException.h"

#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;
	uint16_t _port;
	id _target;







<
<
<
<







37
38
39
40
41
42
43




44
45
46
47
48
49
50
#import "OFReadFailedException.h"
#import "OFWriteFailedException.h"

#import "socket.h"
#import "socket_helpers.h"
#import "resolver.h"





#ifdef OF_HAVE_THREADS
@interface OFUDPSocket_ResolveThread: OFThread
{
	OFThread *_sourceThread;
	OFString *_host;
	uint16_t _port;
	id _target;
399
400
401
402
403
404
405



406


407
408

409







410
411
412
413
414
415
416
# endif
	} addr;
	socklen_t addrLen;
#endif

#ifdef __wii__
	if (port == 0)



		port = freePort--;


#endif


	results = of_resolve_host(host, port, SOCK_DGRAM);







	@try {
#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
		int flags;
#endif

		if ((_socket = socket(results[0]->family,
		    results[0]->type | SOCK_CLOEXEC,







>
>
>
|
>
>


>
|
>
>
>
>
>
>
>







395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
# endif
	} addr;
	socklen_t addrLen;
#endif

#ifdef __wii__
	if (port == 0)
		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;
	}

	@try {
#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
		int flags;
#endif

		if ((_socket = socket(results[0]->family,
		    results[0]->type | SOCK_CLOEXEC,
434
435
436
437
438
439
440





441
442
443
444
445



446

447
448
449
450
451
452
453
			_socket = INVALID_SOCKET;

			@throw [OFBindFailedException exceptionWithHost: host
								   port: port
								 socket: self
								  errNo: errNo];
		}





	} @finally {
		of_resolver_free(results);
	}

	if (port > 0)



		return port;


#ifndef __wii__
	addrLen = (socklen_t)sizeof(addr.storage);
	if (of_getsockname(_socket, (struct sockaddr*)&addr.storage,
	    &addrLen) != 0) {
		int errNo = of_socket_errno();








>
>
>
>
>




|
>
>
>

>







443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
			_socket = INVALID_SOCKET;

			@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) {
#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) {
		int errNo = of_socket_errno();

603
604
605
606
607
608
609
610







611
- (void)close
{
	if (_socket == INVALID_SOCKET)
		@throw [OFNotOpenException exceptionWithObject: self];

	close(_socket);
	_socket = INVALID_SOCKET;
}







@end







|
>
>
>
>
>
>
>

621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
- (void)close
{
	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

Modified src/macros.h from [a5359bc24a] to [a7d0bdefbc].

579
580
581
582
583
584
585


















586
587
588
589
590
591
592
	{							\
		uint32_t otherCopy = other;			\
		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 char*
of_strdup(const char *string)
{
	char *copy;
	size_t length = strlen(string);








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
	{							\
		uint32_t otherCopy = other;			\
		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;
	size_t length = strlen(string);

Modified src/socket.h from [c74fa51c3e] to [6b8f6a13f5].

81
82
83
84
85
86
87




88
89
90
91
92
93
extern "C" {
#endif
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);




# endif
#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END







>
>
>
>






81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
extern "C" {
#endif
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

Modified src/socket.m from [a318aca5b3] to [ebf56cad93].

15
16
17
18
19
20
21

22
23
24
25
26
27
28
29
30
31
32







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49





50
51
52
53
54
55
56
 */

#include "config.h"

#include <errno.h>

#import "OFException.h"  /* For some E* -> WSAE* defines */

#import "OFLockFailedException.h"
#import "OFUnlockFailedException.h"

#import "socket.h"
#ifdef OF_HAVE_THREADS
# include "threading.h"

static of_once_t onceControl = OF_ONCE_INIT;
static of_mutex_t mutex;
#endif
static bool initialized = false;








static void
init(void)
{
#if defined(_WIN32)
	WSADATA wsa;

	if (WSAStartup(MAKEWORD(2, 0), &wsa))
		return;
#elif defined(__wii__)
	if (net_init() < 0)
		return;
#endif

#ifdef OF_HAVE_THREADS
	if (!of_mutex_new(&mutex))
		return;





#endif

	initialized = true;
}

bool
of_socket_init()







>











>
>
>
>
>
>
>

















>
>
>
>
>







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
 */

#include "config.h"

#include <errno.h>

#import "OFException.h"  /* For some E* -> WSAE* defines */
#import "OFInvalidArgumentException.h"
#import "OFLockFailedException.h"
#import "OFUnlockFailedException.h"

#import "socket.h"
#ifdef OF_HAVE_THREADS
# include "threading.h"

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)
	WSADATA wsa;

	if (WSAStartup(MAKEWORD(2, 0), &wsa))
		return;
#elif defined(__wii__)
	if (net_init() < 0)
		return;
#endif

#ifdef OF_HAVE_THREADS
	if (!of_mutex_new(&mutex))
		return;

# ifdef __wii__
	if (!of_spinlock_new(&spinlock))
		return;
# endif
#endif

	initialized = true;
}

bool
of_socket_init()
182
183
184
185
186
187
188




















































































189
# ifdef OF_HAVE_THREADS
	if (!of_mutex_unlock(&mutex))
		@throw [OFUnlockFailedException exception];
# endif

	return ret;
}




















































































#endif







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# ifdef OF_HAVE_THREADS
	if (!of_mutex_unlock(&mutex))
		@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