bool CMultiHttp::Perform() { struct timeval timeout; int still_running=0; int rc=0; /* select() return code */ CURLMcode mc; /* curl_multi_fdset() return code */ fd_set fdread; fd_set fdwrite; fd_set fdexcep; int maxfd = -1; long curl_timeo = -1; FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* set a suitable timeout to play around with */ timeout.tv_sec = 5; timeout.tv_usec = 0; curl_multi_timeout(m_murl, &curl_timeo); if( curl_timeo==0 ) curl_timeo=50; if(curl_timeo >= 0) { timeout.tv_sec = curl_timeo/1000; if(timeout.tv_sec > 1) timeout.tv_sec = 1; else timeout.tv_usec = (curl_timeo % 1000) * 1000; } /* get file descriptors from the transfers */ mc = curl_multi_fdset(m_murl, &fdread, &fdwrite, &fdexcep, &maxfd); if(mc != CURLM_OK) { LOG_FUNC_P1(_T("curl_multi_fdset() failed, code %d"),mc); return false; } /* On success the value of maxfd is guaranteed to be >= -1. We call select(maxfd + 1, ...); specially in case of (maxfd == -1) there are no fds ready yet so we call select(0, ...) --or Sleep() on Windows-- to sleep 100ms, which is the minimum suggested value in the curl_multi_fdset() doc. */ if(maxfd == -1) { Sleep(100); rc = 0; } else { FD_SET(m_fds[1],&fdread); FD_SET(m_fds[1],&fdwrite); FD_SET(m_fds[1],&fdexcep); rc = ::select(maxfd+2, &fdread,&fdwrite, &fdexcep, &timeout); if(FD_ISSET(m_fds[1],&fdread)) { std::string cmd; if( !recvcmd(m_fds[1],cmd) ) { m_state = CMultiHttp::Terminate; return false; } if( cmd==CMD_CANCEL ) { LOG_FUNC_P0(_T("url 后台线程 收到退出指令")); m_state = CMultiHttp::Terminate; return false; } } } switch(rc) { case -1: /* select error */ break; case 0: default: while( CURLM_CALL_MULTI_PERFORM==curl_multi_perform(m_murl,&still_running) ) ; { struct CURLMsg *m; int msgQ=0; m = curl_multi_info_read(m_murl,&msgQ); if(m && (m->msg == CURLMSG_DONE)) { CURL *e = m->easy_handle; if( !OneComplete(e,m->data.result) ) still_running=0; } } break; } if( still_running ) return true; m_state = CMultiHttp::Terminate; return false; }
bool Net::Session::Select(int timeout_ms) { fd_set rfds, wfds, efds; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); int max_fd; CURLMcode mcode = curl_multi_fdset(multi, &rfds, &wfds, &efds, &max_fd); if (mcode != CURLM_OK) return false; long curl_timeout; mcode = curl_multi_timeout(multi, &curl_timeout); if (mcode == CURLM_OK && curl_timeout >= 0) { if (curl_timeout < 50) curl_timeout = 50; if (timeout_ms < 0 || curl_timeout < (long)timeout_ms) timeout_ms = curl_timeout; } struct timeval timeout, *timeout_p; if (timeout_ms >= 0) { timeout.tv_sec = timeout_ms / 1000; timeout.tv_usec = timeout_ms * 1000; timeout_p = &timeout; } else timeout_p = NULL; int ret = select(max_fd, &rfds, &wfds, &efds, timeout_p); return ret > 0; }
/* Called before all the file descriptors are polled by the glib main loop. We must have a look at all fds that libcurl wants polled. If any of them are new/no longer needed, we have to (de)register them with glib. */ gboolean prepare(GSource* source, gint* timeout) { D((stderr, "prepare\n")); assert(source == &curlSrc->source); if (curlSrc->multiHandle == 0) return FALSE; registerUnregisterFds(); // Handle has been added. we are ready if (curlSrc->callPerform == -1) { s_currTimeout = *timeout = 0; return TRUE; } long curlTimeout = 0; curl_multi_timeout(curlSrc->multiHandle, &curlTimeout); // Curl tells us it is ready if (curlTimeout == 0) { s_currTimeout = *timeout = 0; return TRUE; } // Curl says wait forever. do it only when if we don't have pending // connections if (curlTimeout < 0) { s_currTimeout = *timeout = (s_numEasyHandles > 0) ? GLIBCURL_TIMEOUT : -1; return FALSE; } s_currTimeout = *timeout = MIN(GLIBCURL_TIMEOUT, curlTimeout); return FALSE; }
/** * Function setting up file descriptors and scheduling task to run * * @param plugin plugin as closure * @param now schedule task in 1ms, regardless of what curl may say * @return GNUNET_SYSERR for hard failure, GNUNET_OK for ok */ static int client_schedule (struct Plugin *plugin, int now) { fd_set rs; fd_set ws; fd_set es; int max; struct GNUNET_NETWORK_FDSet *grs; struct GNUNET_NETWORK_FDSet *gws; long to; CURLMcode mret; struct GNUNET_TIME_Relative timeout; /* Cancel previous scheduled task */ if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->client_perform_task); plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; } max = -1; FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); mret = curl_multi_fdset (plugin->client_mh, &rs, &ws, &es, &max); if (mret != CURLM_OK) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), "curl_multi_fdset", __FILE__, __LINE__, curl_multi_strerror (mret)); return GNUNET_SYSERR; } mret = curl_multi_timeout (plugin->client_mh, &to); if (to == -1) timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1); else timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, to); if (now == GNUNET_YES) timeout = GNUNET_TIME_UNIT_MILLISECONDS; if (mret != CURLM_OK) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), "curl_multi_timeout", __FILE__, __LINE__, curl_multi_strerror (mret)); return GNUNET_SYSERR; } grs = GNUNET_NETWORK_fdset_create (); gws = GNUNET_NETWORK_fdset_create (); GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1); GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1); plugin->client_perform_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, timeout, grs, gws, &client_run, plugin); GNUNET_NETWORK_fdset_destroy (gws); GNUNET_NETWORK_fdset_destroy (grs); return GNUNET_OK; }
static void do_select_job(CURLM* cmh) { fd_set fdread; fd_set fdwrite; fd_set fdexcep; int maxfd = -1; long curl_timeo = -1; FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); struct timeval timeout; timeout.tv_sec = 1; timeout.tv_usec = 0; curl_multi_timeout(cmh, &curl_timeo); if (curl_timeo >= 0) { timeout.tv_sec = curl_timeo / 1000; if (timeout.tv_sec > 1) { timeout.tv_sec = 1; } else { timeout.tv_usec = (curl_timeo % 1000) * 1000; } } curl_multi_fdset(cmh, &fdread, &fdwrite, &fdexcep, &maxfd); select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); }
smcp_status_t smcp_curl_proxy_node_update_fdset( smcp_curl_proxy_node_t self, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *error_fd_set, int *max_fd, cms_t *timeout ) { int fd = *max_fd; long cms_timeout = *timeout; curl_multi_fdset( self->curl_multi_handle, read_fd_set, write_fd_set, error_fd_set, &fd ); *max_fd = MAX(*max_fd,fd); curl_multi_timeout( self->curl_multi_handle, &cms_timeout ); if(cms_timeout!=-1) { *timeout = MIN(*timeout,cms_timeout); } return SMCP_STATUS_OK; }
/** * The GSource prepare() method implementation. */ static gboolean curl_source_prepare(G_GNUC_UNUSED GSource *source, G_GNUC_UNUSED gint *timeout_) { http_client_update_fds(); #if LIBCURL_VERSION_NUM >= 0x070f04 http_client.timeout = false; long timeout2; CURLMcode mcode = curl_multi_timeout(http_client.multi, &timeout2); if (mcode == CURLM_OK) { if (timeout2 >= 0 && timeout2 < 10) /* CURL 7.21.1 likes to report "timeout=0", which means we're running in a busy loop. Quite a bad idea to waste so much CPU. Let's use a lower limit of 10ms. */ timeout2 = 10; *timeout_ = timeout2; http_client.timeout = timeout2 >= 0; } else g_warning("curl_multi_timeout() failed: %s\n", curl_multi_strerror(mcode)); #endif return FALSE; }
/* * call-seq: * multi = Curl::Multi.new * easy1 = Curl::Easy.new('url') * easy2 = Curl::Easy.new('url') * * multi.add(easy1) * multi.add(easy2) * * multi.perform do * # while idle other code my execute here * end * * Run multi handles, looping selecting when data can be transfered */ static VALUE ruby_curl_multi_perform(VALUE self) { CURLMcode mcode; ruby_curl_multi *rbcm; int maxfd, rc; fd_set fdread, fdwrite, fdexcep; long timeout; struct timeval tv = {0, 0}; Data_Get_Struct(self, ruby_curl_multi, rbcm); //rb_gc_mark(self); rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) ); while(rbcm->running) { FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* load the fd sets from the multi handle */ mcode = curl_multi_fdset(rbcm->handle, &fdread, &fdwrite, &fdexcep, &maxfd); if (mcode != CURLM_OK) { raise_curl_multi_error_exception(mcode); } /* get the curl suggested time out */ mcode = curl_multi_timeout(rbcm->handle, &timeout); if (mcode != CURLM_OK) { raise_curl_multi_error_exception(mcode); } if (timeout == 0) { /* no delay */ rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) ); continue; } else if (timeout == -1) { timeout = 1; /* You must not wait too long (more than a few seconds perhaps) before you call curl_multi_perform() again */ } if (rb_block_given_p()) { rb_yield(self); } tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout * 1000) % 1000000; rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv); if (rc < 0) { rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno)); } rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) ); } return Qnil; }
void curl_perform_wait() { long timeout_ms = -1; CURLMcode result = curl_multi_timeout(curl_handle, &timeout_ms); if (result != CURLM_OK) log_error("curl_multi_timeout error %d", result); if (timeout_ms < 1) timeout_ms = 1; int numfds = 0; result = curl_multi_wait(curl_handle, NULL, 0, (int)timeout_ms, &numfds); if (result != CURLM_OK) log_error("curl_multi_wait error %d", result); int numrunning = 0; result = curl_multi_perform(curl_handle, &numrunning); if (result != CURLM_OK) log_error("curl_multi_perform error %d", result); int pending = 0; CURLMsg *message; while ((message = curl_multi_info_read(curl_handle, &pending))) { switch (message->msg) { case CURLMSG_DONE: { const char* done_url; CURL* easy = message->easy_handle; curl_easy_getinfo(easy, CURLINFO_EFFECTIVE_URL, &done_url); CURLcode code = message->data.result; printf("%s DONE\ncode:%d - %s\n", done_url, code, curl_easy_strerror(code)); struct curl_slist* list; curl_easy_getinfo(easy, CURLINFO_PRIVATE, &list); --remaining; if (--repeats) { add_download(done_url); } curl_multi_remove_handle(curl_handle, easy); curl_easy_cleanup(easy); curl_slist_free_all(list); break; } default: log_error("CURLMSG default\n"); abort(); } } if (remaining == 0) { curl_multi_cleanup(curl_handle); exit(0); } }
int64_t S3_get_request_context_timeout(S3RequestContext *requestContext) { long timeout; if (curl_multi_timeout(requestContext->curlm, &timeout) != CURLM_OK) { timeout = 0; } return timeout; }
int set_timeout() { long timeout; if (curl_multi_timeout(m_handler, &timeout)) { LOGE("@set_timeout curl_multi_timeout"); return -1; } if(timeout < 0) timeout = MULTI_SELECT_TIMEOUT; m_timeout.tv_sec = timeout / 1000; m_timeout.tv_usec = (timeout % 1000) * 1000; return 0; }
static CURLcode easy_transfer(struct Curl_multi *multi) { bool done = FALSE; CURLMcode mcode = CURLM_OK; CURLcode result = CURLE_OK; while(!done && !mcode) { int still_running = 0; bool gotsocket = FALSE; mcode = Curl_multi_wait(multi, NULL, 0, 1000, NULL, &gotsocket); if(!mcode) { if(!gotsocket) { long sleep_ms; /* If it returns without any filedescriptor instantly, we need to avoid busy-looping during periods where it has nothing particular to wait for */ curl_multi_timeout(multi, &sleep_ms); if(sleep_ms) { if(sleep_ms > 1000) sleep_ms = 1000; Curl_wait_ms((int)sleep_ms); } } mcode = curl_multi_perform(multi, &still_running); } /* only read 'still_running' if curl_multi_perform() return OK */ if(!mcode && !still_running) { int rc; CURLMsg *msg = curl_multi_info_read(multi, &rc); if(msg) { result = msg->data.result; done = TRUE; } } } /* Make sure to return some kind of error if there was a multi problem */ if(mcode) { result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY : /* The other multi errors should never happen, so return something suitably generic */ CURLE_BAD_FUNCTION_ARGUMENT; } return result; }
/** * Initialises the Ecore_Con_Url library. * @return Number of times the library has been initialised without being * shut down. * @ingroup Ecore_Con_Url_Group */ EAPI int ecore_con_url_init(void) { #ifdef HAVE_CURL init_count++; if (init_count > 1) return init_count; if (!ECORE_CON_EVENT_URL_DATA) { ECORE_CON_EVENT_URL_DATA = ecore_event_type_new(); ECORE_CON_EVENT_URL_COMPLETE = ecore_event_type_new(); ECORE_CON_EVENT_URL_PROGRESS = ecore_event_type_new(); } if (!curlm) { long ms; FD_ZERO(&_current_fd_set); if (curl_global_init(CURL_GLOBAL_NOTHING)) { while (_url_con_list) ecore_con_url_destroy(eina_list_data_get(_url_con_list)); return 0; } curlm = curl_multi_init(); if (!curlm) { while (_url_con_list) ecore_con_url_destroy(eina_list_data_get(_url_con_list)); init_count--; return 0; } curl_multi_timeout(curlm, &ms); if (ms <= 0) ms = 1000; _curl_timeout = ecore_timer_add((double) ms / 1000, _ecore_con_url_idler_handler, (void *) 0xACE); ecore_timer_freeze(_curl_timeout); } return 1; #else return 0; #endif }
static PyObject * do_multi_timeout(CurlMultiObject *self) { CURLMcode res; long timeout; if (check_multi_state(self, 1 | 2, "timeout") != 0) { return NULL; } res = curl_multi_timeout(self->multi_handle, &timeout); if (res != CURLM_OK) { CURLERROR_MSG("timeout failed"); } /* Return number of millisecs until timeout */ return Py_BuildValue("l", timeout); }
struct timeval* http_get_timeout(void *d){ struct http_data *data=(struct http_data*)d; long curl_timeo = -1; if(data->cm==NULL) return NULL; curl_multi_timeout(data->cm, &curl_timeo); if(curl_timeo >= 0) { data->timeout.tv_sec = curl_timeo / 1000; if(data->timeout.tv_sec > 1) data->timeout.tv_sec = 1; else data->timeout.tv_usec = (curl_timeo % 1000) * 1000; } return &data->timeout; }
bool CCURLWrapper::Process() { if (m_bDone) return false; if (m_lTimer > GetTime()) return true; Perform(); const long maxwait = 250; // msec long timeout = 0; CheckM(curl_multi_timeout(m_pCurlMulti, &timeout)); timeout = std::min(timeout, maxwait); m_lTimer = GetTime() + timeout; CURLMsg *msg; int qleft; while ((msg = curl_multi_info_read(m_pCurlMulti, &qleft)) != NULL) { if (msg->msg == CURLMSG_DONE) { m_bDone = true; if (msg->data.result != CURLE_OK) m_Result = curl_easy_strerror(msg->data.result); else { long status; Check(curl_easy_getinfo(m_pCurl, CURLINFO_RESPONSE_CODE, &status)); if ((status >= 400) && (status < 600)) // FTP/HTTP 4xx or 5xx code? m_Result = "Error starting download"; // UNDONE? } break; } } return !m_bDone; }
static int wait_perform() { fd_set rd, wr, ex; int maxfd, nrunning; long timeout; CURLMcode errm; FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&ex); if (curl_multi_fdset(curl.multi, &rd, &wr, &ex, &maxfd) != CURLM_OK) maxfd = -1, timeout = 1000; else if (maxfd < 0) timeout = 100; // as recommended by curl_multi_fdset(3) else { if (curl_multi_timeout(curl.multi, &timeout) != CURLM_OK) timeout = 1000; else if (timeout < 0) timeout = 10000; // as recommended by curl_multi_timeout(3) } if (timeout > 0 && ! curl.perform_again) { struct timeval tval; tval.tv_sec = (timeout / 1000); tval.tv_usec = (timeout % 1000) * 1000; if (select(maxfd + 1, &rd, &wr, &ex, &tval) < 0) return -1; } errm = curl_multi_perform(curl.multi, &nrunning); curl.perform_again = 0; if (errm == CURLM_CALL_MULTI_PERFORM) curl.perform_again = 1; else if (errm != CURLM_OK) { errno = multi_errno(errm); return -1; } if (nrunning < curl.nrunning) process_messages(); return 0; }
/** * Run all deferred multi calls and wait for the result * * @param sdb the SimpleDB handle * @return the result */ int sdb_multi_run_and_wait(struct SDB* sdb) { // This code was inspired by the implementation of readdir() in s3fs by Randy Rizun int running, r; while (curl_multi_perform(sdb->curl_multi, &running) == CURLM_CALL_MULTI_PERFORM) usleep(5); while (running) { fd_set read_fd_set; fd_set write_fd_set; fd_set exc_fd_set; FD_ZERO(&read_fd_set); FD_ZERO(&write_fd_set); FD_ZERO(&exc_fd_set); long ms; if ((r = curl_multi_timeout(sdb->curl_multi, &ms)) != CURLM_OK) return SDB_CURLM_ERROR(r); if (ms < 0) ms = 50; if (ms > 0) { struct timeval timeout; timeout.tv_sec = 1000 * ms / 1000000; timeout.tv_usec = 1000 * ms % 1000000; int max_fd; if ((r = curl_multi_fdset(sdb->curl_multi, &read_fd_set, &write_fd_set, &exc_fd_set, &max_fd)) != CURLM_OK) return SDB_CURLM_ERROR(r); if (select(max_fd + 1, &read_fd_set, &write_fd_set, &exc_fd_set, &timeout) == -1) return SDB_E_FD_ERROR; } while (curl_multi_perform(sdb->curl_multi, &running) == CURLM_CALL_MULTI_PERFORM) usleep(5); } return SDB_OK; }
/* * Simply download a HTTP file. */ int main(void) { CURL *http_handle; CURLM *multi_handle; int still_running; /* keep number of running handles */ http_handle = curl_easy_init(); /* set the options (I left out a few, you'll get the point anyway) */ curl_easy_setopt(http_handle, CURLOPT_URL, "http://www.example.com/"); /* init a multi stack */ multi_handle = curl_multi_init(); /* add the individual transfers */ curl_multi_add_handle(multi_handle, http_handle); /* we start some action by calling perform right away */ curl_multi_perform(multi_handle, &still_running); do { struct timeval timeout; int rc; /* select() return code */ fd_set fdread; fd_set fdwrite; fd_set fdexcep; int maxfd = -1; long curl_timeo = -1; FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* set a suitable timeout to play around with */ timeout.tv_sec = 1; timeout.tv_usec = 0; curl_multi_timeout(multi_handle, &curl_timeo); if(curl_timeo >= 0) { timeout.tv_sec = curl_timeo / 1000; if(timeout.tv_sec > 1) timeout.tv_sec = 1; else timeout.tv_usec = (curl_timeo % 1000) * 1000; } /* get file descriptors from the transfers */ curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); /* In a real-world program you OF COURSE check the return code of the function calls. On success, the value of maxfd is guaranteed to be greater or equal than -1. We call select(maxfd + 1, ...), specially in case of (maxfd == -1), we call select(0, ...), which is basically equal to sleep. */ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); switch(rc) { case -1: /* select error */ still_running = 0; printf("select() returns error, this is badness\n"); break; case 0: default: /* timeout or readable/writable sockets */ curl_multi_perform(multi_handle, &still_running); break; } } while(still_running); curl_multi_cleanup(multi_handle); curl_easy_cleanup(http_handle); return 0; }
static void curl_main () { fd_set rs; fd_set ws; fd_set es; int max; struct GNUNET_NETWORK_FDSet nrs; struct GNUNET_NETWORK_FDSet nws; struct GNUNET_TIME_Relative delay; long timeout; int running; struct CURLMsg *msg; max = 0; FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); curl_multi_perform (multi, &running); if (running == 0) { GNUNET_assert (NULL != (msg = curl_multi_info_read (multi, &running))); if (msg->msg == CURLMSG_DONE) { if (msg->data.result != CURLE_OK) { fprintf (stderr, "%s failed at %s:%d: `%s'\n", "curl_multi_perform", __FILE__, __LINE__, curl_easy_strerror (msg->data.result)); global_ret = 1; } } curl_multi_remove_handle (multi, curl); curl_multi_cleanup (multi); curl_easy_cleanup (curl); curl = NULL; multi = NULL; if (cbc.pos != strlen ("/hello_world")) { GNUNET_break (0); global_ret = 2; } if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) { GNUNET_break (0); global_ret = 3; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download complete, shutting down!\n"); do_shutdown (); return; } GNUNET_assert (CURLM_OK == curl_multi_fdset (multi, &rs, &ws, &es, &max)); if ( (CURLM_OK != curl_multi_timeout (multi, &timeout)) || (-1 == timeout) ) delay = GNUNET_TIME_UNIT_SECONDS; else delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, (unsigned int) timeout); GNUNET_NETWORK_fdset_copy_native (&nrs, &rs, max + 1); GNUNET_NETWORK_fdset_copy_native (&nws, &ws, max + 1); curl_task_id = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, delay, &nrs, &nws, &curl_task, NULL); }
static void tr_webThreadFunc( void * vsession ) { int unused; CURLM * multi; struct tr_web * web; int taskCount = 0; tr_session * session = vsession; /* try to enable ssl for https support; but if that fails, * try a plain vanilla init */ if( curl_global_init( CURL_GLOBAL_SSL ) ) curl_global_init( 0 ); web = tr_new0( struct tr_web, 1 ); web->close_mode = ~0; web->taskLock = tr_lockNew( ); web->tasks = NULL; multi = curl_multi_init( ); session->web = web; for( ;; ) { long msec; CURLMsg * msg; CURLMcode mcode; struct tr_web_task * task; if( web->close_mode == TR_WEB_CLOSE_NOW ) break; if( ( web->close_mode == TR_WEB_CLOSE_WHEN_IDLE ) && !taskCount ) break; /* add tasks from the queue */ tr_lockLock( web->taskLock ); while(( task = tr_list_pop_front( &web->tasks ))) { dbgmsg( "adding task to curl: [%s]", task->url ); curl_multi_add_handle( multi, createEasy( session, task )); /*fprintf( stderr, "adding a task.. taskCount is now %d\n", taskCount );*/ ++taskCount; } tr_lockUnlock( web->taskLock ); /* maybe wait a little while before calling curl_multi_perform() */ msec = 0; curl_multi_timeout( multi, &msec ); if( msec < 0 ) msec = THREADFUNC_MAX_SLEEP_MSEC; if( msec > 0 ) { int usec; int max_fd; struct timeval t; fd_set r_fd_set, w_fd_set, c_fd_set; max_fd = 0; FD_ZERO( &r_fd_set ); FD_ZERO( &w_fd_set ); FD_ZERO( &c_fd_set ); curl_multi_fdset( multi, &r_fd_set, &w_fd_set, &c_fd_set, &max_fd ); if( msec > THREADFUNC_MAX_SLEEP_MSEC ) msec = THREADFUNC_MAX_SLEEP_MSEC; usec = msec * 1000; t.tv_sec = usec / 1000000; t.tv_usec = usec % 1000000; tr_select( max_fd+1, &r_fd_set, &w_fd_set, &c_fd_set, &t ); } /* call curl_multi_perform() */ do { mcode = curl_multi_perform( multi, &unused ); } while( mcode == CURLM_CALL_MULTI_PERFORM ); /* pump completed tasks from the multi */ while(( msg = curl_multi_info_read( multi, &unused ))) { if(( msg->msg == CURLMSG_DONE ) && ( msg->easy_handle != NULL )) { struct tr_web_task * task; CURL * e = msg->easy_handle; curl_easy_getinfo( e, CURLINFO_PRIVATE, (void*)&task ); curl_easy_getinfo( e, CURLINFO_RESPONSE_CODE, &task->code ); curl_multi_remove_handle( multi, e ); curl_easy_cleanup( e ); /*fprintf( stderr, "removing a completed task.. taskCount is now %d (response code: %d, response len: %d)\n", taskCount, (int)task->code, (int)evbuffer_get_length(task->response) );*/ tr_runInEventThread( task->session, task_finish_func, task ); --taskCount; } } } /* cleanup */ curl_multi_cleanup( multi ); tr_lockFree( web->taskLock ); tr_free( web ); session->web = NULL; }
int test(char *URL) { CURL *easy; CURLM *multi_handle; int still_running; /* keep number of running handles */ CURLMsg *msg; /* for picking up messages with the transfer status */ int msgs_left; /* how many messages are left */ /* Allocate one CURL handle per transfer */ easy = curl_easy_init(); /* init a multi stack */ multi_handle = curl_multi_init(); /* add the individual transfer */ curl_multi_add_handle(multi_handle, easy); /* set the options (I left out a few, you'll get the point anyway) */ curl_easy_setopt(easy, CURLOPT_URL, URL); curl_easy_setopt(easy, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)testDataSize); curl_easy_setopt(easy, CURLOPT_POSTFIELDS, testData); /* we start some action by calling perform right away */ curl_multi_perform(multi_handle, &still_running); do { struct timeval timeout; int rc; /* select() return code */ CURLMcode mc; /* curl_multi_fdset() return code */ fd_set fdread; fd_set fdwrite; fd_set fdexcep; int maxfd = -1; long curl_timeo = -1; FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* set a suitable timeout to play around with */ timeout.tv_sec = 1; timeout.tv_usec = 0; curl_multi_timeout(multi_handle, &curl_timeo); if(curl_timeo >= 0) { timeout.tv_sec = curl_timeo / 1000; if(timeout.tv_sec > 1) timeout.tv_sec = 1; else timeout.tv_usec = (curl_timeo % 1000) * 1000; } /* get file descriptors from the transfers */ mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); if(mc != CURLM_OK) { fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc); break; } /* On success the value of maxfd is guaranteed to be >= -1. We call select(maxfd + 1, ...); specially in case of (maxfd == -1) there are no fds ready yet so we call select(0, ...) --or Sleep() on Windows-- to sleep 100ms, which is the minimum suggested value in the curl_multi_fdset() doc. */ if(maxfd == -1) { #ifdef _WIN32 Sleep(100); rc = 0; #else /* Portable sleep for platforms other than Windows. */ struct timeval wait = { 0, 100 * 1000 }; /* 100ms */ rc = select(0, NULL, NULL, NULL, &wait); #endif } else { /* Note that on some platforms 'timeout' may be modified by select(). If you need access to the original value save a copy beforehand. */ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); } switch(rc) { case -1: /* select error */ break; case 0: /* timeout */ default: /* action */ curl_multi_perform(multi_handle, &still_running); break; } } while(still_running); /* See how the transfers went */ while((msg = curl_multi_info_read(multi_handle, &msgs_left))) { if(msg->msg == CURLMSG_DONE) { printf("HTTP transfer completed with status %d\n", msg->data.result); break; } } curl_multi_cleanup(multi_handle); /* Free the CURL handles */ curl_easy_cleanup(easy); return 0; }
/* * call-seq: * multi = Curl::Multi.new * easy1 = Curl::Easy.new('url') * easy2 = Curl::Easy.new('url') * * multi.add(easy1) * multi.add(easy2) * * multi.perform do * # while idle other code my execute here * end * * Run multi handles, looping selecting when data can be transfered */ VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) { CURLMcode mcode; ruby_curl_multi *rbcm; int maxfd, rc; fd_set fdread, fdwrite, fdexcep; #ifdef _WIN32 fd_set crt_fdread, crt_fdwrite, crt_fdexcep; #endif long timeout_milliseconds; struct timeval tv = {0, 0}; VALUE block = Qnil; rb_scan_args(argc, argv, "0&", &block); Data_Get_Struct(self, ruby_curl_multi, rbcm); timeout_milliseconds = cCurlMutiDefaulttimeout; rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) ); do { while (rbcm->running) { #ifdef HAVE_CURL_MULTI_TIMEOUT /* get the curl suggested time out */ mcode = curl_multi_timeout(rbcm->handle, &timeout_milliseconds); if (mcode != CURLM_OK) { raise_curl_multi_error_exception(mcode); } #else /* libcurl doesn't have a timeout method defined, initialize to -1 we'll pick up the default later */ timeout_milliseconds = -1; #endif if (timeout_milliseconds == 0) { /* no delay */ rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) ); continue; } else if (timeout_milliseconds < 0) { timeout_milliseconds = cCurlMutiDefaulttimeout; /* libcurl doesn't know how long to wait, use a default timeout */ } if (timeout_milliseconds > cCurlMutiDefaulttimeout) { timeout_milliseconds = cCurlMutiDefaulttimeout; /* buggy versions libcurl sometimes reports huge timeouts... let's cap it */ } tv.tv_sec = 0; /* never wait longer than 1 second */ tv.tv_usec = (int)(timeout_milliseconds * 1000); /* XXX: int is the right type for OSX, what about linux? */ if (timeout_milliseconds == 0) { /* no delay */ rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) ); continue; } if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); } FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* load the fd sets from the multi handle */ mcode = curl_multi_fdset(rbcm->handle, &fdread, &fdwrite, &fdexcep, &maxfd); if (mcode != CURLM_OK) { raise_curl_multi_error_exception(mcode); } #ifdef _WIN32 create_crt_fd(&fdread, &crt_fdread); create_crt_fd(&fdwrite, &crt_fdwrite); create_crt_fd(&fdexcep, &crt_fdexcep); #endif rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv); #ifdef _WIN32 cleanup_crt_fd(&fdread, &crt_fdread); cleanup_crt_fd(&fdwrite, &crt_fdwrite); cleanup_crt_fd(&fdexcep, &crt_fdexcep); #endif switch(rc) { case -1: rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno)); break; case 0: rb_curl_multi_read_info( self, rbcm->handle ); if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); } default: rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) ); break; } } rb_curl_multi_read_info( self, rbcm->handle ); if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); } } while( rbcm->running ); return Qtrue; }
static void tr_webThreadFunc( void * vsession ) { CURLM * multi; struct tr_web * web; int taskCount = 0; struct tr_web_task * task; tr_session * session = vsession; /* try to enable ssl for https support; but if that fails, * try a plain vanilla init */ if( curl_global_init( CURL_GLOBAL_SSL ) ) curl_global_init( 0 ); web = tr_new0( struct tr_web, 1 ); web->close_mode = ~0; web->taskLock = tr_lockNew( ); web->tasks = NULL; web->curl_verbose = getenv( "TR_CURL_VERBOSE" ) != NULL; web->cookie_filename = tr_buildPath( session->configDir, "cookies.txt", NULL ); multi = curl_multi_init( ); session->web = web; for( ;; ) { long msec; int unused; CURLMsg * msg; CURLMcode mcode; if( web->close_mode == TR_WEB_CLOSE_NOW ) break; if( ( web->close_mode == TR_WEB_CLOSE_WHEN_IDLE ) && ( web->tasks == NULL ) ) break; /* add tasks from the queue */ tr_lockLock( web->taskLock ); while( web->tasks != NULL ) { /* pop the task */ task = web->tasks; web->tasks = task->next; task->next = NULL; dbgmsg( "adding task to curl: [%s]", task->url ); curl_multi_add_handle( multi, createEasy( session, web, task )); /*fprintf( stderr, "adding a task.. taskCount is now %d\n", taskCount );*/ ++taskCount; } tr_lockUnlock( web->taskLock ); /* maybe wait a little while before calling curl_multi_perform() */ msec = 0; curl_multi_timeout( multi, &msec ); if( msec < 0 ) msec = THREADFUNC_MAX_SLEEP_MSEC; if( session->isClosed ) msec = 100; /* on shutdown, call perform() more frequently */ if( msec > 0 ) { int usec; int max_fd; struct timeval t; fd_set r_fd_set, w_fd_set, c_fd_set; max_fd = 0; FD_ZERO( &r_fd_set ); FD_ZERO( &w_fd_set ); FD_ZERO( &c_fd_set ); curl_multi_fdset( multi, &r_fd_set, &w_fd_set, &c_fd_set, &max_fd ); if( msec > THREADFUNC_MAX_SLEEP_MSEC ) msec = THREADFUNC_MAX_SLEEP_MSEC; usec = msec * 1000; t.tv_sec = usec / 1000000; t.tv_usec = usec % 1000000; tr_select( max_fd+1, &r_fd_set, &w_fd_set, &c_fd_set, &t ); } /* call curl_multi_perform() */ do { mcode = curl_multi_perform( multi, &unused ); } while( mcode == CURLM_CALL_MULTI_PERFORM ); /* pump completed tasks from the multi */ while(( msg = curl_multi_info_read( multi, &unused ))) { if(( msg->msg == CURLMSG_DONE ) && ( msg->easy_handle != NULL )) { double total_time; struct tr_web_task * task; long req_bytes_sent; CURL * e = msg->easy_handle; curl_easy_getinfo( e, CURLINFO_PRIVATE, (void*)&task ); curl_easy_getinfo( e, CURLINFO_RESPONSE_CODE, &task->code ); curl_easy_getinfo( e, CURLINFO_REQUEST_SIZE, &req_bytes_sent ); curl_easy_getinfo( e, CURLINFO_TOTAL_TIME, &total_time ); task->did_connect = task->code>0 || req_bytes_sent>0; task->did_timeout = !task->code && ( total_time >= task->timeout_secs ); curl_multi_remove_handle( multi, e ); curl_easy_cleanup( e ); /*fprintf( stderr, "removing a completed task.. taskCount is now %d (response code: %d, response len: %d)\n", taskCount, (int)task->code, (int)evbuffer_get_length(task->response) );*/ tr_runInEventThread( task->session, task_finish_func, task ); --taskCount; } } } /* Discard any remaining tasks. * This is rare, but can happen on shutdown with unresponsive trackers. */ while( web->tasks != NULL ) { task = web->tasks; web->tasks = task->next; dbgmsg( "Discarding task \"%s\"", task->url ); task_free( task ); } /* cleanup */ curl_multi_cleanup( multi ); tr_lockFree( web->taskLock ); tr_free( web->cookie_filename ); tr_free( web ); session->web = NULL; }
int cetcd_multi_watch(cetcd_client *cli) { int i, count; int maxfd, left, added; long timeout; long backoff, backoff_max; fd_set r, w, e; cetcd_array *watchers; cetcd_watcher *watcher; CURLM *mcurl; struct timeval tv; mcurl = curl_multi_init(); watchers = &cli->watchers; count = cetcd_array_size(watchers); for (i = 0; i < count; ++i) { watcher = cetcd_array_get(watchers, i); curl_easy_setopt(watcher->curl, CURLOPT_PRIVATE, watcher); curl_multi_add_handle(mcurl, watcher->curl); } backoff = 100; /*100ms*/ backoff_max = 1000; /*1 sec*/ for(;;) { curl_multi_perform(mcurl, &left); if (left) { FD_ZERO(&r); FD_ZERO(&w); FD_ZERO(&e); curl_multi_fdset(mcurl, &r, &w, &e, &maxfd); curl_multi_timeout(mcurl, &timeout); if (timeout == -1) { timeout = 100; /*wait for 0.1 seconds*/ } tv.tv_sec = timeout/1000; tv.tv_usec = (timeout%1000)*1000; /*TODO handle errors*/ select(maxfd+1, &r, &w, &e, &tv); } added = cetcd_reap_watchers(cli, mcurl); if (added == 0 && left == 0) { /* It will call curl_multi_perform immediately if: * 1. left is 0 * 2. a new attempt should be issued * It is expected to sleep a mount time between attempts. * So we fix this by increasing added counter only * when a new request should be issued. * When added is 0, maybe there are retring requests or nothing. * Either situations should wait before issuing the request. * */ if (backoff < backoff_max) { backoff = 2 * backoff; } else { backoff = backoff_max; } tv.tv_sec = backoff/1000; tv.tv_usec = (backoff%1000) * 1000; select(1, 0, 0, 0, &tv); } } curl_multi_cleanup(mcurl); return count; }
static void gst_curl_multi_context_loop (gpointer thread_data) { GstCurlMultiContext* thiz; gint rc; struct timeval timeout; int maxfd = -1; long curl_timeo = -1; fd_set fdread, fdwrite, fdexcep; thiz = (GstCurlMultiContext *) thread_data; g_mutex_lock (&thiz->mutex); /* Someone is holding a reference to us, but isn't using us so to avoid * unnecessary clock cycle wasting, sit in a conditional wait until woken. */ while (thiz->sources == 0 && thiz->refcount > 0) { GST_DEBUG ("Entering wait state..."); g_cond_wait (&thiz->signal, &thiz->mutex); GST_DEBUG ("Received wake up call!"); } /* check the exit condition */ if (thiz->refcount <= 0) { GST_DEBUG ("Exiting"); g_mutex_unlock (&thiz->mutex); return; } FD_ZERO (&fdread); FD_ZERO (&fdwrite); FD_ZERO (&fdexcep); timeout.tv_sec = 1; timeout.tv_usec = 0; curl_multi_timeout (thiz->multi_handle, &curl_timeo); if (curl_timeo >= 0) { timeout.tv_sec = curl_timeo / 1000; if (timeout.tv_sec > 1) { timeout.tv_sec = 1; } else { timeout.tv_usec = (curl_timeo % 1000) * 1000; } } /* get file descriptors from the transfers */ curl_multi_fdset (thiz->multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); /* Because curl can possibly take some time here, be nice and let go of the * mutex so other threads can perform state/queue operations as we don't * care about those until the end of this. */ g_mutex_unlock (&thiz->mutex); rc = select (maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); g_mutex_lock (&thiz->mutex); switch (rc) { case -1: /* select error */ break; case 0: default: /* timeout or readable/writable sockets */ curl_multi_perform (thiz->multi_handle, &thiz->sources); break; } gst_curl_multi_context_process_msgs (thiz); g_mutex_unlock(&thiz->mutex); }
/* * Upload all files over HTTP/2, using the same physical connection! */ int main(int argc, char **argv) { CURL *easy[NUM_HANDLES]; CURLM *multi_handle; int i; int still_running; /* keep number of running handles */ const char *filename = "index.html"; if(argc > 1) /* if given a number, do that many transfers */ num_transfers = atoi(argv[1]); if(argc > 2) /* if given a file name, upload this! */ filename = argv[2]; if(!num_transfers || (num_transfers > NUM_HANDLES)) num_transfers = 3; /* a suitable low default */ /* init a multi stack */ multi_handle = curl_multi_init(); for(i=0; i<num_transfers; i++) { easy[i] = curl_easy_init(); /* set options */ setup(easy[i], i, filename); /* add the individual transfer */ curl_multi_add_handle(multi_handle, easy[i]); } curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); /* We do HTTP/2 so let's stick to one connection per host */ curl_multi_setopt(multi_handle, CURLMOPT_MAX_HOST_CONNECTIONS, 1L); /* we start some action by calling perform right away */ curl_multi_perform(multi_handle, &still_running); do { struct timeval timeout; int rc; /* select() return code */ CURLMcode mc; /* curl_multi_fdset() return code */ fd_set fdread; fd_set fdwrite; fd_set fdexcep; int maxfd = -1; long curl_timeo = -1; FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* set a suitable timeout to play around with */ timeout.tv_sec = 1; timeout.tv_usec = 0; curl_multi_timeout(multi_handle, &curl_timeo); if(curl_timeo >= 0) { timeout.tv_sec = curl_timeo / 1000; if(timeout.tv_sec > 1) timeout.tv_sec = 1; else timeout.tv_usec = (curl_timeo % 1000) * 1000; } /* get file descriptors from the transfers */ mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); if(mc != CURLM_OK) { fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc); break; } /* On success the value of maxfd is guaranteed to be >= -1. We call select(maxfd + 1, ...); specially in case of (maxfd == -1) there are no fds ready yet so we call select(0, ...) --or Sleep() on Windows-- to sleep 100ms, which is the minimum suggested value in the curl_multi_fdset() doc. */ if(maxfd == -1) { #ifdef _WIN32 Sleep(100); rc = 0; #else /* Portable sleep for platforms other than Windows. */ struct timeval wait = { 0, 100 * 1000 }; /* 100ms */ rc = select(0, NULL, NULL, NULL, &wait); #endif } else { /* Note that on some platforms 'timeout' may be modified by select(). If you need access to the original value save a copy beforehand. */ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); } switch(rc) { case -1: /* select error */ break; case 0: default: /* timeout or readable/writable sockets */ curl_multi_perform(multi_handle, &still_running); break; } } while(still_running); curl_multi_cleanup(multi_handle); for(i=0; i<num_transfers; i++) curl_easy_cleanup(easy[i]); return 0; }
int main(void) { CURL *curl; CURLM *mcurl; int still_running = 1; struct timeval mp_start; char mp_timedout = 0; struct WriteThis pooh; struct curl_slist* rcpt_list = NULL; pooh.counter = 0; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if(!curl) return 1; mcurl = curl_multi_init(); if(!mcurl) return 2; rcpt_list = curl_slist_append(rcpt_list, RECEPIENT); /* more addresses can be added here rcpt_list = curl_slist_append(rcpt_list, "*****@*****.**"); */ curl_easy_setopt(curl, CURLOPT_URL, "smtp://" SMTPSERVER SMTPPORT); curl_easy_setopt(curl, CURLOPT_USERNAME, USERNAME); curl_easy_setopt(curl, CURLOPT_PASSWORD, PASSWORD); curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); curl_easy_setopt(curl, CURLOPT_MAIL_FROM, MAILFROM); curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, rcpt_list); curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER,0); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); curl_easy_setopt(curl, CURLOPT_READDATA, &pooh); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_SSLVERSION, 0); curl_easy_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0); curl_multi_add_handle(mcurl, curl); mp_timedout = 0; mp_start = tvnow(); /* we start some action by calling perform right away */ curl_multi_perform(mcurl, &still_running); while(still_running) { struct timeval timeout; int rc; /* select() return code */ fd_set fdread; fd_set fdwrite; fd_set fdexcep; int maxfd = -1; long curl_timeo = -1; FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* set a suitable timeout to play around with */ timeout.tv_sec = 1; timeout.tv_usec = 0; curl_multi_timeout(mcurl, &curl_timeo); if(curl_timeo >= 0) { timeout.tv_sec = curl_timeo / 1000; if(timeout.tv_sec > 1) timeout.tv_sec = 1; else timeout.tv_usec = (curl_timeo % 1000) * 1000; } /* get file descriptors from the transfers */ curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd); /* In a real-world program you OF COURSE check the return code of the function calls. On success, the value of maxfd is guaranteed to be greater or equal than -1. We call select(maxfd + 1, ...), specially in case of (maxfd == -1), we call select(0, ...), which is basically equal to sleep. */ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); if (tvdiff(tvnow(), mp_start) > MULTI_PERFORM_HANG_TIMEOUT) { fprintf(stderr, "ABORTING TEST, since it seems " "that it would have run forever.\n"); break; } switch(rc) { case -1: /* select error */ break; case 0: /* timeout */ default: /* action */ curl_multi_perform(mcurl, &still_running); break; } } curl_slist_free_all(rcpt_list); curl_multi_remove_handle(mcurl, curl); curl_multi_cleanup(mcurl); curl_easy_cleanup(curl); curl_global_cleanup(); return 0; }
int test(char *URL) { CURLM *cm = NULL; CURLSH *sh = NULL; CURL *ch = NULL; int unfinished; cm = curl_multi_init(); if(!cm) return 1; sh = curl_share_init(); if(!sh) goto cleanup; curl_share_setopt(sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); curl_share_setopt(sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); ch = curl_easy_init(); if(!ch) goto cleanup; curl_easy_setopt(ch, CURLOPT_SHARE, sh); curl_easy_setopt(ch, CURLOPT_URL, URL); curl_easy_setopt(ch, CURLOPT_COOKIEFILE, "log/cookies1905"); curl_easy_setopt(ch, CURLOPT_COOKIEJAR, "log/cookies1905"); curl_multi_add_handle(cm, ch); unfinished = 1; while(unfinished) { int MAX = 0; long max_tout; fd_set R, W, E; struct timeval timeout; FD_ZERO(&R); FD_ZERO(&W); FD_ZERO(&E); curl_multi_perform(cm, &unfinished); curl_multi_fdset(cm, &R, &W, &E, &MAX); curl_multi_timeout(cm, &max_tout); if(max_tout > 0) { timeout.tv_sec = max_tout / 1000; timeout.tv_usec = (max_tout % 1000) * 1000; } else { timeout.tv_sec = 0; timeout.tv_usec = 1000; } select(MAX + 1, &R, &W, &E, &timeout); } curl_easy_setopt(ch, CURLOPT_COOKIELIST, "FLUSH"); curl_easy_setopt(ch, CURLOPT_SHARE, NULL); curl_multi_remove_handle(cm, ch); cleanup: curl_easy_cleanup(ch); curl_share_cleanup(sh); curl_multi_cleanup(cm); return 0; }
int main(void) { CURL *curl; CURLM *mcurl; int still_running = 1; struct timeval mp_start; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if(!curl) return 1; mcurl = curl_multi_init(); if(!mcurl) return 2; /* Set username and password */ curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); /* This will fetch message 1 from the user's inbox */ curl_easy_setopt(curl, CURLOPT_URL, "imap://imap.example.com/INBOX/;UID=1"); /* Tell the multi stack about our easy handle */ curl_multi_add_handle(mcurl, curl); /* Record the start time which we can use later */ mp_start = tvnow(); /* We start some action by calling perform right away */ curl_multi_perform(mcurl, &still_running); while(still_running) { struct timeval timeout; fd_set fdread; fd_set fdwrite; fd_set fdexcep; int maxfd = -1; int rc; CURLMcode mc; /* curl_multi_fdset() return code */ long curl_timeo = -1; /* Initialise the file descriptors */ FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* Set a suitable timeout to play around with */ timeout.tv_sec = 1; timeout.tv_usec = 0; curl_multi_timeout(mcurl, &curl_timeo); if(curl_timeo >= 0) { timeout.tv_sec = curl_timeo / 1000; if(timeout.tv_sec > 1) timeout.tv_sec = 1; else timeout.tv_usec = (curl_timeo % 1000) * 1000; } /* get file descriptors from the transfers */ mc = curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd); if(mc != CURLM_OK) { fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc); break; } /* On success the value of maxfd is guaranteed to be >= -1. We call select(maxfd + 1, ...); specially in case of (maxfd == -1) there are no fds ready yet so we call select(0, ...) --or Sleep() on Windows-- to sleep 100ms, which is the minimum suggested value in the curl_multi_fdset() doc. */ if(maxfd == -1) { #ifdef _WIN32 Sleep(100); rc = 0; #else /* Portable sleep for platforms other than Windows. */ struct timeval wait = { 0, 100 * 1000 }; /* 100ms */ rc = select(0, NULL, NULL, NULL, &wait); #endif } else { /* Note that on some platforms 'timeout' may be modified by select(). If you need access to the original value save a copy beforehand. */ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); } if(tvdiff(tvnow(), mp_start) > MULTI_PERFORM_HANG_TIMEOUT) { fprintf(stderr, "ABORTING: Since it seems that we would have run forever.\n"); break; } switch(rc) { case -1: /* select error */ break; case 0: /* timeout */ default: /* action */ curl_multi_perform(mcurl, &still_running); break; } } /* Always cleanup */ curl_multi_remove_handle(mcurl, curl); curl_multi_cleanup(mcurl); curl_easy_cleanup(curl); curl_global_cleanup(); return 0; }