ObjFW  Diff

Differences From Artifact [a985ec70c8]:

To Artifact [f120fb3aeb]:

  • File src/OFTCPSocket.m — part of check-in [62e2de30b9] at 2015-02-16 08:39:17 on branch trunk — Explicitly pass errno to exceptions

    The old behaviour where the exception would access errno directly on
    creation of the exception was very fragile. The two main problems with
    it were that sometimes it would pick up an errno even though none had
    been set and in other cases that when the exception was created errno
    had already been overridden.

    This also greatly increases errno handling on Win32, especially in
    conjunction with sockets. It can still be improved further, though. (user: js, size: 12995) [annotate] [blame] [check-ins using]


16
17
18
19
20
21
22


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


29
30
31
32
33
34
35







+
+




-
-








#define OF_TCP_SOCKET_M

#define __NO_EXT_QNX

#include "config.h"

#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <assert.h>

#import "OFTCPSocket.h"
#import "OFTCPSocket+SOCKS5.h"
#import "OFString.h"
#import "OFThread.h"
#import "OFTimer.h"
#import "OFRunLoop.h"
#import "OFRunLoop+Private.h"
265
266
267
268
269
270
271

272
273
274
275
276
277
278
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279







+








- (void)connectToHost: (OFString*)host
		 port: (uint16_t)port
{
	OFString *destinationHost = host;
	uint16_t destinationPort = port;
	of_resolver_result_t **results, **iter;
	int errNo = 0;

	if (_socket != INVALID_SOCKET)
		@throw [OFAlreadyConnectedException exceptionWithSocket: self];

	_listening = false;

	/* Make sure to clear the read buffer in case the socket is reused */
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
324
325
326
327
328
329
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
324
325
326
327
328

329
330
331
332
333
334
335
336
337







-
+
+
+

+








+
+


+











-
+
+







		of_resolver_result_t *result = *iter;
#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
		int flags;
#endif

		if ((_socket = socket(result->family,
		    result->type | SOCK_CLOEXEC,
		    result->protocol)) == INVALID_SOCKET)
		    result->protocol)) == INVALID_SOCKET) {
			errNo = of_socket_errno();

			continue;
		}

#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, result->address,
		    result->addressLength) == -1) {
			errNo = of_socket_errno();

			close(_socket);
			_socket = INVALID_SOCKET;

			continue;
		}

		break;
	}

	of_resolver_free(results);

	if (_socket == INVALID_SOCKET)
		@throw [OFConnectionFailedException exceptionWithHost: host
								 port: port
							       socket: self];
							       socket: self
								errNo: errNo];

	if (_SOCKS5Host != nil)
		[self OF_SOCKS5ConnectToHost: destinationHost
					port: destinationPort];
}

#ifdef OF_HAVE_THREADS
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
426
427
428
429
430
431
432
433
434
435


436
437

438
439
440


441
442
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
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491



492
493
494
495



496
497
498
499



500
501
502
503
504
505
506
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
436
437
438
439
440
441
442
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
472
473
474
475
476
477
478
479
480
481
482
483
484
485


486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509

510
511
512
513
514
515

516
517
518
519
520
521

522
523
524
525
526
527
528
529
530
531







-
-
-
+
+
+
+
+






-
-
+
+
-
-



+
+


+


-
+
+











+
+


+


-
+
+














-
+
+













-
-
+
+
+
+




















-
+
+
+



-
+
+
+



-
+
+
+







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

		if ((_socket = socket(results[0]->family,
		    results[0]->type | SOCK_CLOEXEC,
		    results[0]->protocol)) == INVALID_SOCKET)
			@throw [OFBindFailedException exceptionWithHost: host
								   port: port
								 socket: self];
			@throw [OFBindFailedException
			    exceptionWithHost: host
					 port: port
				       socket: self
					errNo: of_socket_errno()];

