curl-cpp
static c++17 wrapper for curl with -fno-exceptions support
Classes | Public Types | Public Member Functions | Protected Member Functions | Protected Attributes | List of all members
curl::Multi_t Class Reference
Collaboration diagram for curl::Multi_t:
Collaboration graph

Classes

class  Exception
 

Public Types

using perform_ret_t = Ret_except< int, std::bad_alloc, Exception, Recursive_api_call_Exception, libcurl_bug >
 
using socket_callback_t = int(*)(CURL *curl_easy, curl_socket_t s, int what, void *userp, void *per_socketp)
 
using timer_callback_t = int(*)(CURLM *multi, long timeout_ms, void *userp)
 

Public Member Functions

 Multi_t ()=default
 
 Multi_t (void *multi) noexcept
 
 Multi_t (const Multi_t &)=delete
 
 Multi_t (Multi_t &&) noexcept
 
Multi_toperator= (const Multi_t &)=delete
 
Multi_toperator= (Multi_t &&) noexcept
 
 operator bool () const noexcept
 
bool add_easy (Easy_ref_t &easy) noexcept
 
void remove_easy (Easy_ref_t &easy) noexcept
 
std::size_t get_number_of_handles () const noexcept
 
void set_multiplexing (long max_concurrent_stream) noexcept
 
auto poll (curl_waitfd *extra_fds=nullptr, unsigned extra_nfds=0U, int timeout=0) noexcept -> Ret_except< int, std::bad_alloc, libcurl_bug >
 
auto break_or_poll (curl_waitfd *extra_fds=nullptr, unsigned extra_nfds=0U, int timeout=0) noexcept -> Ret_except< int, std::bad_alloc, libcurl_bug >
 
template<class perform_callback_t , class T >
auto perform (perform_callback_t &&perform_callback, T &&arg) noexcept -> perform_ret_t
 
void register_callback (socket_callback_t socket_callback, void *socket_data, timer_callback_t timer_callback, void *timer_data) noexcept
 
auto multi_assign (curl_socket_t socketfd, void *per_sockptr) noexcept -> Ret_except< void, std::invalid_argument >
 
template<class perform_callback_t , class T >
auto multi_socket_action (curl_socket_t socketfd, int ev_bitmask, perform_callback_t &&perform_callback, T &&arg) noexcept -> perform_ret_t
 
 ~Multi_t ()
 

Protected Member Functions

auto get_finished_easy () const noexcept -> std::pair< Easy_ref_t, Easy_ref_t::perform_ret_t >
 
template<class perform_callback_t , class T >
void callback_on_finished_easy (perform_callback_t &&perform_callback, T &&arg)
 
auto perform_impl () noexcept -> perform_ret_t
 
auto multi_socket_action_impl (curl_socket_t socketfd, int ev_bitmask) noexcept -> perform_ret_t
 
auto check_perform (long code, int running_handles_tmp, const char *fname) noexcept -> Ret_except< int, std::bad_alloc, Exception, Recursive_api_call_Exception, libcurl_bug >
 

Protected Attributes

void * curl_multi = nullptr
 
std::size_t handles = 0
 

Detailed Description

Examples
curl_multi_poll.cc, curl_multi_poll2.cc, curl_multi_socket_action_epoll.cc, curl_multi_socket_action_event.cc, and curl_multi_socket_action_uv.cc.

Definition at line 29 of file curl_multi.hpp.

Member Typedef Documentation

◆ socket_callback_t

using curl::Multi_t::socket_callback_t = int (*)(CURL *curl_easy, curl_socket_t s, int what, void *userp, void *per_socketp)
Returns
should be 0

Interface for using arbitary event-based interface - multi_socket interface

Precondition for using this interface:

  • curl_t::has_multi_socket_support()

Definition at line 213 of file curl_multi.hpp.

◆ timer_callback_t

using curl::Multi_t::timer_callback_t = int (*)(CURLM *multi, long timeout_ms, void *userp)
Parameters
timeout_ms-1 means you should delete the timer. All other values are valid expire times in number of milliseconds.
Returns
should be 0 on success, -1 on failure.

