From b35f310a4db391cd16ed144c14b020d38e91c2ae Mon Sep 17 00:00:00 2001 From: Coldwings Date: Thu, 6 Jul 2023 14:31:10 +0800 Subject: [PATCH 1/2] Fix curl destruct order; add url unescape. Signed-off-by: Coldwings --- net/curl.cpp | 12 +++++++++--- net/curl.h | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/net/curl.cpp b/net/curl.cpp index 20d831f4..a35a4402 100644 --- a/net/curl.cpp +++ b/net/curl.cpp @@ -109,7 +109,7 @@ static uint64_t on_timer(void* = nullptr) { } /* CURLMOPT_TIMERFUNCTION */ static int timer_cb(CURLM*, long timeout_ms, void*) { - if (timeout_ms >= 0) { + if (timeout_ms >= 0 && cctx.g_timer) { cctx.g_timer->reset(timeout_ms * 1000UL); } return 0; @@ -244,11 +244,11 @@ int libcurl_init(long flags, long pipelining, long maxconn) { return 0; } void libcurl_fini() { + delete cctx.g_timer; + cctx.g_timer = nullptr; cctx.g_loop->stop(); delete cctx.g_loop; cctx.g_loop = nullptr; - delete cctx.g_timer; - cctx.g_timer = nullptr; delete cctx.g_poller; cctx.g_poller = nullptr; CURLMcode ret = curl_multi_cleanup(cctx.g_libcurl_multi); @@ -262,5 +262,11 @@ std::string url_escape(const char* str) { DEFER(curl_free(s)); return std::string(s); } + +std::string url_unescape(const char* str) { + auto s = curl_unescape(str, 0); + DEFER(curl_free(s)); + return std::string(s); +} } // namespace net } diff --git a/net/curl.h b/net/curl.h index 61501f79..65dee2f2 100644 --- a/net/curl.h +++ b/net/curl.h @@ -43,6 +43,7 @@ int curl_perform(CURL* curl, uint64_t timeout); void libcurl_fini(); std::string url_escape(const char*); +std::string url_unescape(const char*); inline void convert(const std::string& v, uint64_t& value) { value = std::atoll(v.c_str()); @@ -291,6 +292,12 @@ class cURL { return setopt(CURLOPT_FOLLOWLOCATION, v), setopt(CURLOPT_MAXREDIRS, max_redir); } + cURL& set_proxy(const char* proxy) { + return setopt(CURLOPT_PROXY, proxy); + } + cURL& set_noproxy(const char* proxy) { + return setopt(CURLOPT_NOPROXY, proxy); + } template cURL& set_header_container(T* stream) { return setopt(CURLOPT_HEADERDATA, (void*)stream), @@ -332,6 +339,9 @@ class cURL { setopt(CURLOPT_HTTPGET, 1L); setopt(CURLOPT_URL, url); setopt(CURLOPT_HTTPHEADER, headers.list); +#if LIBCURL_VERSION_MAJOR > 7 || LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 37 + setopt(CURLOPT_PROXYHEADER, proxy_headers.list); +#endif set_write_stream(stream); ret = (CURLcode)net::curl_perform(m_curl, timeout); return get_response_code(); @@ -341,6 +351,9 @@ class cURL { setopt(CURLOPT_HTTPGET, 1L); setopt(CURLOPT_URL, url); setopt(CURLOPT_HTTPHEADER, headers.list); +#if LIBCURL_VERSION_MAJOR > 7 || LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 37 + setopt(CURLOPT_PROXYHEADER, proxy_headers.list); +#endif ret = (CURLcode)net::curl_perform(m_curl, timeout); return get_response_code(); } @@ -350,6 +363,9 @@ class cURL { setopt(CURLOPT_URL, url); setopt(CURLOPT_CUSTOMREQUEST, "HEAD"); setopt(CURLOPT_HTTPHEADER, headers.list); +#if LIBCURL_VERSION_MAJOR > 7 || LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 37 + setopt(CURLOPT_PROXYHEADER, proxy_headers.list); +#endif set_write_stream(stream); ret = (CURLcode)net::curl_perform(m_curl, timeout); return get_response_code(); @@ -370,6 +386,9 @@ class cURL { long POST(const char* url, const char* post_fields, W* wstream, uint64_t timeout = -1) { setopt(CURLOPT_HTTPHEADER, headers.list); +#if LIBCURL_VERSION_MAJOR > 7 || LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 37 + setopt(CURLOPT_PROXYHEADER, proxy_headers.list); +#endif setopt(CURLOPT_POSTFIELDS, post_fields); return POST(url, wstream, timeout); } @@ -380,6 +399,9 @@ class cURL { setopt(CURLOPT_URL, url); setopt(CURLOPT_POST, 1L); setopt(CURLOPT_HTTPHEADER, headers.list); +#if LIBCURL_VERSION_MAJOR > 7 || LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 37 + setopt(CURLOPT_PROXYHEADER, proxy_headers.list); +#endif ret = (CURLcode)net::curl_perform(m_curl, timeout); return get_response_code(); } @@ -392,6 +414,9 @@ class cURL { setopt(CURLOPT_PUT, 1L); setopt(CURLOPT_URL, url); setopt(CURLOPT_HTTPHEADER, headers.list); +#if LIBCURL_VERSION_MAJOR > 7 || LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 37 + setopt(CURLOPT_PROXYHEADER, proxy_headers.list); +#endif // setopt(CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size); ret = (CURLcode)net::curl_perform(m_curl, timeout); return get_response_code(); @@ -400,6 +425,9 @@ class cURL { setopt(CURLOPT_URL, url); setopt(CURLOPT_CUSTOMREQUEST, "DELETE"); setopt(CURLOPT_HTTPHEADER, headers.list); +#if LIBCURL_VERSION_MAJOR > 7 || LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 37 + setopt(CURLOPT_PROXYHEADER, proxy_headers.list); +#endif ret = (CURLcode)net::curl_perform(m_curl, timeout); return get_response_code(); } @@ -421,6 +449,16 @@ class cURL { return *this; } + cURL& append_proxy_header(const std::string& key, const std::string& val) { + proxy_headers.append(key + std::string(": ") + val); + return *this; + } + + cURL& clear_proxy_header() { + proxy_headers.clear(); + return *this; + } + struct slist { struct curl_slist* list = nullptr; slist() = default; @@ -447,7 +485,7 @@ class cURL { CURL* m_curl; char m_errmsg[CURL_ERROR_SIZE]; CURLcode ret = CURLE_OK; - slist headers; + slist headers, proxy_headers; template cURL& _setopt(CURLoption option, T arg) { if (ret != CURLE_OK) return *this; From 1dc7dac9a684de49ec4265b57f479c344585ddb6 Mon Sep 17 00:00:00 2001 From: Coldwings Date: Thu, 6 Jul 2023 14:32:54 +0800 Subject: [PATCH 2/2] photon thread alloc using static object Signed-off-by: Coldwings --- common/callback.h | 8 ++-- thread/test/CMakeLists.txt | 6 ++- thread/test/test-lib-data.cpp | 89 +++++++++++++++++++++++++++++++++++ thread/thread.cpp | 33 +++++-------- 4 files changed, 111 insertions(+), 25 deletions(-) create mode 100644 thread/test/test-lib-data.cpp diff --git a/common/callback.h b/common/callback.h index 4b7be5ae..60d74f6a 100644 --- a/common/callback.h +++ b/common/callback.h @@ -50,12 +50,12 @@ struct Delegate : public Delegate_Base template // Function with U* as the 1st argument using UFunc = R (*)(U*, Ts...); - Delegate(void* obj, Func func) { bind(obj, func); } - Delegate(Func func, void* obj) { bind(obj, func); } - Delegate(Func0 func0) { bind(func0); } + constexpr Delegate(void* obj, Func func) : _obj(obj), _func(func) {} + constexpr Delegate(Func func, void* obj) : _obj(obj), _func(func) {} + constexpr Delegate(Func0 func0) : _obj(nullptr), _func((Func&)func0) {} template - Delegate(U* obj, UFunc func) { bind(obj, func); } + constexpr Delegate(U* obj, UFunc func) : _obj(obj), _func((Func&)func) {} template Delegate(U* obj, UMFunc func) { bind(obj, func); } diff --git a/thread/test/CMakeLists.txt b/thread/test/CMakeLists.txt index 32fbd141..9a2d0218 100644 --- a/thread/test/CMakeLists.txt +++ b/thread/test/CMakeLists.txt @@ -28,4 +28,8 @@ add_test(NAME test-tls-order-native COMMAND $ add_executable(test-tls-order-photon test-tls-order-photon.cpp) target_link_libraries(test-tls-order-photon PRIVATE photon_shared ${testing_libs}) -add_test(NAME test-tls-order-photon COMMAND $) \ No newline at end of file +add_test(NAME test-tls-order-photon COMMAND $) + +add_executable(test-lib-data test-lib-data.cpp) +target_link_libraries(test-lib-data PRIVATE photon_shared ${testing_libs}) +add_test(NAME test-lib-data COMMAND $) \ No newline at end of file diff --git a/thread/test/test-lib-data.cpp b/thread/test/test-lib-data.cpp new file mode 100644 index 00000000..ffb85dbb --- /dev/null +++ b/thread/test/test-lib-data.cpp @@ -0,0 +1,89 @@ +/* +Copyright 2022 The Photon Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include +#include +#include +#include +#include +#include + +bool popen_test(const std::string& cmd, int expect = 0) { + puts(cmd.c_str()); + auto p = popen(cmd.c_str(), "r"); + char buffer[4096]; + while (fgets(buffer, sizeof(buffer), p) != NULL) + ; + auto r = pclose(p); + if (WIFEXITED(r)) return WEXITSTATUS(r) == expect; + puts("Not exit"); + return false; +} + +std::string popen_read(const std::string& cmd, int expect = 0) { + std::string ret; + puts(cmd.c_str()); + auto p = popen(cmd.c_str(), "r"); + char buffer[4096]; + while (fgets(buffer, sizeof(buffer), p) != NULL) { + ret += buffer; + puts(buffer); + } + pclose(p); + return ret; +} + +std::string libpath(uint64_t pid) { + auto path = + popen_read("cat /proc/" + std::to_string(pid) + + "/maps | grep libphoton | tr -s ' ' | cut -f 6 -d ' '" + " | head -n 1"); + EXPECT_FALSE(path.empty()); + char* tp = strdup(path.c_str()); + path = dirname(tp); + puts(path.c_str()); + free(tp); + return path; +} + +TEST(static_lib, photon_thread_alloc) { +#ifdef __linux__ + auto pid = getpid(); + auto p = libpath(pid) + "/libphoton.a"; + EXPECT_TRUE(popen_test("objdump -tr \"" + p + + "\" | grep photon_thread_allocE | grep .data")); + EXPECT_TRUE(popen_test("objdump -tr \"" + p + + "\" | grep photon_thread_deallocE | grep .data")); +#endif +} + +TEST(shared_lib, photon_thread_alloc) { +#ifdef __linux__ + auto pid = getpid(); + auto p = libpath(pid) + "/libphoton.so"; + EXPECT_TRUE(popen_test("objdump -tr \"" + p + + "\" | grep photon_thread_allocE | grep .data")); + EXPECT_TRUE(popen_test("objdump -tr \"" + p + + "\" | grep photon_thread_deallocE | grep .data")); +#endif +} + +int main(int argc, char** argv) { + photon::init(photon::INIT_EVENT_NONE, 0); + DEFER(photon::fini()); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/thread/thread.cpp b/thread/thread.cpp index 4a105262..e4d71fab 100644 --- a/thread/thread.cpp +++ b/thread/thread.cpp @@ -130,17 +130,10 @@ namespace photon free(ptr); } - Delegate &photon_thread_alloc() { - static Delegate _photon_thread_alloc( - &default_photon_thread_stack_alloc, nullptr); - return _photon_thread_alloc; - } - - Delegate &photon_thread_dealloc() { - static Delegate _photon_thread_dealloc( - &default_photon_thread_stack_dealloc, nullptr); - return _photon_thread_dealloc; - } + static Delegate photon_thread_alloc( + &default_photon_thread_stack_alloc, nullptr); + static Delegate photon_thread_dealloc( + &default_photon_thread_stack_dealloc, nullptr); struct vcpu_t; struct thread; @@ -290,7 +283,7 @@ namespace photon assert(state == states::DONE); // `buf` and `stack_size` will always store on register // when calling deallocating. - photon_thread_dealloc()(buf, stack_size); + photon_thread_dealloc(buf, stack_size); } }; @@ -845,7 +838,7 @@ R"( LOG_ERROR_RETURN(ENOSYS, nullptr, "Photon not initialized in this vCPU (OS thread)"); size_t randomizer = (rand() % 32) * (1024 + 8); stack_size = align_up(randomizer + stack_size + sizeof(thread), PAGE_SIZE); - char *ptr = (char *)photon_thread_alloc()(stack_size); + char* ptr = (char*)photon_thread_alloc(stack_size); auto p = ptr + stack_size - sizeof(thread) - randomizer; (uint64_t&)p &= ~63; auto th = new (p) thread; @@ -1815,13 +1808,6 @@ R"( return --_n_vcpu; } - void set_photon_thread_stack_allocator( - Delegate _photon_thread_alloc, - Delegate _photon_thread_dealloc) { - photon_thread_alloc() = _photon_thread_alloc; - photon_thread_dealloc() = _photon_thread_dealloc; - } - void* stackful_malloc(size_t size) { return CURRENT->stackful_malloc(size); } @@ -1829,4 +1815,11 @@ R"( void stackful_free(void* ptr) { CURRENT->stackful_free(ptr); } + + void set_photon_thread_stack_allocator( + Delegate _photon_thread_alloc, + Delegate _photon_thread_dealloc) { + photon_thread_alloc = _photon_thread_alloc; + photon_thread_dealloc = _photon_thread_dealloc; + } }