コード例 #1
0
ファイル: cl_download.c プロジェクト: dourvaris/iodfe
void DL_End( CURLcode res, CURLMcode resm )
{
	CURLMsg *msg;
	int msgs;

	if( dl_verbose->integer == 0 && dl_showprogress->integer == 2 && !curlm )
		Com_Printf( "\n" );
	
	if( curlm )
	{	
		// res = final download result
		while( ( msg = curl_multi_info_read( curlm, &msgs ) ) )
		{
			if( msg->msg != CURLMSG_DONE )
			{
				if( dl_error[0] == '\0' )
					Q_strncpyz( dl_error, "Download Interrupted.", sizeof(dl_error) );
			}
			else if( msg->easy_handle == curl )
			{
				if( msg->data.result != CURLE_OK );
					res = msg->data.result;
			}
			else
			{
				Com_Printf( "Invalid cURL handle.\n" );
			}
		}

		curl_multi_cleanup( curlm );
		curlm = NULL;		
	}

	if( curl )
	{
		curl_easy_cleanup( curl );
		curl = NULL;
	}

	// get possible error messages
	if( !*dl_error && res != CURLE_OK )
		Q_strncpyz( dl_error, curl_easy_strerror(res), sizeof(dl_error) );
	if( !*dl_error && resm != CURLM_OK )
		Q_strncpyz( dl_error, curl_multi_strerror(resm), sizeof(dl_error) );
	if( !*dl_error && !f )
		Q_strncpyz( dl_error, "File is not opened.", sizeof(dl_error) );

	if (f) {
		FS_FCloseFile(f);
		f = 0;
		if (!*dl_error) {	// download succeeded
			char dest[MAX_OSPATH];
			Com_Printf("Download complete, restarting filesystem.\n");
			Q_strncpyz(dest, path, strlen(path)-3);	// -4 +1 for the trailing \0
			Q_strcat(dest, sizeof(dest), ".pk3");
			if (!FS_FileExists(dest)) {
				FS_SV_Rename(path, dest);
				FS_Restart(clc.checksumFeed);
				if (dl_showmotd->integer && *motd) {
					Com_Printf("Server motd: %s\n", motd);
				}
			} else {
				// normally such errors should be caught upon starting the transfer. Anyway better do
				// it here again - the filesystem might have changed, plus this may help contain some
				// bugs / exploitable flaws in the code.
				Com_Printf("Failed to copy downloaded file to its location - file already exists.\n");
				FS_HomeRemove(path);
			}
		} else {
			FS_HomeRemove(path);
		}
	}

	Cvar_Set( "cl_downloadName", "" );  // hide the ui downloading screen
	Cvar_SetValue( "cl_downloadSize", 0 );
	Cvar_SetValue( "cl_downloadCount", 0 );
	Cvar_SetValue( "cl_downloadTime", 0 );
	Cvar_Set( "cl_downloadMotd", "" );

	if( *dl_error )
	{
		if( clc.state == CA_CONNECTED )
			Com_Error( ERR_DROP, "%s\n", dl_error ); // download error while connecting, can not continue loading
		else
			Com_Printf( "%s\n", dl_error ); // download error while in game, do not disconnect

		*dl_error = '\0';
	}
	else
	{
		if (strlen(Cvar_VariableString("cl_downloadDemo"))) {
			Cbuf_AddText( va("demo %s\n", Cvar_VariableString("cl_downloadDemo") ) );
		// download completed, request new gamestate to check possible new map if we are not already in game
		} else if( clc.state == CA_CONNECTED)
			CL_AddReliableCommand( "donedl", qfalse); // get new gamestate info from server
	}
}
コード例 #2
0
ファイル: curl_multi.cpp プロジェクト: skyjack/curlcpp
 const string curl_multi::error_to_string(const CURLMcode code) const noexcept {
     return curl_multi_strerror(code);
 }
コード例 #3
0
ファイル: MultiAdapter.cpp プロジェクト: artcom/y60
void
MultiAdapter::checkCurlStatus(CURLMcode theStatusCode, const std::string & theWhere) {
    if (theStatusCode != CURLM_OK) {
        throw asl::Exception(curl_multi_strerror(theStatusCode), theWhere);
    }
};
コード例 #4
0
ファイル: rest_methods.c プロジェクト: liviuchircu/opensips
enum async_ret_code resume_async_http_req(int fd, struct sip_msg *msg, void *_param)
{
	CURLcode rc;
	CURLMcode mrc;
	rest_async_param *param = (rest_async_param *)_param;
	int running = 0, max_fd;
	long http_rc;
	fd_set rset, wset, eset;
	pv_value_t val;
	int ret = 1, retr;
	CURLM *multi_handle;

	multi_handle = param->multi_list->multi_handle;

	retr = 0;
	do {
		mrc = curl_multi_perform(multi_handle, &running);
		if (mrc != CURLM_CALL_MULTI_PERFORM)
			break;
		LM_DBG("retry last perform...\n");
		usleep(_async_resume_retr_itv);
		retr += _async_resume_retr_itv;
	} while (retr < _async_resume_retr_timeout);

	if (mrc != CURLM_OK) {
		LM_ERR("curl_multi_perform: %s\n", curl_multi_strerror(mrc));
		return -1;
	}

	LM_DBG("running handles: %d\n", running);
	if (running == 1) {
		LM_DBG("transfer in progress...\n");
		async_status = ASYNC_CONTINUE;
		return 1;
	}

	if (running != 0) {
		LM_BUG("non-zero running handles!! (%d)", running);
		abort();
	}

	FD_ZERO(&rset);
	mrc = curl_multi_fdset(multi_handle, &rset, &wset, &eset, &max_fd);
	if (mrc != CURLM_OK) {
		LM_ERR("curl_multi_fdset: %s\n", curl_multi_strerror(mrc));
		ret = -1;
		goto out;
	}

	if (max_fd == -1) {
		if (FD_ISSET(fd, &rset)) {
			LM_BUG("fd %d is still in rset!", fd);
			abort();
		}

	} else if (FD_ISSET(fd, &rset)) {
		LM_DBG("fd %d still transferring...\n", fd);
		async_status = ASYNC_CONTINUE;
		return 1;
	}

	curl_slist_free_all(param->header_list);

	if (del_transfer(fd) != 0) {
		LM_BUG("failed to delete fd %d", fd);
		abort();
	}

	mrc = curl_multi_remove_handle(multi_handle, param->handle);
	if (mrc != CURLM_OK) {
		LM_ERR("curl_multi_remove_handle: %s\n", curl_multi_strerror(mrc));
		/* default async status is ASYNC_DONE */
		return -1;
	}
	put_multi(param->multi_list);

	val.flags = PV_VAL_STR;
	val.rs = param->body;
	if (pv_set_value(msg, param->body_pv, 0, &val) != 0)
		LM_ERR("failed to set output body pv\n");

	if (param->ctype_pv) {
		val.rs = param->ctype;
		if (pv_set_value(msg, param->ctype_pv, 0, &val) != 0)
			LM_ERR("failed to set output ctype pv\n");
	}

	if (param->code_pv) {
		rc = curl_easy_getinfo(param->handle, CURLINFO_RESPONSE_CODE, &http_rc);
		if (rc != CURLE_OK) {
			LM_ERR("curl_easy_getinfo: %s\n", curl_easy_strerror(rc));
			http_rc = 0;
		}

		LM_DBG("Last response code: %ld\n", http_rc);

		val.flags = PV_VAL_INT|PV_TYPE_INT;
		val.ri = (int)http_rc;
		if (pv_set_value(msg, param->code_pv, 0, &val) != 0)
			LM_ERR("failed to set output code pv\n");
	}

out:
	pkg_free(param->body.s);
	if (param->ctype_pv && param->ctype.s)
		pkg_free(param->ctype.s);
	curl_easy_cleanup(param->handle);
	if ( param->tparam ) {
		pkg_free( param->tparam );
	}
	pkg_free(param);

	/* default async status is ASYNC_DONE */
	return ret;
}
コード例 #5
0
ファイル: curl_error.cpp プロジェクト: Cyarix/freelan
	std::string curlm_category_impl::message(int ev) const
	{
		return curl_multi_strerror(static_cast<CURLMcode>(ev));
	}
コード例 #6
0
ファイル: curl_input_plugin.c プロジェクト: raumzeitlabor/mpd
/**
 * Wait for the libcurl socket.
 *
 * @return -1 on error, 0 if no data is available yet, 1 if data is
 * available
 */
static int
input_curl_select(struct input_curl *c, GError **error_r)
{
	fd_set rfds, wfds, efds;
	int max_fd, ret;
	CURLMcode mcode;
	struct timeval timeout = {
		.tv_sec = 1,
		.tv_usec = 0,
	};

	assert(!c->eof);

	FD_ZERO(&rfds);
	FD_ZERO(&wfds);
	FD_ZERO(&efds);

	mcode = curl_multi_fdset(c->multi, &rfds, &wfds, &efds, &max_fd);
	if (mcode != CURLM_OK) {
		g_set_error(error_r, curl_quark(), mcode,
			    "curl_multi_fdset() failed: %s",
			    curl_multi_strerror(mcode));
		return -1;
	}

#if LIBCURL_VERSION_NUM >= 0x070f04
	long timeout2;
	mcode = curl_multi_timeout(c->multi, &timeout2);
	if (mcode != CURLM_OK) {
		g_warning("curl_multi_timeout() failed: %s\n",
			  curl_multi_strerror(mcode));
		return -1;
	}

	if (timeout2 >= 0) {
		if (timeout2 > 10000)
			timeout2 = 10000;

		timeout.tv_sec = timeout2 / 1000;
		timeout.tv_usec = (timeout2 % 1000) * 1000;
	}
#endif

	ret = select(max_fd + 1, &rfds, &wfds, &efds, &timeout);
	if (ret < 0)
		g_set_error(error_r, g_quark_from_static_string("errno"),
			    errno,
			    "select() failed: %s\n", g_strerror(errno));

	return ret;
}

