ObjFW  Diff

Differences From Artifact [9048cbfc52]:

To Artifact [b89d5a3a8f]:


1
2

3
4
5
6
7
8
9
1

2
3
4
5
6
7
8
9

-
+







/*
 * Copyright (c) 2008-2022 Jonathan Schleifer <js@nil.im>
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
419
420
421
422
423
424
425
426

427
428
429
430
431
432
433
419
420
421
422
423
424
425

426
427
428
429
430
431
432
433







-
+







{
	OFMutableDictionary *ret = [OFMutableDictionary dictionary];
	OFEnumerator OF_GENERIC(OFMutableArray *) *objectEnumerator;
	OFMutableArray *array;

	for (uint_fast16_t j = 0; j < count; j++) {
		OFString *name = parseName(buffer, length, i,
		    maxAllowedPointers);
		    maxAllowedPointers).lowercaseString;
		OFDNSClass DNSClass;
		OFDNSRecordType recordType;
		uint32_t TTL;
		uint16_t dataLength;
		OFDNSResourceRecord *record;

		if (*i + 10 > length)
462
463
464
465
466
467
468














469
470
471
472
473
474
475
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+







	while ((array = [objectEnumerator nextObject]) != nil)
		[array makeImmutable];

	[ret makeImmutable];

	return ret;
}

static bool
containsExpiredRecord(OFDNSResponseRecords responseRecords, uint32_t age)
{
	OFEnumerator *enumerator = [responseRecords objectEnumerator];
	OFArray OF_GENERIC(OFDNSResourceRecord *) *records;

	while ((records = [enumerator nextObject]) != nil)
		for (OFDNSResourceRecord *record in records)
			if (record.TTL < age)
				return true;

	return false;
}

@implementation OFDNSResolverContext
- (instancetype)initWithQuery: (OFDNSQuery *)query
			   ID: (OFNumber *)ID
		     settings: (OFDNSResolverSettings *)settings
		     delegate: (id <OFDNSResolverQueryDelegate>)delegate
{
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







+







{
	self = [super init];

	@try {
		_settings = [[OFDNSResolverSettings alloc] init];
		_queries = [[OFMutableDictionary alloc] init];
		_TCPQueries = [[OFMutableDictionary alloc] init];
		_cache = [[OFMutableDictionary alloc] init];

		[_settings reload];
	} @catch (id e) {
		[self release];
		@throw e;
	}

597
598
599
600
601
602
603


604
605
606
607
608
609
610
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627







+
+







	[_IPv4Socket release];
#ifdef OF_HAVE_IPV6
	[_IPv6Socket cancelAsyncRequests];
	[_IPv6Socket release];
#endif
	[_queries release];
	[_TCPQueries release];
	[_cache release];
	[_lastNameServers release];

	[super dealloc];
}

- (OFDictionary *)staticHosts
{
	return _settings->_staticHosts;
674
675
676
677
678
679
680
681

682
683

684
685
686

687
688

689
690
691
692
693
694
695
691
692
693
694
695
696
697

698
699

700
701
702

703
704

705
706
707
708
709
710
711
712







-
+

-
+


-
+

-
+







- (void)setMinNumberOfDotsInAbsoluteName:
    (unsigned int)minNumberOfDotsInAbsoluteName
{
	_settings->_minNumberOfDotsInAbsoluteName =
	    minNumberOfDotsInAbsoluteName;
}

- (bool)usesTCP
- (bool)forcesTCP
{
	return _settings->_usesTCP;
	return _settings->_forcesTCP;
}

- (void)setUsesTCP: (bool)usesTCP
- (void)setForcesTCP: (bool)forcesTCP
{
	_settings->_usesTCP = usesTCP;
	_settings->_forcesTCP = forcesTCP;
}

- (OFTimeInterval)configReloadInterval
{
	return _settings->_configReloadInterval;
}

719
720
721
722
723
724
725
726

727
728
729
730
731
732
733
736
737
738
739
740
741
742

743
744
745
746
747
748
749
750







-
+







		     repeats: false];
	[[OFRunLoop currentRunLoop] addTimer: context->_cancelTimer
				     forMode: runLoopMode];

	nameServer = [context->_settings->_nameServers
	    objectAtIndex: context->_nameServersIndex];

	if (context->_settings->_usesTCP) {
	if (context->_settings->_forcesTCP) {
		OFEnsure(context->_TCPSocket == nil);

		context->_TCPSocket = [[OFTCPSocket alloc] init];
		[_TCPQueries setObject: context forKey: context->_TCPSocket];

		context->_TCPSocket.delegate = self;
		[context->_TCPSocket asyncConnectToHost: nameServer
784
785
786
787
788
789
790







































791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806






























807
808
809
810
811
812
813
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







	[sock asyncSendData: context->_queryData
		   receiver: &context->_usedNameServer
		runLoopMode: runLoopMode];
	[sock asyncReceiveIntoBuffer: _buffer
			      length: bufferLength
			 runLoopMode: runLoopMode];
}

- (void)of_cleanUpCache
{
	OFTimeInterval now = [[OFDate date] timeIntervalSince1970];
	OFMutableArray *removeList;

	if (_lastNameServers != _settings->_nameServers &&
	    ![_lastNameServers isEqual: _settings->_nameServers]) {
		OFArray *old = _lastNameServers;
		_lastNameServers = [_settings->_nameServers copy];
		[old release];

		[_cache removeAllObjects];

		return;
	}

	if (now - _lastCacheCleanup < 1)
		return;

	_lastCacheCleanup = now;
	removeList = [OFMutableArray arrayWithCapacity: _cache.count];

	for (OFDNSQuery *query in _cache) {
		OFPair OF_GENERIC(OFDate *, OFDNSResponse *) *entry =
		    [_cache objectForKey: query];
		uint32_t age =
		    (uint32_t)now - [entry.firstObject timeIntervalSince1970];
		OFDNSResponse *response = entry.secondObject;

		if (containsExpiredRecord(response.answerRecords, age) ||
		    containsExpiredRecord(response.authorityRecords, age) ||
		    containsExpiredRecord(response.additionalRecords, age))
			[removeList addObject: query];
	}

	for (OFDNSQuery *query in removeList)
		[_cache removeObjectForKey: query];
}

- (void)asyncPerformQuery: (OFDNSQuery *)query
		 delegate: (id <OFDNSResolverQueryDelegate>)delegate
{
	[self asyncPerformQuery: query
		    runLoopMode: OFDefaultRunLoopMode
		       delegate: delegate];
}

- (void)asyncPerformQuery: (OFDNSQuery *)query
	      runLoopMode: (OFRunLoopMode)runLoopMode
		 delegate: (id <OFDNSResolverQueryDelegate>)delegate
{
	void *pool = objc_autoreleasePoolPush();
	OFNumber *ID;
	OFDNSResolverContext *context;
	OFPair OF_GENERIC(OFDate *, OFDNSResponse *) *cacheEntry;

	[self of_cleanUpCache];

	if ((cacheEntry = [_cache objectForKey: query]) != nil) {
		uint32_t age =
		    (uint32_t)-[cacheEntry.firstObject timeIntervalSinceNow];
		OFDNSResponse *response = cacheEntry.secondObject;

		if (!containsExpiredRecord(response.answerRecords, age) &&
		    !containsExpiredRecord(response.authorityRecords, age) &&
		    !containsExpiredRecord(response.additionalRecords, age)) {
			OFTimer *timer = [OFTimer
			    timerWithTimeInterval: 0
					   target: delegate
					 selector: @selector(resolver:
						       didPerformQuery:response:
						       exception:)
					   object: self
					   object: query
					   object: response
					   object: nil
					  repeats: false];
			[[OFRunLoop currentRunLoop] addTimer: timer
						     forMode: runLoopMode];

			objc_autoreleasePoolPop(pool);
			return;
		}
	}

	/* Random, unused ID */
	do {
		ID = [OFNumber numberWithUnsignedShort: OFRandom16()];
	} while ([_queries objectForKey: ID] != nil);

	if (query.domainName.UTF8StringLength > 253)
