uvco 0.1
Loading...
Searching...
No Matches
Classes | Public Member Functions | Static Public Member Functions | Private Attributes | List of all members
uvco::UvCurlContext_ Class Reference

Classes

struct  PollCtx
 A uv poll handle with its associated CurlRequest_. More...
 

Public Member Functions

 UvCurlContext_ (const Loop &loop)
 
 UvCurlContext_ (const UvCurlContext_ &)=delete
 
 UvCurlContext_ (UvCurlContext_ &&)=delete
 
UvCurlContext_operator= (const UvCurlContext_ &)=delete
 
UvCurlContext_operator= (UvCurlContext_ &&)=delete
 
 ~UvCurlContext_ ()
 
void addHandle (CURL *handle)
 Add a Curl easy handle to the multi handle.
 
void removeHandle (CURL *handle)
 Remove a Curl easy handle from the multi handle.
 
void checkCurlInfo () const
 Checks with Curl for any completed/errored requests.
 
void initPoll (CurlRequestCore_ *request, curl_socket_t newSocket) noexcept
 
void uvStartPoll (curl_socket_t socket, unsigned int events) noexcept
 
void uvStopPoll (curl_socket_t socket) noexcept
 
CurlRequestCore_getRequest (curl_socket_t socket)
 
Promise< void > close ()
 Close all open sockets and the timer.
 

Static Public Member Functions

static int curlSocketFunction (CURL *easy, curl_socket_t socket, int action, void *userp, void *)
 
static int curlTimerFunction (CURLM *, long timeoutMs, void *userp)
 Called by Curl to inform us of a timeout to set up.
 
static void onUvTimeout (uv_timer_t *timer)
 Called by libuv when a timeout timer expires.
 
static void onCurlSocketActive (uv_poll_t *poll, int status, int events)
 Called by libuv when there is activity on a curl socket.
 

Private Attributes

CURLM * multi_
 
uv_loop_t * loop_
 
uv_timer_t timer_
 
std::map< curl_socket_t, PollCtxpolls_
 

Detailed Description

Contains references to the libcurl multi handle and the libuv loop. Only valid as long as one loop instance is running. Used as context for curl socket functions (SOCKETDATA) and timer functions (TIMERDATA).

Constructor & Destructor Documentation

◆ UvCurlContext_() [1/3]