static bool
fill_buffer(struct input_stream *is, GError **error_r)
{
	struct input_curl *c = (struct input_curl *)is;
	CURLMcode mcode = CURLM_CALL_MULTI_PERFORM;

	while (!c->eof && g_queue_is_empty(c->buffers)) {
		int running_handles;
		bool bret;

		if (mcode != CURLM_CALL_MULTI_PERFORM) {
			/* if we're still here, there is no input yet
			   - wait for input */
			int ret = input_curl_select(c, error_r);
			if (ret <= 0)
				/* no data yet or error */
				return false;
		}

		mcode = curl_multi_perform(c->multi, &running_handles);
		if (mcode != CURLM_OK && mcode != CURLM_CALL_MULTI_PERFORM) {
			g_set_error(error_r, curl_quark(), mcode,
				    "curl_multi_perform() failed: %s",
				    curl_multi_strerror(mcode));
			c->eof = true;
			is->ready = true;
			return false;
		}

		bret = input_curl_multi_info_read(c, error_r);
		if (!bret)
			return false;
	}

	return !g_queue_is_empty(c->buffers);
}

/**
 * Mark a part of the buffer object as consumed.
 */
static struct buffer *
consume_buffer(struct buffer *buffer, size_t length)
{
	assert(buffer != NULL);
	assert(buffer->consumed < buffer->size);

	buffer->consumed += length;
	if (buffer->consumed < buffer->size)
		return buffer;

	assert(buffer->consumed == buffer->size);

	g_free(buffer);

	return NULL;
}
コード例 #7
0
void handleError(CURLMcode code) {
    if (code != CURLM_OK) {
        throw std::runtime_error(std::string("CURL multi error: ") + curl_multi_strerror(code));
    }
}
コード例 #8
0
ファイル: net_http_curl.c プロジェクト: GuardTime/libksi
static int performN(KSI_NetworkClient *client, KSI_RequestHandle **arr, size_t arr_len) {
	int res = KSI_UNKNOWN_ERROR;
	CURLM *cm = NULL;
	CURLMcode cres;
	size_t i;
	int count;
	char buf[1024];
	fd_set fdread;
	fd_set fdwrite;
	fd_set fdexcep;
	int maxfd = -1;
	struct timeval timeout;

	FD_ZERO(&fdread);
	FD_ZERO(&fdwrite);
	FD_ZERO(&fdexcep);

	if (client == NULL || (arr == NULL && arr_len != 0)) {
		res = KSI_INVALID_ARGUMENT;
		goto cleanup;
	}

	KSI_ERR_clearErrors(client->ctx);

	KSI_LOG_debug(client->ctx, "Starting cURL multi perform.");

	timeout.tv_sec = 0;
	timeout.tv_usec = 100;

	cm = curl_multi_init();
	if (cm == NULL) {
		KSI_pushError(client->ctx, res = KSI_OUT_OF_MEMORY, NULL);
		goto cleanup;
	}

	for (i = 0; i < arr_len; i++) {
		CurlNetHandleCtx *pctx = arr[i]->implCtx;
		cres = curl_multi_add_handle(cm, pctx->curl);
		if (cres != CURLM_OK) {
			KSI_snprintf(buf, sizeof(buf), "Curl error occurred: %s", curl_multi_strerror(cres));
			KSI_pushError(client->ctx, res = KSI_UNKNOWN_ERROR, buf);
			goto cleanup;
		}
	}

	curl_multi_setopt(cm, CURLMOPT_PIPELINING, 1);

	do {
		cres  = curl_multi_fdset(cm, &fdread, &fdwrite, &fdexcep, &maxfd);
		if (cres != CURLM_OK) {
			KSI_snprintf(buf, sizeof(buf), "Curl error occurred: %s", curl_multi_strerror(cres));
			KSI_pushError(client->ctx, res = KSI_UNKNOWN_ERROR, buf);
			goto cleanup;
		}

		select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);

		cres = curl_multi_perform(cm, &count);
		if (cres != CURLM_OK && cres != CURLM_CALL_MULTI_PERFORM) {
			KSI_snprintf(buf, sizeof(buf), "Curl error occurred: %s", curl_multi_strerror(cres));
			KSI_pushError(client->ctx, res = KSI_UNKNOWN_ERROR, buf);
			goto cleanup;
		}
	} while (count > 0 || cres == CURLM_CALL_MULTI_PERFORM);

	/* Remove the handles from the multi container. */
	for (i = 0; i < arr_len; i++) {
		CurlNetHandleCtx *pctx = arr[i]->implCtx;
		cres = curl_multi_remove_handle(cm, pctx->curl);
		if (cres != CURLM_OK) {
			KSI_snprintf(buf, sizeof(buf), "Curl error occurred: %s", curl_multi_strerror(cres));
			KSI_pushError(client->ctx, res = KSI_UNKNOWN_ERROR, buf);
			goto cleanup;
		}
		arr[i]->response = pctx->raw;
		pctx->raw = NULL;

		arr[i]->response_length = pctx->len;
		arr[i]->completed = true;

		res = updateStatus(arr[i]);
		if (res != KSI_OK) goto cleanup;
	}

	KSI_LOG_debug(client->ctx, "Finished cURL multi perform.");


	res = KSI_OK;

