All Classes Files Functions Enumerations Enumerator Pages
libcurl.hpp
1 /*
2  * Copyright (c) 2024-2025, NVIDIA CORPORATION.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #ifndef KVIKIO_LIBCURL_FOUND
19 #error \
20  "cannot include the remote IO API, please build KvikIO with libcurl (-DKvikIO_REMOTE_SUPPORT=ON)"
21 #endif
22 
23 #include <functional>
24 #include <memory>
25 #include <sstream>
26 #include <string>
27 #include <vector>
28 
29 #include <curl/curl.h>
30 
31 namespace kvikio {
32 
50 class LibCurl {
51  public:
52  // We hold a unique pointer to the raw curl handle and set `curl_easy_cleanup` as its Deleter.
53  using UniqueHandlePtr = std::unique_ptr<CURL, std::function<decltype(curl_easy_cleanup)>>;
54 
55  private:
56  std::mutex _mutex{};
57  // Curl handles free to be used.
58  std::vector<UniqueHandlePtr> _free_curl_handles{};
59 
60  LibCurl();
61  ~LibCurl() noexcept;
62 
63  public:
64  static LibCurl& instance();
65 
69  UniqueHandlePtr get_free_handle();
70 
74  UniqueHandlePtr get_handle();
75 
79  void retain_handle(UniqueHandlePtr handle);
80 };
81 
88 class CurlHandle {
89  private:
90  char _errbuf[CURL_ERROR_SIZE];
91  LibCurl::UniqueHandlePtr _handle;
92  std::string _source_file;
93  std::string _source_line;
94 
95  public:
105  CurlHandle(LibCurl::UniqueHandlePtr handle, std::string source_file, std::string source_line);
106  ~CurlHandle() noexcept;
107 
111  CurlHandle(CurlHandle const&) = delete;
112  CurlHandle& operator=(CurlHandle const&) = delete;
113  CurlHandle(CurlHandle&& o) = delete;
114  CurlHandle& operator=(CurlHandle&& o) = delete;
115 
119  CURL* handle() noexcept;
120 
129  template <typename VAL>
130  void setopt(CURLoption option, VAL value)
131  {
132  CURLcode err = curl_easy_setopt(handle(), option, value);
133  if (err != CURLE_OK) {
134  std::stringstream ss;
135  ss << "curl_easy_setopt() error near " << _source_file << ":" << _source_line;
136  ss << "(" << curl_easy_strerror(err) << ")";
137  throw std::runtime_error(ss.str());
138  }
139  }
140 
146  void perform();
147 
156  template <typename OUTPUT>
157  void getinfo(CURLINFO info, OUTPUT* output)
158  {
159  CURLcode err = curl_easy_getinfo(handle(), info, output);
160  if (err != CURLE_OK) {
161  std::stringstream ss;
162  ss << "curl_easy_getinfo() error near " << _source_file << ":" << _source_line;
163  ss << "(" << curl_easy_strerror(err) << ")";
164  throw std::runtime_error(ss.str());
165  }
166  }
167 };
168 
169 namespace detail {
184 __attribute__((noinline)) inline std::string fix_conda_file_path_hack(std::string filename)
185 {
186  if (filename.data() != nullptr) { return std::string{filename.data()}; }
187  return std::string{};
188 }
189 } // namespace detail
190 
196 #define create_curl_handle() \
197  kvikio::CurlHandle(kvikio::LibCurl::instance().get_handle(), \
198  kvikio::detail::fix_conda_file_path_hack(__FILE__), \
199  KVIKIO_STRINGIFY(__LINE__))
200 
201 } // namespace kvikio
Representation of a curl easy handle pointer and its operations.
Definition: libcurl.hpp:88
void setopt(CURLoption option, VAL value)
Set option for the curl handle.
Definition: libcurl.hpp:130
CurlHandle(LibCurl::UniqueHandlePtr handle, std::string source_file, std::string source_line)
Construct a new curl handle.
void getinfo(CURLINFO info, OUTPUT *output)
Extract information from a curl handle.
Definition: libcurl.hpp:157
void perform()
Perform a blocking network transfer using previously set options.
CURL * handle() noexcept
Get the underlying curl easy handle pointer.
Singleton class to initialize and cleanup the global state of libcurl.
Definition: libcurl.hpp:50
UniqueHandlePtr get_free_handle()
Returns a free curl handle if available.
void retain_handle(UniqueHandlePtr handle)
Retain a curl handle for later use.
UniqueHandlePtr get_handle()
Returns a curl handle, create a new handle if none is available.