diff options
Diffstat (limited to 'Swiften')
-rw-r--r-- | Swiften/EventLoop/SConscript | 2 | ||||
-rw-r--r-- | Swiften/Network/BoostNetworkFactories.cpp | 13 | ||||
-rw-r--r-- | Swiften/Network/SConscript | 19 | ||||
-rwxr-xr-x | Swiften/Network/UnboundDomainNameResolver.cpp | 241 | ||||
-rwxr-xr-x | Swiften/Network/UnboundDomainNameResolver.h | 51 | ||||
-rw-r--r-- | Swiften/Network/UnixNetworkEnvironment.cpp | 7 | ||||
-rw-r--r-- | Swiften/QA/NetworkTest/DomainNameResolverTest.cpp | 22 | ||||
-rw-r--r-- | Swiften/QA/NetworkTest/SConscript | 3 | ||||
-rw-r--r-- | Swiften/SConscript | 5 |
9 files changed, 349 insertions, 14 deletions
diff --git a/Swiften/EventLoop/SConscript b/Swiften/EventLoop/SConscript index b405f6b..8bef8fb 100644 --- a/Swiften/EventLoop/SConscript +++ b/Swiften/EventLoop/SConscript @@ -12,7 +12,7 @@ sources = [ objects = swiften_env.SwiftenObject(sources) swiften_env.Append(SWIFTEN_OBJECTS = [objects]) -if swiften_env["PLATFORM"] == "darwin" : +if swiften_env["PLATFORM"] == "darwin" and swiften_env["target"] == "native": myenv = swiften_env.Clone() myenv.Append(CXXFLAGS = myenv["OBJCCFLAGS"]) objects = myenv.SwiftenObject([ diff --git a/Swiften/Network/BoostNetworkFactories.cpp b/Swiften/Network/BoostNetworkFactories.cpp index 9f781e4..72e826a 100644 --- a/Swiften/Network/BoostNetworkFactories.cpp +++ b/Swiften/Network/BoostNetworkFactories.cpp @@ -7,7 +7,7 @@ #include <Swiften/Network/BoostNetworkFactories.h> #include <Swiften/Network/BoostTimerFactory.h> #include <Swiften/Network/BoostConnectionFactory.h> -#include <Swiften/Network/PlatformDomainNameResolver.h> + #include <Swiften/Network/BoostConnectionServerFactory.h> #include <Swiften/Network/PlatformNATTraversalWorker.h> #include <Swiften/Parser/PlatformXMLParserFactory.h> @@ -20,6 +20,12 @@ #include <Swiften/Crypto/PlatformCryptoProvider.h> #include <Swiften/Crypto/CryptoProvider.h> +#ifdef USE_UNBOUND +#include <Swiften/Network/UnboundDomainNameResolver.h> +#else +#include <Swiften/Network/PlatformDomainNameResolver.h> +#endif + namespace Swift { BoostNetworkFactories::BoostNetworkFactories(EventLoop* eventLoop) : eventLoop(eventLoop){ @@ -36,7 +42,12 @@ BoostNetworkFactories::BoostNetworkFactories(EventLoop* eventLoop) : eventLoop(e tlsFactories = new PlatformTLSFactories(); proxyProvider = new PlatformProxyProvider(); idnConverter = PlatformIDNConverter::create(); +#ifdef USE_UNBOUND + // TODO: What to do about idnConverter. + domainNameResolver = new UnboundDomainNameResolver(ioServiceThread.getIOService(), eventLoop); +#else domainNameResolver = new PlatformDomainNameResolver(idnConverter, eventLoop); +#endif cryptoProvider = PlatformCryptoProvider::create(); } diff --git a/Swiften/Network/SConscript b/Swiften/Network/SConscript index e0e5e63..ea0fb62 100644 --- a/Swiften/Network/SConscript +++ b/Swiften/Network/SConscript @@ -2,6 +2,10 @@ Import("swiften_env") myenv = swiften_env.Clone() +if myenv.get("unbound", False) : + myenv.MergeFlags(myenv.get("UNBOUND_FLAGS", {})) + myenv.MergeFlags(myenv.get("LDNS_FLAGS", {})) + sourceList = [ "ProxiedConnection.cpp", "HTTPConnectProxiedConnection.cpp", @@ -30,9 +34,6 @@ sourceList = [ "DomainNameResolver.cpp", "DomainNameAddressQuery.cpp", "DomainNameServiceQuery.cpp", - "PlatformDomainNameResolver.cpp", - "PlatformDomainNameServiceQuery.cpp", - "PlatformDomainNameAddressQuery.cpp", "StaticDomainNameResolver.cpp", "HostAddress.cpp", "HostAddressPort.cpp", @@ -53,8 +54,16 @@ sourceList = [ "NATTraversalRemovePortForwardingRequest.cpp", "NATTraversalInterface.cpp", ] - -if myenv["PLATFORM"] == "darwin" : + +if myenv.get("unbound", False) : + myenv.Append(CPPDEFINES = "USE_UNBOUND") + sourceList.append("UnboundDomainNameResolver.cpp") +else : + sourceList.append("PlatformDomainNameResolver.cpp") + sourceList.append("PlatformDomainNameServiceQuery.cpp") + sourceList.append("PlatformDomainNameAddressQuery.cpp") + +if myenv["PLATFORM"] == "darwin" and myenv["target"] != "android": myenv.Append(FRAMEWORKS = ["CoreServices", "SystemConfiguration"]) sourceList += [ "MacOSXProxyProvider.cpp" ] sourceList += [ "UnixNetworkEnvironment.cpp" ] diff --git a/Swiften/Network/UnboundDomainNameResolver.cpp b/Swiften/Network/UnboundDomainNameResolver.cpp new file mode 100755 index 0000000..d986385 --- /dev/null +++ b/Swiften/Network/UnboundDomainNameResolver.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "UnboundDomainNameResolver.h" + +#include <vector> + +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/enable_shared_from_this.hpp> + +#include <Swiften/Base/Log.h> +#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/Network/DomainNameAddressQuery.h> +#include <Swiften/Network/DomainNameResolveError.h> +#include <Swiften/Network/DomainNameServiceQuery.h> +#include <Swiften/Network/HostAddress.h> +#include <Swiften/Network/TimerFactory.h> + +#include <arpa/inet.h> +#include <unbound.h> +#include <ldns/ldns.h> +#include <unistd.h> + +namespace Swift { + +class UnboundQuery { + public: + UnboundQuery(UnboundDomainNameResolver* resolver, ub_ctx* context) : resolver(resolver), ubContext(context) {} + virtual ~UnboundQuery() {} + virtual void handleResult(int err, ub_result* result) = 0; + protected: + UnboundDomainNameResolver* resolver; + ub_ctx* ubContext; +}; + +struct UnboundWrapperHelper { + UnboundWrapperHelper(UnboundDomainNameResolver* resolver, boost::shared_ptr<UnboundQuery> query) : resolver(resolver), query(query) {} + UnboundDomainNameResolver* resolver; + boost::shared_ptr<UnboundQuery> query; +}; + +class UnboundDomainNameServiceQuery : public DomainNameServiceQuery, public UnboundQuery, public boost::enable_shared_from_this<UnboundDomainNameServiceQuery> { + public: + UnboundDomainNameServiceQuery(UnboundDomainNameResolver* resolver, ub_ctx* context, std::string name) : UnboundQuery(resolver, context), name(name) { + } + + virtual ~UnboundDomainNameServiceQuery() { } + + virtual void run() { + int retval; + UnboundWrapperHelper* helper = new UnboundWrapperHelper(resolver, shared_from_this()); + + retval = ub_resolve_async(ubContext, const_cast<char*>(name.c_str()), LDNS_RR_TYPE_SRV, + 1 /* CLASS IN (internet) */, + helper, UnboundDomainNameResolver::unbound_callback_wrapper, NULL); + if(retval != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(retval) << std::endl; + delete helper; + } + } + + void handleResult(int err, struct ub_result* result) { + std::vector<DomainNameServiceQuery::Result> serviceRecords; + + if(err != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(err) << std::endl; + } else { + if(result->havedata) { + ldns_pkt* replyPacket = 0; + ldns_buffer* buffer = ldns_buffer_new(1024); + if (buffer && ldns_wire2pkt(&replyPacket, static_cast<const uint8_t*>(result->answer_packet), result->answer_len) == LDNS_STATUS_OK) { + ldns_rr_list* rrList = ldns_pkt_answer(replyPacket); + for (size_t n = 0; n < ldns_rr_list_rr_count(rrList); n++) { + ldns_rr* rr = ldns_rr_list_rr(rrList, n); + if ((ldns_rr_get_type(rr) != LDNS_RR_TYPE_SRV) || + (ldns_rr_get_class(rr) != LDNS_RR_CLASS_IN) || + (ldns_rr_rd_count(rr) != 4)) { + continue; + } + + DomainNameServiceQuery::Result serviceRecord; + serviceRecord.priority = ldns_rdf2native_int16(ldns_rr_rdf(rr, 0)); + serviceRecord.weight = ldns_rdf2native_int16(ldns_rr_rdf(rr, 1)); + serviceRecord.port = ldns_rdf2native_int16(ldns_rr_rdf(rr, 2)); + + ldns_buffer_rewind(buffer); + if ((ldns_rdf2buffer_str_dname(buffer, ldns_rr_rdf(rr, 3)) != LDNS_STATUS_OK) || + (ldns_buffer_position(buffer) < 2) || + !ldns_buffer_reserve(buffer, 1)) { + // either name invalid, empty or buffer to small + continue; + } + char terminator = 0; + ldns_buffer_write(buffer, &terminator, sizeof(terminator)); + + serviceRecord.hostname = std::string(reinterpret_cast<char*>(ldns_buffer_at(buffer, 0))); + serviceRecords.push_back(serviceRecord); + SWIFT_LOG(debug) << "hostname " << serviceRecord.hostname << " added" << std::endl; + } + } + if (replyPacket) ldns_pkt_free(replyPacket); + if (buffer) ldns_buffer_free(buffer); + } + } + + ub_resolve_free(result); + onResult(serviceRecords); + } + + private: + std::string name; +}; + +class UnboundDomainNameAddressQuery : public DomainNameAddressQuery, public UnboundQuery, public boost::enable_shared_from_this<UnboundDomainNameAddressQuery> { + public: + UnboundDomainNameAddressQuery(UnboundDomainNameResolver* resolver, ub_ctx* context, std::string name) : UnboundQuery(resolver, context), name(name) { + } + + virtual ~UnboundDomainNameAddressQuery() { } + + virtual void run() { + int retval; + UnboundWrapperHelper* helper = new UnboundWrapperHelper(resolver, shared_from_this()); + + //FIXME: support AAAA queries in some way + retval = ub_resolve_async(ubContext, const_cast<char*>(name.c_str()), LDNS_RR_TYPE_A, + 1 /* CLASS IN (internet) */, + helper, UnboundDomainNameResolver::unbound_callback_wrapper, NULL); + if(retval != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(retval) << std::endl; + delete helper; + } + } + + void handleResult(int err, struct ub_result* result) { + std::vector<HostAddress> addresses; + boost::optional<DomainNameResolveError> error; + SWIFT_LOG(debug) << "Result for: " << name << std::endl; + + if(err != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(err) << std::endl; + error = DomainNameResolveError(); + } else { + if(result->havedata) { + for(int i=0; result->data[i]; i++) { + char address[100]; + const char* addressStr = 0; + if ((addressStr = inet_ntop(AF_INET, result->data[i], address, 100))) { + SWIFT_LOG(debug) << "IPv4 address: " << addressStr << std::endl; + addresses.push_back(HostAddress(std::string(addressStr))); + } else if ((addressStr = inet_ntop(AF_INET6, result->data[i], address, 100))) { + SWIFT_LOG(debug) << "IPv6 address: " << addressStr << std::endl; + addresses.push_back(HostAddress(std::string(addressStr))); + } else { + SWIFT_LOG(debug) << "inet_ntop() failed" << std::endl; + error = DomainNameResolveError(); + } + } + } else { + error = DomainNameResolveError(); + } + } + + ub_resolve_free(result); + onResult(addresses, error); + } + + private: + std::string name; +}; + +UnboundDomainNameResolver::UnboundDomainNameResolver(boost::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop) : ioService(ioService), ubDescriptior(*ioService), eventLoop(eventLoop) { + ubContext = ub_ctx_create(); + if(!ubContext) { + SWIFT_LOG(debug) << "could not create unbound context" << std::endl; + } + eventOwner = boost::make_shared<EventOwner>(); + + ub_ctx_async(ubContext, true); + + int ret; + + /* read /etc/resolv.conf for DNS proxy settings (from DHCP) */ + if( (ret=ub_ctx_resolvconf(ubContext, const_cast<char*>("/etc/resolv.conf"))) != 0) { + SWIFT_LOG(debug) << "error reading resolv.conf: " << ub_strerror(ret) << ". errno says: " << strerror(errno) << std::endl; + } + /* read /etc/hosts for locally supplied host addresses */ + if( (ret=ub_ctx_hosts(ubContext, const_cast<char*>("/etc/hosts"))) != 0) { + SWIFT_LOG(debug) << "error reading hosts: " << ub_strerror(ret) << ". errno says: " << strerror(errno) << std::endl; + } + + ubDescriptior.assign(ub_fd(ubContext)); + + ubDescriptior.async_read_some(boost::asio::null_buffers(), boost::bind(&UnboundDomainNameResolver::handleUBSocketReadable, this, boost::asio::placeholders::error)); +} + +UnboundDomainNameResolver::~UnboundDomainNameResolver() { + eventLoop->removeEventsFromOwner(eventOwner); + if (ubContext) { + ub_ctx_delete(ubContext); + } +} + +void UnboundDomainNameResolver::unbound_callback(boost::shared_ptr<UnboundQuery> query, int err, ub_result* result) { + query->handleResult(err, result); +} + +void UnboundDomainNameResolver::unbound_callback_wrapper(void* data, int err, ub_result* result) { + UnboundWrapperHelper* helper = static_cast<UnboundWrapperHelper*>(data); + UnboundDomainNameResolver* resolver = helper->resolver; + resolver->unbound_callback(helper->query, err, result); + delete helper; +} + +void UnboundDomainNameResolver::handleUBSocketReadable(boost::system::error_code) { + eventLoop->postEvent(boost::bind(&UnboundDomainNameResolver::processData, this), eventOwner); + ubDescriptior.async_read_some(boost::asio::null_buffers(), boost::bind(&UnboundDomainNameResolver::handleUBSocketReadable, this, boost::asio::placeholders::error)); +} + +void UnboundDomainNameResolver::processData() { + if (ub_poll(ubContext)) { + int ret = ub_process(ubContext); + if(ret != 0) { + SWIFT_LOG(debug) << "resolve error: " << ub_strerror(ret) << std::endl; + } + } +} + +boost::shared_ptr<DomainNameServiceQuery> UnboundDomainNameResolver::createServiceQuery(const std::string& name) { + return boost::make_shared<UnboundDomainNameServiceQuery>(this, ubContext, name); +} + +boost::shared_ptr<DomainNameAddressQuery> UnboundDomainNameResolver::createAddressQuery(const std::string& name) { + return boost::make_shared<UnboundDomainNameAddressQuery>(this, ubContext, name); +} + +} diff --git a/Swiften/Network/UnboundDomainNameResolver.h b/Swiften/Network/UnboundDomainNameResolver.h new file mode 100755 index 0000000..0db8a66 --- /dev/null +++ b/Swiften/Network/UnboundDomainNameResolver.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Network/DomainNameResolver.h> +#include <Swiften/Network/Timer.h> +#include <Swiften/EventLoop/EventOwner.h> + +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/asio.hpp> + +struct ub_ctx; +struct ub_result; + +namespace Swift { + class EventLoop; + class TimerFactory; + + class UnboundDomainNameResolver; + class UnboundQuery; + + class UnboundDomainNameResolver : public DomainNameResolver, public EventOwner, public boost::enable_shared_from_this<UnboundDomainNameResolver> { + public: + UnboundDomainNameResolver(boost::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop); + virtual ~UnboundDomainNameResolver(); + + virtual boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const std::string& name); + virtual boost::shared_ptr<DomainNameAddressQuery> createAddressQuery(const std::string& name); + + static void unbound_callback_wrapper(void* data, int err, ub_result* result); + + private: + void unbound_callback(boost::shared_ptr<UnboundQuery> query, int err, ub_result* result); + + void handleUBSocketReadable(boost::system::error_code); + void processData(); + + private: + boost::shared_ptr<EventOwner> eventOwner; + boost::shared_ptr<boost::asio::io_service> ioService; + boost::asio::posix::stream_descriptor ubDescriptior; + EventLoop* eventLoop; + ub_ctx* ubContext; + }; + +} diff --git a/Swiften/Network/UnixNetworkEnvironment.cpp b/Swiften/Network/UnixNetworkEnvironment.cpp index 5740a65..e1fdc88 100644 --- a/Swiften/Network/UnixNetworkEnvironment.cpp +++ b/Swiften/Network/UnixNetworkEnvironment.cpp @@ -14,7 +14,10 @@ #include <sys/socket.h> #include <arpa/inet.h> #include <net/if.h> + +#ifndef __ANDROID__ #include <ifaddrs.h> +#endif #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Network/HostAddress.h> @@ -24,7 +27,7 @@ namespace Swift { std::vector<NetworkInterface> UnixNetworkEnvironment::getNetworkInterfaces() const { std::map<std::string, NetworkInterface> interfaces; - +#ifndef __ANDROID__ ifaddrs* addrs = 0; int ret = getifaddrs(&addrs); if (ret != 0) { @@ -49,7 +52,7 @@ std::vector<NetworkInterface> UnixNetworkEnvironment::getNetworkInterfaces() con } freeifaddrs(addrs); - +#endif std::vector<NetworkInterface> result; for (std::map<std::string,NetworkInterface>::const_iterator i = interfaces.begin(); i != interfaces.end(); ++i) { result.push_back(i->second); diff --git a/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp b/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp index 7bbb1a6..bc4f1a3 100644 --- a/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp +++ b/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp @@ -9,11 +9,17 @@ #include <boost/bind.hpp> #include <algorithm> - #include <Swiften/Base/sleep.h> #include <string> #include <Swiften/Base/ByteArray.h> +#ifdef USE_UNBOUND +#include <Swiften/Network/UnboundDomainNameResolver.h> +#else #include <Swiften/Network/PlatformDomainNameResolver.h> +#endif +#include <Swiften/Network/BoostTimerFactory.h> +#include <Swiften/Network/NetworkFactories.h> +#include <Swiften/Network/BoostIOServiceThread.h> #include <Swiften/Network/DomainNameAddressQuery.h> #include <Swiften/Network/DomainNameServiceQuery.h> #include <Swiften/EventLoop/DummyEventLoop.h> @@ -32,24 +38,34 @@ class DomainNameResolverTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(DomainNameResolverTest); CPPUNIT_TEST(testResolveAddress); CPPUNIT_TEST(testResolveAddress_Error); +#ifndef USE_UNBOUND CPPUNIT_TEST(testResolveAddress_IPv6); CPPUNIT_TEST(testResolveAddress_IPv4and6); CPPUNIT_TEST(testResolveAddress_International); +#endif CPPUNIT_TEST(testResolveAddress_Localhost); CPPUNIT_TEST(testResolveAddress_Parallel); +#ifndef USE_UNBOUND CPPUNIT_TEST(testResolveService); +#endif CPPUNIT_TEST(testResolveService_Error); CPPUNIT_TEST_SUITE_END(); public: void setUp() { + ioServiceThread = new BoostIOServiceThread(); eventLoop = new DummyEventLoop(); +#ifdef USE_UNBOUND + resolver = new UnboundDomainNameResolver(ioServiceThread->getIOService(), eventLoop); +#else idnConverter = boost::shared_ptr<IDNConverter>(PlatformIDNConverter::create()); resolver = new PlatformDomainNameResolver(idnConverter.get(), eventLoop); +#endif resultsAvailable = false; } void tearDown() { + delete ioServiceThread; delete resolver; delete eventLoop; } @@ -211,14 +227,16 @@ class DomainNameResolverTest : public CppUnit::TestFixture { } private: + BoostIOServiceThread* ioServiceThread; DummyEventLoop* eventLoop; boost::shared_ptr<IDNConverter> idnConverter; + boost::shared_ptr<TimerFactory> timerFactory; bool resultsAvailable; std::vector<HostAddress> addressQueryResult; std::vector<HostAddress> allAddressQueryResults; boost::optional<DomainNameResolveError> addressQueryError; std::vector<DomainNameServiceQuery::Result> serviceQueryResult; - PlatformDomainNameResolver* resolver; + DomainNameResolver* resolver; }; CPPUNIT_TEST_SUITE_REGISTRATION(DomainNameResolverTest); diff --git a/Swiften/QA/NetworkTest/SConscript b/Swiften/QA/NetworkTest/SConscript index e1dea26..b090165 100644 --- a/Swiften/QA/NetworkTest/SConscript +++ b/Swiften/QA/NetworkTest/SConscript @@ -11,6 +11,9 @@ if env["TEST"] : myenv.MergeFlags(myenv["SWIFTEN_DEP_FLAGS"]) myenv.MergeFlags(myenv["CPPUNIT_FLAGS"]) + if env.get("unbound", False) : + myenv.Append(CPPDEFINES = ["USE_UNBOUND"]) + tester = myenv.Program("NetworkTest", [ "BoostConnectionServerTest.cpp", "BoostConnectionTest.cpp", diff --git a/Swiften/SConscript b/Swiften/SConscript index aab9984..9da1858 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -6,7 +6,7 @@ Import("env") # Flags ################################################################################ -swiften_dep_modules = ["BOOST", "GCONF", "ICU", "LIBIDN", "ZLIB", "OPENSSL", "LIBXML", "EXPAT", "AVAHI", "LIBMINIUPNPC", "LIBNATPMP", "SQLITE"] +swiften_dep_modules = ["BOOST", "GCONF", "ICU", "LIBIDN", "ZLIB", "LDNS", "UNBOUND", "OPENSSL", "LIBXML", "EXPAT", "AVAHI", "LIBMINIUPNPC", "LIBNATPMP", "SQLITE"] external_swiften_dep_modules = ["BOOST"] if env["SCONS_STAGE"] == "flags" : @@ -65,7 +65,6 @@ if env["SCONS_STAGE"] == "flags" : if env.get("HAVE_SCHANNEL", 0) : dep_env.Append(LIBS = ["Winscard"]) - for var, e in [("SWIFTEN_FLAGS", swiften_env), ("SWIFTEN_DEP_FLAGS", dep_env)] : env[var] = { "CPPDEFINES": e.get("CPPDEFINES", []), @@ -471,7 +470,7 @@ if env["SCONS_STAGE"] == "build" : continue # Library-specific files - if file.endswith("_Private.h") or file.startswith("Schannel") or file.startswith("CAPI") or file.startswith("MacOSX") or file.startswith("Windows") or file.endswith("_Windows.h") or file.startswith("SQLite") or file == "ICUConverter.h" : + if file.endswith("_Private.h") or file.startswith("Schannel") or file.startswith("CAPI") or file.startswith("MacOSX") or file.startswith("Windows") or file.endswith("_Windows.h") or file.startswith("SQLite") or file == "ICUConverter.h" or file == "UnboundDomainNameResolver.h" : continue # Specific headers we don't want to globally include |