* Use curl's new polling interface so we don't have to switch to

select() while http transfers are active.


git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1065 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
rakshasa
2008-08-27 08:41:08 +00:00
parent c627d6dc0c
commit be8b59b00b
15 changed files with 124 additions and 156 deletions
+47 -13
View File
@@ -43,6 +43,7 @@
#include "rak/functional.h"
#include "curl_get.h"
#include "curl_socket.h"
#include "curl_stack.h"
namespace core {
@@ -51,6 +52,15 @@ CurlStack::CurlStack() :
m_handle((void*)curl_multi_init()),
m_active(0),
m_maxActive(32) {
m_taskTimeout.set_slot(rak::mem_fn(this, &CurlStack::receive_timeout));
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_TIMERDATA, this);
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_SOCKETDATA, this);
#if (LIBCURL_VERSION_NUM >= 0x071000)
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_TIMERFUNCTION, &CurlStack::set_timeout);
#endif
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_SOCKETFUNCTION, &CurlSocket::receive_socket);
}
CurlStack::~CurlStack() {
@@ -58,6 +68,7 @@ CurlStack::~CurlStack() {
front()->close();
curl_multi_cleanup((CURLM*)m_handle);
priority_queue_erase(&taskScheduler, &m_taskTimeout);
}
CurlGet*
@@ -65,16 +76,31 @@ CurlStack::new_object() {
return new CurlGet(this);
}
CurlSocket*
CurlStack::new_socket(int fd) {
CurlSocket* socket = new CurlSocket(fd, this);
curl_multi_assign((CURLM*)m_handle, fd, socket);
return socket;
}
void
CurlStack::perform() {
CurlStack::receive_action(CurlSocket* socket, int events) {
CURLMcode code;
do {
int count;
code = curl_multi_perform((CURLM*)m_handle, &count);
#if (LIBCURL_VERSION_NUM >= 0x071003)
code = curl_multi_socket_action((CURLM*)m_handle, socket != NULL ? socket->file_descriptor() : CURL_SOCKET_TIMEOUT, events, &count);
#else
code = curl_multi_socket((CURLM*)m_handle, socket != NULL ? socket->file_descriptor() : CURL_SOCKET_TIMEOUT, &count);
#endif
if (code > 0)
throw torrent::internal_error("Error calling curl_multi_perform.");
throw torrent::internal_error("Error calling curl_multi_socket_action.");
// Socket might be removed when cleaning handles below, future calls should not use it.
socket = NULL;
events = 0;
if ((unsigned int)count != size()) {
// Done with some handles.
@@ -83,31 +109,29 @@ CurlStack::perform() {
while ((msg = curl_multi_info_read((CURLM*)m_handle, &t)) != NULL) {
if (msg->msg != CURLMSG_DONE)
throw torrent::internal_error("CurlStack::perform() msg->msg != CURLMSG_DONE.");
throw torrent::internal_error("CurlStack::receive_action() msg->msg != CURLMSG_DONE.");
iterator itr = std::find_if(begin(), end(), rak::equal(msg->easy_handle, std::mem_fun(&CurlGet::handle)));
if (itr == end())
throw torrent::internal_error("Could not find CurlGet with the right easy_handle.");
if (msg->data.result == CURLE_OK)
(*itr)->signal_done().emit();
else
(*itr)->signal_failed().emit(curl_easy_strerror(msg->data.result));
}
if (empty())
priority_queue_erase(&taskScheduler, &m_taskTimeout);
}
} while (code == CURLM_CALL_MULTI_PERFORM);
}
unsigned int
CurlStack::fdset(fd_set* readfds, fd_set* writefds, fd_set* exceptfds) {
int maxFd = 0;
if (curl_multi_fdset((CURLM*)m_handle, readfds, writefds, exceptfds, &maxFd) != 0)
throw torrent::internal_error("Error calling curl_multi_fdset.");
return std::max(maxFd, 0);
void
CurlStack::receive_timeout() {
receive_action(NULL, 0);
}
void
@@ -179,4 +203,14 @@ CurlStack::global_cleanup() {
curl_global_cleanup();
}
int
CurlStack::set_timeout(void* handle, long timeout_ms, void* userp) {
CurlStack* stack = (CurlStack*)userp;
priority_queue_erase(&taskScheduler, &stack->m_taskTimeout);
priority_queue_insert(&taskScheduler, &stack->m_taskTimeout, cachedTime + rak::timer::from_milliseconds(timeout_ms));
return 0;
}
}