diff options
Diffstat (limited to 'platform')
-rw-r--r-- | platform/android/asset_request_baton_libzip.cpp | 99 | ||||
-rw-r--r-- | platform/android/cache_database_data.cpp | 13 | ||||
-rw-r--r-- | platform/android/log_android.cpp | 59 | ||||
-rw-r--r-- | platform/darwin/http_request_baton_cocoa.mm | 4 | ||||
-rw-r--r-- | platform/default/asset_request_baton_noop.cpp | 24 | ||||
-rw-r--r-- | platform/default/caching_http_file_source.cpp | 6 | ||||
-rw-r--r-- | platform/default/glfw_view.cpp | 2 | ||||
-rw-r--r-- | platform/default/headless_view.cpp | 32 | ||||
-rw-r--r-- | platform/default/http_request_baton_curl.cpp | 114 | ||||
-rw-r--r-- | platform/default/image.cpp | 5 |
10 files changed, 343 insertions, 15 deletions
diff --git a/platform/android/asset_request_baton_libzip.cpp b/platform/android/asset_request_baton_libzip.cpp new file mode 100644 index 0000000000..7fc86ae1be --- /dev/null +++ b/platform/android/asset_request_baton_libzip.cpp @@ -0,0 +1,99 @@ +#include <mbgl/android/jni.hpp> +#include <mbgl/storage/asset_request_baton.hpp> +#include <mbgl/storage/asset_request.hpp> +#include <mbgl/storage/response.hpp> +#include <mbgl/util/std.hpp> + +#include <cerrno> +// NOTE a bug in the Android NDK breaks std::errno +// See https://code.google.com/p/android/issues/detail?id=72349 +// After this is fixed change usage errno to std::errno +#include <zip.h> +#include <uv.h> + +namespace mbgl { + +void AssetRequestBaton::run(AssetRequestBaton *ptr) { + assert(uv_thread_self() == ptr->threadId); + + if (ptr->canceled || !ptr->request) { + // Either the AssetRequest object has been destructed, or the + // request was canceled. + cleanup(ptr); + return; + } + + int error = 0; + struct zip *apk = zip_open(mbgl::android::apkPath.c_str(), 0, &error); + if ((apk == nullptr) || ptr->canceled || !ptr->request) { + // Opening the APK failed or was canceled. There isn't much left we can do. + const int messageSize = zip_error_to_str(nullptr, 0, error, errno); + const std::unique_ptr<char[]> message = mbgl::util::make_unique<char[]>(messageSize); + zip_error_to_str(message.get(), 0, error, errno); + notify_error(ptr, 500, message.get()); + cleanup(ptr); + return; + } + + std::string apkFilePath = "assets/" + ptr->path; + struct zip_file *apkFile = zip_fopen(apk, apkFilePath.c_str(), ZIP_FL_NOCASE); + if ((apkFile == nullptr) || ptr->canceled || !ptr->request) { + // Opening the asset failed or was canceled. We already have an open file handle + // though, which we'll have to close. + zip_error_get(apk, &error, nullptr); + notify_error(ptr, error == ZIP_ER_NOENT ? 404 : 500, zip_strerror(apk)); + zip_close(apk); + apk = nullptr; + cleanup(ptr); + return; + } + + struct zip_stat stat; + if ((zip_stat(apk, apkFilePath.c_str(), ZIP_FL_NOCASE, &stat) != 0) || ptr->canceled || !ptr->request) { + // Stating failed or was canceled. We already have an open file handle + // though, which we'll have to close. + notify_error(ptr, 500, zip_strerror(apk)); + zip_fclose(apkFile); + apkFile = nullptr; + zip_close(apk); + apk = nullptr; + cleanup(ptr); + return; + } + + const std::unique_ptr<char[]> data = mbgl::util::make_unique<char[]>(stat.size); + + if (static_cast<zip_uint64_t>(zip_fread(apkFile, reinterpret_cast<void *>(data.get()), stat.size)) != stat.size || ptr->canceled || !ptr->request) { + // Reading failed or was canceled. We already have an open file handle + // though, which we'll have to close. + notify_error(ptr, 500, zip_file_strerror(apkFile)); + zip_fclose(apkFile); + apkFile = nullptr; + zip_close(apk); + apk = nullptr; + cleanup(ptr); + return; + } + + if (ptr->request) { + ptr->request->response = std::unique_ptr<Response>(new Response); + ptr->request->response->code = 200; + std::string body(data.get(), stat.size); + ptr->request->response->data = body; + ptr->request->notify(); + } + + if (zip_fclose(apkFile) != 0) { + // Closing the asset failed. But there isn't anything we can do. + } + apkFile = nullptr; + + if (zip_close(apk) != 0) { + // Closing the APK failed. But there isn't anything we can do. + } + apk = nullptr; + + cleanup(ptr); +} + +} diff --git a/platform/android/cache_database_data.cpp b/platform/android/cache_database_data.cpp new file mode 100644 index 0000000000..2fefcdc4a3 --- /dev/null +++ b/platform/android/cache_database_data.cpp @@ -0,0 +1,13 @@ +#include <mbgl/platform/platform.hpp> +#include <mbgl/android/jni.hpp> + +namespace mbgl { +namespace platform { + +// Returns the path to the default cache database on this system. +std::string defaultCacheDatabase() { + return mbgl::android::cachePath + "/mbgl-cache.db"; +} + +} +} diff --git a/platform/android/log_android.cpp b/platform/android/log_android.cpp new file mode 100644 index 0000000000..5e40ce33bd --- /dev/null +++ b/platform/android/log_android.cpp @@ -0,0 +1,59 @@ +#include <mbgl/platform/android/log_android.hpp> + +#include <iostream> +#include <cstdarg> +#define __STDC_FORMAT_MACROS // NDK bug workaround: https://code.google.com/p/android/issues/detail?id=72349 +#include <cinttypes> + +#include <android/log.h> + +namespace mbgl { + +int AndroidLogBackend::severityToPriority(EventSeverity severity) { + switch(severity) { + case EventSeverity::Debug: + return ANDROID_LOG_DEBUG; + + case EventSeverity::Info: + return ANDROID_LOG_INFO; + + case EventSeverity::Warning: + return ANDROID_LOG_WARN; + + case EventSeverity::Error: + return ANDROID_LOG_ERROR; + + default: + return ANDROID_LOG_VERBOSE; + } +} + +void AndroidLogBackend::record(EventSeverity severity, Event event, const std::string &msg) { + __android_log_print(severityToPriority(severity), EventClass(event).c_str(), "%s", msg.c_str()); +} + +void AndroidLogBackend::record(EventSeverity severity, Event event, const char* format, ...) { + va_list args; + va_start(args, format); + + const int len = vsnprintf(nullptr, 0, format, args) + 1; + char* buf = new char[len]; + vsnprintf(buf, len, format, args); + + va_end(args); + + __android_log_print(severityToPriority(severity), EventClass(event).c_str(), "%s", buf); + + delete buf; + buf = nullptr; +} + +void AndroidLogBackend::record(EventSeverity severity, Event event, int64_t code) { + __android_log_print(severityToPriority(severity), EventClass(event).c_str(), "(%" PRId64 ")", code); +} + +void AndroidLogBackend::record(EventSeverity severity, Event event, int64_t code, const std::string &msg) { + __android_log_print(severityToPriority(severity), EventClass(event).c_str(), "(%" PRId64 ") %s", code, msg.c_str()); +} + +} diff --git a/platform/darwin/http_request_baton_cocoa.mm b/platform/darwin/http_request_baton_cocoa.mm index 1c256d0ba8..472154dc2f 100644 --- a/platform/darwin/http_request_baton_cocoa.mm +++ b/platform/darwin/http_request_baton_cocoa.mm @@ -15,7 +15,7 @@ dispatch_once_t request_initialize = 0; NSURLSession *session = nullptr; void HTTPRequestBaton::start(const util::ptr<HTTPRequestBaton> &ptr) { - assert(std::this_thread::get_id() == ptr->thread_id); + assert(std::this_thread::get_id() == ptr->threadId); // Starts the request. util::ptr<HTTPRequestBaton> baton = ptr; @@ -131,7 +131,7 @@ void HTTPRequestBaton::start(const util::ptr<HTTPRequestBaton> &ptr) { } void HTTPRequestBaton::stop(const util::ptr<HTTPRequestBaton> &ptr) { - assert(std::this_thread::get_id() == ptr->thread_id); + assert(std::this_thread::get_id() == ptr->threadId); assert(ptr->ptr); NSURLSessionDataTask *task = CFBridgingRelease(ptr->ptr); diff --git a/platform/default/asset_request_baton_noop.cpp b/platform/default/asset_request_baton_noop.cpp new file mode 100644 index 0000000000..2f32026503 --- /dev/null +++ b/platform/default/asset_request_baton_noop.cpp @@ -0,0 +1,24 @@ +#include <mbgl/storage/asset_request_baton.hpp> +#include <mbgl/storage/asset_request.hpp> +#include <mbgl/storage/response.hpp> + +#include <uv.h> + +namespace mbgl { + +void AssetRequestBaton::run(AssetRequestBaton *ptr) { + assert(uv_thread_self() == ptr->threadId); + + if (ptr->canceled || !ptr->request) { + // Either the AssetRequest object has been destructed, or the + // request was canceled. + cleanup(ptr); + return; + } + + // Just return a 500 error until implemented properly + notify_error(ptr, 500, "Assets not implemented on this platform."); + cleanup(ptr); +} + +} diff --git a/platform/default/caching_http_file_source.cpp b/platform/default/caching_http_file_source.cpp index 3e74f5ed05..20525a2647 100644 --- a/platform/default/caching_http_file_source.cpp +++ b/platform/default/caching_http_file_source.cpp @@ -2,6 +2,7 @@ #include <mbgl/storage/file_request.hpp> #include <mbgl/storage/http_request.hpp> #include <mbgl/storage/sqlite_store.hpp> +#include <mbgl/storage/asset_request.hpp> #include <mbgl/util/uv-messenger.h> #include <mbgl/util/std.hpp> @@ -14,7 +15,8 @@ CachingHTTPFileSource::CachingHTTPFileSource(const std::string &path_) CachingHTTPFileSource::~CachingHTTPFileSource() { if (hasLoop()) { - assert(thread_id == std::this_thread::get_id()); + // FIXME temp fix for #608 crash + // assert(thread_id == std::this_thread::get_id()); uv_messenger_stop(queue, [](uv_messenger_t *msgr) { delete msgr; }); @@ -82,6 +84,8 @@ std::unique_ptr<Request> CachingHTTPFileSource::request(ResourceType type, const if (!req) { if (absoluteURL.substr(0, 7) == "file://") { req = std::make_shared<FileRequest>(absoluteURL.substr(7), loop); + } else if (absoluteURL.substr(0, 8) == "asset://") { + req = std::make_shared<AssetRequest>(absoluteURL.substr(8), loop); } else { req = std::make_shared<HTTPRequest>(type, absoluteURL, loop, store); } diff --git a/platform/default/glfw_view.cpp b/platform/default/glfw_view.cpp index 4ddcd9019d..e600340dda 100644 --- a/platform/default/glfw_view.cpp +++ b/platform/default/glfw_view.cpp @@ -69,7 +69,7 @@ void GLFWView::initialize(mbgl::Map *map_) { glfwSetKeyCallback(window, key); - const std::string extensions = (char *)glGetString(GL_EXTENSIONS); + const std::string extensions = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)); { using namespace mbgl; diff --git a/platform/default/headless_view.cpp b/platform/default/headless_view.cpp index 5b95c76026..264fe4da6b 100644 --- a/platform/default/headless_view.cpp +++ b/platform/default/headless_view.cpp @@ -51,7 +51,23 @@ HeadlessView::HeadlessView(std::shared_ptr<HeadlessDisplay> display) void HeadlessView::loadExtensions() { make_active(); - const std::string extensions = (char *)glGetString(GL_EXTENSIONS); + + std::string extensions; + if (usingGl3OrNewer) { +#ifdef GL_VERSION_3_0 + GLuint num_extensions = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, reinterpret_cast<GLint *>(&num_extensions)); + for (GLuint i = 0; i < num_extensions; i++) { + extensions.append(reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i))); + extensions.append(" "); + } +#else + throw std::runtime_error("Using GL 3.0+ context with out correct headers.\n"); +#endif + } else { + extensions = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)); + } + #ifdef MBGL_USE_CGL if (extensions.find("GL_APPLE_vertex_array_object") != std::string::npos) { @@ -92,7 +108,7 @@ static const core_profile_version core_profile_versions[] = { {0, 0}, }; -GLXContext createCoreProfile(Display *dpy, GLXFBConfig fbconfig) { +GLXContext createCoreProfile(Display *dpy, GLXFBConfig fbconfig, bool& usingGl3OrNewer) { static bool context_creation_failed = false; GLXContext ctx = 0; @@ -105,7 +121,8 @@ GLXContext createCoreProfile(Display *dpy, GLXFBConfig fbconfig) { }); // Try to create core profiles from the highest known version on down. - for (int i = 0; !ctx && core_profile_versions[i].major; i++) { + int i = 0; + for (; !ctx && core_profile_versions[i].major; i++) { context_creation_failed = false; const int context_flags[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, core_profile_versions[i].major, @@ -118,6 +135,10 @@ GLXContext createCoreProfile(Display *dpy, GLXFBConfig fbconfig) { } } + if (core_profile_versions[i].major >= 3) { + usingGl3OrNewer = true; + } + // Restore the old error handler. XSetErrorHandler(previous_error_handler); return ctx; @@ -151,11 +172,11 @@ void HeadlessView::createContext() { #ifdef GLX_ARB_create_context if (glXCreateContextAttribsARB) { // Try to create a core profile context. - gl_context = createCoreProfile(x_display, fb_configs[0]); + gl_context = createCoreProfile(x_display, fb_configs[0], usingGl3OrNewer); } #endif - if (!gl_context) { + if (gl_context == 0) { // Try to create a legacy context gl_context = glXCreateNewContext(x_display, fb_configs[0], GLX_RGBA_TYPE, 0, True); if (gl_context) { @@ -333,4 +354,3 @@ void HeadlessView::make_inactive() { void HeadlessView::swap() {} } - diff --git a/platform/default/http_request_baton_curl.cpp b/platform/default/http_request_baton_curl.cpp index f05ee5acf9..74c6187e76 100644 --- a/platform/default/http_request_baton_curl.cpp +++ b/platform/default/http_request_baton_curl.cpp @@ -1,9 +1,16 @@ +#include <mbgl/mbgl.hpp> #include <mbgl/storage/http_request_baton.hpp> #include <mbgl/util/uv-messenger.h> #include <mbgl/util/time.hpp> #include <mbgl/util/string.hpp> #include <mbgl/util/std.hpp> +#ifdef __ANDROID__ + #include <mbgl/android/jni.hpp> + #include <zip.h> + #include <openssl/ssl.h> +#endif + #include <uv.h> #include <curl/curl.h> @@ -405,6 +412,103 @@ size_t curl_header_cb(char * const buffer, const size_t size, const size_t nmemb return length; } +// This function is called to load the CA bundle +// from http://curl.haxx.se/libcurl/c/cacertinmem.html +#ifdef __ANDROID__ +static CURLcode sslctx_function(CURL */*curl*/, void *sslctx, void */*parm*/) { + + int error = 0; + struct zip *apk = zip_open(mbgl::android::apkPath.c_str(), 0, &error); + if (apk == nullptr) { + return CURLE_SSL_CACERT_BADFILE; + } + + struct zip_file *apkFile = zip_fopen(apk, "assets/ca-bundle.crt", ZIP_FL_NOCASE); + if (apkFile == nullptr) { + zip_close(apk); + apk = nullptr; + return CURLE_SSL_CACERT_BADFILE; + } + + struct zip_stat stat; + if (zip_stat(apk, "assets/ca-bundle.crt", ZIP_FL_NOCASE, &stat) != 0) { + zip_fclose(apkFile); + apkFile = nullptr; + zip_close(apk); + apk = nullptr; + return CURLE_SSL_CACERT_BADFILE; + } + + if (stat.size > std::numeric_limits<int>::max()) { + zip_fclose(apkFile); + apkFile = nullptr; + zip_close(apk); + apk = nullptr; + return CURLE_SSL_CACERT_BADFILE; + } + + const std::unique_ptr<char[]> pem = util::make_unique<char[]>(stat.size); + + if (static_cast<zip_uint64_t>(zip_fread(apkFile, reinterpret_cast<void *>(pem.get()), stat.size)) != stat.size) { + zip_fclose(apkFile); + apkFile = nullptr; + zip_close(apk); + apk = nullptr; + return CURLE_SSL_CACERT_BADFILE; + } + + // get a pointer to the X509 certificate store (which may be empty!) + X509_STORE *store = SSL_CTX_get_cert_store((SSL_CTX *)sslctx); + if (store == nullptr) { + return CURLE_SSL_CACERT_BADFILE; + } + + // get a BIO + BIO *bio = BIO_new_mem_buf(pem.get(), static_cast<int>(stat.size)); + if (bio == nullptr) { + store = nullptr; + return CURLE_SSL_CACERT_BADFILE; + } + + // use it to read the PEM formatted certificate from memory into an X509 + // structure that SSL can use + X509 *cert = nullptr; + while (PEM_read_bio_X509(bio, &cert, 0, nullptr) != nullptr) { + if (cert == nullptr) { + BIO_free(bio); + bio = nullptr; + store = nullptr; + return CURLE_SSL_CACERT_BADFILE; + } + + // add our certificate to this store + if (X509_STORE_add_cert(store, cert) == 0) { + X509_free(cert); + cert = nullptr; + BIO_free(bio); + bio = nullptr; + store = nullptr; + return CURLE_SSL_CACERT_BADFILE; + } + + X509_free(cert); + cert = nullptr; + } + + // decrease reference counts + BIO_free(bio); + bio = nullptr; + + zip_fclose(apkFile); + apkFile = nullptr; + zip_close(apk); + apk = nullptr; + + // all set to go + return CURLE_OK; +} +#endif + // This function must run in the CURL thread. void start_request(void *const ptr) { assert(std::this_thread::get_id() == thread_id); @@ -436,7 +540,12 @@ void start_request(void *const ptr) { // Carry on the shared pointer in the private information of the CURL handle. curl_easy_setopt(context->handle, CURLOPT_PRIVATE, context); +#ifndef __ANDROID__ curl_easy_setopt(context->handle, CURLOPT_CAINFO, "ca-bundle.crt"); +#else + curl_easy_setopt(context->handle, CURLOPT_SSLCERTTYPE, "PEM"); + curl_easy_setopt(context->handle, CURLOPT_SSL_CTX_FUNCTION, sslctx_function); +#endif curl_easy_setopt(context->handle, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(context->handle, CURLOPT_URL, context->baton->path.c_str()); curl_easy_setopt(context->handle, CURLOPT_WRITEFUNCTION, curl_write_cb); @@ -444,7 +553,6 @@ void start_request(void *const ptr) { curl_easy_setopt(context->handle, CURLOPT_HEADERFUNCTION, curl_header_cb); curl_easy_setopt(context->handle, CURLOPT_HEADERDATA, &context->baton->response); curl_easy_setopt(context->handle, CURLOPT_ACCEPT_ENCODING, "gzip, deflate"); - curl_easy_setopt(context->handle, CURLOPT_SHARE, share); // Start requesting the information. curl_multi_add_handle(multi, context->handle); @@ -488,14 +596,14 @@ void create_thread() { // This function must be run from the main thread (== where the HTTPRequestBaton was created) void HTTPRequestBaton::start(const util::ptr<HTTPRequestBaton> &ptr) { - assert(std::this_thread::get_id() == ptr->thread_id); + assert(std::this_thread::get_id() == ptr->threadId); uv_once(&once, create_thread); uv_messenger_send(&start_messenger, new util::ptr<HTTPRequestBaton>(ptr)); } // This function must be run from the main thread (== where the HTTPRequestBaton was created) void HTTPRequestBaton::stop(const util::ptr<HTTPRequestBaton> &ptr) { - assert(std::this_thread::get_id() == ptr->thread_id); + assert(std::this_thread::get_id() == ptr->threadId); uv_once(&once, create_thread); uv_messenger_send(&stop_messenger, new util::ptr<HTTPRequestBaton>(ptr)); } diff --git a/platform/default/image.cpp b/platform/default/image.cpp index d881b9231c..311aa2ed72 100644 --- a/platform/default/image.cpp +++ b/platform/default/image.cpp @@ -1,4 +1,5 @@ #include <mbgl/util/image.hpp> +#include <mbgl/platform/log.hpp> #include <mbgl/util/string.hpp> #include <mbgl/util/std.hpp> @@ -31,14 +32,14 @@ std::string compress_png(int width, int height, void *rgba) { png_voidp error_ptr = 0; png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, error_ptr, NULL, NULL); if (!png_ptr) { - fprintf(stderr, "Couldn't create png_ptr\n"); + Log::Error(Event::Image, "Couldn't create png_ptr"); return ""; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!png_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp)0); - fprintf(stderr, "Couldn't create info_ptr\n"); + Log::Error(Event::Image, "Couldn't create info_ptr"); return ""; } |