Your callback function timer_callback should install a non-repeating timer with an interval of timeout_ms.
When time that timer fires, call multi_socket_action().

The timer_callback will only be called when the timeout expire time is changed.

Definition at line 226 of file curl_multi.hpp.

Constructor & Destructor Documentation

◆ Multi_t() [1/3]

curl::Multi_t::Multi_t ( )
default

Construct an empty Multi_t that can only be move assigned with value or be destroyed.

◆ Multi_t() [2/3]

curl::Multi_t::Multi_t ( void *  multi)
noexcept

This constructor takes CURLM*

Parameters
multipass nullptr for an empty Multi_t that can only be move assigned with value or be destroyed.

Definition at line 15 of file curl_multi.cc.

15  :
16  curl_multi{multi}
17 {}

◆ Multi_t() [3/3]

curl::Multi_t::Multi_t ( Multi_t &&  other)
noexcept
Parameters
otherafter mv operation, other is in unusable state and can only be destroyed or move assign another value.

Definition at line 19 of file curl_multi.cc.

19  :
20  curl_multi{other.curl_multi}
21 {
22  other.curl_multi = nullptr;
23 
24  handles = other.handles;
25 }

◆ ~Multi_t()

curl::Multi_t::~Multi_t ( )
Precondition
get_number_of_handles() == 0

Definition at line 43 of file curl_multi.cc.

44 {
45  if (curl_multi)
46  curl_multi_cleanup(curl_multi);
47 }

Member Function Documentation

◆ get_finished_easy()

auto curl::Multi_t::get_finished_easy ( ) const -> std::pair<Easy_ref_t, Easy_ref_t::perform_ret_t>
protectednoexcept
Returns
handles that are finished. Return nullptr to signal all finished handles are returned.

Definition at line 102 of file curl_multi.cc.

103 {
104  int msgq = 0;
105  for (CURLMsg *m; (m = curl_multi_info_read(curl_multi, &msgq)); )
106  if (m->msg == CURLMSG_DONE) {
107  Easy_ref_t easy_ref{static_cast<char*>(m->easy_handle)};
108  return {easy_ref, easy_ref.check_perform(m->data.result, "")};
109  }
110 
111  return {Easy_ref_t{nullptr}, Easy_ref_t::perform_ret_t{Easy_ref_t::code::ok}};
112 }

◆ operator=()

Multi_t & curl::Multi_t::operator= ( Multi_t &&  other)
noexcept
Parameters
otherafter mv operation, other is in unusable state and can only be destroyed or move assign another value.

Definition at line 26 of file curl_multi.cc.

27 {
28  if (curl_multi)
29  curl_multi_cleanup(curl_multi);
30  curl_multi = other.curl_multi;
31  other.curl_multi = nullptr;
32 
33  handles = other.handles;
34 
35  return *this;
36 }

◆ operator bool()

curl::Multi_t::operator bool ( ) const
noexcept
Returns
true if this object is usable, false otherwise

Definition at line 38 of file curl_multi.cc.

39 {
40  return curl_multi != nullptr;
41 }

◆ add_easy()

bool curl::Multi_t::add_easy ( Easy_ref_t easy)
noexcept
Parameters
easymust be in valid state
Returns
true if not yet added;
false if already added.

Definition at line 49 of file curl_multi.cc.

50 {
51  bool success = curl_multi_add_handle(curl_multi, easy.curl_easy) != CURLM_ADDED_ALREADY;
52 
53  handles += success;
54 
55  return success;
56 }

◆ remove_easy()

void curl::Multi_t::remove_easy ( Easy_ref_t easy)
noexcept

Undefined behavior if easy is not valid or not added to this multi.

Examples
curl_multi_poll.cc, and curl_multi_poll2.cc.

Definition at line 57 of file curl_multi.cc.

58 {
59  --handles;
60  curl_multi_remove_handle(curl_multi, easy.curl_easy);
61 }

◆ set_multiplexing()

