ObjFW  Check-in [ab89c47f42]

Overview
Comment:Partially fix sockets on Nintendo 3DS/Wii

This does not fully fix it yet, but at least the socket tests in the
test suite pass on 3DS now.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: ab89c47f42014b477ca3094d258c196c79cb99a868397f12be342e3d6881ab80
User & Date: js on 2019-01-07 22:59:58
Other Links: manifest | tags
Context
2019-01-12
19:46
objfw-config: Add support for packages check-in: 9911d60502 user: js tags: trunk
2019-01-07
22:59
Partially fix sockets on Nintendo 3DS/Wii check-in: ab89c47f42 user: js tags: trunk
2019-01-03
19:13
Update copyright check-in: 0509d7a844 user: js tags: trunk
Changes

Modified configure.ac from [7c406779e4] to [a713ffb1f0].

780
781
782
783
784
785
786
787
788
789
790
791
792
793
794

		AC_MSG_ERROR([Neither INFINITY or __builtin_inf was found!])
	])
])

case "$host_cpu" in
	arm* | earm*)
		AC_MSG_CHECKING(if VFP2 or above is available)
		AC_TRY_COMPILE([], [
			#if !defined(__arm64__) && !defined(__aarch64__) && \
			    !defined(__ARM64_ARCH_8__)
			__asm__ __volatile__ (
			    "fstmfdd sp!, {d0-d7}"
			);
			#endif







|







780
781
782
783
784
785
786
787
788
789
790
791
792
793
794

		AC_MSG_ERROR([Neither INFINITY or __builtin_inf was found!])
	])
])

case "$host_cpu" in
	arm* | earm*)
		AC_MSG_CHECKING(for VFP2 or above)
		AC_TRY_COMPILE([], [
			#if !defined(__arm64__) && !defined(__aarch64__) && \
			    !defined(__ARM64_ARCH_8__)
			__asm__ __volatile__ (
			    "fstmfdd sp!, {d0-d7}"
			);
			#endif

Modified src/OFRunLoop+Private.h from [9ec5c531e9] to [3fce6b275d].

80
81
82
83
84
85
86

87
88
89
90

91
92
93
94
95
96
97
			     mode: (of_run_loop_mode_t)mode
# ifdef OF_HAVE_BLOCKS
			    block: (nullable
				       of_stream_async_write_string_block_t)
				       block
# endif
			 delegate: (nullable id <OFStreamDelegate>)delegate;

+ (void)of_addAsyncConnectForTCPSocket: (OFTCPSocket *)socket
				  mode: (of_run_loop_mode_t)mode
			      delegate: (id <OFTCPSocketDelegate_Private>)
					    delegate;

+ (void)of_addAsyncAcceptForTCPSocket: (OFTCPSocket *)socket
				 mode: (of_run_loop_mode_t)mode
# ifdef OF_HAVE_BLOCKS
				block: (nullable
					   of_tcp_socket_async_accept_block_t)
					   block
# endif







>




>







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
			     mode: (of_run_loop_mode_t)mode
# ifdef OF_HAVE_BLOCKS
			    block: (nullable
				       of_stream_async_write_string_block_t)
				       block
# endif
			 delegate: (nullable id <OFStreamDelegate>)delegate;
# if !defined(OF_WII) && !defined(OF_NINTENDO_3DS)
+ (void)of_addAsyncConnectForTCPSocket: (OFTCPSocket *)socket
				  mode: (of_run_loop_mode_t)mode
			      delegate: (id <OFTCPSocketDelegate_Private>)
					    delegate;
# endif
+ (void)of_addAsyncAcceptForTCPSocket: (OFTCPSocket *)socket
				 mode: (of_run_loop_mode_t)mode
# ifdef OF_HAVE_BLOCKS
				block: (nullable
					   of_tcp_socket_async_accept_block_t)
					   block
# endif

Modified src/OFRunLoop.m from [7120aa762e] to [f76ad8e6f6].

132
133
134
135
136
137
138

139
140

141
142
143
144
145
146
147
# endif
	OFString *_string;
	of_string_encoding_t _encoding;
	size_t _writtenLength;
}
@end


@interface OFRunLoop_ConnectQueueItem: OFRunLoop_QueueItem
@end


@interface OFRunLoop_AcceptQueueItem: OFRunLoop_QueueItem
{
@public
# ifdef OF_HAVE_BLOCKS
	of_tcp_socket_async_accept_block_t _block;
# endif







>


>







132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# endif
	OFString *_string;
	of_string_encoding_t _encoding;
	size_t _writtenLength;
}
@end

# if !defined(OF_WII) && !defined(OF_NINTENDO_3DS)
@interface OFRunLoop_ConnectQueueItem: OFRunLoop_QueueItem
@end
# endif

@interface OFRunLoop_AcceptQueueItem: OFRunLoop_QueueItem
{
@public
# ifdef OF_HAVE_BLOCKS
	of_tcp_socket_async_accept_block_t _block;
# endif
598
599
600
601
602
603
604

605
606
607
608
609
610
611
	[_block release];
# endif

	[super dealloc];
}
@end


@implementation OFRunLoop_ConnectQueueItem
- (bool)handleObject: (id)object
{
	id exception = nil;
	int errNo;

	if ((errNo = [object of_socketError]) != 0)







>







600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
	[_block release];
# endif

	[super dealloc];
}
@end

# if !defined(OF_WII) && !defined(OF_NINTENDO_3DS)
@implementation OFRunLoop_ConnectQueueItem
- (bool)handleObject: (id)object
{
	id exception = nil;
	int errNo;

	if ((errNo = [object of_socketError]) != 0)
619
620
621
622
623
624
625

626
627
628
629
630
631
632
	    @selector(of_socketDidConnect:exception:)])
		[_delegate of_socketDidConnect: object
				     exception: exception];

	return false;
}
@end