cleanup:

	if (cm != NULL) curl_multi_cleanup(cm);

	return res;

}
コード例 #9
0
ファイル: web.c プロジェクト: fangang190/canary
static void
addTask( void * vtask )
{
    struct tr_web_task * task = vtask;
    const tr_handle * session = task->session;

    if( session && session->web )
    {
        struct tr_web * web = session->web;
        CURL * easy;

        dbgmsg( "adding task #%lu [%s]", task->tag, task->url );

        easy = curl_easy_init( );

        if( !task->range && session->isProxyEnabled ) {
            curl_easy_setopt( easy, CURLOPT_PROXY, session->proxy );
            curl_easy_setopt( easy, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
            curl_easy_setopt( easy, CURLOPT_PROXYPORT, session->proxyPort );
            curl_easy_setopt( easy, CURLOPT_PROXYTYPE,
                                      getCurlProxyType( session->proxyType ) );
        }
        if( !task->range && session->isProxyAuthEnabled ) {
            char * str = tr_strdup_printf( "%s:%s", session->proxyUsername,
                                                    session->proxyPassword );
            curl_easy_setopt( easy, CURLOPT_PROXYUSERPWD, str );
            tr_free( str );
        }

        curl_easy_setopt( easy, CURLOPT_DNS_CACHE_TIMEOUT, 360L );
        curl_easy_setopt( easy, CURLOPT_CONNECTTIMEOUT, 60L );
        curl_easy_setopt( easy, CURLOPT_FOLLOWLOCATION, 1L );
        curl_easy_setopt( easy, CURLOPT_MAXREDIRS, 16L );
        curl_easy_setopt( easy, CURLOPT_NOSIGNAL, 1L );
        curl_easy_setopt( easy, CURLOPT_PRIVATE, task );
        curl_easy_setopt( easy, CURLOPT_SSL_VERIFYHOST, 0L );
        curl_easy_setopt( easy, CURLOPT_SSL_VERIFYPEER, 0L );
        curl_easy_setopt( easy, CURLOPT_URL, task->url );
        curl_easy_setopt( easy, CURLOPT_USERAGENT,
                                           TR_NAME "/" LONG_VERSION_STRING );
        curl_easy_setopt( easy, CURLOPT_VERBOSE,
                                       getenv( "TR_CURL_VERBOSE" ) != NULL );
        curl_easy_setopt( easy, CURLOPT_WRITEDATA, task );
        curl_easy_setopt( easy, CURLOPT_WRITEFUNCTION, writeFunc );
        if( task->range )
            curl_easy_setopt( easy, CURLOPT_RANGE, task->range );
        else /* don't set encoding on webseeds; it messes up binary data */
            curl_easy_setopt( easy, CURLOPT_ENCODING, "" );

        if( web->still_running >= MAX_CONCURRENT_TASKS ) {
            tr_list_append( &web->easy_queue, easy );
            dbgmsg( " >> enqueueing a task ... size is now %d",
                                           tr_list_size( web->easy_queue ) );
        } else {
            const CURLMcode rc = curl_multi_add_handle( web->multi, easy );
            if( rc == CURLM_OK )
                ++web->still_running;
            else
                tr_err( "%s", curl_multi_strerror( rc ) );
        }
    }
}
コード例 #10
0
ファイル: serv_eventclient.c プロジェクト: mingodad/citadel
static void
gotstatus(int nnrun)
{
	CURLMsg *msg;
	int nmsg;

	global.nrun = nnrun;

	CURLM_syslog(LOG_DEBUG,
		     "gotstatus(): about to call curl_multi_info_read\n");
	while ((msg = curl_multi_info_read(global.mhnd, &nmsg))) {
		CURL_syslog(LOG_DEBUG,
			    "got curl multi_info message msg=%d\n",
			    msg->msg);

		if (CURLMSG_DONE == msg->msg) {
			CURL *chnd;
			void *chandle = NULL;
			CURLcode sta;
			CURLMcode msta;
			AsyncIO*IO;

			chandle = NULL;;
			chnd = msg->easy_handle;
			sta = curl_easy_getinfo(chnd,
						CURLINFO_PRIVATE,
						&chandle);
			if (sta) {
				syslog(LOG_ERR,
				       "error asking curl for private"
				       " cookie of curl handle: %s\n",
				       curl_easy_strerror(sta));
				continue;
			}
			IO = (AsyncIO *)chandle;
			if (IO->ID == 0) {
				EVCURL_syslog(LOG_ERR,
					      "Error, invalid IO context %p\n",
					      IO);
				continue;
			}
			SetEVState(IO, eCurlGotStatus);

			EVCURLM_syslog(LOG_DEBUG, "request complete\n");

			IO->CitContext->lastcmd = IO->Now = ev_now(event_base);

			ev_io_stop(event_base, &IO->recv_event);
			ev_io_stop(event_base, &IO->send_event);

			sta = msg->data.result;
			if (sta) {
				EVCURL_syslog(LOG_ERR,
					      "error description: %s\n",
					      IO->HttpReq.errdesc);
				IO->HttpReq.CurlError = curl_easy_strerror(sta);
				EVCURL_syslog(LOG_ERR,
					      "error performing request: %s\n",
					      IO->HttpReq.CurlError);
				if (sta == CURLE_OPERATION_TIMEDOUT)
				{
					IO->SendBuf.fd = 0;
					IO->RecvBuf.fd = 0;
				}
			}
			sta = curl_easy_getinfo(chnd,
						CURLINFO_RESPONSE_CODE,
						&IO->HttpReq.httpcode);
			if (sta)
				EVCURL_syslog(LOG_ERR,
					      "error asking curl for "
					      "response code from request: %s\n",
					      curl_easy_strerror(sta));
			EVCURL_syslog(LOG_DEBUG,
				      "http response code was %ld\n",
				      (long)IO->HttpReq.httpcode);


			curl_slist_free_all(IO->HttpReq.headers);
			IO->HttpReq.headers = NULL;
			msta = curl_multi_remove_handle(global.mhnd, chnd);
			if (msta)
				EVCURL_syslog(LOG_ERR,
					      "warning problem detaching "
					      "completed handle from curl multi: "
					      "%s\n",
					      curl_multi_strerror(msta));

			ev_cleanup_stop(event_base, &IO->abort_by_shutdown);

			IO->HttpReq.attached = 0;
			switch(IO->SendDone(IO))
			{
			case eDBQuery:
				FreeURL(&IO->ConnectMe);
				QueueAnDBOperation(IO);
				break;
			case eSendDNSQuery:
			case eReadDNSReply:
			case eConnect:
			case eSendReply:
			case eSendMore:
			case eSendFile:
			case eReadMessage:
			case eReadMore:
			case eReadPayload:
			case eReadFile:
				break;
			case eTerminateConnection:
			case eAbort:
				curl_easy_cleanup(IO->HttpReq.chnd);
				IO->HttpReq.chnd = NULL;
				FreeStrBuf(&IO->HttpReq.ReplyData);
				FreeURL(&IO->ConnectMe);
				RemoveContext(IO->CitContext);
				IO->Terminate(IO);
			}
		}
	}
}
コード例 #11
0
ファイル: curl.c プロジェクト: arczi84/NetSurf-68k
/**
 * Do some work on current fetches.
 *
 * Must be called regularly to make progress on fetches.
 */
static void fetch_curl_poll(lwc_string *scheme_ignored)
{
	int running, queue;
	CURLMcode codem;
	CURLMsg *curl_msg;

	if (nsoption_bool(suppress_curl_debug) == false) {
		fd_set read_fd_set, write_fd_set, exc_fd_set;
		int max_fd = -1;
		int i;

		FD_ZERO(&read_fd_set);
		FD_ZERO(&write_fd_set);
		FD_ZERO(&exc_fd_set);

		codem = curl_multi_fdset(fetch_curl_multi,
				&read_fd_set, &write_fd_set,
				&exc_fd_set, &max_fd);
		assert(codem == CURLM_OK);

		LOG("Curl file descriptor states (maxfd=%i):", max_fd);
		for (i = 0; i <= max_fd; i++) {
			bool read = false;
			bool write = false;
			bool error = false;

			if (FD_ISSET(i, &read_fd_set)) {
				read = true;
			}
			if (FD_ISSET(i, &write_fd_set)) {
				write = true;
			}
			if (FD_ISSET(i, &exc_fd_set)) {
				error = true;
			}
			if (read || write || error) {
				LOG("  fd %i: %s %s %s", i,
						read  ? "read" : "    ",
						write ? "write" : "     ",
						error ? "error" : "     ");
			}
		}
	}

	/* do any possible work on the current fetches */
	do {
		codem = curl_multi_perform(fetch_curl_multi, &running);
		if (codem != CURLM_OK && codem != CURLM_CALL_MULTI_PERFORM) {
			LOG("curl_multi_perform: %i %s", codem, curl_multi_strerror(codem));
			guit->misc->warning("MiscError", curl_multi_strerror(codem));
			return;
		}
	} while (codem == CURLM_CALL_MULTI_PERFORM);

	/* process curl results */
	curl_msg = curl_multi_info_read(fetch_curl_multi, &queue);
	while (curl_msg) {
		switch (curl_msg->msg) {
			case CURLMSG_DONE:
				fetch_curl_done(curl_msg->easy_handle,
						curl_msg->data.result);
				break;
			default:
				break;
		}
		curl_msg = curl_multi_info_read(fetch_curl_multi, &queue);
	}
}
コード例 #12
0
static void
handle_transfer (GstCurlBaseSink * sink)
{
  GstCurlBaseSinkClass *klass = GST_CURL_BASE_SINK_GET_CLASS (sink);
  gint retval;
  gint activated_fds;
  gint running_handles;
  gint timeout;
  CURLMcode m_code;
  CURLcode e_code;

  GST_OBJECT_LOCK (sink);
  timeout = sink->timeout;
  GST_OBJECT_UNLOCK (sink);

  GST_DEBUG_OBJECT (sink, "handling transfers");

  /* Receiving CURLM_CALL_MULTI_PERFORM means that libcurl may have more data
     available to send or receive - call simply curl_multi_perform before
     poll() on more actions */
  do {
    m_code = curl_multi_perform (sink->multi_handle, &running_handles);
  } while (m_code == CURLM_CALL_MULTI_PERFORM);
  GST_DEBUG_OBJECT (sink, "running handles: %d", running_handles);

  while (running_handles && (m_code == CURLM_OK)) {
    if (klass->transfer_prepare_poll_wait) {
      klass->transfer_prepare_poll_wait (sink);
    }

    activated_fds = gst_poll_wait (sink->fdset, timeout * GST_SECOND);
    if (G_UNLIKELY (activated_fds == -1)) {
      if (errno == EAGAIN || errno == EINTR) {
        GST_DEBUG_OBJECT (sink, "interrupted by signal");
      } else if (errno == EBUSY) {
        GST_DEBUG_OBJECT (sink, "poll stopped");
        retval = GST_FLOW_EOS;

        GST_OBJECT_LOCK (sink);
        if (gst_curl_base_sink_has_buffered_data_unlocked (sink))
          GST_WARNING_OBJECT (sink,
              "discarding render data due to thread close flag");
        GST_OBJECT_UNLOCK (sink);

        goto fail;
      } else {
        sink->error = g_strdup_printf ("poll failed: %s", g_strerror (errno));
        retval = GST_FLOW_ERROR;
        goto fail;
      }
    } else if (G_UNLIKELY (activated_fds == 0)) {
      sink->error = g_strdup_printf ("poll timed out after %" GST_TIME_FORMAT,
          GST_TIME_ARGS (timeout * GST_SECOND));
      retval = GST_FLOW_ERROR;
      goto fail;
    }

    /* readable/writable sockets */
    do {
      m_code = curl_multi_perform (sink->multi_handle, &running_handles);
    } while (m_code == CURLM_CALL_MULTI_PERFORM);
    GST_DEBUG_OBJECT (sink, "running handles: %d", running_handles);
  }

  if (m_code != CURLM_OK) {
    sink->error = g_strdup_printf ("failed to write data: %s",
        curl_multi_strerror (m_code));
    retval = GST_FLOW_ERROR;
    goto fail;
  }

  /* problems still might have occurred on individual transfers even when
   * curl_multi_perform returns CURLM_OK */
  if ((e_code = gst_curl_base_sink_transfer_check (sink)) != CURLE_OK) {
    sink->error = g_strdup_printf ("failed to transfer data: %s",
        curl_easy_strerror (e_code));
    retval = GST_FLOW_ERROR;
    goto fail;
  }

  gst_curl_base_sink_got_response_notify (sink);

  GST_OBJECT_LOCK (sink);
  if (sink->socket_type == CURLSOCKTYPE_ACCEPT) {
    /* FIXME: remove this again once we can depend on libcurl > 7.44.0,
     * see https://github.com/bagder/curl/issues/405.
     */
    if (G_UNLIKELY (sink->fd.fd < 0)) {
      sink->error = g_strdup_printf ("unknown error");
      retval = GST_FLOW_ERROR;
      GST_OBJECT_UNLOCK (sink);
      goto fail;
    }
    if (!gst_poll_remove_fd (sink->fdset, &sink->fd)) {
      sink->error = g_strdup_printf ("failed to remove fd");
      retval = GST_FLOW_ERROR;
      GST_OBJECT_UNLOCK (sink);
      goto fail;
    }
    sink->fd.fd = -1;
  }
  GST_OBJECT_UNLOCK (sink);

  return;

fail:
  GST_OBJECT_LOCK (sink);
  if (sink->flow_ret == GST_FLOW_OK) {
    sink->flow_ret = retval;
  }
  GST_OBJECT_UNLOCK (sink);
  return;
}
コード例 #13
0
static void
handle_transfer (GstCurlBaseSink * sink)
{
  GstCurlBaseSinkClass *klass = GST_CURL_BASE_SINK_GET_CLASS (sink);
  gint retval;
  gint activated_fds;
  gint running_handles;
  gint timeout;
  CURLMcode m_code;
  CURLcode e_code;

  GST_OBJECT_LOCK (sink);
  timeout = sink->timeout;
  GST_OBJECT_UNLOCK (sink);

  /* Receiving CURLM_CALL_MULTI_PERFORM means that libcurl may have more data
     available to send or receive - call simply curl_multi_perform before
     poll() on more actions */
  do {
    m_code = curl_multi_perform (sink->multi_handle, &running_handles);
  } while (m_code == CURLM_CALL_MULTI_PERFORM);

  while (running_handles && (m_code == CURLM_OK)) {
    if (klass->transfer_prepare_poll_wait) {
      klass->transfer_prepare_poll_wait (sink);
    }

    activated_fds = gst_poll_wait (sink->fdset, timeout * GST_SECOND);
    if (G_UNLIKELY (activated_fds == -1)) {
      if (errno == EAGAIN || errno == EINTR) {
        GST_DEBUG_OBJECT (sink, "interrupted by signal");
      } else if (errno == EBUSY) {
        GST_DEBUG_OBJECT (sink, "poll stopped");
        retval = GST_FLOW_EOS;
        goto fail;
      } else {
        GST_DEBUG_OBJECT (sink, "poll failed: %s", g_strerror (errno));
        GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("poll failed"), (NULL));
        retval = GST_FLOW_ERROR;
        goto fail;
      }
    } else if (G_UNLIKELY (activated_fds == 0)) {
      GST_DEBUG_OBJECT (sink, "poll timed out");
      GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("poll timed out"), (NULL));
      retval = GST_FLOW_ERROR;
      goto fail;
    }

    /* readable/writable sockets */
    do {
      m_code = curl_multi_perform (sink->multi_handle, &running_handles);
    } while (m_code == CURLM_CALL_MULTI_PERFORM);
  }

  if (m_code != CURLM_OK) {
    GST_DEBUG_OBJECT (sink, "curl multi error");
    GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("%s",
            curl_multi_strerror (m_code)), (NULL));
    retval = GST_FLOW_ERROR;
    goto fail;
  }

  /* problems still might have occurred on individual transfers even when
   * curl_multi_perform returns CURLM_OK */
  if ((e_code = gst_curl_base_sink_transfer_check (sink)) != CURLE_OK) {
    GST_DEBUG_OBJECT (sink, "curl easy error");
    GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("%s",
            curl_easy_strerror (e_code)), (NULL));
    retval = GST_FLOW_ERROR;
    goto fail;
  }

  gst_curl_base_sink_got_response_notify (sink);

  return;

fail:
  GST_OBJECT_LOCK (sink);
  if (sink->flow_ret == GST_FLOW_OK) {
    sink->flow_ret = retval;
  }
  GST_OBJECT_UNLOCK (sink);
  return;
}
コード例 #14
0
ファイル: pal_multi.cpp プロジェクト: Guruanth/corefx
extern "C" const char* HttpNative_MultiGetErrorString(PAL_CURLMcode code)
{
    return curl_multi_strerror(static_cast<CURLMcode>(code));
}
コード例 #15
0
ファイル: http.c プロジェクト: jayschwa/q2pro
// Actually starts a download by adding it to the curl multi handle.
static void start_download(dlqueue_t *entry, dlhandle_t *dl)
{
    size_t  len;
    char    temp[MAX_QPATH];
    char    escaped[MAX_QPATH * 4];
    CURLMcode ret;
    qerror_t err;

    //yet another hack to accomodate filelists, how i wish i could push :(
    //NULL file handle indicates filelist.
    if (entry->type == DL_LIST) {
        dl->file = NULL;
        dl->path[0] = 0;
        //filelist paths are absolute
        escape_path(entry->path, escaped);
    } else {
        len = Q_snprintf(dl->path, sizeof(dl->path), "%s/%s.tmp", fs_gamedir, entry->path);
        if (len >= sizeof(dl->path)) {
            Com_EPrintf("[HTTP] Refusing oversize temporary file path.\n");
            goto fail;
        }

        //prepend quake path with gamedir
        len = Q_snprintf(temp, sizeof(temp), "%s/%s", http_gamedir(), entry->path);
        if (len >= sizeof(temp)) {
            Com_EPrintf("[HTTP] Refusing oversize server file path.\n");
            goto fail;
        }
        escape_path(temp, escaped);

        err = FS_CreatePath(dl->path);
        if (err < 0) {
            Com_EPrintf("[HTTP] Couldn't create path to '%s': %s\n", dl->path, Q_ErrorString(err));
            goto fail;
        }

        //don't bother with http resume... too annoying if server doesn't support it.
        dl->file = fopen(dl->path, "wb");
        if (!dl->file) {
            Com_EPrintf("[HTTP] Couldn't open '%s' for writing: %s\n", dl->path, strerror(errno));
            goto fail;
        }
    }

    len = Q_snprintf(dl->url, sizeof(dl->url), "%s%s", download_server, escaped);
    if (len >= sizeof(dl->url)) {
        Com_EPrintf("[HTTP] Refusing oversize download URL.\n");
        goto fail;
    }

    dl->buffer = NULL;
    dl->size = 0;
    dl->position = 0;
    dl->queue = entry;
    if (!dl->curl)
        dl->curl = curl_easy_init();

    curl_easy_setopt(dl->curl, CURLOPT_ENCODING, "");
#ifdef _DEBUG
    if (cl_http_debug->integer) {
        curl_easy_setopt(dl->curl, CURLOPT_DEBUGFUNCTION, debug_func);
        curl_easy_setopt(dl->curl, CURLOPT_VERBOSE, 1);
    }
#endif
    curl_easy_setopt(dl->curl, CURLOPT_NOPROGRESS, 0);
    if (dl->file) {
        curl_easy_setopt(dl->curl, CURLOPT_WRITEDATA, dl->file);
        curl_easy_setopt(dl->curl, CURLOPT_WRITEFUNCTION, NULL);
    } else {
        curl_easy_setopt(dl->curl, CURLOPT_WRITEDATA, dl);
        curl_easy_setopt(dl->curl, CURLOPT_WRITEFUNCTION, recv_func);
    }
    curl_easy_setopt(dl->curl, CURLOPT_FAILONERROR, 1);
    curl_easy_setopt(dl->curl, CURLOPT_PROXY, cl_http_proxy->string);
    curl_easy_setopt(dl->curl, CURLOPT_FOLLOWLOCATION, 1);
    curl_easy_setopt(dl->curl, CURLOPT_MAXREDIRS, 5);
    curl_easy_setopt(dl->curl, CURLOPT_PROGRESSFUNCTION, progress_func);
    curl_easy_setopt(dl->curl, CURLOPT_PROGRESSDATA, dl);
    curl_easy_setopt(dl->curl, CURLOPT_USERAGENT, com_version->string);
    curl_easy_setopt(dl->curl, CURLOPT_REFERER, download_referer);
    curl_easy_setopt(dl->curl, CURLOPT_URL, dl->url);

    ret = curl_multi_add_handle(curl_multi, dl->curl);
    if (ret != CURLM_OK) {
        Com_EPrintf("[HTTP] Failed to add download handle: %s\n",
                    curl_multi_strerror(ret));
fail:
        CL_FinishDownload(entry);

        // see if we have more to dl
        CL_RequestNextDownload();
        return;
    }

    Com_DPrintf("[HTTP] Fetching %s...\n", dl->url);
    entry->state = DL_RUNNING;
    curl_handles++;
}
コード例 #16
0
ファイル: http_client.c プロジェクト: deadcafe/trash
static void *
http_client_main( void *args ) {
  UNUSED( args );

  debug( "Starting HTTP client thread ( tid = %#lx ).", pthread_self() );

  init_curl();

  while ( 1 ) {
    int n_msgs = 0;
    CURLMsg *msg = curl_multi_info_read( curl_handle, &n_msgs );
    while ( msg != NULL ) {
      if ( msg->msg != CURLMSG_DONE ) {
        continue;
      }
      http_transaction *transaction = lookup_http_transaction( msg->easy_handle );
      if ( transaction != NULL ) {
        send_http_transaction_to_main( transaction, msg );
      }
      else {
        warn( "Failed to find HTTP transaction record ( easy_handle = %p ).", msg->easy_handle );
      }
      msg = curl_multi_info_read( curl_handle, &n_msgs );
    }

    fd_set fd_read;
    FD_ZERO( &fd_read );
    fd_set fd_write;
    FD_ZERO( &fd_write );
    fd_set fd_excep;
    FD_ZERO( &fd_excep );

    int fd_max = -1;
    long curl_timeout = -1;
     struct timespec timeout = { 10, 0 };
    if ( curl_running ) {
      CURLMcode retval = curl_multi_timeout( curl_handle, &curl_timeout );
      if ( retval != CURLM_OK && retval != CURLM_CALL_MULTI_PERFORM ) {
        error( "Failed to get timeout value from a handle ( handle = %p, error = %s ).", curl_handle, curl_multi_strerror( retval ) );
      }
      if ( curl_timeout >= 0 ) {
        timeout.tv_sec = curl_timeout / 1000;
        if ( timeout.tv_sec > 1 ) {
          timeout.tv_sec = 1;
        }
        else {
          timeout.tv_nsec = ( curl_timeout % 1000 ) * 1000000;
        }
      }
 
      retval = curl_multi_fdset( curl_handle, &fd_read, &fd_write, &fd_excep, &fd_max );
      if ( retval != CURLM_OK && retval != CURLM_CALL_MULTI_PERFORM ) {
        error( "Failed to retrieve fd set from a handle ( handle = %p, error = %s ).", curl_handle, curl_multi_strerror( retval ) );
      }
    }

    if ( http_client_efd >= 0 ) {
#define sizeof( _x ) ( ( int ) sizeof( _x ) )
      FD_SET( http_client_efd, &fd_read );
#undef sizeof
      if ( http_client_efd > fd_max ) {
        fd_max = http_client_efd;
      }
    }
    if ( main_efd >= 0 && main_notify_count > 0 ) {
#define sizeof( _x ) ( ( int ) sizeof( _x ) )
      FD_SET( main_efd, &fd_write );
#undef sizeof
      if ( main_efd > fd_max ) {
        fd_max = main_efd;
      }
    }

    int ret = pselect( fd_max + 1, &fd_read, &fd_write, &fd_excep, &timeout, NULL );
    switch ( ret ) {
      case -1:
      {
        if ( errno == EINTR ) {
          continue;
        }
        char buf[ 256 ];
        memset( buf, '\0', sizeof( buf ) );
        char *error_string = strerror_r( errno, buf, sizeof( buf ) - 1 );
        warn( "Failed to select ( errno = %s [%d] ).", error_string, errno );
      }
      break;

      case 0:
      default:
      {
        if ( curl_running ) {
          CURLMcode retval = curl_multi_perform( curl_handle, &curl_running );
          if ( retval != CURLM_OK && retval != CURLM_CALL_MULTI_PERFORM ) {
            error( "Failed to run a multi handle ( handle = %p, error = %s ).", curl_handle, curl_multi_strerror( retval ) );
          }
        }
#define sizeof( _x ) ( ( int ) sizeof( _x ) )
        if ( http_client_efd >= 0 && FD_ISSET( http_client_efd, &fd_read ) ) {
          retrieve_http_transactions_from_main();
        }
        if ( main_efd >= 0 && FD_ISSET( main_efd, &fd_write ) ) {
          notify_main_actually();
        }
#undef sizeof
      }
      break;
    }
  }

  finalize_curl();

  debug( "Stopping HTTP client thread ( tid = %#lx ).", pthread_self() );

  return NULL;
}
コード例 #17
0
void Downloader::groupBatchDownload(const DownloadUnits &units)
{
    CURLM* multi_handle = curl_multi_init();
    int still_running = 0;
    
    for (auto it = units.cbegin(); it != units.cend(); ++it)
    {
        DownloadUnit unit = it->second;
        std::string srcUrl = unit.srcUrl;
        std::string storagePath = unit.storagePath;
        std::string customId = unit.customId;
        
        FileDescriptor *fDesc = new FileDescriptor();
        ProgressData *data = new ProgressData();
        prepareDownload(srcUrl, storagePath, customId, unit.resumeDownload, fDesc, data);
        
        if (fDesc->fp != NULL)
        {
            CURL* curl = curl_easy_init();
            curl_easy_setopt(curl, CURLOPT_URL, srcUrl.c_str());
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fileWriteFunc);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, fDesc->fp);
            curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false);
            curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, batchDownloadProgressFunc);
            curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, data);
            curl_easy_setopt(curl, CURLOPT_FAILONERROR, true);
            if (_connectionTimeout) curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, _connectionTimeout);
            curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
            curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, LOW_SPEED_LIMIT);
            curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, LOW_SPEED_TIME);
            curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true);
            curl_easy_setopt(curl, CURLOPT_MAXREDIRS, MAX_REDIRS);
            
            // Resuming download support
            if (_supportResuming && unit.resumeDownload)
            {
                // Check already downloaded size for current download unit
                long size = _fileUtils->getFileSize(storagePath + TEMP_EXT);
                if (size != -1)
                {
                    curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, size);
                }
            }
            fDesc->curl = curl;
            
            CURLMcode code = curl_multi_add_handle(multi_handle, curl);
            if (code != CURLM_OK)
            {
                // Avoid memory leak
                fclose(fDesc->fp);
                delete data;
                delete fDesc;
                std::string msg = StringUtils::format("Unable to add curl handler for %s: [curl error]%s", customId.c_str(), curl_multi_strerror(code));
                this->notifyError(msg, code, customId);
            }
            else
            {
                // Add to list for tracking
                _progDatas.push_back(data);
                _files.push_back(fDesc);
            }
        }
    }
    
    // Query multi perform
    CURLMcode curlm_code = CURLM_CALL_MULTI_PERFORM;
    while(CURLM_CALL_MULTI_PERFORM == curlm_code) {
        curlm_code = curl_multi_perform(multi_handle, &still_running);
    }
    if (curlm_code != CURLM_OK) {
        std::string msg = StringUtils::format("Unable to continue the download process: [curl error]%s", curl_multi_strerror(curlm_code));
        this->notifyError(msg, curlm_code);
    }
    else
    {
        bool failed = false;
        while (still_running > 0 && !failed)
        {
            // set a suitable timeout to play around with
            struct timeval select_tv;
            long curl_timeo = -1;
            select_tv.tv_sec = 1;
            select_tv.tv_usec = 0;
            
            curl_multi_timeout(multi_handle, &curl_timeo);
            if(curl_timeo >= 0) {
                select_tv.tv_sec = curl_timeo / 1000;
                if(select_tv.tv_sec > 1)
                    select_tv.tv_sec = 1;
                else
                    select_tv.tv_usec = (curl_timeo % 1000) * 1000;
            }
            
            int rc;
            fd_set fdread;
            fd_set fdwrite;
            fd_set fdexcep;
            int maxfd = -1;
            FD_ZERO(&fdread);
            FD_ZERO(&fdwrite);
            FD_ZERO(&fdexcep);
			// FIXME: when jenkins migrate to ubuntu, we should remove this hack code
#if (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
			curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
			rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &select_tv);
#else          
			rc = curl_multi_wait(multi_handle, nullptr, 0, MAX_WAIT_MSECS, &maxfd);
#endif
            
            switch(rc)
            {
                case -1:
                    failed = true;
                    break;
                case 0:
                default:
                    curlm_code = CURLM_CALL_MULTI_PERFORM;
                    while(CURLM_CALL_MULTI_PERFORM == curlm_code) {
                        curlm_code = curl_multi_perform(multi_handle, &still_running);
                    }
                    if (curlm_code != CURLM_OK) {
                        std::string msg = StringUtils::format("Unable to continue the download process: [curl error]%s", curl_multi_strerror(curlm_code));
                        this->notifyError(msg, curlm_code);
                    }
                    break;
            }
        }
    }
    
    // Clean up and close files
    curl_multi_cleanup(multi_handle);
    for (auto it = _files.begin(); it != _files.end(); ++it)
    {
        FILE *f = (*it)->fp;
        fclose(f);
        CURL *single = (CURL *)((*it)->curl);
        curl_multi_remove_handle(multi_handle, single);
        curl_easy_cleanup(single);
    }
    
    // Check unfinished files and notify errors, succeed files will be renamed from temporary file name to real name
    for (auto it = _progDatas.begin(); it != _progDatas.end(); ++it) {
        ProgressData *data = *it;
        if (data->downloaded < data->totalToDownload || data->totalToDownload == 0)
        {
            this->notifyError(ErrorCode::NETWORK, "Unable to download file", data->customId);
        }
        else
        {
            _fileUtils->renameFile(data->path, data->name + TEMP_EXT, data->name);
        }
    }
    
    clearBatchDownloadData();
}
コード例 #18
0
ファイル: rest_methods.c プロジェクト: Deni90/opensips
/**
 * start_async_http_req - performs an HTTP request, stores results in pvars
 *		- TCP connect phase is synchronous, due to libcurl limitations
 *		- TCP read phase is asynchronous, thanks to the libcurl multi interface
 *
 * @msg:		sip message struct
 * @method:		HTTP verb
 * @url:		HTTP URL to be queried
 * @req_body:	Body of the request (NULL if not needed)
 * @req_ctype:	Value for the "Content-Type: " header of the request (same as ^)
 * @out_handle: CURL easy handle used to perform the transfer
 * @body:	    reply body; gradually reallocated as data arrives
 * @ctype:	    will eventually hold the last "Content-Type" header of the reply
 */