uvco::UvCurlContext_::UvCurlContext_ ( const Loop loop)
explicit
385 : multi_{curl_multi_init()}, loop_{loop.uvloop()}, timer_{} {
386 uv_timer_init(loop_, &timer_);
387 // Set handle data for onUvTimeout callback.
388 setData(&timer_, this);
389
390 // Initialize Curl callbacks.
391 curl_multi_setopt(multi_, CURLMOPT_SOCKETFUNCTION,
393 curl_multi_setopt(multi_, CURLMOPT_SOCKETDATA, this);
394 curl_multi_setopt(multi_, CURLMOPT_TIMERFUNCTION,
396 curl_multi_setopt(multi_, CURLMOPT_TIMERDATA, this);
397}
static int curlSocketFunction(CURL *easy, curl_socket_t socket, int action, void *userp, void *)
Definition curl.cc:473
uv_timer_t timer_
Definition curl.cc:175
uv_loop_t * loop_
Definition curl.cc:174
CURLM * multi_
Definition curl.cc:173
static int curlTimerFunction(CURLM *, long timeoutMs, void *userp)
Called by Curl to inform us of a timeout to set up.
Definition curl.cc:425
void setData(Handle *handle, Data *data)
Definition internal_utils.h:55

◆ UvCurlContext_() [2/3]

uvco::UvCurlContext_::UvCurlContext_ ( const UvCurlContext_ )
delete

◆ UvCurlContext_() [3/3]

uvco::UvCurlContext_::UvCurlContext_ ( UvCurlContext_ &&  )
delete

◆ ~UvCurlContext_()

uvco::UvCurlContext_::~UvCurlContext_ ( )
inline
77 {
78 uv_timer_stop(&timer_);
79 curl_multi_cleanup(multi_);
80 }

Member Function Documentation

◆ addHandle()

void uvco::UvCurlContext_::addHandle ( CURL *  handle)
inline

Add a Curl easy handle to the multi handle.

83{ curl_multi_add_handle(multi_, handle); }

◆ checkCurlInfo()

void uvco::UvCurlContext_::checkCurlInfo ( ) const

Checks with Curl for any completed/errored requests.

399 {
400 CURLMsg *msg{};
401 long responseCode{};
402 long verifyResult{};
403 int inQueue{};
404
405 // Check for completed requests.
406 while (nullptr != (msg = curl_multi_info_read(multi_, &inQueue))) {
407 if (msg->msg == CURLMSG_DONE) {
408 CurlRequestCore_ *request{};
409 BOOST_VERIFY(CURLE_OK == curl_easy_getinfo(msg->easy_handle,
410 CURLINFO_PRIVATE, &request));
411 BOOST_VERIFY(CURLE_OK == curl_easy_getinfo(msg->easy_handle,
412 CURLINFO_RESPONSE_CODE,
413 &responseCode));
414 BOOST_VERIFY(CURLE_OK == curl_easy_getinfo(msg->easy_handle,
415 CURLINFO_SSL_VERIFYRESULT,
416 &verifyResult));
417 request->setCurlStatus(msg->data.result);
418 request->setResponseCode(responseCode);
419 request->setVerifyResult(verifyResult);
420 request->onError(0);
421 }
422 }
423}

◆ close()

Promise< void > uvco::UvCurlContext_::close ( )
inline

Close all open sockets and the timer.

152 {
153 co_await closeHandle(&timer_);
154
155 std::vector<Promise<void>> promises;
156 promises.reserve(polls_.size());
157 for (auto &[socket, poll] : polls_) {
158 promises.push_back(closeHandle(&poll));
159 }
160 for (auto &promise : promises) {
161 co_await promise;
162 }
163 polls_.clear();
164 }
std::map< curl_socket_t, PollCtx > polls_
Definition curl.cc:176
Promise< void > closeHandle(T *handle, C closer)
Definition close.h:28

◆ curlSocketFunction()

int uvco::UvCurlContext_::curlSocketFunction ( CURL *  easy,
curl_socket_t  socket,
int  action,
void *  userp,
void *   
)
static

Called by Curl to inform us of a new socket to monitor or a socket to be removed.

475 {
476 auto *context = static_cast<UvCurlContext_ *>(userp);
477
478 switch (action) {
479 case CURL_POLL_IN:
480 case CURL_POLL_OUT:
481 case CURL_POLL_INOUT: {
482 unsigned int watchFor{};
483
484 // Obtain request object so it can be associated with socket for error
485 // handling.
486 CurlRequestCore_ *request{};
487 curl_easy_getinfo(easy, CURLINFO_PRIVATE, &request);
488
489 if (action != CURL_POLL_IN) {
490 watchFor |= UV_WRITABLE;
491 }
492 if (action != CURL_POLL_OUT) {
493 watchFor |= UV_READABLE;
494 }
495
496 context->initPoll(request, socket);
497 context->uvStartPoll(socket, watchFor);
498 break;
499 }
500
501 case CURL_POLL_REMOVE: {
502 context->uvStopPoll(socket);
503 break;
504 }
505
506 default:
507 BOOST_ASSERT(false);
508 }
509
510 return 0;
511}
UvCurlContext_(const Loop &loop)
Definition curl.cc:384

◆ curlTimerFunction()

int uvco::UvCurlContext_::curlTimerFunction ( CURLM *  ,
long  timeoutMs,
void *  userp 
)
static

Called by Curl to inform us of a timeout to set up.

426 {
427 auto *curl = static_cast<UvCurlContext_ *>(userp);
428 uv_timer_t &timer = curl->timer_;
429 if (timeoutMs < 0) {
430 uv_timer_stop(&timer);
431 } else {
432 uv_timer_start(&timer, UvCurlContext_::onUvTimeout, timeoutMs, 0);
433 }
434 return 0;
435}
static void onUvTimeout(uv_timer_t *timer)
Called by libuv when a timeout timer expires.
Definition curl.cc:437

◆ getRequest()

CurlRequestCore_ & uvco::UvCurlContext_::getRequest ( curl_socket_t  socket)
inline

Returns the CurlRequest associated with the given socket. This is essential for notifying individual requests of socket errors; socket errors occur in a uv callbcak which only has access to the socket.

145 {
146 const auto it = polls_.find(socket);
147 BOOST_ASSERT(it != polls_.end());
148 return *it->second.request;
149 }

◆ initPoll()

void uvco::UvCurlContext_::initPoll ( CurlRequestCore_ request,
curl_socket_t  newSocket 
)
inlinenoexcept
112 {
113 const auto it = polls_.find(newSocket);
114 if (it != polls_.end()) {
115 // Already initialized. Ensure that socket is associated with the correct
116 // request in case Curl reuses a socket.
117 it->second.request = request;
118 return;
119 }
120 const auto newPollCtx = polls_.emplace(newSocket, uv_poll_t{});
121 uv_poll_t &poll = newPollCtx.first->second.poll;
122 newPollCtx.first->second.request = request;
123 uv_poll_init_socket(loop_, &poll, newSocket);
124 setData(&poll, this);
125 }

◆ onCurlSocketActive()

void uvco::UvCurlContext_::onCurlSocketActive ( uv_poll_t *  poll,
int  status,
int  events 
)
static

Called by libuv when there is activity on a curl socket.

445 {
446 int runningHandles{};
447 unsigned int flags{};
448 auto *context = getData<UvCurlContext_>(poll);
449
450 curl_socket_t socket{};
451 const uv_status filenoStatus = uv_fileno((uv_handle_t *)poll, &socket);
452 if (filenoStatus != 0) {
453 throw UvcoException{filenoStatus, "while getting file descriptor"};
454 }
455
456 if (status != 0) {
457 context->getRequest(socket).onError(status);
458 return;
459 }
460
461 if ((static_cast<unsigned>(events) & UV_READABLE) != 0) {
462 flags |= CURL_CSELECT_IN;
463 }
464 if ((static_cast<unsigned>(events) & UV_WRITABLE) != 0) {
465 flags |= CURL_CSELECT_OUT;
466 }
467
468 curl_multi_socket_action(context->multi_, socket, static_cast<int>(flags),
469 &runningHandles);
470 context->checkCurlInfo();
471}
int uv_status
Result of a libuv operation, an errno error code.
Definition internal_utils.h:22

◆ onUvTimeout()

void uvco::UvCurlContext_::onUvTimeout ( uv_timer_t *  timer)
static

Called by libuv when a timeout timer expires.

437 {
438 auto *curl = getData<UvCurlContext_>(timer);
439 int runningHandles = 0;
440 curl_multi_socket_action(curl->multi_, CURL_SOCKET_TIMEOUT, 0,
441 &runningHandles);
442}

◆ operator=() [1/2]

UvCurlContext_ & uvco::UvCurlContext_::operator= ( const UvCurlContext_ )
delete

◆ operator=() [2/2]

UvCurlContext_ & uvco::UvCurlContext_::operator= ( UvCurlContext_ &&  )
delete

◆ removeHandle()

void uvco::UvCurlContext_::removeHandle ( CURL *  handle)
inline

Remove a Curl easy handle from the multi handle.

86{ curl_multi_remove_handle(multi_, handle); }

◆ uvStartPoll()

void uvco::UvCurlContext_::uvStartPoll ( curl_socket_t  socket,
unsigned int  events 
)
inlinenoexcept
127 {
128 const auto it = polls_.find(socket);
129 BOOST_ASSERT(it != polls_.end());
130 uv_poll_t &poll = it->second.poll;
131 uv_poll_start(&poll, static_cast<int>(events),
133 }
static void onCurlSocketActive(uv_poll_t *poll, int status, int events)
Called by libuv when there is activity on a curl socket.
Definition curl.cc:444

◆ uvStopPoll()

void uvco::UvCurlContext_::uvStopPoll ( curl_socket_t  socket)
inlinenoexcept
135 {
136 const auto it = polls_.find(socket);
137 if (it != polls_.end()) {
138 uv_poll_stop(&it->second.poll);
139 }
140 }

Member Data Documentation

◆ loop_

uv_loop_t* uvco::UvCurlContext_::loop_
private

◆ multi_

CURLM* uvco::UvCurlContext_::multi_
private

◆ polls_

std::map<curl_socket_t, PollCtx> uvco::UvCurlContext_::polls_
private

◆ timer_

uv_timer_t uvco::UvCurlContext_::timer_
private

The documentation for this class was generated from the following file: