ObjFW  Diff

Differences From Artifact [221615e7cb]:

To Artifact [b4efbde4c5]:


82
83
84
85
86
87
88

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
 *
 *  - Resolve with each search domain
 *  - Fallback to TCP
 */

@interface OFDNSResolverQuery: OFObject
{

	OFString *_host, *_domainName;
	of_dns_resource_record_class_t _recordClass;
	of_dns_resource_record_type_t _recordType;
	OFNumber *_ID;
	OFArray OF_GENERIC(OFString *) *_nameServers, *_searchDomains;
	size_t _nameServersIndex, _searchDomainsIndex;
	size_t _attempt;
	id _target;
	SEL _selector;
	id _context;
	OFData *_queryData;
	OFTimer *_cancelTimer;
}

@property (readonly, nonatomic) OFString *host, *domainName;
@property (readonly, nonatomic) of_dns_resource_record_class_t recordClass;
@property (readonly, nonatomic) of_dns_resource_record_type_t recordType;
@property (readonly, nonatomic) OFNumber *ID;
@property (readonly, nonatomic) OFArray OF_GENERIC(OFString *) *nameServers;
@property (readonly, nonatomic) OFArray OF_GENERIC(OFString *) *searchDomains;
@property (nonatomic) size_t nameServersIndex;
@property (nonatomic) size_t searchDomainsIndex;
@property (nonatomic) size_t attempt;
@property (readonly, nonatomic) id target;
@property (readonly, nonatomic) SEL selector;
@property (readonly, nonatomic) id context;
@property (readonly, nonatomic) OFData *queryData;
@property (retain, nonatomic) OFTimer *cancelTimer;

- (instancetype)initWithHost: (OFString *)host
		  domainName: (OFString *)domainName
		 recordClass: (of_dns_resource_record_class_t)recordClass
		  recordType: (of_dns_resource_record_type_t)recordType
			  ID: (OFNumber *)ID
		 nameServers: (OFArray OF_GENERIC(OFString *) *)nameServers
	       searchDomains: (OFArray OF_GENERIC(OFString *) *)searchDomains







>














<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103















104
105
106
107
108
109
110
 *
 *  - Resolve with each search domain
 *  - Fallback to TCP
 */

@interface OFDNSResolverQuery: OFObject
{
@public
	OFString *_host, *_domainName;
	of_dns_resource_record_class_t _recordClass;
	of_dns_resource_record_type_t _recordType;
	OFNumber *_ID;
	OFArray OF_GENERIC(OFString *) *_nameServers, *_searchDomains;
	size_t _nameServersIndex, _searchDomainsIndex;
	size_t _attempt;
	id _target;
	SEL _selector;
	id _context;
	OFData *_queryData;
	OFTimer *_cancelTimer;
}
















- (instancetype)initWithHost: (OFString *)host
		  domainName: (OFString *)domainName
		 recordClass: (of_dns_resource_record_class_t)recordClass
		  recordType: (of_dns_resource_record_type_t)recordType
			  ID: (OFNumber *)ID
		 nameServers: (OFArray OF_GENERIC(OFString *) *)nameServers
	       searchDomains: (OFArray OF_GENERIC(OFString *) *)searchDomains
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
	    [target methodForSelector: selector];

	method(target, selector, resolver, domainName, answerRecords,
	    authorityRecords, additionalRecords, context, exception);
}

@implementation OFDNSResolverQuery
@synthesize host = _host, domainName = _domainName, recordClass = _recordClass;
@synthesize recordType = _recordType, ID = _ID, nameServers = _nameServers;
@synthesize searchDomains = _searchDomains;
@synthesize nameServersIndex = _nameServersIndex;
@synthesize searchDomainsIndex = _searchDomainsIndex, attempt = _attempt;
@synthesize target = _target, selector = _selector, context = _context;
@synthesize queryData = _queryData, cancelTimer = _cancelTimer;

- (instancetype)initWithHost: (OFString *)host
		  domainName: (OFString *)domainName
		 recordClass: (of_dns_resource_record_class_t)recordClass
		  recordType: (of_dns_resource_record_type_t)recordType
			  ID: (OFNumber *)ID
		 nameServers: (OFArray OF_GENERIC(OFString *) *)nameServers
	       searchDomains: (OFArray OF_GENERIC(OFString *) *)searchDomains







<
<
<
<
<
<
<
<







519
520
521
522
523
524
525