int start_async_http_req(struct sip_msg *msg, enum rest_client_method method,
					     char *url, char *req_body, char *req_ctype,
					     CURL **out_handle, str *body, str *ctype)
{
	CURL *handle;
	CURLcode rc;
	CURLMcode mrc;
	fd_set rset, wset, eset;
	int max_fd, fd, i;
	long busy_wait, timeout;
	long retry_time, check_time = 5; /* 5ms looping time */
	int msgs_in_queue;
	CURLMsg *cmsg;

	if (transfers == FD_SETSIZE) {
		LM_ERR("too many ongoing tranfers: %d\n", FD_SETSIZE);
		clean_header_list;
		return ASYNC_NO_IO;
	}

	handle = curl_easy_init();
	if (!handle) {
		LM_ERR("Init curl handle failed!\n");
		clean_header_list;
		return ASYNC_NO_IO;
	}

	w_curl_easy_setopt(handle, CURLOPT_URL, url);

	switch (method) {
	case REST_CLIENT_POST:
		w_curl_easy_setopt(handle, CURLOPT_POST, 1);
		w_curl_easy_setopt(handle, CURLOPT_POSTFIELDS, req_body);

		if (req_ctype) {
			sprintf(print_buff, "Content-Type: %s", req_ctype);
			header_list = curl_slist_append(header_list, print_buff);
			w_curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header_list);
		}
		break;
	case REST_CLIENT_GET:
		break;

	default:
		LM_ERR("Unsupported rest_client_method: %d, defaulting to GET\n", method);
	}

	if (header_list)
		w_curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header_list);

	w_curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, connection_timeout);
	w_curl_easy_setopt(handle, CURLOPT_TIMEOUT, curl_timeout);

	w_curl_easy_setopt(handle, CURLOPT_VERBOSE, 1);
	w_curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1);
	w_curl_easy_setopt(handle, CURLOPT_STDERR, stdout);

	w_curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_func);
	w_curl_easy_setopt(handle, CURLOPT_WRITEDATA, body);

	if (ctype) {
		w_curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, header_func);
		w_curl_easy_setopt(handle, CURLOPT_HEADERDATA, ctype);
	}

	if (ssl_capath)
		w_curl_easy_setopt(handle, CURLOPT_CAPATH, ssl_capath);

	if (!ssl_verifypeer)
		w_curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0L);

	if (!ssl_verifyhost)
		w_curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0L);

	curl_multi_add_handle(multi_handle, handle);

	timeout = connection_timeout_ms;
	/* obtain a read fd in "connection_timeout" seconds at worst */
	for (timeout = connection_timeout_ms; timeout > 0; timeout -= busy_wait) {
		mrc = curl_multi_perform(multi_handle, &running_handles);
		if (mrc != CURLM_OK) {
			LM_ERR("curl_multi_perform: %s\n", curl_multi_strerror(mrc));
			goto error;
		}

		mrc = curl_multi_timeout(multi_handle, &retry_time);
		if (mrc != CURLM_OK) {
			LM_ERR("curl_multi_timeout: %s\n", curl_multi_strerror(mrc));
			goto error;
		}

		if (retry_time == -1) {
			LM_INFO("curl_multi_timeout() returned -1, pausing %ldms...\n",
					sleep_on_bad_timeout);
			busy_wait = sleep_on_bad_timeout;
			usleep(1000UL * busy_wait);
			continue;
		}

		if (retry_time > connection_timeout_ms)
			LM_INFO("initial TCP connect: we must wait at least %ldms! Please "
			        "consider increasing 'connection_timeout'!\n", retry_time);

		busy_wait = retry_time < timeout ? retry_time : timeout;

		/**
		 * libcurl is currently stuck in internal operations (connect)
		 *    we have to wait a bit until we receive a read fd
		 */
		for (i = 0; i < busy_wait; i += check_time) {
			/* transfer may have already been completed!! */
			while ((cmsg = curl_multi_info_read(multi_handle, &msgs_in_queue))) {
				if (cmsg->easy_handle == handle && cmsg->msg == CURLMSG_DONE) {
					LM_DBG("done, no need for async!\n");

					clean_header_list;
					*out_handle = handle;
					return ASYNC_SYNC;
				}
			}

			FD_ZERO(&rset);
			mrc = curl_multi_fdset(multi_handle, &rset, &wset, &eset, &max_fd);
			if (mrc != CURLM_OK) {
				LM_ERR("curl_multi_fdset: %s\n", curl_multi_strerror(mrc));
				goto error;
			}

			if (max_fd != -1) {
				for (fd = 0; fd <= max_fd; fd++) {
					if (FD_ISSET(fd, &rset)) {

						LM_DBG(" >>>>>>>>>> fd %d ISSET(read)\n", fd);
						if (is_new_transfer(fd)) {
							LM_DBG("add fd to read list: %d\n", fd);
							add_transfer(fd);
							goto success;
						}
					}
				}
			}

			usleep(1000UL * check_time);
		}
	}

	LM_ERR("timeout while connecting to '%s' (%ld sec)\n", url, connection_timeout);
	goto error;

