ObjFW  Diff

Differences From Artifact [b00741c4c9]:

To Artifact [3305aefb9e]:

  • File src/OFTCPSocket.m — part of check-in [3d16a30f41] at 2013-06-22 12:12:36 on branch trunk — Rework exceptions.

    This mostly removes the argument for the class in which the exception
    occurred. As backtraces were recently added for all platforms, the
    passed class does not give any extra information on where the exception
    occurred anymore.

    This also removes a few other arguments which were not too helpful. In
    the past, the idea was to pass as many arguments as possible so that it
    is easier to find the origin of the exception. However, as backtraces
    are a much better way to find the origin, those are not useful anymore
    and just make the exception more cumbersome to use. The rule is now to
    only pass arguments that might help in recovering from the exception or
    provide information that is otherwise not easily accessible. (user: js, size: 17438) [annotate] [blame] [check-ins using]


330
331
332
333
334
335
336
337

338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361


362
363
364
365
366
367
368
369
330
331
332
333
334
335
336

337


338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357


358
359

360
361
362
363
364
365
366







-
+
-
-




















-
-
+
+
-







- (void)connectToHost: (OFString*)host
		 port: (uint16_t)port
{
	OFString *destinationHost = host;
	uint16_t destinationPort = port;

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

	if (_SOCKS5Host != nil) {
		/* Connect to the SOCKS5 proxy instead */
		host = _SOCKS5Host;
		port = _SOCKS5Port;
	}

#ifdef HAVE_THREADSAFE_GETADDRINFO
	struct addrinfo hints, *res, *res0;
	char portCString[7];

	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_flags = AI_NUMERICSERV;
	snprintf(portCString, 7, "%" PRIu16, port);

	if (getaddrinfo([host cStringWithEncoding: OF_STRING_ENCODING_NATIVE],
	    portCString, &hints, &res0))
		@throw [OFAddressTranslationFailedException
		    exceptionWithClass: [self class]
				socket: self
		    exceptionWithHost: host
			       socket: self];
				  host: host];

	for (res = res0; res != NULL; res = res->ai_next) {
		if ((_socket = socket(res->ai_family, res->ai_socktype,
		    res->ai_protocol)) == INVALID_SOCKET)
			continue;

		if (connect(_socket, res->ai_addr, res->ai_addrlen) == -1) {
390
391
392
393
394
395
396
397
398



399
400
401
402
403
404
405
406
407
408
409



410
411
412
413
414
415
416
417
418
387
388
389
390
391
392
393


394
395
396


397
398
399
400
401
402
403


404
405
406


407
408
409
410
411
412
413







-
-
+
+
+
-
-







-
-
+
+
+
-
-







	addr.sin_port = OF_BSWAP16_IF_LE(port);

	if ((addr.sin_addr.s_addr = inet_addr([host cStringWithEncoding:
	    OF_STRING_ENCODING_NATIVE])) != (in_addr_t)(-1)) {
		if ((_socket = socket(AF_INET, SOCK_STREAM,
		    0)) == INVALID_SOCKET) {
			@throw [OFConnectionFailedException
			    exceptionWithClass: [self class]
					socket: self
			    exceptionWithHost: host
					 port: port
				       socket: self];
					  host: host
					  port: port];
		}

		if (connect(_socket, (struct sockaddr*)&addr,
		    sizeof(addr)) == -1) {
			close(_socket);
			_socket = INVALID_SOCKET;
			@throw [OFConnectionFailedException
			    exceptionWithClass: [self class]
					socket: self
			    exceptionWithHost: host
					 port: port
				       socket: self];
					  host: host
					  port: port];
		}

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

		return;
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
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







-
-
+
+
-








-
-
-
+
+
+
-
-







	if ((he = gethostbyname([host cStringWithEncoding:
	    OF_STRING_ENCODING_NATIVE])) == NULL) {
# ifdef OF_HAVE_THREADS
		[addrlist release];
		[mutex unlock];
# endif
		@throw [OFAddressTranslationFailedException
		    exceptionWithClass: [self class]
				socket: self
		    exceptionWithHost: host
			       socket: self];
				  host: host];
	}

	if (he->h_addrtype != AF_INET ||
	    (_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
# ifdef OF_HAVE_THREADS
		[addrlist release];
		[mutex unlock];
# endif
		@throw [OFConnectionFailedException
		    exceptionWithClass: [self class]
				socket: self
		@throw [OFConnectionFailedException exceptionWithHost: host
								 port: port
							       socket: self];
				  host: host
				  port: port];
	}

# ifdef OF_HAVE_THREADS
	@try {
		for (ip = he->h_addr_list; *ip != NULL; ip++)
			[addrlist addItem: ip];

483
484
485
486
487
488
489
490
491
492



493
494
495
496
497
498
499
500
501
475
476
477
478
479
480
481



482
483
484


485
486
487
488
489
490
491







-
-
-
+
+
+
-
-







	if (!connected) {
		close(_socket);
		_socket = INVALID_SOCKET;
	}
#endif

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

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

#ifdef OF_HAVE_THREADS
548
549
550
551
552
553
554
555

556
557
558
559
560

561
562

563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
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
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627


628
629
630
631
632
633
634


635
636
637
638
639
640
641
642
643
644
645
646
647
648
649



650
651
652
653
654
655

656
657
658
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
684
685
686
687
688
689
690
691
692
693
694



695
696
697
698
699
700
701
702

703
704
705
706

707
708

709
710
711
712
713
714
715
538
539
540
541
542
543
544

545


546
547

548


549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568


569
570

571
572
573


574
575
576


577
578
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
611
612
613


614
615

616
617
618
619
620
621
622
623
624
625
626
627


628
629
630


631
632
633

634


635
636
637
638


639
640
641


642
643
644
645
646
647
648
649
650
651
652


653
654
655


656
657
658
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
684
685
686
687







-
+
-
-


-
+
-
-
+



















-
-
+
+
-



-
-
+
+
+
-
-



-
+
-
-





-
-
+
+
+
-
-



















-
-
+
+
-




-
-
+
+
-












-
-
+
+
+
-
-



-
+
-
-




-
-
+
+
+
-
-











-
-
+
+
+
-
-












-
-
+
+
+
-
-





-
+
-


-
+
-
-
+







#endif
	} addr;
#ifndef __wii__
	socklen_t addrLen;
#endif

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

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

#ifdef __wii__
	if (port == 0)
		port = freePort--;
#endif

#ifdef HAVE_THREADSAFE_GETADDRINFO
	struct addrinfo hints, *res;
	char portCString[7];

	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_flags = AI_NUMERICSERV | AI_PASSIVE;
	snprintf(portCString, 7, "%" PRIu16, port);

	if (getaddrinfo([host cStringWithEncoding: OF_STRING_ENCODING_NATIVE],
	    portCString, &hints, &res))
		@throw [OFAddressTranslationFailedException
		    exceptionWithClass: [self class]
				socket: self
		    exceptionWithHost: host
			       socket: self];
				  host: host];

	if ((_socket = socket(res->ai_family, SOCK_STREAM,
	    0)) == INVALID_SOCKET)
		@throw [OFBindFailedException exceptionWithClass: [self class]
							  socket: self
		@throw [OFBindFailedException exceptionWithHost: host
							   port: port
							 socket: self];
							    host: host
							    port: port];

	if (setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&one,
	    sizeof(one)))
		@throw [OFSetOptionFailedException
		@throw [OFSetOptionFailedException exceptionWithStream: self];
		    exceptionWithClass: [self class]
				stream: self];

	if (bind(_socket, res->ai_addr, res->ai_addrlen) == -1) {
		freeaddrinfo(res);
		close(_socket);
		_socket = INVALID_SOCKET;
		@throw [OFBindFailedException exceptionWithClass: [self class]
							  socket: self
		@throw [OFBindFailedException exceptionWithHost: host
							   port: port
							 socket: self];
							    host: host
							    port: port];
	}

	freeaddrinfo(res);