void curl::Multi_t::set_multiplexing ( long  max_concurrent_stream)
noexcept

HTTP2 multiplexing configuration.

Precondition
curl_t::has_http2_multiplex_support()
Parameters
max_concurrent_streammax concurrent stream for a given connection.
Should be between [0, 2 ^ 31 - 1].
Set it to 0 disable multiplexing.

Since curl_t::version >= 7.62.0 (version released way after http2 multiplex support) , multiplex is turned on by default.

NOTE that libcurl not always accept max_concurrent_stream tuning.
Check curl_t::has_max_concurrent_stream_support().

If libcurl does not support tuning, this option will be only used for turning on and off the http2 multiplex.

Definition at line 68 of file curl_multi.cc.

69 {
70  long bitmask = max_concurrent_stream != 0 ? CURLPIPE_MULTIPLEX : CURLPIPE_NOTHING;
71  curl_multi_setopt(curl_multi, CURLMOPT_PIPELINING, bitmask);
72 
73  if (max_concurrent_stream >= 1)
74  curl_multi_setopt(curl_multi, CURLMOPT_MAX_CONCURRENT_STREAMS, max_concurrent_stream);
75 }

◆ poll()

auto curl::Multi_t::poll ( curl_waitfd *  extra_fds = nullptr,
unsigned  extra_nfds = 0U,
int  timeout = 0 
) -> Ret_except<int, std::bad_alloc, libcurl_bug>
noexcept
Precondition
curl_t::has_multi_poll_support()
Parameters
timeoutMust be >= 0, in ms. Pass 0 for infinite.
Returns
number of fd on which interested events occured.

poll can return if interesting events has happened or timeout ms has passed and nothing has heppend.

It also can return due to pending internal timeout that has a shorter expiry time than timeout_ms.

Definition at line 78 of file curl_multi.cc.

80 {
81  int numfds;
82 
83  auto code = curl_multi_poll(curl_multi, extra_fds, extra_nfds, timeout, &numfds);
84  if (code == CURLM_OUT_OF_MEMORY)
85  return {std::bad_alloc{}};
86  else if (code == CURLM_INTERNAL_ERROR)
87  return {libcurl_bug{"Bug in curl_multi_poll!"}};
88 
89  assert(code == CURLM_OK);
90  return {numfds};
91 }
Here is the caller graph for this function:

◆ break_or_poll()

auto curl::Multi_t::break_or_poll ( curl_waitfd *  extra_fds = nullptr,
unsigned  extra_nfds = 0U,
int  timeout = 0 
) -> Ret_except<int, std::bad_alloc, libcurl_bug>
noexcept
Precondition
curl_t::has_multi_poll_support()
Parameters
timeoutMust be >= 0, in ms. Pass 0 for infinite.
Returns
-1 when get_number_of_handles() == 0; Otherwise number of fd on which interested events occured, can be 0.

Behavior is same as poll.

Definition at line 93 of file curl_multi.cc.

95 {
96  if (get_number_of_handles() == 0)
97  return {-1};
98  else
99  return poll(extra_fds, extra_nfds, timeout);
100 }
Here is the call graph for this function:

◆ perform()

template<class perform_callback_t , class T >
auto curl::Multi_t::perform ( perform_callback_t &&  perform_callback,
T &&  arg 
) -> perform_ret_t
inlinenoexcept
Precondition
perform_callback is set.
Parameters
argwill be passed to perform_callback
perform_callbackMust be callable with (Easy_ref_t, Easy_ref_t::perform_ret_t, Multi_t&, T)
If you want to destroy and free easy.curl_easy, you must first multi.remove_easy(easy_ref) it.
If easy_ref isn't removed from Multi, then the same transfer will happen again in the next call to Multi_t::perform.
Returns
number of running handles

perform() is called only if poll is used.

After perform, perform_callback will be called for each completed easy.

YOU MUST CALL perform() after to start the transfer, then poll

Using libcurl version >= 7.10.3 can provide better error message if Easy_ref_t::ProtocolInternal_error is thrown.