success:
	clean_header_list;
	*out_handle = handle;
	return fd;

error:
	mrc = curl_multi_remove_handle(multi_handle, handle);
	if (mrc != CURLM_OK)
		LM_ERR("curl_multi_remove_handle: %s\n", curl_multi_strerror(mrc));

cleanup:
	clean_header_list;
	curl_easy_cleanup(handle);
	return ASYNC_NO_IO;
}
コード例 #19
0
ファイル: curl_input_plugin.c プロジェクト: raumzeitlabor/mpd
static bool
input_curl_easy_init(struct input_curl *c, GError **error_r)
{
	CURLcode code;
	CURLMcode mcode;

	c->eof = false;

	c->easy = curl_easy_init();
	if (c->easy == NULL) {
		g_set_error(error_r, curl_quark(), 0,
			    "curl_easy_init() failed");
		return false;
	}

	mcode = curl_multi_add_handle(c->multi, c->easy);
	if (mcode != CURLM_OK) {
		g_set_error(error_r, curl_quark(), mcode,
			    "curl_multi_add_handle() failed: %s",
			    curl_multi_strerror(mcode));
		return false;
	}

	curl_easy_setopt(c->easy, CURLOPT_USERAGENT,
			 "Music Player Daemon " VERSION);
	curl_easy_setopt(c->easy, CURLOPT_HEADERFUNCTION,
			 input_curl_headerfunction);
	curl_easy_setopt(c->easy, CURLOPT_WRITEHEADER, c);
	curl_easy_setopt(c->easy, CURLOPT_WRITEFUNCTION,
			 input_curl_writefunction);
	curl_easy_setopt(c->easy, CURLOPT_WRITEDATA, c);
	curl_easy_setopt(c->easy, CURLOPT_HTTP200ALIASES, http_200_aliases);
	curl_easy_setopt(c->easy, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt(c->easy, CURLOPT_MAXREDIRS, 5);
	curl_easy_setopt(c->easy, CURLOPT_FAILONERROR, true);
	curl_easy_setopt(c->easy, CURLOPT_ERRORBUFFER, c->error);
	curl_easy_setopt(c->easy, CURLOPT_NOPROGRESS, 1l);
	curl_easy_setopt(c->easy, CURLOPT_NOSIGNAL, 1l);
	curl_easy_setopt(c->easy, CURLOPT_CONNECTTIMEOUT, 10l);

	if (proxy != NULL)
		curl_easy_setopt(c->easy, CURLOPT_PROXY, proxy);

	if (proxy_port > 0)
		curl_easy_setopt(c->easy, CURLOPT_PROXYPORT, (long)proxy_port);

	if (proxy_user != NULL && proxy_password != NULL) {
		char *proxy_auth_str =
			g_strconcat(proxy_user, ":", proxy_password, NULL);
		curl_easy_setopt(c->easy, CURLOPT_PROXYUSERPWD, proxy_auth_str);
		g_free(proxy_auth_str);
	}

	code = curl_easy_setopt(c->easy, CURLOPT_URL, c->url);
	if (code != CURLE_OK) {
		g_set_error(error_r, curl_quark(), code,
			    "curl_easy_setopt() failed: %s",
			    curl_easy_strerror(code));
		return false;
	}

	c->request_headers = NULL;
	c->request_headers = curl_slist_append(c->request_headers,
					       "Icy-Metadata: 1");
	curl_easy_setopt(c->easy, CURLOPT_HTTPHEADER, c->request_headers);

	return true;
}
コード例 #20
0
ファイル: rest_methods.c プロジェクト: Deni90/opensips
enum async_ret_code resume_async_http_req(int fd, struct sip_msg *msg, void *_param)
{
	CURLcode rc;
	CURLMcode mrc;
	rest_async_param *param = (rest_async_param *)_param;
	int running, max_fd;
	long http_rc;
	fd_set rset, wset, eset;
	pv_value_t val;

	mrc = curl_multi_perform(multi_handle, &running);
	if (mrc != CURLM_OK) {
		LM_ERR("curl_multi_perform: %s\n", curl_multi_strerror(mrc));
		return -1;
	}
	LM_DBG("running handles: %d\n", running);

	if (running == running_handles) {
		async_status = ASYNC_CONTINUE;
		return 1;
	}

	if (running > running_handles) {
		LM_BUG("incremented handles!!");
		/* default async status is DONE */
		return -1;
	}

	running_handles = running;

	FD_ZERO(&rset);
	mrc = curl_multi_fdset(multi_handle, &rset, &wset, &eset, &max_fd);
	if (mrc != CURLM_OK) {
		LM_ERR("curl_multi_fdset: %s\n", curl_multi_strerror(mrc));
		/* default async status is DONE */
		return -1;
	}

	if (max_fd == -1) {
		if (running_handles != 0) {
			LM_BUG("running_handles == %d", running_handles);
			abort();
			/* default async status is DONE */
			return -1;
		}

		if (FD_ISSET(fd, &rset)) {
			LM_BUG("fd %d is still in rset!", fd);
			abort();
			/* default async status is DONE */
			return -1;
		}

	} else if (FD_ISSET(fd, &rset)) {
		LM_DBG("fd %d still transferring...\n", fd);
		async_status = ASYNC_CONTINUE;
		return 1;
	}

	if (del_transfer(fd) != 0) {
		LM_BUG("failed to delete fd %d", fd);
		abort();
		/* default async status is DONE */
		return -1;
	}

	mrc = curl_multi_remove_handle(multi_handle, param->handle);
	if (mrc != CURLM_OK) {
		LM_ERR("curl_multi_remove_handle: %s\n", curl_multi_strerror(mrc));
		/* default async status is DONE */
		return -1;
	}

	val.flags = PV_VAL_STR;
	val.rs = param->body;
	if (pv_set_value(msg, param->body_pv, 0, &val) != 0)
		LM_ERR("failed to set output body pv\n");

	if (param->ctype_pv) {
		val.rs = param->ctype;
		if (pv_set_value(msg, param->ctype_pv, 0, &val) != 0)
			LM_ERR("failed to set output ctype pv\n");
	}

	if (param->code_pv) {
		rc = curl_easy_getinfo(param->handle, CURLINFO_RESPONSE_CODE, &http_rc);
		if (rc != CURLE_OK) {
			LM_ERR("curl_easy_getinfo: %s\n", curl_easy_strerror(rc));
			http_rc = 0;
		}

		LM_DBG("Last response code: %ld\n", http_rc);

		val.flags = PV_VAL_INT|PV_TYPE_INT;
		val.ri = (int)http_rc;
		if (pv_set_value(msg, param->code_pv, 0, &val) != 0)
			LM_ERR("failed to set output code pv\n");
	}

	pkg_free(param->body.s);
	if (param->ctype_pv && param->ctype.s)
		pkg_free(param->ctype.s);
	curl_easy_cleanup(param->handle);
	pkg_free(param);

	/* default async status is DONE */
	return 1;
}
コード例 #21
0
ファイル: rest_methods.c プロジェクト: liviuchircu/opensips
/**
 * start_async_http_req - performs an HTTP request, stores results in pvars
 *		- TCP connect phase is synchronous, due to libcurl limitations
 *		- TCP read phase is asynchronous, thanks to the libcurl multi interface
 *
 * @msg:		sip message struct
 * @method:		HTTP verb
 * @url:		HTTP URL to be queried
 * @req_body:	Body of the request (NULL if not needed)
 * @req_ctype:	Value for the "Content-Type: " header of the request (same as ^)
 * @async_parm: output param, will contain async handles
 * @body:	    reply body; gradually reallocated as data arrives
 * @ctype:	    will eventually hold the last "Content-Type" header of the reply
 */
int start_async_http_req(struct sip_msg *msg, enum rest_client_method method,
					     char *url, char *req_body, char *req_ctype,
					     rest_async_param *async_parm, str *body, str *ctype)
{
	CURL *handle;
	CURLcode rc;
	CURLMcode mrc;
	fd_set rset, wset, eset;
	int max_fd, fd;
	long busy_wait, timeout;
	long retry_time;
	OSS_CURLM *multi_list;
	CURLM *multi_handle;

	if (transfers == FD_SETSIZE) {
		LM_ERR("too many ongoing transfers: %d\n", FD_SETSIZE);
		goto cleanup;
	}

	handle = curl_easy_init();
	if (!handle) {
		LM_ERR("Init curl handle failed!\n");
		goto cleanup;
	}

	w_curl_easy_setopt(handle, CURLOPT_URL, url);
	if (curl_http_version != CURL_HTTP_VERSION_NONE)
		w_curl_easy_setopt(handle, CURLOPT_HTTP_VERSION, curl_http_version);

	if (tls_dom) {
		w_curl_easy_setopt(handle, CURLOPT_SSLCERT, tls_dom->cert.s);
		w_curl_easy_setopt(handle, CURLOPT_SSLKEY, tls_dom->pkey.s);
		tls_api.release_domain(tls_dom);
		tls_dom = NULL;
	}

	switch (method) {
	case REST_CLIENT_POST:
		w_curl_easy_setopt(handle, CURLOPT_POST, 1);
		w_curl_easy_setopt(handle, CURLOPT_POSTFIELDS, req_body);

		if (req_ctype) {
			sprintf(print_buff, "Content-Type: %s", req_ctype);
			header_list = curl_slist_append(header_list, print_buff);
			w_curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header_list);
		}
		break;
	case REST_CLIENT_PUT:
		w_curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "PUT");
		w_curl_easy_setopt(handle, CURLOPT_POSTFIELDS, req_body);

		if (req_ctype) {
			sprintf(print_buff, "Content-Type: %s", req_ctype);
			header_list = curl_slist_append(header_list, print_buff);
			w_curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header_list);
		}
		break;

	case REST_CLIENT_GET:
		break;

	default:
		LM_ERR("Unsupported rest_client_method: %d, defaulting to GET\n", method);
	}

	if (header_list)
		w_curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header_list);

	w_curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, connection_timeout);
	w_curl_easy_setopt(handle, CURLOPT_TIMEOUT, curl_timeout);

	w_curl_easy_setopt(handle, CURLOPT_VERBOSE, 1);
	w_curl_easy_setopt(handle, CURLOPT_STDERR, stdout);
	w_curl_easy_setopt(handle, CURLOPT_FAILONERROR, 0);

	w_curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_func);
	w_curl_easy_setopt(handle, CURLOPT_WRITEDATA, body);

	if (ctype) {
		w_curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, header_func);
		w_curl_easy_setopt(handle, CURLOPT_HEADERDATA, ctype);
	}

	if (ssl_capath)
		w_curl_easy_setopt(handle, CURLOPT_CAPATH, ssl_capath);

	if (!ssl_verifypeer)
		w_curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0L);

	if (!ssl_verifyhost)
		w_curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0L);

	if ( rest_trace_enabled() ) {
		async_parm->tparam = pkg_malloc(sizeof(rest_trace_param_t));
		if ( !async_parm->tparam ) {
			LM_ERR("no more pkg mem!\n");
			clean_header_list;
			return -1;
		}

		memset( async_parm->tparam, 0, sizeof *async_parm->tparam);

		async_parm->tparam->callid = msg->callid->body;

		w_curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, trace_rest_request_cb);
		w_curl_easy_setopt(handle, CURLOPT_DEBUGDATA, async_parm->tparam);
	}

	multi_list = get_multi();
	if (!multi_list) {
		LM_INFO("failed to get a multi handle, doing blocking query\n");
		rc = curl_easy_perform(handle);
		clean_header_list;
		async_parm->handle = handle;
		return ASYNC_SYNC;
	}

	multi_handle = multi_list->multi_handle;
	curl_multi_add_handle(multi_handle, handle);

	timeout = connection_timeout_ms;
	busy_wait = connect_poll_interval;

	/* obtain a read fd in "connection_timeout" seconds at worst */
	for (timeout = connection_timeout_ms; timeout > 0; timeout -= busy_wait) {
		mrc = curl_multi_perform(multi_handle, &running_handles);
		if (mrc != CURLM_OK && mrc != CURLM_CALL_MULTI_PERFORM) {
			LM_ERR("curl_multi_perform: %s\n", curl_multi_strerror(mrc));
			goto error;
		}

		mrc = curl_multi_timeout(multi_handle, &retry_time);
		if (mrc != CURLM_OK) {
			LM_ERR("curl_multi_timeout: %s\n", curl_multi_strerror(mrc));
			goto error;
		}

		LM_DBG("libcurl TCP connect: we should wait up to %ldms "
		       "(timeout=%ldms, poll=%ldms)!\n", retry_time,
		       connection_timeout_ms, connect_poll_interval);

		if (retry_time == -1) {
			LM_DBG("curl_multi_timeout() returned -1, pausing %ldms...\n",
			        busy_wait);
			goto busy_wait;
		}

		/* transfer may have already been completed!! */
		if (running_handles == 0) {
			LM_DBG("done, no need for async!\n");

			clean_header_list;
			async_parm->handle = handle;
			mrc = curl_multi_remove_handle(multi_handle, handle);
			if (mrc != CURLM_OK) {
				LM_ERR("curl_multi_remove_handle: %s\n", curl_multi_strerror(mrc));
			}
			put_multi(multi_list);
			return ASYNC_SYNC;
		}

		FD_ZERO(&rset);
		mrc = curl_multi_fdset(multi_handle, &rset, &wset, &eset, &max_fd);
		if (mrc != CURLM_OK) {
			LM_ERR("curl_multi_fdset: %s\n", curl_multi_strerror(mrc));
			goto error;
		}

		if (max_fd != -1) {
			for (fd = 0; fd <= max_fd; fd++) {
				if (FD_ISSET(fd, &rset)) {

					LM_DBG("ongoing transfer on fd %d\n", fd);
					if (is_new_transfer(fd)) {
						LM_DBG(">>> add fd %d to ongoing transfers\n", fd);
						add_transfer(fd);
						goto success;
					}
				}
			}
		}

		/*
		 * from curl_multi_timeout() docs: "retry_time" milliseconds "at most!"
		 *         -> we'll wait only 1/10 of this time before retrying
		 */
		busy_wait = connect_poll_interval < timeout ?
		            connect_poll_interval : timeout;

busy_wait:
		/* libcurl seems to be stuck in internal operations (TCP connect?) */
		LM_DBG("busy waiting %ldms ...\n", busy_wait);
		usleep(1000UL * busy_wait);
	}

	LM_ERR("timeout while connecting to '%s' (%ld sec)\n", url, connection_timeout);
	goto error;

success:
	async_parm->header_list = header_list;
	async_parm->handle = handle;
	async_parm->multi_list = multi_list;
	header_list = NULL;
	return fd;

error:
	mrc = curl_multi_remove_handle(multi_handle, handle);
	if (mrc != CURLM_OK) {
		LM_ERR("curl_multi_remove_handle: %s\n", curl_multi_strerror(mrc));
	}
	put_multi(multi_list);

	curl_easy_cleanup(handle);

cleanup:
	clean_header_list;
	if (tls_dom) {
		tls_api.release_domain(tls_dom);
		tls_dom = NULL;
	}
	return ASYNC_NO_IO;
}
コード例 #22
0
ファイル: fastestmirror.c プロジェクト: huttli/librepo
static gboolean
lr_fastestmirror_perform(GSList *list,
                         LrFastestMirrorCb cb,
                         void *cbdata,
                         GError **err)
{
    assert(!err || *err == NULL);

    if (!list)
        return TRUE;

    CURLM *multihandle = curl_multi_init();
    if (!multihandle) {
        g_set_error(err, LR_FASTESTMIRROR_ERROR, LRE_CURL,
                    "curl_multi_init() error");
        return FALSE;
    }

    // Add curl easy handles to multi handle
    long handles_added = 0;
    for (GSList *elem = list; elem; elem = g_slist_next(elem)) {
        LrFastestMirror *mirror = elem->data;
        if (mirror->curl) {
            curl_multi_add_handle(multihandle, mirror->curl);
            handles_added++;
        }
    }

    if (handles_added == 0) {
        curl_multi_cleanup(multihandle);
        return TRUE;
    }

    cb(cbdata, LR_FMSTAGE_DETECTION, (void *) &handles_added);

    int still_running;
    gdouble elapsed_time = 0.0;
    GTimer *timer = g_timer_new();
    g_timer_start(timer);

    do {
        struct timeval timeout;
        int rc, cm_rc;
        int maxfd = -1;
        long curl_timeout = -1;
        fd_set fdread, fdwrite, fdexcep;

        FD_ZERO(&fdread);
        FD_ZERO(&fdwrite);
        FD_ZERO(&fdexcep);

        // Set suitable timeout to play around with
        timeout.tv_sec  = 0;
        timeout.tv_usec = HALF_OF_SECOND_IN_MICROS;

        cm_rc = curl_multi_timeout(multihandle, &curl_timeout);
        if (cm_rc != CURLM_OK) {
            g_set_error(err, LR_FASTESTMIRROR_ERROR, LRE_CURLM,
                        "curl_multi_timeout() error: %s",
                        curl_multi_strerror(cm_rc));
            curl_multi_cleanup(multihandle);
            return FALSE;
        }

        // Set timeout to a reasonable value
        if (curl_timeout >= 0) {
            timeout.tv_sec = curl_timeout / 1000;
            if (timeout.tv_sec >= 1) {
                timeout.tv_sec = 0;
                timeout.tv_usec = HALF_OF_SECOND_IN_MICROS;
            } else {
                timeout.tv_usec = (curl_timeout % 1000) * 1000;
                if (timeout.tv_usec > HALF_OF_SECOND_IN_MICROS)
                    timeout.tv_usec = HALF_OF_SECOND_IN_MICROS;
            }
        }

        // Get file descriptors from the transfers
        cm_rc = curl_multi_fdset(multihandle, &fdread, &fdwrite,
                                 &fdexcep, &maxfd);
        if (cm_rc != CURLM_OK) {
            g_set_error(err, LR_FASTESTMIRROR_ERROR, LRE_CURLM,
                        "curl_multi_fdset() error: %s",
                        curl_multi_strerror(cm_rc));
            return FALSE;
        }

        rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
        if (rc < 0) {
            if (errno == EINTR) {
                g_debug("%s: select() interrupted by signal", __func__);
            } else {
                g_set_error(err, LR_FASTESTMIRROR_ERROR, LRE_SELECT,
                            "select() error: %s", strerror(errno));
                return FALSE;
            }
        }

        curl_multi_perform(multihandle, &still_running);

        // Break loop after some reasonable amount of time
        elapsed_time = g_timer_elapsed(timer, NULL);

    } while(still_running && elapsed_time < LENGT_OF_MEASUREMENT);

    g_timer_destroy(timer);

    // Remove curl easy handles from multi handle
    // and calculate plain_connect_time
    for (GSList *elem = list; elem; elem = g_slist_next(elem)) {
        LrFastestMirror *mirror = elem->data;
        CURL *curl = mirror->curl;

        if (!curl)
            continue;

        // Remove handle
        curl_multi_remove_handle(multihandle, curl);

        // Calculate plain_connect_time
        char *effective_url;
        curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);

        if (!effective_url) {
            // No effective url is most likely an error
            mirror->plain_connect_time = DBL_MAX;
        } else if (g_str_has_prefix(effective_url, "file://")) {
            // Local directories are considered to be the best mirrors
            mirror->plain_connect_time = 0.0;
        } else {
            // Get connect time
            double namelookup_time;
            double connect_time;
            double plain_connect_time;
            curl_easy_getinfo(curl, CURLINFO_NAMELOOKUP_TIME, &namelookup_time);
            curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &connect_time);

            if (connect_time == 0.0) {
                // Zero connect time is most likely an error
                plain_connect_time = DBL_MAX;
            } else {
                plain_connect_time = connect_time - namelookup_time;
            }

            mirror->plain_connect_time = plain_connect_time;
            //g_debug("%s: name_lookup: %3.6f connect_time:  %3.6f (%3.6f) | %s",
            //        __func__, namelookup_time, connect_time,
            //        mirror->plain_connect_time, mirror->url);
        }
    }

    curl_multi_cleanup(multihandle);
    return TRUE;
}
コード例 #23
0
void CurlStreamFile::fillCache(std::streampos size){
#if 1
	assert(size >= 0);
	if(! _running || _cached >=size){
		return ;
	}
	fd_set readfd, writefd, exceptfd;
	int maxfd;
	CURLMcode mcode;
	timeval tv;
	//hard-coded slect timeout
	//this number is kept low to give more thread switch
	//opportunities while waitting for a load
	const long maxSleepUsec = 10000; //1/100 of a second

	const unsigned int userTimeout = 60000;
	WallClockTimer lastProgress;
	while(_running){
		fillCacheNonBlocking();
		if(_cached>=size || !_running) break;

		FD_ZERO(&readfd);
		FD_ZERO(&writefd);
		FD_ZERO(&exceptfd);
		mcode = curl_multi_fdset(_mCurlHandle, &readfd, &writefd,
				&exceptfd, &maxfd);
		if(mcode != CURLM_OK){
			throw SnailException(curl_multi_strerror(mcode));
		}
		if(maxfd<0){
			//as of libcurl 7.21.x, the DNS resolving appears to be
			//going on in the background, so curl_multi_fdset fails to
			//return anything useful, So we use the user timeout value
			//to give DNS enough time to resolve the lookup
			if(userTimeout && lastProgress.elapsed()>userTimeout){
				return ;
			}else{
				continue;
			}
		}//if(maxfd<0)
		tv.tv_sec = 0;
		tv.tv_usec = maxSleepUsec;
		//wait for data on the filedescriptors until a timeout set in rc file
		int ret = select(maxfd+1, &readfd, &writefd, &exceptfd, &tv);
#if !defined(WIN32)
		if(ret == -1){
			if(errno == EINTR){
				cout<<"select() was interrupted by a singal"<<endl;
				ret = 0;
			}else{
				std::ostringstream os;
				os<<"error polling data from connection to"<<_url<<":"<<strerror(errno);
				throw SnailException(os.str());
			}
		}
#endif
		if(!ret){
			//timeout check the clock to see
			//if we expired the user timeout
			if(userTimeout && lastProgress.elapsed() > userTimeout){
				cout<<"timeout ("<<userTimeout<<") while loading from URL"<<_url<<endl;
				return ;
			}
		}else{
			lastProgress.restart();
		}
	}//while(....
	processMessages();
#endif
}
コード例 #24
0
ファイル: http_client_curl.c プロジェクト: L0op/RuneAudioNext
/**
 * Updates all registered GPollFD objects, unregisters old ones,
 * registers new ones.
 */