#else
	memset(&addr, 0, sizeof(addr));
	addr.in.sin_family = AF_INET;
	addr.in.sin_port = OF_BSWAP16_IF_LE(port);

	if ((addr.in.sin_addr.s_addr = inet_addr([host cStringWithEncoding:
	    OF_STRING_ENCODING_NATIVE])) == (in_addr_t)(-1)) {
# ifdef OF_HAVE_THREADS
		[mutex lock];
		@try {
# endif
			struct hostent *he;

			if ((he = gethostbyname([host cStringWithEncoding:
			    OF_STRING_ENCODING_NATIVE])) == NULL)
				@throw [OFAddressTranslationFailedException
				    exceptionWithClass: [self class]
						socket: self
				    exceptionWithHost: host
					       socket: self];
						  host: host];

			if (he->h_addrtype != AF_INET ||
			    he->h_addr_list[0] == NULL) {
				@throw [OFAddressTranslationFailedException
				    exceptionWithClass: [self class]
						socket: self
				    exceptionWithHost: host
					       socket: self];
						  host: host];
			}

			memcpy(&addr.in.sin_addr.s_addr, he->h_addr_list[0],
			    he->h_length);
# ifdef OF_HAVE_THREADS
		} @finally {
			[mutex unlock];
		}
# endif
	}

	if ((_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
		@throw [OFBindFailedException exceptionWithClass: [self class]
							  socket: self
		@throw [OFBindFailedException exceptionWithHost: host
							   port: port
							 socket: self];
							    host: host
							    port: port];

	if (setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&one,
	    sizeof(one)))
		@throw [OFSetOptionFailedException
		@throw [OFSetOptionFailedException exceptionWithStream: self];
		    exceptionWithClass: [self class]
				stream: self];

	if (bind(_socket, (struct sockaddr*)&addr.in, sizeof(addr.in)) == -1) {
		close(_socket);
		_socket = INVALID_SOCKET;
		@throw [OFBindFailedException exceptionWithClass: [self class]
							  socket: self
		@throw [OFBindFailedException exceptionWithHost: host
							   port: port
							 socket: self];
							    host: host
							    port: port];
	}
#endif

	if (port > 0)
		return port;

#ifndef __wii__
	addrLen = sizeof(addr.storage);
	if (getsockname(_socket, (struct sockaddr*)&addr, &addrLen)) {
		close(_socket);
		_socket = INVALID_SOCKET;
		@throw [OFBindFailedException exceptionWithClass: [self class]
							  socket: self
		@throw [OFBindFailedException exceptionWithHost: host
							   port: port
							 socket: self];
							    host: host
							    port: port];
	}

	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 exceptionWithClass: [self class]
						  socket: self
	@throw [OFBindFailedException exceptionWithHost: host
						   port: port
						 socket: self];
						    host: host
						    port: port];
}

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

	if (listen(_socket, backLog) == -1)
		@throw [OFListenFailedException exceptionWithClass: [self class]
		@throw [OFListenFailedException exceptionWithSocket: self
							    socket: self
							   backLog: backLog];
							    backLog: backLog];

	_listening = true;
}