Definition at line 187 of file curl_multi.hpp.

188  {
189  auto ret = perform_impl();
190  callback_on_finished_easy(std::forward<perform_callback_t>(perform_callback), std::forward<T>(arg));
191  return ret;
192  }

◆ register_callback()

void curl::Multi_t::register_callback ( socket_callback_t  socket_callback,
void *  socket_data,
timer_callback_t  timer_callback,
void *  timer_data 
)
noexcept
Parameters
socket_callback,timer_callbacksetting them to nullptr would disable multi_socket_action interface.

You must call this function with non-NULL socket_callback and timer_callback before adding any easy handles.

Definition at line 138 of file curl_multi.cc.

140 {
141  curl_multi_setopt(curl_multi, CURLMOPT_SOCKETFUNCTION, socket_callback);
142  curl_multi_setopt(curl_multi, CURLMOPT_SOCKETDATA, socket_data);
143 
144  curl_multi_setopt(curl_multi, CURLMOPT_TIMERFUNCTION, timer_callback);
145  curl_multi_setopt(curl_multi, CURLMOPT_TIMERDATA, timer_data);
146 }

◆ multi_assign()

auto curl::Multi_t::multi_assign ( curl_socket_t  socketfd,
void *  per_sockptr 
) -> Ret_except<void, std::invalid_argument>
noexcept
Precondition
socketfd must be valid
Returns
std::invalild_argument if socketfd is not valid.

By default, per_sockptr == nullptr.

You can call this function from socket_callback.

Examples
curl_multi_socket_action_uv.cc.

Definition at line 148 of file curl_multi.cc.

150 {
151  auto code = curl_multi_assign(curl_multi, socketfd, per_sockptr);
152  if (code == CURLM_BAD_SOCKET)
153  return {std::invalid_argument{"In curl::Multi_t::multi_assign: socketfd is not valid."}};
154 
155  return {};
156 }

◆ multi_socket_action()

template<class perform_callback_t , class T >
auto curl::Multi_t::multi_socket_action ( curl_socket_t  socketfd,
int  ev_bitmask,
perform_callback_t &&  perform_callback,
T &&  arg 
) -> perform_ret_t
inlinenoexcept
Precondition
enable_multi_socket_interface() is called, perform_callback, socket_callback, timer_callback is set.
Parameters
perform_callbackMust be callable with (Easy_ref_t, Easy_ref_t::perform_ret_t, Multi_t&, T)
If you want to destroy and free easy.curl_easy, you must first multi.remove_easy(easy_ref) it.
If easy_ref isn't removed from Multi, then the same transfer will happen again in the next call to Multi_t::multi_socket_action(socketfd of this easy handler, events, ...).
socketfdfd to be notified;
CURL_SOCKET_TIMEOUT on timeout or to initiate the whole process.
ev_bitmaskOr-ed with 0 or one of the value below:
  • CURL_CSELECT_IN,
  • CURL_CSELECT_OUT,
  • CURL_CSELECT_ERR,

YOU MUST CALL multi_socket_action(CURL_SOCKET_TIMEOUT, 0) to start the transfer, then call waitever poll interface you use

After multi_socket_action, perform_callback will be called for each completed easy.

Using libcurl version >= 7.10.3 can provide better error message if Easy_ref_t::ProtocolInternal_error is thrown.

Examples
curl_multi_socket_action_event.cc, and curl_multi_socket_action_uv.cc.

Definition at line 277 of file curl_multi.hpp.

279  {
280  auto ret = multi_socket_action_impl(socketfd, ev_bitmask);
281  callback_on_finished_easy(std::forward<perform_callback_t>(perform_callback), std::forward<T>(arg));
282  return ret;
283  }

The documentation for this class was generated from the following files:
curl::Multi_t::poll
auto poll(curl_waitfd *extra_fds=nullptr, unsigned extra_nfds=0U, int timeout=0) noexcept -> Ret_except< int, std::bad_alloc, libcurl_bug >
Definition: curl_multi.cc:78