@implementation OFRunLoop_AcceptQueueItem
- (bool)handleObject: (id)object
{
	OFTCPSocket *acceptedSocket;
	id exception = nil;








>







622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
	    @selector(of_socketDidConnect:exception:)])
		[_delegate of_socketDidConnect: object
				     exception: exception];

	return false;
}
@end
# endif

@implementation OFRunLoop_AcceptQueueItem
- (bool)handleObject: (id)object
{
	OFTCPSocket *acceptedSocket;
	id exception = nil;

939
940
941
942
943
944
945

946
947
948
949
950
951
952
953
954
955
956

957
958
959
960
961
962
963
# endif
	queueItem->_string = [string copy];
	queueItem->_encoding = encoding;

	QUEUE_ITEM
}


+ (void)of_addAsyncConnectForTCPSocket: (OFTCPSocket *)stream
				  mode: (of_run_loop_mode_t)mode
			      delegate: (id <OFTCPSocketDelegate_Private>)
					    delegate
{
	NEW_WRITE(OFRunLoop_ConnectQueueItem, stream, mode)

	queueItem->_delegate = [delegate retain];

	QUEUE_ITEM
}


+ (void)of_addAsyncAcceptForTCPSocket: (OFTCPSocket *)stream
				 mode: (of_run_loop_mode_t)mode
# ifdef OF_HAVE_BLOCKS
				block: (of_tcp_socket_async_accept_block_t)block
# endif
			     delegate: (id <OFTCPSocketDelegate>)delegate







>











>







943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
# endif
	queueItem->_string = [string copy];
	queueItem->_encoding = encoding;

	QUEUE_ITEM
}

# if !defined(OF_WII) && !defined(OF_NINTENDO_3DS)
+ (void)of_addAsyncConnectForTCPSocket: (OFTCPSocket *)stream
				  mode: (of_run_loop_mode_t)mode
			      delegate: (id <OFTCPSocketDelegate_Private>)
					    delegate
{
	NEW_WRITE(OFRunLoop_ConnectQueueItem, stream, mode)

	queueItem->_delegate = [delegate retain];

	QUEUE_ITEM
}
# endif

+ (void)of_addAsyncAcceptForTCPSocket: (OFTCPSocket *)stream
				 mode: (of_run_loop_mode_t)mode
# ifdef OF_HAVE_BLOCKS
				block: (of_tcp_socket_async_accept_block_t)block
# endif
			     delegate: (id <OFTCPSocketDelegate>)delegate

Modified src/OFTCPSocket+Private.h from [cb31d2ee88] to [b58e9bf256].

16
17
18
19
20
21
22

23

24
25
26
27
28
29
30
31
32
 */

#import "OFTCPSocket.h"

OF_ASSUME_NONNULL_BEGIN

@interface OFTCPSocket ()

@property (readonly, nonatomic) int of_socketError;


- (bool)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

OF_ASSUME_NONNULL_END







>

>









16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 */

#import "OFTCPSocket.h"

OF_ASSUME_NONNULL_BEGIN

@interface OFTCPSocket ()
#ifndef OF_WII
@property (readonly, nonatomic) int of_socketError;
#endif