944
945
946
947
948
949
950
951

952
953
954

955
956
957
958
959
960
961
1030
1031
1032
1033
1034
1035
1036

1037
1038
1039

1040
1041
1042
1043
1044
1045
1046
1047







-
+


-
+







		if ((buffer[2] & 0x78) != (queryDataBuffer[2] & 0x78))
			@throw [OFInvalidServerResponseException exception];

		/* TC */
		if (buffer[2] & 0x02) {
			OFRunLoopMode runLoopMode;

			if (context->_settings->_usesTCP)
			if (context->_settings->_forcesTCP)
				@throw [OFTruncatedDataException exception];

			context->_settings->_usesTCP = true;
			context->_settings->_forcesTCP = true;
			runLoopMode = [OFRunLoop currentRunLoop].currentMode;
			[self of_sendQueryForContext: context
					 runLoopMode: runLoopMode];
			return false;
		}

		/* RCODE */
1036
1037
1038
1039
1040
1041
1042









1043
1044
1045
1046
1047
1048
1049
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144







+
+
+
+
+
+
+
+
+







	} @catch (id e) {
		exception = e;
	}

	if (exception != nil)
		response = nil;

	[self of_cleanUpCache];

	if (response != nil)
		[_cache setObject: [OFPair pairWithFirstObject: [OFDate date]
						  secondObject: response]
			   forKey: context->_query];
	else
		[_cache removeObjectForKey: context->_query];

	[context->_delegate resolver: self
		     didPerformQuery: context->_query
			    response: response
			   exception: exception];

	return false;
}