- (void)listen
{
	[self listenWithBackLog: SOMAXCONN];
724
725
726
727
728
729
730
731

732
733
734
735
736
737
738
739
696
697
698
699
700
701
702

703

704
705
706
707
708
709
710







-
+
-








	client = [[[[self class] alloc] init] autorelease];
	addrLen = sizeof(*addr);
	addr = [client allocMemoryWithSize: addrLen];

	if ((socket = accept(_socket, (struct sockaddr*)addr,
	    &addrLen)) == INVALID_SOCKET)
		@throw [OFAcceptFailedException exceptionWithClass: [self class]
		@throw [OFAcceptFailedException exceptionWithSocket: self];
							    socket: self];

	client->_socket = socket;
	client->_sockAddr = addr;
	client->_sockAddrLen = addrLen;

	return client;
}
755
756
757
758
759
760
761
762

763
764
765
766
767
768
769
770
771
772
773

774
775
776
777
778
779
780
781
782
783

784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800

801
802
803
804
805
806
807
726
727
728
729
730
731
732

733


734
735
736
737
738
739
740


741

742
743
744
745
746
747
748
749

750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766

767
768
769
770
771
772
773
774







-
+
-
-







-
-
+
-








-
+
















-
+







#endif

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

	if (setsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, (char*)&v, sizeof(v)))
		@throw [OFSetOptionFailedException
		@throw [OFSetOptionFailedException exceptionWithStream: self];
		    exceptionWithClass: [self class]
				stream: self];
}

- (OFString*)remoteAddress
{
	char *host;

	if (_sockAddr == NULL || _sockAddrLen == 0)
		@throw [OFInvalidArgumentException
		    exceptionWithClass: [self class]
		@throw [OFNotConnectedException exceptionWithSocket: self];
			      selector: _cmd];

#ifdef HAVE_THREADSAFE_GETADDRINFO
	host = [self allocMemoryWithSize: NI_MAXHOST];

	@try {
		if (getnameinfo((struct sockaddr*)_sockAddr, _sockAddrLen, host,
		    NI_MAXHOST, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV))
			@throw [OFAddressTranslationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithSocket: self];

		return [OFString stringWithCString: host
					  encoding: OF_STRING_ENCODING_NATIVE];
	} @finally {
		[self freeMemory: host];
	}
#else
# ifdef OF_HAVE_THREADS
	[mutex lock];

	@try {
# endif
		host = inet_ntoa(((struct sockaddr_in*)_sockAddr)->sin_addr);

		if (host == NULL)
			@throw [OFAddressTranslationFailedException
			    exceptionWithClass: [self class]];
			    exceptionWithSocket: self];

		return [OFString stringWithCString: host
					  encoding: OF_STRING_ENCODING_NATIVE];
# ifdef OF_HAVE_THREADS
	} @finally {
		[mutex unlock];
	}