#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 (setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR,
		    (const char*)&one, (socklen_t)sizeof(one)))
		setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR,
		    (const char*)&one, (socklen_t)sizeof(one));
			@throw [OFSetOptionFailedException
			    exceptionWithStream: self];

		if (bind(_socket, results[0]->address,
		    results[0]->addressLength) == -1) {
			int errNo = of_socket_errno();

			close(_socket);
			_socket = INVALID_SOCKET;

			@throw [OFBindFailedException exceptionWithHost: host
								   port: port
								 socket: self];
								 socket: self
								  errNo: errNo];
		}
	} @finally {
		of_resolver_free(results);
	}

	if (port > 0)
		return port;

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

		close(_socket);
		_socket = INVALID_SOCKET;

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

	if (addr.storage.ss_family == AF_INET)
		return OF_BSWAP16_IF_LE(addr.in.sin_port);
# ifdef AF_INET6
	if (addr.storage.ss_family == AF_INET6)
		return OF_BSWAP16_IF_LE(addr.in6.sin6_port);
# endif
#endif

	close(_socket);
	_socket = INVALID_SOCKET;
	@throw [OFBindFailedException exceptionWithHost: host
						   port: port
						 socket: self];
						 socket: self
						  errNo: EAFNOSUPPORT];
}

- (void)listen
{
	[self listenWithBackLog: SOMAXCONN];
}

- (void)listenWithBackLog: (int)backLog
{
	if (_socket == INVALID_SOCKET)
		@throw [OFNotConnectedException exceptionWithSocket: self];

	if (listen(_socket, backLog) == -1)
		@throw [OFListenFailedException exceptionWithSocket: self
							    backLog: backLog];
		@throw [OFListenFailedException
		    exceptionWithSocket: self
				backLog: backLog
				  errNo: of_socket_errno()];

	_listening = true;
}

- (instancetype)accept
{
	OFTCPSocket *client = [[[[self class] alloc] init] autorelease];
#if (!defined(HAVE_PACCEPT) && !defined(HAVE_ACCEPT4)) || !defined(SOCK_CLOEXEC)
# if defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
	int flags;
# endif
#endif

	client->_address = [client
	    allocMemoryWithSize: sizeof(struct sockaddr_storage)];
	client->_addressLength = (socklen_t)sizeof(struct sockaddr_storage);

#if defined(HAVE_PACCEPT) && defined(SOCK_CLOEXEC)
	if ((client->_socket = paccept(_socket, client->_address,
	   &client->_addressLength, NULL, SOCK_CLOEXEC)) == INVALID_SOCKET)
		@throw [OFAcceptFailedException exceptionWithSocket: self];
		@throw [OFAcceptFailedException
		    exceptionWithSocket: self
				  errNo: of_socket_errno()];
#elif defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
	if ((client->_socket = accept4(_socket, client->_address,
	   &client->_addressLength, SOCK_CLOEXEC)) == INVALID_SOCKET)
		@throw [OFAcceptFailedException exceptionWithSocket: self];
		@throw [OFAcceptFailedException
		    exceptionWithSocket: self
				  errNo: of_socket_errno()];
#else
	if ((client->_socket = accept(_socket, client->_address,
	   &client->_addressLength)) == INVALID_SOCKET)
		@throw [OFAcceptFailedException exceptionWithSocket: self];
		@throw [OFAcceptFailedException
		    exceptionWithSocket: self
				  errNo: of_socket_errno()];

# if defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
	if ((flags = fcntl(client->_socket, F_GETFD, 0)) != -1)
		fcntl(client->_socket, F_SETFD, flags | FD_CLOEXEC);
# endif
#endif

537
538
539
540
541
542
543
544



545
546
547
548
549
550
551
562
563
564
565
566
567
568

569
570
571
572
573
574
575
576
577
578







-
+
+
+








- (void)setKeepAlivesEnabled: (bool)enable
{
	int v = enable;

	if (setsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE,
	    (char*)&v, (socklen_t)sizeof(v)))
		@throw [OFSetOptionFailedException exceptionWithStream: self];
		@throw [OFSetOptionFailedException
		    exceptionWithStream: self
				  errNo: of_socket_errno()];
}

- (OFString*)remoteAddress
{
	OFString *ret;

	if (_socket == INVALID_SOCKET)