From 437e70ff9d254b11a30a4926010a91543d7f282c Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Tue, 13 Aug 2013 19:17:40 +0200 Subject: Adding basic support for Android and Unbound (No IPv6 yet). Change-Id: I1d74324515b20e0dc3d0ef4aa2f556fea7b4bee3 License: This patch is BSD-licensed, see Documentation/Licenses/BSD-simplified.txt for details.s diff --git a/3rdParty/Boost/02_android_compilation_fixes.diff b/3rdParty/Boost/02_android_compilation_fixes.diff new file mode 100644 index 0000000..9aba7e1 --- /dev/null +++ b/3rdParty/Boost/02_android_compilation_fixes.diff @@ -0,0 +1,36 @@ +diff --git a/3rdParty/Boost/src/boost/detail/endian.hpp b/3rdParty/Boost/src/boost/detail/endian.hpp +index 98c870c..ac77a2e 100644 +--- a/3rdParty/Boost/src/boost/detail/endian.hpp ++++ b/3rdParty/Boost/src/boost/detail/endian.hpp +@@ -66,8 +66,8 @@ + || defined(_M_ALPHA) || defined(__amd64) \ + || defined(__amd64__) || defined(_M_AMD64) \ + || defined(__x86_64) || defined(__x86_64__) \ +- || defined(_M_X64) || defined(__bfin__) +- ++ || defined(_M_X64) || defined(__bfin__) \ ++ || defined(ANDROID) + # define BOOST_LITTLE_ENDIAN + # define BOOST_BYTE_ORDER 1234 + #else +diff --git a/3rdParty/Boost/src/libs/filesystem/src/operations.cpp b/3rdParty/Boost/src/libs/filesystem/src/operations.cpp +index 16a336f..d066e40 100644 +--- a/3rdParty/Boost/src/libs/filesystem/src/operations.cpp ++++ b/3rdParty/Boost/src/libs/filesystem/src/operations.cpp +@@ -73,10 +73,14 @@ using std::wstring; + const fs::path dot_dot_path(".."); + # include + # include +-# if !defined(__APPLE__) && !defined(__OpenBSD__) ++# if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(ANDROID) + # include + # define BOOST_STATVFS statvfs + # define BOOST_STATVFS_F_FRSIZE vfs.f_frsize ++# elif defined (ANDROID) ++# include ++# define BOOST_STATVFS statfs ++# define BOOST_STATVFS_F_FRSIZE static_cast(vfs.f_bsize) + # else + # ifdef __OpenBSD__ + # include + -- \ No newline at end of file diff --git a/3rdParty/Ldns/01_andoird_compilation_fixes.diff b/3rdParty/Ldns/01_andoird_compilation_fixes.diff new file mode 100644 index 0000000..9d6ec08 --- /dev/null +++ b/3rdParty/Ldns/01_andoird_compilation_fixes.diff @@ -0,0 +1,15 @@ +--- 3rdParty/Ldns/src/ldns/ldns/ldns.h 2013-04-12 14:30:16.000000000 +0200 ++++ 3rdParty/Ldns/src/ldns/ldns/ldns.h 2013-04-12 14:30:48.000000000 +0200 +@@ -123,6 +123,12 @@ + #include + #include + ++#ifdef __ANDROID__ ++#ifndef in_port_t ++#define in_port_t uint16_t ++#endif ++#endif ++ + #ifdef __cplusplus + extern "C" { + #endif diff --git a/3rdParty/Ldns/SConscript b/3rdParty/Ldns/SConscript new file mode 100644 index 0000000..a43bde7 --- /dev/null +++ b/3rdParty/Ldns/SConscript @@ -0,0 +1,70 @@ +Import("env") + +if env.get("LDNS_BUNDLED", False) : + + if env["PLATFORM"] == "win32" : + cppflags = ["/I" + Dir("#/3rdParty/Ldns/src/ldns").abspath] + else : + cppflags = [("-isystem", Dir("#/3rdParty/Ldns/src/ldns").abspath)] + + +################################################################################ +# Flags +################################################################################ + + if env["SCONS_STAGE"] == "flags" : + env["LDNS_FLAGS"] = { + "CPPPATH": [Dir("src/ldns")], + "CPPFLAGS": cppflags, + "LIBPATH": [env.Dir(".")], + "LIBS": ["Swiften_Ldns"], + } + if env["target"] == "android" : + env["LDNS_FLAGS"]["CPPPATH"].append(Dir("src/android")) + +################################################################################ +# Build +################################################################################ + + if env["SCONS_STAGE"] == "build" : + myenv = env.Clone() + myenv.Append(CPPDEFINES = [("LDNS_STATICLIB")]) + myenv.Append(CPPPATH = ["src/ldns", "."]) + if env["target"] == "android" : + myenv.Append(CPPPATH = ["src/android"]) + myenv.UseFlags(env["OPENSSL_FLAGS"]) + + env["LDNS_OBJECTS"] = myenv.SwiftenObject([ + "src/ldns/compat/b32_ntop.c", + "src/ldns/compat/b32_pton.c", + "src/ldns/compat/b64_ntop.c", + "src/ldns/compat/b64_pton.c", + "src/ldns/buffer.c", + "src/ldns/dname.c", + "src/ldns/dnssec_sign.c", + "src/ldns/dnssec_verify.c", + "src/ldns/dnssec_zone.c", + "src/ldns/dnssec.c", + "src/ldns/error.c", + "src/ldns/higher.c", + "src/ldns/host2str.c", + "src/ldns/host2wire.c", + "src/ldns/keys.c", + "src/ldns/linktest.c", + "src/ldns/net.c", + "src/ldns/packet.c", + "src/ldns/parse.c", + "src/ldns/rbtree.c", + "src/ldns/rdata.c", + "src/ldns/resolver.c", + "src/ldns/rr_functions.c", + "src/ldns/rr.c", + "src/ldns/sha1.c", + "src/ldns/sha2.c", + "src/ldns/str2host.c", + "src/ldns/tsig.c", + "src/ldns/update.c", + "src/ldns/util.c", + "src/ldns/wire2host.c", + "src/ldns/zone.c", + ]) diff --git a/3rdParty/Ldns/prepare_ldns.sh b/3rdParty/Ldns/prepare_ldns.sh new file mode 100755 index 0000000..e057301 --- /dev/null +++ b/3rdParty/Ldns/prepare_ldns.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +curl -o src/ldns-1.6.16.tar.gz http://www.nlnetlabs.nl/downloads/ldns/ldns-1.6.16.tar.gz +cd src +tar -xf ldns-1.6.16.tar.gz +mv ldns-1.6.16 ldns \ No newline at end of file diff --git a/3rdParty/LibMiniUPnPc/01_android_compilation_fixes.diff b/3rdParty/LibMiniUPnPc/01_android_compilation_fixes.diff new file mode 100644 index 0000000..4d7ade5 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/01_android_compilation_fixes.diff @@ -0,0 +1,16 @@ +diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c +index 87f6155..0c31416 100644 +--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c ++++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c +@@ -44,6 +44,10 @@ + #define MIN(x,y) (((x)<(y))?(x):(y)) + #endif + ++#ifdef __ANDROID__ ++#define MIN(x,y) (((x)<(y))?(x):(y)) ++#endif ++ + #include "miniupnpcstrings.h" + #include "miniwget.h" + #include "connecthostport.h" +-- \ No newline at end of file diff --git a/3rdParty/LibNATPMP/01_android_compilation_fix.diff b/3rdParty/LibNATPMP/01_android_compilation_fix.diff new file mode 100644 index 0000000..78943aa --- /dev/null +++ b/3rdParty/LibNATPMP/01_android_compilation_fix.diff @@ -0,0 +1,34 @@ +diff --git a/3rdParty/LibNATPMP/src/libnatpmp/getgateway.h b/3rdParty/LibNATPMP/src/libnatpmp/getgateway.h +index 9432528..51dadb7 100644 +--- a/3rdParty/LibNATPMP/src/libnatpmp/getgateway.h ++++ b/3rdParty/LibNATPMP/src/libnatpmp/getgateway.h +@@ -27,6 +27,11 @@ typedef unsigned short uint16_t; + #endif + #include "declspec.h" + ++#ifdef ANDROID ++#include ++#define in_addr_t uint32_t ++#endif ++ + /* getdefaultgateway() : + * return value : + * 0 : success +diff --git a/3rdParty/LibNATPMP/src/libnatpmp/natpmp.h b/3rdParty/LibNATPMP/src/libnatpmp/natpmp.h +index 1175b58..c870371 100644 +--- a/3rdParty/LibNATPMP/src/libnatpmp/natpmp.h ++++ b/3rdParty/LibNATPMP/src/libnatpmp/natpmp.h +@@ -39,6 +39,12 @@ typedef unsigned short uint16_t; + #include + #endif + ++#ifdef ANDROID ++#include ++#define in_addr_t uint32_t ++#endif ++ ++ + typedef struct { + int s; /* socket */ + in_addr_t gateway; /* default gateway (IPv4) */ +-- \ No newline at end of file diff --git a/3rdParty/Unbound/01_android_fixes.diff b/3rdParty/Unbound/01_android_fixes.diff new file mode 100644 index 0000000..c8144ad --- /dev/null +++ b/3rdParty/Unbound/01_android_fixes.diff @@ -0,0 +1,13 @@ +--- a/3rdParty/Unbound/src/unbound/libunbound/libunbound.c ++++ b/3rdParty/Unbound/src/unbound/libunbound/libunbound.c +@@ -812,6 +812,10 @@ ub_ctx_resolvconf(struct ub_ctx* ctx, char* fname) + char* parse, *addr; + int r; + ++#ifdef __ANDROID__ ++ ub_ctx_set_fwd(ctx, "8.8.8.8"); ++ ub_ctx_set_fwd(ctx, "8.8.4.4"); ++#endif + if(fname == NULL) { + #if !defined(UB_ON_WINDOWS) || !defined(HAVE_WINDOWS_H) + fname = "/etc/resolv.conf"; \ No newline at end of file diff --git a/3rdParty/Unbound/SConscript b/3rdParty/Unbound/SConscript new file mode 100644 index 0000000..99cd6a3 --- /dev/null +++ b/3rdParty/Unbound/SConscript @@ -0,0 +1,108 @@ +Import("env") + +if env.get("UNBOUND_BUNDLED", False) : + + if env["PLATFORM"] == "win32" : + cppflags = ["/I" + Dir("#/3rdParty/Unbound/src/unbound").abspath] + else : + cppflags = [("-isystem", Dir("#/3rdParty/Unbound/src/unbound").abspath)] + + +################################################################################ +# Flags +################################################################################ + + if env["SCONS_STAGE"] == "flags" : + env["UNBOUND_FLAGS"] = { + "CPPPATH": [Dir("src/unbound/libunbound")], + "CPPFLAGS": cppflags, + "LIBPATH": [env.Dir(".")], + "LIBS": ["Swiften_Unbound"], + } + if env["target"] == "android" : + env["UNBOUND_FLAGS"]["CPPPATH"].append(Dir("src/android/compat")) + +################################################################################ +# Build +################################################################################ + + if env["SCONS_STAGE"] == "build" : + myenv = env.Clone() + myenv.Append(CPPDEFINES = [("UNBOUND_STATICLIB")]) + myenv.Append(CPPPATH = ["../Ldns/src/ldns", "src/unbound", "."]) + if env["target"] == "android" : + myenv.Append(CPPPATH = ["src/android/compat", "src/android/config"]) + myenv.Append(CPPPATH = ["../Ldns/src/android"]) + myenv.UseFlags(env["OPENSSL_FLAGS"]) + + unbound_objects = [ + "src/unbound/daemon/acl_list.c", + "src/unbound/daemon/cachedump.c", + "src/unbound/daemon/daemon.c", + "src/unbound/daemon/remote.c", + "src/unbound/daemon/stats.c", + "src/unbound/daemon/unbound.c", + # duplicate symbols: "src/src/daemon/worker.c", + "src/unbound/iterator/iter_delegpt.c", + "src/unbound/iterator/iter_donotq.c", + "src/unbound/iterator/iter_fwd.c", + "src/unbound/iterator/iter_hints.c", + "src/unbound/iterator/iter_priv.c", + "src/unbound/iterator/iter_resptype.c", + "src/unbound/iterator/iter_scrub.c", + "src/unbound/iterator/iter_utils.c", + "src/unbound/iterator/iterator.c", + "src/unbound/libunbound/context.c", + "src/unbound/libunbound/libunbound.c", + "src/unbound/libunbound/libworker.c", + "src/unbound/services/cache/dns.c", + "src/unbound/services/cache/infra.c", + "src/unbound/services/cache/rrset.c", + "src/unbound/services/listen_dnsport.c", + "src/unbound/services/localzone.c", + "src/unbound/services/mesh.c", + "src/unbound/services/modstack.c", + "src/unbound/services/outbound_list.c", + "src/unbound/services/outside_network.c", + "src/unbound/util/alloc.c", + "src/unbound/util/config_file.c", + "src/unbound/util/configlexer.c", + "src/unbound/util/configparser.c", + "src/unbound/util/data/dname.c", + "src/unbound/util/data/msgencode.c", + "src/unbound/util/data/msgparse.c", + "src/unbound/util/data/msgreply.c", + "src/unbound/util/data/packed_rrset.c", + "src/unbound/util/fptr_wlist.c", + "src/unbound/util/locks.c", + "src/unbound/util/log.c", + "src/unbound/util/mini_event.c", + "src/unbound/util/module.c", + "src/unbound/util/net_help.c", + "src/unbound/util/netevent.c", + "src/unbound/util/random.c", + "src/unbound/util/rbtree.c", + "src/unbound/util/regional.c", + "src/unbound/util/rtt.c", + "src/unbound/util/storage/dnstree.c", + "src/unbound/util/storage/lookup3.c", + "src/unbound/util/storage/lruhash.c", + "src/unbound/util/storage/slabhash.c", + "src/unbound/util/timehist.c", + "src/unbound/util/tube.c", + #src/unbound/util/winsock_event.c + "src/unbound/validator/autotrust.c", + "src/unbound/validator/val_anchor.c", + "src/unbound/validator/val_kcache.c", + "src/unbound/validator/val_kentry.c", + "src/unbound/validator/val_neg.c", + "src/unbound/validator/val_nsec.c", + "src/unbound/validator/val_nsec3.c", + "src/unbound/validator/val_secalgo.c", + "src/unbound/validator/val_sigcrypt.c", + "src/unbound/validator/val_utils.c", + "src/unbound/validator/validator.c", + ] + if env["target"] == "android" : + unbound_objects.append("src/android/compat/glob.c") + env["UNBOUND_OBJECTS"] = myenv.SwiftenObject(unbound_objects) diff --git a/3rdParty/Unbound/prepare_unbound.sh b/3rdParty/Unbound/prepare_unbound.sh new file mode 100755 index 0000000..b506ae4 --- /dev/null +++ b/3rdParty/Unbound/prepare_unbound.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +curl -o src/unbound-1.4.20.tar.gz http://www.unbound.net/downloads/unbound-1.4.20.tar.gz +cd src +tar -xf unbound-1.4.20.tar.gz +mv unbound-1.4.20 unbound \ No newline at end of file diff --git a/BuildTools/SCons/SConscript.boot b/BuildTools/SCons/SConscript.boot index 9ac3cca..8429737 100644 --- a/BuildTools/SCons/SConscript.boot +++ b/BuildTools/SCons/SConscript.boot @@ -19,7 +19,9 @@ vars.Add(BoolVariable("debug", "Compile with debug information", "yes")) vars.Add(BoolVariable("allow_warnings", "Allow compilation warnings during compilation", "yes")) vars.Add(BoolVariable("assertions", "Compile with assertions", "yes")) vars.Add(BoolVariable("max_jobs", "Build with maximum number of parallel jobs", "no")) -vars.Add(EnumVariable("target", "Choose a target platform for compilation", "native", ["native", "iphone-simulator", "iphone-device", "xcode"])) +vars.Add(EnumVariable("target", "Choose a target platform for compilation", "native", ["native", "iphone-simulator", "iphone-device", "xcode", "android"])) +vars.Add('android_toolchain', "Path to Android toolchain") +vars.Add('android_sdk_bin', "Path to Android SDK's tools directory") vars.Add(BoolVariable("swift_mobile", "Build mobile Swift", "no")) vars.Add(BoolVariable("swiften_dll", "Build Swiften as dynamically linked library", "no")) if os.name != "nt" : @@ -68,6 +70,7 @@ vars.Add(BoolVariable("build_examples", "Build example programs", "yes")) vars.Add(BoolVariable("enable_variants", "Build in a separate dir under build/, depending on compile flags", "no")) vars.Add(BoolVariable("experimental", "Build experimental features", "yes")) vars.Add(BoolVariable("set_iterator_debug_level", "Set _ITERATOR_DEBUG_LEVEL=0", "yes")) +vars.Add(BoolVariable("unbound", "Build bundled ldns and unbound. Use them for DNS lookup.", "no")) ################################################################################ # Set up default build & configure environment @@ -284,7 +287,7 @@ if env["PLATFORM"] == "win32" : env["LINKCOM"] = [env["LINKCOM"], 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;1'] env["SHLINKCOM"] = [env["SHLINKCOM"], 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;2'] -if env["PLATFORM"] == "darwin" and not env["target"] in ["iphone-device", "iphone-simulator", "xcode"] : +if env["PLATFORM"] == "darwin" and not env["target"] in ["iphone-device", "iphone-simulator", "xcode", "android"] : env["PLATFORM_FLAGS"]["FRAMEWORKS"] += ["IOKit", "AppKit", "SystemConfiguration", "Security", "SecurityInterface"] # Testing @@ -351,6 +354,17 @@ if target in ["iphone-device", "iphone-simulator", "xcode"] : # Bit of a hack, because BOOST doesn't know the endianness for ARM env.Append(CPPDEFINES = ["_LITTLE_ENDIAN"]) +################################################################################ +# Android +################################################################################ +if target in ["android"] : + env["ENV"]["PATH"] = env["android_toolchain"] + "/bin:" + env["ENV"]["PATH"] + env["CC"] = "arm-linux-androideabi-gcc" + env["CXX"] = "arm-linux-androideabi-g++" + env["RANLIB"] = "arm-linux-androideabi-ranlib" + env.Append(CPPDEFINES = ["ANDROID"]) + env.Append(CPPDEFINES = ["_REENTRANT", "_GLIBCXX__PTHREADS"]) + # CCache if env.get("ccache", False) : env["ENV"]["HOME"] = os.environ["HOME"] diff --git a/BuildTools/SCons/SConstruct b/BuildTools/SCons/SConstruct index 75baf21..8f4d440 100644 --- a/BuildTools/SCons/SConstruct +++ b/BuildTools/SCons/SConstruct @@ -333,6 +333,14 @@ if not env.get("HAVE_ICU", False) and not env.get("HAVE_LIBIDN", False) : env["HAVE_LIBIDN"] = 1 env["LIBIDN_BUNDLED"] = 1 +# Unbound +if env["unbound"] : + env["LDNS_BUNDLED"] = 1 + env["UNBOUND_BUNDLED"] = 1 +else : + env["LDNS_FLAGS"] = {} + env["UNBOUND_FLAGS"] = {} + # LibMiniUPnPc if env["experimental"] : libminiupnpc_flags = {"CPPPATH": ["/usr/include/miniupnpc/"]} @@ -427,7 +435,7 @@ if env["qt"] : # OpenSSL openssl_env = conf_env.Clone() -if env.get("openssl_force_bundled", False) or env["target"] in ("iphone-device", "iphone-simulator", "xcode") : +if env.get("openssl_force_bundled", False) or env["target"] in ("iphone-device", "iphone-simulator", "xcode", "android") : env["OPENSSL_BUNDLED"] = True env["HAVE_OPENSSL"] = True else : @@ -480,7 +488,7 @@ if hunspell_conf.CheckCXXHeader("hunspell/hunspell.hxx") and hunspell_conf.Check hunspell_conf.Finish() # Bonjour -if env["PLATFORM"] == "darwin" : +if env["PLATFORM"] == "darwin" and env["target"] == "native" : env["HAVE_BONJOUR"] = 1 elif env.get("bonjour", False) : bonjour_env = conf_env.Clone() diff --git a/BuildTools/SCons/Tools/Test.py b/BuildTools/SCons/Tools/Test.py index c52f448..ee16ec4 100644 --- a/BuildTools/SCons/Tools/Test.py +++ b/BuildTools/SCons/Tools/Test.py @@ -19,13 +19,24 @@ def generate(env) : for i in ["HOME", "USERPROFILE", "APPDATA"]: if os.environ.get(i, "") : test_env["ENV"][i] = os.environ[i] - if test_env["PLATFORM"] == "darwin" : - test_env["ENV"]["DYLD_FALLBACK_LIBRARY_PATH"] = ":".join(map(lambda x : str(x), test_env.get("LIBPATH", []))) - elif test_env["PLATFORM"] == "win32" : - test_env["ENV"]["PATH"] = ";".join(map(lambda x : str(x), test_env.get("LIBRUNPATH", []))) + ";" + test_env["ENV"]["PATH"] + if env["target"] == "android" : + test_env["ENV"]["PATH"] = env["android_sdk_bin"] + ";" + test_env["ENV"]["PATH"] + else : + if test_env["PLATFORM"] == "darwin" : + test_env["ENV"]["DYLD_FALLBACK_LIBRARY_PATH"] = ":".join(map(lambda x : str(x), test_env.get("LIBPATH", []))) + elif test_env["PLATFORM"] == "win32" : + test_env["ENV"]["PATH"] = ";".join(map(lambda x : str(x), test_env.get("LIBRUNPATH", []))) + ";" + test_env["ENV"]["PATH"] + # Run the test - test_env.Command("**dummy**", target, + if env["target"] == "android": + exec_name = os.path.basename(cmd) + test_env.Command("**dummy**", target, SCons.Action.Action( + ["adb shell mount -o rw,remount /system", + "adb push " + cmd + " /system/usr/bin/" + exec_name, + "adb shell SWIFT_CLIENTTEST_JID=\"" + os.getenv("SWIFT_CLIENTTEST_JID") + "\" SWIFT_CLIENTTEST_PASS=\"" + os.getenv("SWIFT_CLIENTTEST_PASS") + "\" " + env.get("TEST_RUNNER", "") + "/system/usr/bin/" + exec_name], cmdstr = "$TESTCOMSTR")) + else : + test_env.Command("**dummy**", target, SCons.Action.Action(ignore_prefix + env.get("TEST_RUNNER", "") + cmd + " " + params, cmdstr = "$TESTCOMSTR")) def registerScriptTests(env, scripts, name, type) : 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 #include #include -#include + #include #include #include @@ -20,6 +20,12 @@ #include #include +#ifdef USE_UNBOUND +#include +#else +#include +#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 + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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 query) : resolver(resolver), query(query) {} + UnboundDomainNameResolver* resolver; + boost::shared_ptr query; +}; + +class UnboundDomainNameServiceQuery : public DomainNameServiceQuery, public UnboundQuery, public boost::enable_shared_from_this { + 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(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 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(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(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 { + 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(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 addresses; + boost::optional 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 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(); + + 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("/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("/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 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(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 UnboundDomainNameResolver::createServiceQuery(const std::string& name) { + return boost::make_shared(this, ubContext, name); +} + +boost::shared_ptr UnboundDomainNameResolver::createAddressQuery(const std::string& name) { + return boost::make_shared(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 +#include +#include + +#include +#include +#include + +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 { + public: + UnboundDomainNameResolver(boost::shared_ptr ioService, EventLoop* eventLoop); + virtual ~UnboundDomainNameResolver(); + + virtual boost::shared_ptr createServiceQuery(const std::string& name); + virtual boost::shared_ptr createAddressQuery(const std::string& name); + + static void unbound_callback_wrapper(void* data, int err, ub_result* result); + + private: + void unbound_callback(boost::shared_ptr query, int err, ub_result* result); + + void handleUBSocketReadable(boost::system::error_code); + void processData(); + + private: + boost::shared_ptr eventOwner; + boost::shared_ptr 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 #include #include + +#ifndef __ANDROID__ #include +#endif #include #include @@ -24,7 +27,7 @@ namespace Swift { std::vector UnixNetworkEnvironment::getNetworkInterfaces() const { std::map interfaces; - +#ifndef __ANDROID__ ifaddrs* addrs = 0; int ret = getifaddrs(&addrs); if (ret != 0) { @@ -49,7 +52,7 @@ std::vector UnixNetworkEnvironment::getNetworkInterfaces() con } freeifaddrs(addrs); - +#endif std::vector result; for (std::map::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 #include - #include #include #include +#ifdef USE_UNBOUND +#include +#else #include +#endif +#include +#include +#include #include #include #include @@ -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(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; + boost::shared_ptr timerFactory; bool resultsAvailable; std::vector addressQueryResult; std::vector allAddressQueryResults; boost::optional addressQueryError; std::vector 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 -- cgit v0.10.2-6-g49f6