526
527
528
529
530
531
532
	    [target methodForSelector: selector];

	method(target, selector, resolver, domainName, answerRecords,
	    authorityRecords, additionalRecords, context, exception);
}

@implementation OFDNSResolverQuery








- (instancetype)initWithHost: (OFString *)host
		  domainName: (OFString *)domainName
		 recordClass: (of_dns_resource_record_class_t)recordClass
		  recordType: (of_dns_resource_record_type_t)recordType
			  ID: (OFNumber *)ID
		 nameServers: (OFArray OF_GENERIC(OFString *) *)nameServers
	       searchDomains: (OFArray OF_GENERIC(OFString *) *)searchDomains
1069
1070
1071
1072
1073
1074
1075
1076

1077

1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
}

- (void)of_sendQuery: (OFDNSResolverQuery *)query
{
	of_socket_address_t address;
	OFUDPSocket *sock;

	[[query cancelTimer] invalidate];

	[query setCancelTimer: [OFTimer

	    scheduledTimerWithTimeInterval: TIMEOUT
				    target: self
				  selector: @selector(of_queryWithIDTimedOut:)
				    object: query
				   repeats: false]];

	address = of_socket_address_parse_ip(
	    [[query nameServers] objectAtIndex: [query nameServersIndex]], 53);

	switch (address.family) {
#ifdef OF_HAVE_IPV6
	case OF_SOCKET_ADDRESS_FAMILY_IPV6:
		if (_IPv6Socket == nil) {
			_IPv6Socket = [[OFUDPSocket alloc] init];
			[_IPv6Socket bindToHost: @"::"







|
>
|
>




|


|







1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
}

- (void)of_sendQuery: (OFDNSResolverQuery *)query
{
	of_socket_address_t address;
	OFUDPSocket *sock;

	[query->_cancelTimer invalidate];
	[query->_cancelTimer release];
	query->_cancelTimer = nil;
	query->_cancelTimer = [[OFTimer
	    scheduledTimerWithTimeInterval: TIMEOUT
				    target: self
				  selector: @selector(of_queryWithIDTimedOut:)
				    object: query
				   repeats: false] retain];

	address = of_socket_address_parse_ip(
	    [query->_nameServers objectAtIndex: query->_nameServersIndex], 53);

	switch (address.family) {
#ifdef OF_HAVE_IPV6
	case OF_SOCKET_ADDRESS_FAMILY_IPV6:
		if (_IPv6Socket == nil) {
			_IPv6Socket = [[OFUDPSocket alloc] init];
			[_IPv6Socket bindToHost: @"::"
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175

		sock = _IPv4Socket;
		break;
	default:
		@throw [OFInvalidArgumentException exception];
	}

	[sock asyncSendBuffer: [[query queryData] items]
		       length: [[query queryData] count]
		     receiver: address
		       target: self
		     selector: @selector(of_socket:didSendBuffer:bytesSent:
				   receiver:context:exception:)
		      context: query];
}

- (void)of_queryWithIDTimedOut: (OFDNSResolverQuery *)query
{
	OFResolveHostFailedException *exception;

	if (query == nil)
		return;

	if ([query nameServersIndex] + 1 < [[query nameServers] count]) {
		[query setNameServersIndex: [query nameServersIndex] + 1];
		[self of_sendQuery: query];
		return;
	}

	if ([query attempt] < ATTEMPTS) {
		[query setAttempt: [query attempt] + 1];
		[query setNameServersIndex: 0];
		[self of_sendQuery: query];
		return;
	}

	query = [[query retain] autorelease];
	[_queries removeObjectForKey: [query ID]];

	exception = [OFResolveHostFailedException
	    exceptionWithHost: [query host]
		  recordClass: [query recordClass]
		   recordType: [query recordType]
			error: OF_DNS_RESOLVER_ERROR_TIMEOUT];

	callback([query target], [query selector], self, [query domainName],
	    nil, nil, nil, [query context], exception);
}

- (size_t)of_socket: (OFUDPSocket *)sock
      didSendBuffer: (void **)buffer
	  bytesSent: (size_t)bytesSent
	   receiver: (of_socket_address_t *)receiver
	    context: (OFDNSResolverQuery *)query
	  exception: (id)exception
{
	if (exception != nil) {
		query = [[query retain] autorelease];
		[_queries removeObjectForKey: [query ID]];

		callback([query target], [query selector], self,
		    [query domainName], nil, nil, nil, [query context],
		    exception);

		return 0;
	}

	[sock asyncReceiveIntoBuffer: [self allocMemoryWithSize: 512]
			      length: 512







|
|














|
|




|
|
|





|


|
|
|


|
|











|

|
|







1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155

		sock = _IPv4Socket;
		break;
	default:
		@throw [OFInvalidArgumentException exception];
	}

	[sock asyncSendBuffer: [query->_queryData items]
		       length: [query->_queryData count]
		     receiver: address
		       target: self
		     selector: @selector(of_socket:didSendBuffer:bytesSent:
				   receiver:context:exception:)
		      context: query];
}

- (void)of_queryWithIDTimedOut: (OFDNSResolverQuery *)query
{
	OFResolveHostFailedException *exception;

	if (query == nil)
		return;

	if (query->_nameServersIndex + 1 < [query->_nameServers count]) {
		query->_nameServersIndex++;
		[self of_sendQuery: query];
		return;
	}

	if (query->_attempt < ATTEMPTS) {
		query->_attempt++;
		query->_nameServersIndex = 0;
		[self of_sendQuery: query];
		return;
	}

	query = [[query retain] autorelease];
	[_queries removeObjectForKey: query->_ID];

	exception = [OFResolveHostFailedException
	    exceptionWithHost: query->_host
		  recordClass: query->_recordClass
		   recordType: query->_recordType
			error: OF_DNS_RESOLVER_ERROR_TIMEOUT];

	callback(query->_target, query->_selector, self, query->_domainName,
	    nil, nil, nil, query->_context, exception);
}

- (size_t)of_socket: (OFUDPSocket *)sock
      didSendBuffer: (void **)buffer
	  bytesSent: (size_t)bytesSent
	   receiver: (of_socket_address_t *)receiver
	    context: (OFDNSResolverQuery *)query
	  exception: (id)exception
{
	if (exception != nil) {
		query = [[query retain] autorelease];
		[_queries removeObjectForKey: query->_ID];

		callback(query->_target, query->_selector, self,
		    query->_domainName, nil, nil, nil, query->_context,
		    exception);

		return 0;
	}

	[sock asyncReceiveIntoBuffer: [self allocMemoryWithSize: 512]
			      length: 512
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210


1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225

1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
	       context: (id)context
	     exception: (id)exception
{
	OFArray *answerRecords = nil, *authorityRecords = nil;
	OFArray *additionalRecords = nil;
	OFNumber *ID;
	OFDNSResolverQuery *query;
	OFData *queryData;

	if (exception != nil)
		return false;

	if (length < 2)
		/* We can't get the ID to get the query. Give up. */
		return false;

	ID = [OFNumber numberWithUInt16: (buffer[0] << 8) | buffer[1]];
	query = [[[_queries objectForKey: ID] retain] autorelease];

	if (query == nil)
		return false;

	[[query cancelTimer] invalidate];


	[_queries removeObjectForKey: ID];

	queryData = [query queryData];

	@try {
		const unsigned char *queryDataBuffer;
		size_t i;
		of_dns_resolver_error_t error;
		uint16_t numQuestions, numAnswers, numAuthorityRecords;
		uint16_t numAdditionalRecords;

		if (length < 12)
			@throw [OFTruncatedDataException exception];

		if ([queryData itemSize] != 1 || [queryData count] < 12)

			@throw [OFInvalidArgumentException exception];

		queryDataBuffer = [queryData items];

		/* QR */
		if ((buffer[2] & 0x80) == 0)
			@throw [OFInvalidServerReplyException exception];

		/* Opcode */
		if ((buffer[2] & 0x78) != (queryDataBuffer[2] & 0x78))







<














|
>
>


<
<










|
>


|







1168
1169
1170
1171
1172
1173
1174

1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193


1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
	       context: (id)context
	     exception: (id)exception
{
	OFArray *answerRecords = nil, *authorityRecords = nil;
	OFArray *additionalRecords = nil;
	OFNumber *ID;
	OFDNSResolverQuery *query;


	if (exception != nil)
		return false;

	if (length < 2)
		/* We can't get the ID to get the query. Give up. */
		return false;

	ID = [OFNumber numberWithUInt16: (buffer[0] << 8) | buffer[1]];
	query = [[[_queries objectForKey: ID] retain] autorelease];

	if (query == nil)
		return false;

	[query->_cancelTimer invalidate];
	[query->_cancelTimer release];
	query->_cancelTimer = nil;
	[_queries removeObjectForKey: ID];



	@try {
		const unsigned char *queryDataBuffer;
		size_t i;
		of_dns_resolver_error_t error;
		uint16_t numQuestions, numAnswers, numAuthorityRecords;
		uint16_t numAdditionalRecords;

		if (length < 12)
			@throw [OFTruncatedDataException exception];

		if ([query->_queryData itemSize] != 1 ||
		    [query->_queryData count] < 12)
			@throw [OFInvalidArgumentException exception];

		queryDataBuffer = [query->_queryData items];

		/* QR */
		if ((buffer[2] & 0x80) == 0)
			@throw [OFInvalidServerReplyException exception];

		/* Opcode */
		if ((buffer[2] & 0x78) != (queryDataBuffer[2] & 0x78))
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
		default:
			error = OF_DNS_RESOLVER_ERROR_UNKNOWN;
			break;
		}

		if (buffer[3] & 0x0F)
			@throw [OFResolveHostFailedException
			    exceptionWithHost: [query host]
				  recordClass: [query recordClass]
				   recordType: [query recordType]
					error: error];

		numQuestions = (buffer[4] << 8) | buffer[5];
		numAnswers = (buffer[6] << 8) | buffer[7];
		numAuthorityRecords = (buffer[8] << 8) | buffer[9];
		numAdditionalRecords = (buffer[10] << 8) | buffer[11];








|
|
|







1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
		default:
			error = OF_DNS_RESOLVER_ERROR_UNKNOWN;
			break;
		}

		if (buffer[3] & 0x0F)
			@throw [OFResolveHostFailedException
			    exceptionWithHost: query->_host
				  recordClass: query->_recordClass
				   recordType: query->_recordType
					error: error];

		numQuestions = (buffer[4] << 8) | buffer[5];
		numAnswers = (buffer[6] << 8) | buffer[7];
		numAuthorityRecords = (buffer[8] << 8) | buffer[9];
		numAdditionalRecords = (buffer[10] << 8) | buffer[11];

1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311

		answerRecords = parseSection(buffer, length, &i, numAnswers);
		authorityRecords = parseSection(buffer, length, &i,
		    numAuthorityRecords);
		additionalRecords = parseSection(buffer, length, &i,
		    numAdditionalRecords);
	} @catch (id e) {
		callback([query target], [query selector], self,
		    [query domainName], nil, nil, nil, [query context], e);
		return false;
	}

	callback([query target], [query selector], self, [query domainName],
	    answerRecords, authorityRecords, additionalRecords,
	    [query context], nil);

	return false;
}

- (void)close
{
	void *pool = objc_autoreleasePoolPush();







|
|



|

|







1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291

		answerRecords = parseSection(buffer, length, &i, numAnswers);
		authorityRecords = parseSection(buffer, length, &i,
		    numAuthorityRecords);
		additionalRecords = parseSection(buffer, length, &i,
		    numAdditionalRecords);
	} @catch (id e) {
		callback(query->_target, query->_selector, self,
		    query->_domainName, nil, nil, nil, query->_context, e);
		return false;
	}

	callback(query->_target, query->_selector, self, query->_domainName,
	    answerRecords, authorityRecords, additionalRecords,
	    query->_context, nil);

	return false;
}

- (void)close
{
	void *pool = objc_autoreleasePoolPush();
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
#endif

	enumerator = [_queries objectEnumerator];
	while ((query = [enumerator nextObject]) != nil) {
		OFResolveHostFailedException *exception;

		exception = [OFResolveHostFailedException
		    exceptionWithHost: [query host]
			  recordClass: [query recordClass]
			   recordType: [query recordType]
				error: OF_DNS_RESOLVER_ERROR_CANCELED];

		callback([query target], [query selector], self,
		    [query domainName], nil, nil, nil, [query context],
		    exception);
	}

	[_queries removeAllObjects];

	objc_autoreleasePoolPop(pool);
}
@end







|
|
|


|
|








1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
#endif

	enumerator = [_queries objectEnumerator];
	while ((query = [enumerator nextObject]) != nil) {
		OFResolveHostFailedException *exception;

		exception = [OFResolveHostFailedException
		    exceptionWithHost: query->_host
			  recordClass: query->_recordClass
			   recordType: query->_recordType
				error: OF_DNS_RESOLVER_ERROR_CANCELED];

		callback(query->_target, query->_selector, self,
		    query->_domainName, nil, nil, nil, query->_context,
		    exception);
	}

	[_queries removeAllObjects];

	objc_autoreleasePoolPop(pool);
}
@end