- (bool)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

OF_ASSUME_NONNULL_END

Modified src/OFTCPSocket.m from [94bf69c96d] to [909cd558d8].

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
287
288
289
290
291
292

293

294




295
296
297
298
299
300
301
			return;
		}

		[self tryNextAddressWithRunLoopMode: runLoopMode];
		return;
	}














	[_socket setBlocking: false];


	if (![_socket of_connectSocketToAddress: &address
					  errNo: &errNo]) {

		if (errNo == EINPROGRESS) {
			[OFRunLoop of_addAsyncConnectForTCPSocket: _socket
							     mode: runLoopMode
							 delegate: self];
			return;
		} else {

			[_socket of_closeSocket];

			if (_socketAddressesIndex >= [_socketAddresses count]) {
				_exception = [[OFConnectionFailedException
				    alloc] initWithHost: _host
						   port: _port
						 socket: _socket
						  errNo: errNo];
				[self didConnect];
				return;
			}

			[self tryNextAddressWithRunLoopMode: runLoopMode];
			return;

		}

	}





	[self didConnect];
}

-	(void)resolver: (OFDNSResolver *)resolver
  didResolveDomainName: (OFString *)domainName
       socketAddresses: (OFData *)socketAddresses







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

>



>






>














>

>

>
>
>
>







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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
			return;
		}

		[self tryNextAddressWithRunLoopMode: runLoopMode];
		return;
	}

#if defined(OF_NINTENDO_3DS) || defined(OF_WII)
	/*
	 * On Wii and 3DS, connect() fails if non-blocking is enabled.
	 *
	 * Additionally, on Wii, there is no getsockopt(), so it would not be
	 * possible to get the error (or success) after connecting anyway.
	 *
	 * So for now, connecting is blocking on Wii and 3DS.
	 *
	 * FIXME: Use a different thread as a work around.
	 */
	[_socket setBlocking: true];
#else
	[_socket setBlocking: false];
#endif

	if (![_socket of_connectSocketToAddress: &address
					  errNo: &errNo]) {
#if !defined(OF_NINTENDO_3DS) && !defined(OF_WII)
		if (errNo == EINPROGRESS) {
			[OFRunLoop of_addAsyncConnectForTCPSocket: _socket
							     mode: runLoopMode
							 delegate: self];
			return;
		} else {
#endif
			[_socket of_closeSocket];

			if (_socketAddressesIndex >= [_socketAddresses count]) {
				_exception = [[OFConnectionFailedException
				    alloc] initWithHost: _host
						   port: _port
						 socket: _socket
						  errNo: errNo];
				[self didConnect];
				return;
			}

			[self tryNextAddressWithRunLoopMode: runLoopMode];
			return;
#if !defined(OF_NINTENDO_3DS) && !defined(OF_WII)
		}
#endif
	}

#if defined(OF_NINTENDO_3DS) || defined(OF_WII)
	[_socket setBlocking: false];
#endif

	[self didConnect];
}

-	(void)resolver: (OFDNSResolver *)resolver
  didResolveDomainName: (OFString *)domainName
       socketAddresses: (OFData *)socketAddresses
659
660
661
662
663
664
665

666
667
668
669
670
671
672
673
674
675
676

677
678
679
680
681
682
683

- (void)of_closeSocket
{
	closesocket(_socket);
	_socket = INVALID_SOCKET;
}


- (int)of_socketError
{
	int errNo;
	socklen_t len = sizeof(errNo);

	if (getsockopt(_socket, SOL_SOCKET, SO_ERROR, (char *)&errNo,
	    &len) != 0)
		return of_socket_errno();

	return errNo;
}


