Hi all I have read this(http://curl.haxx.se/libcurl/c/multi-single.html) and carefully, but I still don't understand how to keep multi interface work again without recreate it when select call failed.
Attached is my code, I call CMultiCurl::Poll in an infinite loop. When I need
to post something, I call CMultiCurl::Post.
This work first, but I don't know when and how, select call failed, then
nothing goes right.
Please help me out, thanks very much.
___________________________________________________________________________________________
int CMultiCurl::Poll(int timeout/*msec*/)
{
struct timeval rTimeo;
rTimeo.tv_sec = timeout / 1000;
rTimeo.tv_usec = (timeout % 1000) * 1000;
long curlTimeo = -1;
curl_multi_timeout(m_mcurl, &curlTimeo);
if (curlTimeo >= 0 && curlTimeo < timeout)
{
rTimeo.tv_sec = curlTimeo / 1000;
rTimeo.tv_usec = (curlTimeo % 1000) * 1000;
}
//XA_TRACE("multi_curl select timeout: %d, %d", rTimeo.tv_sec, rTimeo.tv_usec);
fd_set fdread;
fd_set fdwrite;
fd_set fdexcep;
int maxfd = -1;
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcep);
int ret = curl_multi_fdset(m_mcurl, &fdread, &fdwrite, &fdexcep, &maxfd);
if (ret != 0)
{
XA_ERROR("%d", ret);
return -1;
}
ret = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &rTimeo);
if (ret == -1)
{
XA_ERROR("%d: %s", ret, strerror(errno));
return -1;
}
int stillR = 0;
while (CURLM_CALL_MULTI_PERFORM
== (ret = curl_multi_perform(m_mcurl, &stillR))) {}
if (ret != 0)
{
XA_ERROR("%d", ret);
}
// check msg
int rest = 0;
CURLMsg *msg = NULL;
while (NULL != (msg = curl_multi_info_read(m_mcurl, &rest)))
{
if (msg->msg == CURLMSG_DONE)
{
MCB *mcb = (MCB *)GetFromMap(msg->easy_handle);
DelFromMap(msg->easy_handle);
XA_ASSERT(mcb != NULL);
if (mcb->ptr != NULL)
{
m_callback(msg->data.result, mcb->ptr, mcb->buf, mcb->used);
delete [] mcb->buf;
}
if (mcb->slist != NULL)
{
curl_slist_free_all(mcb->slist);
}
delete mcb;
curl_multi_remove_handle(m_mcurl, msg->easy_handle);
curl_easy_cleanup(msg->easy_handle);
}
}
return 0;
}#include "MultiCurl.h"
typedef struct _MCB
{
struct curl_slist *slist;
void *ptr;
char *buf;
int total;
int used;
}MCB;
static size_t CurlWriteCallback( char *ptr, size_t size, size_t nmemb, void
*userdata)
{
if (size * nmemb == 0) return 0;
int len = (int)(size * nmemb);
// debug
//char debug[1024*16];
//snprintf(debug, 1024*16, ptr, len);
//printf("\n###\n%s\n###\n", debug);
MCB *mcb = (MCB *)userdata;
if (mcb->ptr == NULL)
{
// do nothing
return len;
}
if (len + mcb->used > mcb->total)
{
XA_ERROR("buffer is too small: curSize:%d, at least:%d",
mcb->total, len + mcb->used);
return 0; // This will abort the transfer and return
CURLE_WRITE_ERROR.
}
memcpy(mcb->buf + mcb->used, ptr, len);
mcb->used += len;
return len;
}
int CMultiCurl::Init(MultiCurlCallback callback, int bufLen)
{
m_callback = callback;
m_mcurl = curl_multi_init();
if (m_mcurl == NULL)
{
XA_ERROR("");
return -1;
}
m_bufLen = bufLen;
return 0;
}
int CMultiCurl::Poll(int timeout/*msec*/)
{
struct timeval rTimeo;
rTimeo.tv_sec = timeout / 1000;
rTimeo.tv_usec = (timeout % 1000) * 1000;
long curlTimeo = -1;
curl_multi_timeout(m_mcurl, &curlTimeo);
if (curlTimeo >= 0 && curlTimeo < timeout)
{
rTimeo.tv_sec = curlTimeo / 1000;
rTimeo.tv_usec = (curlTimeo % 1000) * 1000;
}
//XA_TRACE("multi_curl select timeout: %d, %d", rTimeo.tv_sec,
rTimeo.tv_usec);
fd_set fdread;
fd_set fdwrite;
fd_set fdexcep;
int maxfd = -1;
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcep);
int ret = curl_multi_fdset(m_mcurl, &fdread, &fdwrite, &fdexcep,
&maxfd);
if (ret != 0)
{
XA_ERROR("%d", ret);
return -1;
}
ret = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &rTimeo);
if (ret == -1)
{
XA_ERROR("%d: %s", ret, strerror(errno));
return -1;
}
int stillR = 0;
while (CURLM_CALL_MULTI_PERFORM
== (ret = curl_multi_perform(m_mcurl,
&stillR))) {}
if (ret != 0)
{
XA_ERROR("%d", ret);
}
// check msg
int rest = 0;
CURLMsg *msg = NULL;
while (NULL != (msg = curl_multi_info_read(m_mcurl, &rest)))
{
if (msg->msg == CURLMSG_DONE)
{
MCB *mcb = (MCB *)GetFromMap(msg->easy_handle);
DelFromMap(msg->easy_handle);
XA_ASSERT(mcb != NULL);
if (mcb->ptr != NULL)
{
m_callback(msg->data.result, mcb->ptr,
mcb->buf, mcb->used);
delete [] mcb->buf;
}
if (mcb->slist != NULL)
{
curl_slist_free_all(mcb->slist);
}
delete mcb;
curl_multi_remove_handle(m_mcurl, msg->easy_handle);
curl_easy_cleanup(msg->easy_handle);
}
}
return 0;
}
int CMultiCurl::Exit()
{
return 0;
}
int CMultiCurl::Post(const char *url, const char *param, void *ptr,
const char *host, int timeout/*msec*/,
const char *encoding)
{
CURL *curl = curl_easy_init();
XA_ASSERT(curl != NULL);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
//curl_easy_setopt(curl, CURLOPT_HEADER, 1);
curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_POST, 1);
//curl_easy_setopt(curl, CURLOPT_POSTFIELDS, param);
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, param);
curl_easy_setopt(curl, CURLOPT_URL, url);
struct curl_slist *slist = NULL;
if (host != NULL)
{
char buf[256];
snprintf(buf, 256, "Host:%s", host);
slist = curl_slist_append(slist, buf);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
}
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout);
curl_easy_setopt(curl, CURLOPT_ENCODING , encoding);
MCB *mcb = new MCB();
mcb->slist = slist;
mcb->ptr = ptr;
mcb->buf = NULL;
mcb->total = 0;
mcb->used = 0;
if (ptr != NULL)// otherwise no callback
{
mcb->buf = new char[m_bufLen];
mcb->total = m_bufLen;
}
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)mcb);
// debug
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
//printf("\n##post\n%s\n##\n", param);
int ret = curl_multi_add_handle(m_mcurl, curl);
XA_ASSERT(ret == 0);
AddToMap(curl, (void *)mcb);
return 0;
}
void CMultiCurl::AddToMap(CURL* key, void *value)
{
unsigned long k = (unsigned long)key;
int c = m_mcbMap.count(k);
XA_ASSERT(c == 0);
m_mcbMap[k] = value;
return;
}
void CMultiCurl::DelFromMap(CURL *key)
{
unsigned long k = (unsigned long)key;
int c = m_mcbMap.count(k);
XA_ASSERT(c == 1);
m_mcbMap.erase(k);
return;
}
void *CMultiCurl::GetFromMap(CURL *key)
{
unsigned long k = (unsigned long)key;
int c = m_mcbMap.count(k);
XA_ASSERT(c == 1);
return m_mcbMap[k];
}
MultiCurl.h
Description: Binary data
------------------------------------------------------------------- List admin: http://cool.haxx.se/list/listinfo/curl-library Etiquette: http://curl.haxx.se/mail/etiquette.html