static void
http_client_update_fds(void)
{
	fd_set rfds, wfds, efds;
	int max_fd;
	CURLMcode mcode;
	GSList *fds;

	FD_ZERO(&rfds);
	FD_ZERO(&wfds);
	FD_ZERO(&efds);

	mcode = curl_multi_fdset(http_client.multi, &rfds, &wfds,
				 &efds, &max_fd);
	if (mcode != CURLM_OK) {
		g_warning("curl_multi_fdset() failed: %s\n",
			  curl_multi_strerror(mcode));
		return;
	}

	fds = http_client.fds;
	http_client.fds = NULL;

	while (fds != NULL) {
		GPollFD *poll_fd = fds->data;
		gushort events = http_client_fd_events(poll_fd->fd, &rfds,
						       &wfds, &efds);

		assert(poll_fd->events != 0);

		fds = g_slist_remove(fds, poll_fd);

		if (events != poll_fd->events)
			g_source_remove_poll(http_client.source, poll_fd);

		if (events != 0) {
			if (events != poll_fd->events) {
				poll_fd->events = events;
				g_source_add_poll(http_client.source, poll_fd);
			}

			http_client.fds = g_slist_prepend(http_client.fds,
							  poll_fd);
		} else {
			g_free(poll_fd);
		}
	}

	for (int fd = 0; fd <= max_fd; ++fd) {
		gushort events = http_client_fd_events(fd, &rfds,
						       &wfds, &efds);
		if (events != 0) {
			GPollFD *poll_fd = g_new(GPollFD, 1);
			poll_fd->fd = fd;
			poll_fd->events = events;
			g_source_add_poll(http_client.source, poll_fd);
			http_client.fds = g_slist_prepend(http_client.fds,
							  poll_fd);
		}
	}
}