- (void)connectToHost: (OFString *)host
		 port: (uint16_t)port
{
	void *pool = objc_autoreleasePoolPush();
	id <OFTCPSocketDelegate> delegate = [_delegate retain];
	OFTCPSocket_ConnectDelegate *connectDelegate =







>











>







681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707

- (void)of_closeSocket
{
	closesocket(_socket);
	_socket = INVALID_SOCKET;
}

#ifndef OF_WII
- (int)of_socketError
{
	int errNo;
	socklen_t len = sizeof(errNo);

	if (getsockopt(_socket, SOL_SOCKET, SO_ERROR, (char *)&errNo,
	    &len) != 0)
		return of_socket_errno();

	return errNo;
}
#endif

- (void)connectToHost: (OFString *)host
		 port: (uint16_t)port
{
	void *pool = objc_autoreleasePoolPush();
	id <OFTCPSocketDelegate> delegate = [_delegate retain];
	OFTCPSocket_ConnectDelegate *connectDelegate =

Modified src/OFUDPSocket.m from [20728b2787] to [08c14deedf].

150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

#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 defined(OF_WII) || defined(OF_NINTENDO_3DS)
	if (port != 0) {
#endif
		if (bind(_socket, &address->sockaddr.sockaddr,
		    address->length) != 0) {
			int errNo = of_socket_errno();

			closesocket(_socket);
			_socket = INVALID_SOCKET;







|







150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

#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 defined(OF_WII) || defined(OF_NINTENDO_3DS)
	if (of_socket_address_get_port(address) != 0) {
#endif
		if (bind(_socket, &address->sockaddr.sockaddr,
		    address->length) != 0) {
			int errNo = of_socket_errno();

			closesocket(_socket);
			_socket = INVALID_SOCKET;

Modified src/socket.h from [975b336f99] to [e3ee93c786].

128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
} of_socket_address_t;

#ifdef __cplusplus
extern "C" {
#endif
extern bool of_socket_init(void);
extern int of_socket_errno(void);
# ifndef OF_WII
extern int of_getsockname(of_socket_t sock, struct sockaddr *restrict addr,
    socklen_t *restrict addrLen);
# endif

/*!
 * @brief Parses the specified IP and port into an of_socket_address_t.
 *







|







128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
} of_socket_address_t;

#ifdef __cplusplus
extern "C" {
#endif
extern bool of_socket_init(void);
extern int of_socket_errno(void);
# if !defined(OF_WII) && !defined(OF_NINTENDO_3DS)
extern int of_getsockname(of_socket_t sock, struct sockaddr *restrict addr,
    socklen_t *restrict addrLen);
# endif

/*!
 * @brief Parses the specified IP and port into an of_socket_address_t.
 *

Modified src/socket.m from [4c91a4fb68] to [e7074a55dd].

237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
	of_socket_address_t ret;
	struct sockaddr_in *addrIn = &ret.sockaddr.in;
	OFArray OF_GENERIC(OFString *) *components;
	uint32_t addr;

	memset(&ret, '\0', sizeof(ret));
	ret.family = OF_SOCKET_ADDRESS_FAMILY_IPV4;
#ifndef OF_WII
	ret.length = sizeof(ret.sockaddr.in);
#else
	ret.length = 8;
#endif

	addrIn->sin_family = AF_INET;
	addrIn->sin_port = OF_BSWAP16_IF_LE(port);
#ifdef OF_WII
	addrIn->sin_len = ret.length;
#endif







|
|

|







237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
	of_socket_address_t ret;
	struct sockaddr_in *addrIn = &ret.sockaddr.in;
	OFArray OF_GENERIC(OFString *) *components;
	uint32_t addr;

	memset(&ret, '\0', sizeof(ret));
	ret.family = OF_SOCKET_ADDRESS_FAMILY_IPV4;
#if defined(OF_WII) || defined(OF_NINTENDO_3DS)
	ret.length = 8;
#else
	ret.length = sizeof(ret.sockaddr.in);
#endif

	addrIn->sin_family = AF_INET;
	addrIn->sin_port = OF_BSWAP16_IF_LE(port);
#ifdef OF_WII
	addrIn->sin_len = ret.length;
#endif
401
402
403
404
405
406
407
408
409
410
411
412
413

414
415
416
417
418
419
420
	const struct sockaddr_in6 *addrIn6_1, *addrIn6_2;

	if (address1->family != address2->family)
		return false;

	switch (address1->family) {
	case OF_SOCKET_ADDRESS_FAMILY_IPV4:
#ifndef OF_WII
		if (address1->length < (socklen_t)sizeof(struct sockaddr_in) ||
		    address2->length < (socklen_t)sizeof(struct sockaddr_in))
			@throw [OFInvalidArgumentException exception];
#else
		if (address1->length < 8 || address2->length < 8)

			@throw [OFInvalidArgumentException exception];
#endif

		addrIn1 = &address1->sockaddr.in;
		addrIn2 = &address2->sockaddr.in;

		if (addrIn1->sin_port != addrIn2->sin_port)







|
|
<


|
>







401
402
403
404
405
406
407
408
409

410
411
412
413
414
415
416
417
418
419
420
	const struct sockaddr_in6 *addrIn6_1, *addrIn6_2;

	if (address1->family != address2->family)
		return false;

	switch (address1->family) {
	case OF_SOCKET_ADDRESS_FAMILY_IPV4:
#if defined(OF_WII) || defined(OF_NINTENDO_3DS)
		if (address1->length < 8 || address2->length < 8)

			@throw [OFInvalidArgumentException exception];
#else
		if (address1->length < (socklen_t)sizeof(struct sockaddr_in) ||
		    address2->length < (socklen_t)sizeof(struct sockaddr_in))
			@throw [OFInvalidArgumentException exception];
#endif

		addrIn1 = &address1->sockaddr.in;
		addrIn2 = &address2->sockaddr.in;

		if (addrIn1->sin_port != addrIn2->sin_port)
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
	uint32_t hash;

	OF_HASH_INIT(hash);
	OF_HASH_ADD(hash, address->family);

	switch (address->family) {
	case OF_SOCKET_ADDRESS_FAMILY_IPV4:
#ifndef OF_WII
		if (address->length < (socklen_t)sizeof(struct sockaddr_in))
			@throw [OFInvalidArgumentException exception];
#else
		if (address->length < 8)
			@throw [OFInvalidArgumentException exception];
#endif

		OF_HASH_ADD(hash, address->sockaddr.in.sin_port >> 8);
		OF_HASH_ADD(hash, address->sockaddr.in.sin_port);
		OF_HASH_ADD(hash, address->sockaddr.in.sin_addr.s_addr >> 24);
		OF_HASH_ADD(hash, address->sockaddr.in.sin_addr.s_addr >> 16);







|
|


|







452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
	uint32_t hash;

	OF_HASH_INIT(hash);
	OF_HASH_ADD(hash, address->family);

	switch (address->family) {
	case OF_SOCKET_ADDRESS_FAMILY_IPV4:
#if defined(OF_WII) || defined(OF_NINTENDO_3DS)
		if (address->length < 8)
			@throw [OFInvalidArgumentException exception];
#else
		if (address->length < (socklen_t)sizeof(struct sockaddr_in))
			@throw [OFInvalidArgumentException exception];
#endif

		OF_HASH_ADD(hash, address->sockaddr.in.sin_port >> 8);
		OF_HASH_ADD(hash, address->sockaddr.in.sin_port);
		OF_HASH_ADD(hash, address->sockaddr.in.sin_addr.s_addr >> 24);
		OF_HASH_ADD(hash, address->sockaddr.in.sin_addr.s_addr >> 16);

Modified src/socket_helpers.h from [e20459ca44] to [cefe3ad662].

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#ifdef OF_WII
# define accept(sock, addr, addrlen) net_accept(sock, addr, addrlen)
# define bind(sock, addr, addrlen) net_bind(sock, addr, addrlen)
# define closesocket(sock) net_close(sock)
# define connect(sock, addr, addrlen) \
    net_connect(sock, (struct sockaddr *)addr, addrlen)
# define fcntl(fd, cmd, flags) net_fcntl(fd, cmd, flags)
# define getsockopt(sock, level, name, value, len) \
    net_getsockopt(sock, level, name, value, len)
# define h_errno 0
# define hstrerror(err) "unknown (no hstrerror)"
# define listen(sock, backlog) net_listen(sock, backlog)
# define poll(fds, nfds, timeout) net_poll(fds, nfds, timeout)
# define recv(sock, buf, len, flags) net_recv(sock, buf, len, flags)
# define recvfrom(sock, buf, len, flags, addr, addrlen) \
    net_recvfrom(sock, buf, len, flags, addr, addrlen)







<
<







64
65
66
67
68
69
70


71
72
73
74
75
76
77
#ifdef OF_WII
# define accept(sock, addr, addrlen) net_accept(sock, addr, addrlen)
# define bind(sock, addr, addrlen) net_bind(sock, addr, addrlen)
# define closesocket(sock) net_close(sock)
# define connect(sock, addr, addrlen) \
    net_connect(sock, (struct sockaddr *)addr, addrlen)
# define fcntl(fd, cmd, flags) net_fcntl(fd, cmd, flags)


# define h_errno 0
# define hstrerror(err) "unknown (no hstrerror)"
# define listen(sock, backlog) net_listen(sock, backlog)
# define poll(fds, nfds, timeout) net_poll(fds, nfds, timeout)
# define recv(sock, buf, len, flags) net_recv(sock, buf, len, flags)
# define recvfrom(sock, buf, len, flags, addr, addrlen) \
    net_recvfrom(sock, buf, len, flags, addr, addrlen)