浏览代码

resolve_hostname_addresses: retrieve every addresses associated with a hostname

James 8 年之前
父节点
当前提交
010a3433df
共有 5 个文件被更改,包括 113 次插入27 次删除
  1. 74 18
      core/io/ip.cpp
  2. 3 1
      core/io/ip.h
  3. 20 0
      doc/base/classes.xml
  4. 15 6
      drivers/unix/ip_unix.cpp
  5. 1 2
      drivers/unix/ip_unix.h

+ 74 - 18
core/io/ip.cpp

@@ -41,13 +41,13 @@ struct _IP_ResolverPrivate {
 	struct QueueItem {
 
 		volatile IP::ResolverStatus status;
-		IP_Address response;
+		List<IP_Address> response;
 		String hostname;
 		IP::Type type;
 
 		void clear() {
 			status = IP::RESOLVER_STATUS_NONE;
-			response = IP_Address();
+			response.clear();
 			type = IP::TYPE_NONE;
 			hostname = "";
 		};
@@ -81,12 +81,8 @@ struct _IP_ResolverPrivate {
 
 			if (queue[i].status != IP::RESOLVER_STATUS_WAITING)
 				continue;
-			queue[i].response = IP::get_singleton()->resolve_hostname(queue[i].hostname, queue[i].type);
-
-			if (!queue[i].response.is_valid())
-				queue[i].status = IP::RESOLVER_STATUS_ERROR;
-			else
-				queue[i].status = IP::RESOLVER_STATUS_DONE;
+			IP::get_singleton()->_resolve_hostname(queue[i].response, queue[i].hostname, queue[i].type);
+			queue[i].status = queue[i].response.empty() ? IP::RESOLVER_STATUS_ERROR : IP::RESOLVER_STATUS_DONE;
 		}
 	}
 
@@ -104,7 +100,7 @@ struct _IP_ResolverPrivate {
 		}
 	}
 
-	HashMap<String, IP_Address> cache;
+	HashMap<String, List<IP_Address> > cache;
 
 	static String get_cache_key(String p_hostname, IP::Type p_type) {
 		return itos(p_type) + p_hostname;
@@ -115,17 +111,44 @@ IP_Address IP::resolve_hostname(const String &p_hostname, IP::Type p_type) {
 
 	resolver->mutex->lock();
 
+	List<IP_Address> res;
+
 	String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type);
 	if (resolver->cache.has(key)) {
-		IP_Address res = resolver->cache[key];
-		resolver->mutex->unlock();
-		return res;
+		res = resolver->cache[key];
+	} else {
+		_resolve_hostname(res, p_hostname, p_type);
+		resolver->cache[key] = res;
+	}
+	resolver->mutex->unlock();
+
+	for (int i = 0; i < res.size(); ++i) {
+		if (res[i].is_valid()) {
+			return res[i];
+		}
+	}
+	return IP_Address();
+}
+
+Array IP::resolve_hostname_addresses(const String &p_hostname, Type p_type) {
+
+	resolver->mutex->lock();
+
+	String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type);
+	if (!resolver->cache.has(key)) {
+		_resolve_hostname(resolver->cache[key], p_hostname, p_type);
 	}
 
-	IP_Address res = _resolve_hostname(p_hostname, p_type);
-	resolver->cache[key] = res;
+	List<IP_Address> res = resolver->cache[key];
 	resolver->mutex->unlock();
-	return res;
+
+	Array result;
+	for (int i = 0; i < res.size(); ++i) {
+		if (res[i].is_valid()) {
+			result.push_back(String(res[i]));
+		}
+	}
+	return result;
 }
 
 IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Type p_type) {
@@ -147,7 +170,7 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Typ
 		resolver->queue[id].response = resolver->cache[key];
 		resolver->queue[id].status = IP::RESOLVER_STATUS_DONE;
 	} else {
-		resolver->queue[id].response = IP_Address();
+		resolver->queue[id].response = List<IP_Address>();
 		resolver->queue[id].status = IP::RESOLVER_STATUS_WAITING;
 		if (resolver->thread)
 			resolver->sem->post();
@@ -187,10 +210,41 @@ IP_Address IP::get_resolve_item_address(ResolverID p_id) const {
 		return IP_Address();
 	}
 
-	IP_Address res = resolver->queue[p_id].response;
+	List<IP_Address> res = resolver->queue[p_id].response;
 
 	resolver->mutex->unlock();
-	return res;
+
+	for (int i = 0; i < res.size(); ++i) {
+		if (res[i].is_valid()) {
+			return res[i];
+		}
+	}
+	return IP_Address();
+}
+
+Array IP::get_resolve_item_addresses(ResolverID p_id) const {
+
+	ERR_FAIL_INDEX_V(p_id, IP::RESOLVER_MAX_QUERIES, Array());
+
+	resolver->mutex->lock();
+
+	if (resolver->queue[p_id].status != IP::RESOLVER_STATUS_DONE) {
+		ERR_PRINTS("Resolve of '" + resolver->queue[p_id].hostname + "'' didn't complete yet.");
+		resolver->mutex->unlock();
+		return Array();
+	}
+
+	List<IP_Address> res = resolver->queue[p_id].response;
+
+	resolver->mutex->unlock();
+
+	Array result;
+	for (int i = 0; i < res.size(); ++i) {
+		if (res[i].is_valid()) {
+			result.push_back(String(res[i]));
+		}
+	}
+	return result;
 }
 
 void IP::erase_resolve_item(ResolverID p_id) {
@@ -235,9 +289,11 @@ Array IP::_get_local_addresses() const {
 void IP::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("resolve_hostname", "host", "ip_type"), &IP::resolve_hostname, DEFVAL(IP::TYPE_ANY));
+	ObjectTypeDB::bind_method(_MD("resolve_hostname_addresses", "host", "ip_type"), &IP::resolve_hostname_addresses);
 	ObjectTypeDB::bind_method(_MD("resolve_hostname_queue_item", "host", "ip_type"), &IP::resolve_hostname_queue_item, DEFVAL(IP::TYPE_ANY));
 	ObjectTypeDB::bind_method(_MD("get_resolve_item_status", "id"), &IP::get_resolve_item_status);
 	ObjectTypeDB::bind_method(_MD("get_resolve_item_address", "id"), &IP::get_resolve_item_address);
+	ObjectTypeDB::bind_method(_MD("get_resolve_item_addresses", "id"), &IP::get_resolve_item_addresses);
 	ObjectTypeDB::bind_method(_MD("erase_resolve_item", "id"), &IP::erase_resolve_item);
 	ObjectTypeDB::bind_method(_MD("get_local_addresses"), &IP::_get_local_addresses);
 	ObjectTypeDB::bind_method(_MD("clear_cache"), &IP::clear_cache, DEFVAL(""));

+ 3 - 1
core/io/ip.h

@@ -70,17 +70,19 @@ protected:
 	static IP *singleton;
 	static void _bind_methods();
 
-	virtual IP_Address _resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY) = 0;
 	Array _get_local_addresses() const;
 
 	static IP *(*_create)();
 
 public:
 	IP_Address resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY);
