diff options
| -rw-r--r-- | Swiften/Network/PlatformDomainNameResolver.cpp | 23 | ||||
| -rw-r--r-- | Swiften/Network/PlatformDomainNameServiceQuery.cpp | 19 | ||||
| -rw-r--r-- | Swiften/Network/PlatformDomainNameServiceQuery.h | 5 | 
3 files changed, 44 insertions, 3 deletions
| diff --git a/Swiften/Network/PlatformDomainNameResolver.cpp b/Swiften/Network/PlatformDomainNameResolver.cpp index e30615b..3636cd6 100644 --- a/Swiften/Network/PlatformDomainNameResolver.cpp +++ b/Swiften/Network/PlatformDomainNameResolver.cpp @@ -1,81 +1,100 @@  #include "Swiften/Network/PlatformDomainNameResolver.h"  // Putting this early on, because some system types conflict with thread  #include "Swiften/Network/PlatformDomainNameServiceQuery.h"  #include <string>  #include <vector>  #include <boost/asio.hpp>  #include <boost/bind.hpp> +#include <boost/thread.hpp>  #include <boost/enable_shared_from_this.hpp>  #include <idna.h>  #include <algorithm>  #include "Swiften/Base/String.h"  #include "Swiften/Network/HostAddress.h"  #include "Swiften/EventLoop/MainEventLoop.h"  #include "Swiften/Network/HostAddressPort.h"  #include "Swiften/Network/DomainNameAddressQuery.h"  using namespace Swift;  namespace {  	struct AddressQuery : public DomainNameAddressQuery, public boost::enable_shared_from_this<AddressQuery>, public EventOwner { -		AddressQuery(const String& host) : hostname(host) {} +		AddressQuery(const String& host) : hostname(host), thread(NULL), safeToJoin(false) {} -		virtual void run() { +		~AddressQuery() { +			if (safeToJoin) { +				thread->join(); +			} +			else { +				// FIXME: UGLYYYYY +			} +			delete thread; +		} + +		void run() { +			safeToJoin = false; +			thread = new boost::thread(boost::bind(&AddressQuery::doRun, shared_from_this())); +		} +		 +		void doRun() {  			boost::asio::ip::tcp::resolver resolver(ioService);  			boost::asio::ip::tcp::resolver::query query(hostname.getUTF8String(), "5222");  			try {  				boost::asio::ip::tcp::resolver::iterator endpointIterator = resolver.resolve(query);  				if (endpointIterator == boost::asio::ip::tcp::resolver::iterator()) {  					emitError();  				}  				else {  					boost::asio::ip::address address = (*endpointIterator).endpoint().address();  					HostAddress result = (address.is_v4() ? HostAddress(&address.to_v4().to_bytes()[0], 4) : HostAddress(&address.to_v6().to_bytes()[0], 16));  					MainEventLoop::postEvent(  							boost::bind(boost::ref(onResult), result, boost::optional<DomainNameResolveError>()),   							shared_from_this());  				}  			}  			catch (...) {  				emitError();  			} +			safeToJoin = true;  		}  		void emitError() {  			MainEventLoop::postEvent(boost::bind(boost::ref(onResult), HostAddress(), boost::optional<DomainNameResolveError>(DomainNameResolveError())), shared_from_this());  		}  		boost::asio::io_service ioService;  		String hostname; +		boost::thread* thread; +		bool safeToJoin;  	};  	String getNormalized(const String& domain) {  		char* output;  		if (idna_to_ascii_8z(domain.getUTF8Data(), &output, 0) == IDNA_SUCCESS) {  			String result(output);  			free(output);  			return result;  		}  		else {  			return domain;  		}  	}  }  namespace Swift {  PlatformDomainNameResolver::PlatformDomainNameResolver() {  }  boost::shared_ptr<DomainNameServiceQuery> PlatformDomainNameResolver::createServiceQuery(const String& name) {  	return boost::shared_ptr<DomainNameServiceQuery>(new PlatformDomainNameServiceQuery(getNormalized(name)));  }  boost::shared_ptr<DomainNameAddressQuery> PlatformDomainNameResolver::createAddressQuery(const String& name) {  	return boost::shared_ptr<DomainNameAddressQuery>(new AddressQuery(getNormalized(name)));  }  } diff --git a/Swiften/Network/PlatformDomainNameServiceQuery.cpp b/Swiften/Network/PlatformDomainNameServiceQuery.cpp index eeb9fd6..12afbb7 100644 --- a/Swiften/Network/PlatformDomainNameServiceQuery.cpp +++ b/Swiften/Network/PlatformDomainNameServiceQuery.cpp @@ -1,86 +1,101 @@  #include "Swiften/Network/PlatformDomainNameServiceQuery.h"  #include "Swiften/Base/Platform.h"  #include <stdlib.h>  #ifdef SWIFTEN_PLATFORM_WINDOWS  #undef UNICODE  #include <windows.h>  #include <windns.h>  #ifndef DNS_TYPE_SRV  #define DNS_TYPE_SRV 33  #endif  #else  #include <arpa/nameser.h>  #include <arpa/nameser_compat.h>  #include <resolv.h>  #endif  #include <boost/bind.hpp>  #include "Swiften/Base/ByteArray.h"  #include "Swiften/EventLoop/MainEventLoop.h"  #include "Swiften/Base/foreach.h"  using namespace Swift;  namespace {  	struct SRVRecordPriorityComparator {  		bool operator()(const DomainNameServiceQuery::Result& a, const DomainNameServiceQuery::Result& b) const {  			return a.priority < b.priority;  		}  	};  }  namespace Swift { -PlatformDomainNameServiceQuery::PlatformDomainNameServiceQuery(const String& service) : service(service) { +PlatformDomainNameServiceQuery::PlatformDomainNameServiceQuery(const String& service) : thread(NULL), service(service), safeToJoin(true) { +} + +PlatformDomainNameServiceQuery::~PlatformDomainNameServiceQuery() { +	if (safeToJoin) { +		thread->join(); +	} +	else { +		// FIXME: UGLYYYYY +	} +	delete thread;  }  void PlatformDomainNameServiceQuery::run() { +	safeToJoin = false; +	thread = new boost::thread(boost::bind(&PlatformDomainNameServiceQuery::doRun, shared_from_this())); +} + +void PlatformDomainNameServiceQuery::doRun() {  	std::vector<DomainNameServiceQuery::Result> records;  #if defined(SWIFTEN_PLATFORM_WINDOWS)  	DNS_RECORD* responses;  	// FIXME: This conversion doesn't work if unicode is deffed above  	if (DnsQuery(service.getUTF8Data(), DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &responses, NULL) != ERROR_SUCCESS) {  		emitError();  		return;  	}  	DNS_RECORD* currentEntry = responses;  	while (currentEntry) {  		if (currentEntry->wType == DNS_TYPE_SRV) {  			SRVRecord record;  			record.priority = currentEntry->Data.SRV.wPriority;  			record.weight = currentEntry->Data.SRV.wWeight;  			record.port = currentEntry->Data.SRV.wPort;  			// The pNameTarget is actually a PCWSTR, so I would have expected this   			// conversion to not work at all, but it does.  			// Actually, it doesn't. Fix this and remove explicit cast  			// Remove unicode undef above as well  			record.hostname = std::string((const char*) currentEntry->Data.SRV.pNameTarget);  			records.push_back(record);  		}  		currentEntry = currentEntry->pNext;  	}  	DnsRecordListFree(responses, DnsFreeRecordList);  #else  	ByteArray response;  	response.resize(NS_PACKETSZ);  	int responseLength = res_query(const_cast<char*>(service.getUTF8Data()), ns_c_in, ns_t_srv, reinterpret_cast<u_char*>(response.getData()), response.getSize());  	if (responseLength == -1) {  		emitError();  		return;  	}  	// Parse header  	HEADER* header = reinterpret_cast<HEADER*>(response.getData());  	unsigned char* messageStart = reinterpret_cast<unsigned char*>(response.getData());  	unsigned char* messageEnd = messageStart + responseLength;  	unsigned char* currentEntry = messageStart + NS_HFIXEDSZ;  	// Skip over the queries  	int queriesCount = ntohs(header->qdcount);  	while (queriesCount > 0) { @@ -100,57 +115,59 @@ void PlatformDomainNameServiceQuery::run() {  		int entryLength = dn_skipname(currentEntry, messageEnd);  		currentEntry += entryLength;  		currentEntry += NS_RRFIXEDSZ;  		// Priority  		if (currentEntry + 2 >= messageEnd) {  			emitError();  			return;  		}  		record.priority = ns_get16(currentEntry);  		currentEntry += 2;  		// Weight  		if (currentEntry + 2 >= messageEnd) {  			emitError();  			return;  		}  		record.weight = ns_get16(currentEntry);  		currentEntry += 2;  		// Port  		if (currentEntry + 2 >= messageEnd) {  			emitError();  			return;  		}  		record.port = ns_get16(currentEntry);  		currentEntry += 2;   		// Hostname  		if (currentEntry >= messageEnd) {  			emitError();  			return;  		}  		ByteArray entry;  		entry.resize(NS_MAXDNAME);  		entryLength = dn_expand(messageStart, messageEnd, currentEntry, entry.getData(), entry.getSize());  		if (entryLength < 0) {  			emitError();  			return;  		}  		record.hostname = String(entry.getData());  		records.push_back(record);  		currentEntry += entryLength;  		answersCount--;  	}  #endif +	safeToJoin = true;  	std::sort(records.begin(), records.end(), SRVRecordPriorityComparator());  	MainEventLoop::postEvent(boost::bind(boost::ref(onResult), records));   }  void PlatformDomainNameServiceQuery::emitError() { +	safeToJoin = true;  	MainEventLoop::postEvent(boost::bind(boost::ref(onResult), std::vector<DomainNameServiceQuery::Result>()), shared_from_this());  }  } diff --git a/Swiften/Network/PlatformDomainNameServiceQuery.h b/Swiften/Network/PlatformDomainNameServiceQuery.h index 58257af..1b1c1b5 100644 --- a/Swiften/Network/PlatformDomainNameServiceQuery.h +++ b/Swiften/Network/PlatformDomainNameServiceQuery.h @@ -1,22 +1,27 @@  #pragma once +#include <boost/thread.hpp>  #include <boost/enable_shared_from_this.hpp>  #include "Swiften/Network/DomainNameServiceQuery.h"  #include "Swiften/EventLoop/EventOwner.h"  #include "Swiften/Base/String.h"  namespace Swift {  	class PlatformDomainNameServiceQuery : public DomainNameServiceQuery, public boost::enable_shared_from_this<PlatformDomainNameServiceQuery>, public EventOwner {  		public:  			PlatformDomainNameServiceQuery(const String& service); +			~PlatformDomainNameServiceQuery();  			virtual void run();  		private: +			void doRun();  			void emitError();  		private: +			boost::thread* thread; +			bool safeToJoin;  			String service;  	};  } | 
 Swift
 Swift