Пример #1
0
void wswcurl_init( void ) {
	if( wswcurl_mempool ) {
		return;
	}

	wswcurl_mempool = Mem_AllocPool( NULL, "Curl" );

	// HTTP proxy settings
	http_proxy = Cvar_Get( "http_proxy", "", CVAR_ARCHIVE );
	http_proxyuserpwd = Cvar_Get( "http_proxyuserpwd", "", CVAR_ARCHIVE );

	wswcurl_loadlib();

	if( curlLibrary ) {
		qcurl_global_init( CURL_GLOBAL_ALL );

		curldummy = qcurl_easy_init();
		curlmulti = qcurl_multi_init();
	}

	curldummy_mutex = QMutex_Create();

	http_requests_mutex = QMutex_Create();

#ifdef USE_OPENSSL
	if( cryptoLibrary ) {
		int mutex_num;
		crypto_num_mutexes = qCRYPTO_num_locks();
		crypto_mutexes = WMALLOC( crypto_num_mutexes * sizeof( *crypto_mutexes ) );
		for( mutex_num = 0; mutex_num < crypto_num_mutexes; mutex_num++ )
			crypto_mutexes[mutex_num] = QMutex_Create();
		qCRYPTO_set_locking_callback( wswcurl_crypto_lockcallback );
	}
#endif
}
Пример #2
0
/*
====================
CheckPendingDownloads

checks if there are free download slots to start new downloads in.
To not start too many downloads at once, only one download is added at a time,
up to a maximum number of cl_curl_maxdownloads are running.
====================
*/
static void CheckPendingDownloads(void)
{
	const char *h;
	if(!curl_dll)
		return;
	if(numdownloads < cl_curl_maxdownloads.integer)
	{
		downloadinfo *di;
		for(di = downloads; di; di = di->next)
		{
			if(!di->started)
			{
				if(!di->buffer)
				{
					Con_Printf("Downloading %s -> %s", CleanURL(di->url), di->filename);

					di->stream = FS_OpenRealFile(di->filename, "ab", false);
					if(!di->stream)
					{
						Con_Printf("\nFAILED: Could not open output file %s\n", di->filename);
						Curl_EndDownload(di, CURL_DOWNLOAD_FAILED, CURLE_OK);
						return;
					}
					FS_Seek(di->stream, 0, SEEK_END);
					di->startpos = FS_Tell(di->stream);

					if(di->startpos > 0)
						Con_Printf(", resuming from position %ld", (long) di->startpos);
					Con_Print("...\n");
				}
				else
				{
					Con_DPrintf("Downloading %s -> memory\n", CleanURL(di->url));
					di->startpos = 0;
				}

				di->curle = qcurl_easy_init();
				di->slist = NULL;
				qcurl_easy_setopt(di->curle, CURLOPT_URL, di->url);
				qcurl_easy_setopt(di->curle, CURLOPT_USERAGENT, engineversion);
				qcurl_easy_setopt(di->curle, CURLOPT_REFERER, di->referer);
				qcurl_easy_setopt(di->curle, CURLOPT_RESUME_FROM, (long) di->startpos);
				qcurl_easy_setopt(di->curle, CURLOPT_FOLLOWLOCATION, 1);
				qcurl_easy_setopt(di->curle, CURLOPT_WRITEFUNCTION, CURL_fwrite);
				qcurl_easy_setopt(di->curle, CURLOPT_LOW_SPEED_LIMIT, (long) 256);
				qcurl_easy_setopt(di->curle, CURLOPT_LOW_SPEED_TIME, (long) 45);
				qcurl_easy_setopt(di->curle, CURLOPT_WRITEDATA, (void *) di);
				qcurl_easy_setopt(di->curle, CURLOPT_PRIVATE, (void *) di);
				qcurl_easy_setopt(di->curle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP);
				if(qcurl_easy_setopt(di->curle, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP) != CURLE_OK)
				{
					Con_Printf("^1WARNING:^7 for security reasons, please upgrade to libcurl 7.19.4 or above. In a later version of DarkPlaces, HTTP redirect support will be disabled for this libcurl version.\n");
					//qcurl_easy_setopt(di->curle, CURLOPT_FOLLOWLOCATION, 0);
				}
				if(di->post_content_type)
				{
					qcurl_easy_setopt(di->curle, CURLOPT_POST, 1);
					qcurl_easy_setopt(di->curle, CURLOPT_POSTFIELDS, di->postbuf);
					qcurl_easy_setopt(di->curle, CURLOPT_POSTFIELDSIZE, di->postbufsize);
					di->slist = qcurl_slist_append(di->slist, va("Content-Type: %s", di->post_content_type));
				}

				// parse extra headers into slist
				// \n separated list!
				h = di->extraheaders;
				while(h)
				{
					const char *hh = strchr(h, '\n');
					if(hh)
					{
						char *buf = (char *) Mem_Alloc(tempmempool, hh - h + 1);
						memcpy(buf, h, hh - h);
						buf[hh - h] = 0;
						di->slist = qcurl_slist_append(di->slist, buf);
						h = hh + 1;
					}
					else
					{
						di->slist = qcurl_slist_append(di->slist, h);
						h = NULL;
					}
				}

				qcurl_easy_setopt(di->curle, CURLOPT_HTTPHEADER, di->slist);

				
				qcurl_multi_add_handle(curlm, di->curle);
				di->started = true;
				++numdownloads;
				if(numdownloads >= cl_curl_maxdownloads.integer)
					break;
			}
		}
	}
}
Пример #3
0
void CL_cURL_BeginDownload( const char *localName, const char *remoteURL )
{
    clc.cURLUsed = qtrue;
    Com_Printf("URL: %s\n", remoteURL);
    Com_DPrintf("***** CL_cURL_BeginDownload *****\n"
                "Localname: %s\n"
                "RemoteURL: %s\n"
                "****************************\n", localName, remoteURL);
    CL_cURL_Cleanup();
    Q_strncpyz(clc.downloadURL, remoteURL, sizeof(clc.downloadURL));
    Q_strncpyz(clc.downloadName, localName, sizeof(clc.downloadName));
    Com_sprintf(clc.downloadTempName, sizeof(clc.downloadTempName),
                "%s.tmp", localName);

    // Set so UI gets access to it
    Cvar_Set("cl_downloadName", localName);
    Cvar_Set("cl_downloadSize", "0");
    Cvar_Set("cl_downloadCount", "0");
    Cvar_SetValue("cl_downloadTime", cls.realtime);

    clc.downloadBlock = 0; // Starting new file
    clc.downloadCount = 0;

    clc.downloadCURL = qcurl_easy_init();
    if(!clc.downloadCURL) {
        Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_easy_init() "
                  "failed\n");
        return;
    }
    clc.download = FS_SV_FOpenFileWrite(clc.downloadTempName);
    if(!clc.download) {
        Com_Error(ERR_DROP, "CL_cURL_BeginDownload: failed to open "
                  "%s for writing\n", clc.downloadTempName);
        return;
    }
    qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEDATA, clc.download);
    if(com_developer->integer)
        qcurl_easy_setopt(clc.downloadCURL, CURLOPT_VERBOSE, 1);
    qcurl_easy_setopt(clc.downloadCURL, CURLOPT_URL, clc.downloadURL);
    qcurl_easy_setopt(clc.downloadCURL, CURLOPT_TRANSFERTEXT, 0);
    qcurl_easy_setopt(clc.downloadCURL, CURLOPT_REFERER, va("ioQ3://%s",
                      NET_AdrToString(clc.serverAddress)));
    qcurl_easy_setopt(clc.downloadCURL, CURLOPT_USERAGENT, va("%s %s",
                      Q3_VERSION, qcurl_version()));
    qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEFUNCTION,
                      CL_cURL_CallbackWrite);
    qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEDATA, &clc.download);
    qcurl_easy_setopt(clc.downloadCURL, CURLOPT_NOPROGRESS, 0);
    qcurl_easy_setopt(clc.downloadCURL, CURLOPT_PROGRESSFUNCTION,
                      CL_cURL_CallbackProgress);
    qcurl_easy_setopt(clc.downloadCURL, CURLOPT_PROGRESSDATA, NULL);
    qcurl_easy_setopt(clc.downloadCURL, CURLOPT_FAILONERROR, 1);
    qcurl_easy_setopt(clc.downloadCURL, CURLOPT_FOLLOWLOCATION, 1);
    qcurl_easy_setopt(clc.downloadCURL, CURLOPT_MAXREDIRS, 5);
    clc.downloadCURLM = qcurl_multi_init();
    if(!clc.downloadCURLM) {
        qcurl_easy_cleanup(clc.downloadCURL);
        clc.downloadCURL = NULL;
        Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_multi_init() "
                  "failed\n");
        return;
    }
    qcurl_multi_add_handle(clc.downloadCURLM, clc.downloadCURL);

    if(!(clc.sv_allowDownload & DLF_NO_DISCONNECT) &&
            !clc.cURLDisconnected) {

        CL_AddReliableCommand("disconnect");
        CL_WritePacket();
        CL_WritePacket();
        CL_WritePacket();
        clc.cURLDisconnected = qtrue;
    }
}
Пример #4
0
wswcurl_req *wswcurl_create( const char *iface, const char *furl, ... ) {
	wswcurl_req *retreq;
	CURL *curl;
	CURLcode res;
	char url[4 * 1024]; // 4kb url buffer?
	va_list arg;
	const char *proxy = http_proxy->string;
	const char *proxy_userpwd = http_proxyuserpwd->string;

	if( !curlLibrary ) {
		Com_Printf( "!!! WARNING: external library is missing (libcurl).\n" );
		return NULL;
	}

	// Prepare url formatting with variable arguments
	va_start( arg, furl );
	Q_vsnprintfz( url, sizeof( url ), furl, arg );
	va_end( arg );

	// Initialize structure
	if( !( curl = qcurl_easy_init() ) ) {
		return NULL;
	}

	// allocate, copy
	retreq = ( wswcurl_req * )WMALLOC( sizeof( wswcurl_req ) );
	memset( retreq, 0, sizeof( *retreq ) );

	retreq->curl = curl;
	retreq->url = ( char* )WMALLOC( strlen( url ) + 1 );
	memcpy( retreq->url, url, strlen( url ) + 1 );

	CURLSETOPT( curl, res, CURLOPT_URL, retreq->url );
	CURLSETOPT( curl, res, CURLOPT_WRITEFUNCTION, wswcurl_write );
	CURLSETOPT( curl, res, CURLOPT_NOPROGRESS, 1 );
	CURLSETOPT( curl, res, CURLOPT_FOLLOWLOCATION, 1 );
	CURLSETOPT( curl, res, CURLOPT_HEADERFUNCTION, wswcurl_readheader );
	CURLSETOPT( curl, res, CURLOPT_CONNECTTIMEOUT, WCONNECTTIMEOUT );
#if defined( APPLICATION ) && defined( APP_VERSION_STR ) && defined( OSNAME ) && defined( CPUSTRING )
	CURLSETOPT( curl, res, CURLOPT_USERAGENT, APPLICATION "/"APP_VERSION_STR " (compatible; N; "OSNAME "; "CPUSTRING ")" );
#endif
	CURLSETOPT( curl, res, CURLOPT_WRITEDATA, ( void * )retreq );
	CURLSETOPT( curl, res, CURLOPT_WRITEHEADER, ( void * )retreq );
	CURLSETOPT( curl, res, CURLOPT_PRIVATE, ( void * )retreq );
	if( iface && *iface ) {
		CURLSETOPT( curl, res, CURLOPT_INTERFACE, ( void * )iface );
	}
	CURLSETOPT( curl, res, CURLOPT_NOSIGNAL, 1 );

	if( developer->integer ) {
		CURLSETOPT( curl, res, CURLOPT_DEBUGFUNCTION, &wswcurl_debug_callback );
		CURLSETOPT( curl, res, CURLOPT_DEBUGDATA, ( void * )retreq );
		CURLSETOPT( curl, res, CURLOPT_VERBOSE, 1 );
	}

	// HTTP proxy settings
	if( proxy && *proxy ) {
		CURLSETOPT( curl, res, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );

		CURLSETOPT( curl, res, CURLOPT_PROXY, proxy );
		if( proxy_userpwd && *proxy_userpwd ) {
			CURLSETOPT( curl, res, CURLOPT_PROXYUSERPWD, proxy_userpwd );
		}
	}

	wswcurl_set_timeout( retreq, WTIMEOUT );

	// link
	QMutex_Lock( http_requests_mutex );

	retreq->prev = NULL;
	retreq->next = http_requests;
	if( retreq->next ) {
		retreq->next->prev = retreq;
	} else {
		http_requests_hnode = retreq;
	}
	http_requests = retreq;

	CURLDBG( ( va( "   CURL CREATE %s\n", url ) ) );

	QMutex_Unlock( http_requests_mutex );

	return retreq;
}