diff --git a/runtime-light/state/image-state.h b/runtime-light/state/image-state.h index 389316405d..2304ee059d 100644 --- a/runtime-light/state/image-state.h +++ b/runtime-light/state/image-state.h @@ -18,6 +18,7 @@ #include "runtime-light/allocator/allocator-state.h" #include "runtime-light/core/reference-counter/reference-counter-functions.h" #include "runtime-light/k2-platform/k2-api.h" +#include "runtime-light/stdlib/curl/curl-state.h" #include "runtime-light/stdlib/diagnostics/logs.h" #include "runtime-light/stdlib/file/file-system-state.h" #include "runtime-light/stdlib/math/math-state.h" @@ -46,6 +47,7 @@ struct ImageState final : private vk::not_copyable { TimeImageState time_image_state; MathImageState math_image_state; RpcImageState rpc_image_state; + CurlImageState curl_image_state; ImageState() noexcept { if (const int64_t sysconf_max_buffer_size{k2::sysconf(_SC_GETPW_R_SIZE_MAX)}; sysconf_max_buffer_size != -1) { diff --git a/runtime-light/stdlib/curl/curl-multi-functions.h b/runtime-light/stdlib/curl/curl-multi-functions.h index 52098085fa..c14552a36e 100644 --- a/runtime-light/stdlib/curl/curl-multi-functions.h +++ b/runtime-light/stdlib/curl/curl-multi-functions.h @@ -46,7 +46,7 @@ inline auto f$curl_multi_add_handle(kphp::web::curl::multi_type multi_id, kphp:: auto res{co_await kphp::forks::id_managed(kphp::web::composite_transfer_add(kphp::web::composite_transfer{multi_id}, kphp::web::simple_transfer{easy_id}))}; if (!res.has_value()) [[unlikely]] { - multi_ctx.set_errno(res.error().code, res.error().description); + multi_ctx.set_errno(res.error().code); kphp::web::curl::print_error("could not add a curl easy handler into multi handle", std::move(res.error())); co_return multi_ctx.error_code; } @@ -67,7 +67,7 @@ inline auto f$curl_multi_remove_handle(kphp::web::curl::multi_type multi_id, auto res{ co_await kphp::forks::id_managed(kphp::web::composite_transfer_remove(kphp::web::composite_transfer{multi_id}, kphp::web::simple_transfer{easy_id}))}; if (!res.has_value()) [[unlikely]] { - multi_ctx.set_errno(res.error().code, res.error().description); + multi_ctx.set_errno(res.error().code); kphp::web::curl::print_error("could not remove a curl easy handler from multi handle", std::move(res.error())); co_return multi_ctx.error_code; } @@ -100,7 +100,7 @@ inline auto f$curl_multi_setopt(kphp::web::curl::multi_type multi_id, int64_t op return true; } default: - multi_ctx.set_errno(kphp::web::curl::CURLME::UNKNOWN_OPTION, "a libcurl function was given an incorrect PROXYTYPE kind"); + multi_ctx.set_errno(kphp::web::curl::CURLME::UNKNOWN_OPTION); return false; } } @@ -130,7 +130,7 @@ inline auto f$curl_multi_exec(kphp::web::curl::multi_type multi_id, int64_t& sti auto res{co_await kphp::forks::id_managed(kphp::web::composite_transfer_perform(kphp::web::composite_transfer{multi_id}))}; auto& multi_ctx{curl_state.multi_ctx.get_or_init(multi_id)}; if (!res.has_value()) [[unlikely]] { - multi_ctx.set_errno(res.error().code, res.error().description); + multi_ctx.set_errno(res.error().code); kphp::web::curl::print_error("could not execute curl multi handle", std::move(res.error())); co_return multi_ctx.error_code; } @@ -148,7 +148,7 @@ inline auto f$curl_multi_getcontent(kphp::web::curl::easy_type easy_id) noexcept if (easy_ctx.return_transfer) { auto res{co_await kphp::forks::id_managed(kphp::web::simple_transfer_get_response(kphp::web::simple_transfer{easy_id}))}; if (!res.has_value()) [[unlikely]] { - easy_ctx.set_errno(res.error().code, res.error().description); + easy_ctx.set_errno(res.error().code); kphp::web::curl::print_error("could not get response of curl easy handle", std::move(res.error())); co_return false; } @@ -165,7 +165,7 @@ inline auto f$curl_multi_close(kphp::web::curl::multi_type multi_id) noexcept -> auto& multi_ctx{curl_state.multi_ctx.get_or_init(multi_id)}; auto res{co_await kphp::forks::id_managed(kphp::web::composite_transfer_close(kphp::web::composite_transfer{multi_id}))}; if (!res.has_value()) [[unlikely]] { - multi_ctx.set_errno(res.error().code, res.error().description); + multi_ctx.set_errno(res.error().code); kphp::web::curl::print_error("could not close curl multi handle", std::move(res.error())); co_return; } @@ -173,18 +173,39 @@ inline auto f$curl_multi_close(kphp::web::curl::multi_type multi_id) noexcept -> co_return; } -inline auto f$curl_multi_strerror(kphp::web::curl::multi_type multi_id) noexcept -> Optional { - auto& curl_state{CurlInstanceState::get()}; - if (!curl_state.multi_ctx.has(multi_id)) [[unlikely]] { +inline auto f$curl_multi_strerror(int64_t error_num) noexcept -> Optional { + switch (static_cast(error_num)) { + case kphp::web::curl::CURLME::CALL_MULTI_PERFORM: + return CurlImageState::get().CURLME_CALL_MULTI_PERFORM; + case kphp::web::curl::CURLME::OK: + return CurlImageState::get().CURLME_OK; + case kphp::web::curl::CURLME::BAD_HANDLE: + return CurlImageState::get().CURLME_BAD_HANDLE; + case kphp::web::curl::CURLME::BAD_EASY_HANDLE: + return CurlImageState::get().CURLME_BAD_EASY_HANDLE; + case kphp::web::curl::CURLME::OUT_OF_MEMORY: + return CurlImageState::get().CURLME_OUT_OF_MEMORY; + case kphp::web::curl::CURLME::INTERNAL_ERROR: + return CurlImageState::get().CURLME_INTERNAL_ERROR; + case kphp::web::curl::CURLME::BAD_SOCKET: + return CurlImageState::get().CURLME_BAD_SOCKET; + case kphp::web::curl::CURLME::UNKNOWN_OPTION: + return CurlImageState::get().CURLME_UNKNOWN_OPTION; + case kphp::web::curl::CURLME::ADDED_ALREADY: + return CurlImageState::get().CURLME_ADDED_ALREADY; + case kphp::web::curl::CURLME::RECURSIVE_API_CALL: + return CurlImageState::get().CURLME_RECURSIVE_API_CALL; + case kphp::web::curl::CURLME::WAKEUP_FAILURE: + return CurlImageState::get().CURLME_WAKEUP_FAILURE; + case kphp::web::curl::CURLME::BAD_FUNCTION_ARGUMENT: + return CurlImageState::get().CURLME_BAD_FUNCTION_ARGUMENT; + case kphp::web::curl::CURLME::ABORTED_BY_CALLBACK: + return CurlImageState::get().CURLME_ABORTED_BY_CALLBACK; + case kphp::web::curl::CURLME::UNRECOVERABLE_POLL: + return CurlImageState::get().CURLME_UNRECOVERABLE_POLL; + default: return {}; } - auto& multi_ctx{curl_state.multi_ctx.get_or_init(multi_id)}; - if (multi_ctx.error_code != static_cast(kphp::web::curl::CURLME::OK)) [[likely]] { - const auto* const desc_data{reinterpret_cast(multi_ctx.error_description.data())}; - const auto desc_size{static_cast(multi_ctx.error_description.size())}; - return string{desc_data, desc_size}; - } - return {}; } inline auto f$curl_multi_errno(kphp::web::curl::multi_type multi_id) noexcept -> Optional { @@ -205,7 +226,7 @@ inline auto f$curl_multi_select(kphp::web::curl::multi_type multi_id, double tim auto res{co_await kphp::forks::id_managed(kphp::web::composite_transfer_wait_updates( kphp::web::composite_transfer{multi_id}, std::chrono::duration_cast(std::chrono::duration{timeout})))}; if (!res.has_value()) [[unlikely]] { - multi_ctx.set_errno(res.error().code, res.error().description); + multi_ctx.set_errno(res.error().code); kphp::web::curl::print_error("could not select curl multi handle", std::move(res.error())); co_return multi_ctx.error_code; } diff --git a/runtime-light/stdlib/curl/curl-state.cpp b/runtime-light/stdlib/curl/curl-state.cpp index 8472e76a1b..019d97fdc6 100644 --- a/runtime-light/stdlib/curl/curl-state.cpp +++ b/runtime-light/stdlib/curl/curl-state.cpp @@ -4,8 +4,13 @@ #include "runtime-light/stdlib/curl/curl-state.h" +#include "runtime-light/state/image-state.h" #include "runtime-light/state/instance-state.h" CurlInstanceState& CurlInstanceState::get() noexcept { return InstanceState::get().curl_instance_state; } + +const CurlImageState& CurlImageState::get() noexcept { + return ImageState::get().curl_image_state; +} diff --git a/runtime-light/stdlib/curl/curl-state.h b/runtime-light/stdlib/curl/curl-state.h index 2b93506482..b6a551f7e2 100644 --- a/runtime-light/stdlib/curl/curl-state.h +++ b/runtime-light/stdlib/curl/curl-state.h @@ -7,8 +7,10 @@ #include "common/mixin/not_copyable.h" #include "runtime-common/core/allocator/script-allocator.h" #include "runtime-common/core/std/containers.h" +#include "runtime-light/core/reference-counter/reference-counter-functions.h" #include "runtime-light/stdlib/curl/curl-context.h" #include "runtime-light/stdlib/curl/defs.h" +#include "runtime-light/stdlib/diagnostics/logs.h" struct CurlInstanceState final : private vk::not_copyable { public: @@ -58,3 +60,54 @@ inline auto CurlInstanceState::multi_ctx::get_or_init(kphp::web::curl::multi_typ inline auto CurlInstanceState::multi_ctx::has(kphp::web::curl::multi_type multi_id) noexcept -> bool { return ctx.find(multi_id) != ctx.end(); } + +struct CurlImageState final : private vk::not_copyable { + string CURLME_CALL_MULTI_PERFORM{kphp::web::curl::details::CURLME_CALL_MULTI_PERFORM.data(), kphp::web::curl::details::CURLME_CALL_MULTI_PERFORM.size()}; + string CURLME_OK{kphp::web::curl::details::CURLME_OK.data(), kphp::web::curl::details::CURLME_OK.size()}; + string CURLME_BAD_HANDLE{kphp::web::curl::details::CURLME_BAD_HANDLE.data(), kphp::web::curl::details::CURLME_BAD_HANDLE.size()}; + string CURLME_BAD_EASY_HANDLE{kphp::web::curl::details::CURLME_BAD_EASY_HANDLE.data(), kphp::web::curl::details::CURLME_BAD_EASY_HANDLE.size()}; + string CURLME_OUT_OF_MEMORY{kphp::web::curl::details::CURLME_OUT_OF_MEMORY.data(), kphp::web::curl::details::CURLME_OUT_OF_MEMORY.size()}; + string CURLME_INTERNAL_ERROR{kphp::web::curl::details::CURLME_INTERNAL_ERROR.data(), kphp::web::curl::details::CURLME_INTERNAL_ERROR.size()}; + string CURLME_BAD_SOCKET{kphp::web::curl::details::CURLME_BAD_SOCKET.data(), kphp::web::curl::details::CURLME_BAD_SOCKET.size()}; + string CURLME_UNKNOWN_OPTION{kphp::web::curl::details::CURLME_UNKNOWN_OPTION.data(), kphp::web::curl::details::CURLME_UNKNOWN_OPTION.size()}; + string CURLME_ADDED_ALREADY{kphp::web::curl::details::CURLME_ADDED_ALREADY.data(), kphp::web::curl::details::CURLME_ADDED_ALREADY.size()}; + string CURLME_RECURSIVE_API_CALL{kphp::web::curl::details::CURLME_RECURSIVE_API_CALL.data(), kphp::web::curl::details::CURLME_RECURSIVE_API_CALL.size()}; + string CURLME_WAKEUP_FAILURE{kphp::web::curl::details::CURLME_WAKEUP_FAILURE.data(), kphp::web::curl::details::CURLME_WAKEUP_FAILURE.size()}; + string CURLME_BAD_FUNCTION_ARGUMENT{kphp::web::curl::details::CURLME_BAD_FUNCTION_ARGUMENT.data(), + kphp::web::curl::details::CURLME_BAD_FUNCTION_ARGUMENT.size()}; + string CURLME_ABORTED_BY_CALLBACK{kphp::web::curl::details::CURLME_ABORTED_BY_CALLBACK.data(), kphp::web::curl::details::CURLME_ABORTED_BY_CALLBACK.size()}; + string CURLME_UNRECOVERABLE_POLL{kphp::web::curl::details::CURLME_UNRECOVERABLE_POLL.data(), kphp::web::curl::details::CURLME_UNRECOVERABLE_POLL.size()}; + + CurlImageState() noexcept { + kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_CALL_MULTI_PERFORM, ExtraRefCnt::for_global_const), + kphp::core::is_reference_counter_recursive(CURLME_CALL_MULTI_PERFORM, ExtraRefCnt::for_global_const))); + kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_OK, ExtraRefCnt::for_global_const), + kphp::core::is_reference_counter_recursive(CURLME_OK, ExtraRefCnt::for_global_const))); + kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_BAD_HANDLE, ExtraRefCnt::for_global_const), + kphp::core::is_reference_counter_recursive(CURLME_BAD_HANDLE, ExtraRefCnt::for_global_const))); + kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_BAD_EASY_HANDLE, ExtraRefCnt::for_global_const), + kphp::core::is_reference_counter_recursive(CURLME_BAD_EASY_HANDLE, ExtraRefCnt::for_global_const))); + kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_OUT_OF_MEMORY, ExtraRefCnt::for_global_const), + kphp::core::is_reference_counter_recursive(CURLME_OUT_OF_MEMORY, ExtraRefCnt::for_global_const))); + kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_INTERNAL_ERROR, ExtraRefCnt::for_global_const), + kphp::core::is_reference_counter_recursive(CURLME_INTERNAL_ERROR, ExtraRefCnt::for_global_const))); + kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_BAD_SOCKET, ExtraRefCnt::for_global_const), + kphp::core::is_reference_counter_recursive(CURLME_BAD_SOCKET, ExtraRefCnt::for_global_const))); + kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_UNKNOWN_OPTION, ExtraRefCnt::for_global_const), + kphp::core::is_reference_counter_recursive(CURLME_UNKNOWN_OPTION, ExtraRefCnt::for_global_const))); + kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_ADDED_ALREADY, ExtraRefCnt::for_global_const), + kphp::core::is_reference_counter_recursive(CURLME_ADDED_ALREADY, ExtraRefCnt::for_global_const))); + kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_RECURSIVE_API_CALL, ExtraRefCnt::for_global_const), + kphp::core::is_reference_counter_recursive(CURLME_RECURSIVE_API_CALL, ExtraRefCnt::for_global_const))); + kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_WAKEUP_FAILURE, ExtraRefCnt::for_global_const), + kphp::core::is_reference_counter_recursive(CURLME_WAKEUP_FAILURE, ExtraRefCnt::for_global_const))); + kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_BAD_FUNCTION_ARGUMENT, ExtraRefCnt::for_global_const), + kphp::core::is_reference_counter_recursive(CURLME_BAD_FUNCTION_ARGUMENT, ExtraRefCnt::for_global_const))); + kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_ABORTED_BY_CALLBACK, ExtraRefCnt::for_global_const), + kphp::core::is_reference_counter_recursive(CURLME_ABORTED_BY_CALLBACK, ExtraRefCnt::for_global_const))); + kphp::log::assertion((kphp::core::set_reference_counter_recursive(CURLME_UNRECOVERABLE_POLL, ExtraRefCnt::for_global_const), + kphp::core::is_reference_counter_recursive(CURLME_UNRECOVERABLE_POLL, ExtraRefCnt::for_global_const))); + } + + static const CurlImageState& get() noexcept; +}; diff --git a/runtime-light/stdlib/curl/defs.h b/runtime-light/stdlib/curl/defs.h index 93688c9d61..f76e433bd2 100644 --- a/runtime-light/stdlib/curl/defs.h +++ b/runtime-light/stdlib/curl/defs.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include "runtime-light/stdlib/web-transfer-lib/defs.h" @@ -259,6 +260,11 @@ enum class CURLME : int16_t { BAD_SOCKET = 5, UNKNOWN_OPTION = 6, ADDED_ALREADY = 7, + RECURSIVE_API_CALL = 8, + WAKEUP_FAILURE = 9, + BAD_FUNCTION_ARGUMENT = 10, + ABORTED_BY_CALLBACK = 11, + UNRECOVERABLE_POLL = 12, }; enum class CURMLOPT : uint64_t { @@ -278,3 +284,22 @@ enum class CURLPIPE : uint8_t { }; } // namespace kphp::web::curl + +namespace kphp::web::curl::details { + +inline constexpr std::string_view CURLME_CALL_MULTI_PERFORM{"Please call curl_multi_perform() soon"}; +inline constexpr std::string_view CURLME_OK{"No error"}; +inline constexpr std::string_view CURLME_BAD_HANDLE{"Invalid multi handle"}; +inline constexpr std::string_view CURLME_BAD_EASY_HANDLE{"Invalid easy handle"}; +inline constexpr std::string_view CURLME_OUT_OF_MEMORY{"Out of memory"}; +inline constexpr std::string_view CURLME_INTERNAL_ERROR{"Internal error"}; +inline constexpr std::string_view CURLME_BAD_SOCKET{"Invalid socket argument"}; +inline constexpr std::string_view CURLME_UNKNOWN_OPTION{"Unknown option"}; +inline constexpr std::string_view CURLME_ADDED_ALREADY{"The easy handle is already added to a multi handle"}; +inline constexpr std::string_view CURLME_RECURSIVE_API_CALL{"API function called from within callback"}; +inline constexpr std::string_view CURLME_WAKEUP_FAILURE{"Wakeup is unavailable or failed"}; +inline constexpr std::string_view CURLME_BAD_FUNCTION_ARGUMENT{"A libcurl function was given a bad argument"}; +inline constexpr std::string_view CURLME_ABORTED_BY_CALLBACK{"Operation was aborted by an application callback"}; +inline constexpr std::string_view CURLME_UNRECOVERABLE_POLL{"Unrecoverable error in select/poll"}; + +} // namespace kphp::web::curl::details diff --git a/tests/phpt/curl/11_curl_multi_error.php b/tests/phpt/curl/11_curl_multi_error.php index b36a4e1cf1..72f6a754ea 100644 --- a/tests/phpt/curl/11_curl_multi_error.php +++ b/tests/phpt/curl/11_curl_multi_error.php @@ -3,7 +3,9 @@ function test_no_error() { $mh = curl_multi_init(); - var_dump(curl_multi_errno($mh)); + $errno = curl_multi_errno($mh); + var_dump($errno); + var_dump(curl_multi_strerror($errno)); curl_multi_close($mh); }