+	Array resolve_hostname_addresses(const String &p_hostname, Type p_type = TYPE_ANY);
 	// async resolver hostname
 	ResolverID resolve_hostname_queue_item(const String &p_hostname, Type p_type = TYPE_ANY);
 	ResolverStatus get_resolve_item_status(ResolverID p_id) const;
 	IP_Address get_resolve_item_address(ResolverID p_id) const;
+	Array get_resolve_item_addresses(ResolverID p_id) const;
+	virtual void _resolve_hostname(List<IP_Address> &r_addresses, const String &p_hostname, Type p_type = TYPE_ANY) const = 0;
 	virtual void get_local_addresses(List<IP_Address> *r_addresses) const = 0;
 	void erase_resolve_item(ResolverID p_id);
 

+ 20 - 0
doc/base/classes.xml

@@ -15782,6 +15782,15 @@
 				Return a resolved item address, or an empty string if an error happened or resolution didn't happen yet (see [method get_resolve_item_status]).
 			</description>
 		</method>
+		<method name="get_resolve_item_addresses" qualifiers="const">
+			<return type="Array">
+			</return>
+			<argument index="0" name="id" type="int">
+			</argument>
+			<description>
+				Return resolved addresses, or an empty array if an error happened or resolution didn't happen yet (see [method get_resolve_item_status]).
+			</description>
+		</method>
 		<method name="get_resolve_item_status" qualifiers="const">
 			<return type="int">
 			</return>
@@ -15802,6 +15811,17 @@
 				Resolve a given hostname, blocking. Resolved hostname is returned as an IPv4 or IPv6 depending on "ip_type".
 			</description>
 		</method>
+		<method name="resolve_hostname_addresses">
+			<return type="Array">
+			</return>
+			<argument index="0" name="host" type="String">
+			</argument>
+			<argument index="1" name="ip_type" type="int" default="3">
+			</argument>
+			<description>
+				Resolve a given hostname, blocking. Addresses are returned as an Array of IPv4 or IPv6 depending on "ip_type".
+			</description>
+		</method>
 		<method name="resolve_hostname_queue_item">
 			<return type="int">
 			</return>

+ 15 - 6
drivers/unix/ip_unix.cpp

@@ -85,7 +85,7 @@ static IP_Address _sockaddr2ip(struct sockaddr *p_addr) {
 	return ip;
 };
 
-IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) {
+void IP_Unix::_resolve_hostname(List<IP_Address> &r_addresses, const String &p_hostname, Type p_type) const {
 
 	struct addrinfo hints;
 	struct addrinfo *result;
@@ -105,19 +105,28 @@ IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) {
 	int s = getaddrinfo(p_hostname.utf8().get_data(), NULL, &hints, &result);
 	if (s != 0) {
 		ERR_PRINT("getaddrinfo failed!");
-		return IP_Address();
+		return;
 	};
 
 	if (result == NULL || result->ai_addr == NULL) {
 		ERR_PRINT("Invalid response from getaddrinfo");
-		return IP_Address();
+		return;
 	};
 
-	IP_Address ip = _sockaddr2ip(result->ai_addr);
+	struct addrinfo *next = result;
 
-	freeaddrinfo(result);
+	do {
+		if (next->ai_addr == NULL) {
+			next = next->ai_next;
+			continue;
+		}
+		IP_Address ip = _sockaddr2ip(next->ai_addr);
+		if (!r_addresses.find(ip))
+			r_addresses.push_back(ip);
+		next = next->ai_next;
+	} while (next);
 
-	return ip;
+	freeaddrinfo(result);
 }
 
 #if defined(WINDOWS_ENABLED)

+ 1 - 2
drivers/unix/ip_unix.h

@@ -37,11 +37,10 @@
 class IP_Unix : public IP {
 	OBJ_TYPE(IP_Unix, IP);
 
-	virtual IP_Address _resolve_hostname(const String &p_hostname, IP::Type p_type);
-
 	static IP *_create_unix();
 
 public:
+	virtual void _resolve_hostname(List<IP_Address> &r_addresses, const String &p_hostname, Type p_type = TYPE_ANY) const;
 	virtual void get_local_addresses(List<IP_Address> *r_addresses) const;
 
 	static void make_default();