Skip to content

Commit 5498204

Browse files
committed
fix memleak / improve curlwrapper
1 parent def79ed commit 5498204

File tree

6 files changed

+101
-86
lines changed

6 files changed

+101
-86
lines changed

src/Downloader/CurlWrapper.cpp

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
1-
1+
/* This file is part of pr-downloader (GPL v2 or later), see the LICENSE file */
22

33
#include <curl/curl.h>
44

55
#include "CurlWrapper.h"
66
#include "Version.h"
77

8-
CURL* CurlWrapper::CurlInit()
8+
CurlWrapper::CurlWrapper()
99
{
10-
CURL* ret;
11-
ret = curl_easy_init();
12-
curl_easy_setopt(ret, CURLOPT_CONNECTTIMEOUT, 30);
10+
handle = curl_easy_init();
11+
curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, 30);
1312

1413
//if transfer is slower this bytes/s than this for CURLOPT_LOW_SPEED_TIME then its aborted
15-
curl_easy_setopt(ret, CURLOPT_LOW_SPEED_LIMIT, 10);
16-
curl_easy_setopt(ret, CURLOPT_LOW_SPEED_TIME, 30);
17-
curl_easy_setopt(ret, CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
18-
curl_easy_setopt(ret, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
19-
curl_easy_setopt(ret, CURLOPT_USERAGENT, getVersion());
20-
curl_easy_setopt(ret, CURLOPT_FAILONERROR, true);
21-
curl_easy_setopt(ret, CURLOPT_FOLLOWLOCATION, 1);
14+
curl_easy_setopt(handle, CURLOPT_LOW_SPEED_LIMIT, 10);
15+
curl_easy_setopt(handle, CURLOPT_LOW_SPEED_TIME, 30);
16+
curl_easy_setopt(handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
17+
curl_easy_setopt(handle, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
18+
curl_easy_setopt(handle, CURLOPT_USERAGENT, getVersion());
19+
curl_easy_setopt(handle, CURLOPT_FAILONERROR, true);
20+
curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
2221

23-
struct curl_slist *list = NULL;
24-
list = curl_slist_append(list, "Cache-Control: no-cache");
25-
curl_easy_setopt(ret, CURLOPT_HTTPHEADER, list);
26-
//FIXME: memleak, has to be freed at shutdown
27-
// curl_slist_free_all(list); /* free the list again */
22+
list = NULL;
23+
list = curl_slist_append(list, "Cache-Control: no-cache");
24+
curl_easy_setopt(handle, CURLOPT_HTTPHEADER, list);
25+
}
2826

29-
return ret;
27+
CurlWrapper::~CurlWrapper()
28+
{
29+
curl_easy_cleanup(handle);
30+
handle = NULL;
31+
curl_slist_free_all(list); /* free the list again */
3032
}

src/Downloader/CurlWrapper.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
1+
/* This file is part of pr-downloader (GPL v2 or later), see the LICENSE file */
12

23
#include <curl/curl.h>
34

4-
class CurlWrapper {
5+
class CurlWrapper
6+
{
57
public:
6-
static CURL* CurlInit();
8+
CurlWrapper();
9+
~CurlWrapper();
10+
CURL* const GetHandle() const {
11+
return handle;
12+
}
13+
private:
14+
CURL* handle;
15+
struct curl_slist *list;
716
};

src/Downloader/Http/DownloadData.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,13 @@ DownloadData::DownloadData()
1010
start_piece=0;
1111
mirror=NULL;
1212
download=NULL;
13-
easy_handle=CurlWrapper::CurlInit();
13+
curlw = new CurlWrapper();
1414
got_ranges = false;
1515
}
1616

1717
DownloadData::~DownloadData()
1818
{
19-
if (easy_handle!=NULL) {
20-
curl_easy_cleanup(easy_handle);
21-
easy_handle=NULL;
22-
}
19+
delete curlw;
20+
curlw = NULL;
2321
}
2422

src/Downloader/Http/DownloadData.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33
#ifndef _DOWNLOAD_DATA_H
44
#define _DOWNLOAD_DATA_H
55

6-
#include <string>
76
#include <vector>
87
class CFile;
98
class Mirror;
109
class IDownload;
11-
typedef void CURL;
10+
class CurlWrapper;
1211

1312
class DownloadData
1413
{
@@ -17,7 +16,7 @@ class DownloadData
1716
~DownloadData();
1817
int start_piece;
1918
std::vector<unsigned int> pieces;
20-
CURL* easy_handle; //curl_easy_handle
19+
CurlWrapper* curlw; //curl_easy_handle
2120
Mirror* mirror; //mirror used
2221
IDownload *download;
2322
bool got_ranges; //true if headers received from server are fine

src/Downloader/Http/HttpDownloader.cpp

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@
2626
#include <sstream>
2727
#include <stdlib.h>
2828

29-
class xmllog: public XmlRpc::XmlRpcLogHandler {
29+
class xmllog: public XmlRpc::XmlRpcLogHandler
30+
{
3031
public:
3132
virtual ~xmllog() {}
32-
void log(int level, const char* msg)
33-
{
33+
void log(int level, const char* msg) {
3434
LOG_INFO("%s",msg);
3535
}
3636
};
@@ -61,12 +61,12 @@ CHttpDownloader::~CHttpDownloader()
6161

6262
bool CHttpDownloader::search(std::list<IDownload*>& res, const std::string& name, IDownload::category cat)
6363
{
64-
CURL* curl = CurlWrapper::CurlInit();
64+
CurlWrapper* curlw = new CurlWrapper();
6565
LOG_DEBUG("%s", name.c_str() );
6666

6767
const std::string method(XMLRPC_METHOD);
6868
//std::string category;
69-
XmlRpc::XmlRpcCurlClient client(curl, XMLRPC_HOST,XMLRPC_PORT, XMLRPC_URI);
69+
XmlRpc::XmlRpcCurlClient client(curlw->GetHandle(), XMLRPC_HOST,XMLRPC_PORT, XMLRPC_URI);
7070
XmlRpc::XmlRpcValue arg;
7171
arg["springname"]=name;
7272
arg["torrent"]=true;
@@ -99,17 +99,20 @@ bool CHttpDownloader::search(std::list<IDownload*>& res, const std::string& name
9999

100100
if (result.getType()!=XmlRpc::XmlRpcValue::TypeArray) {
101101
LOG_ERROR("Returned xml isn't an array!");
102+
delete curlw;
102103
return false;
103104
}
104105

105106
for(int i=0; i<result.size(); i++) {
106107
XmlRpc::XmlRpcValue resfile = result[i];
107108

108109
if (resfile.getType()!=XmlRpc::XmlRpcValue::TypeStruct) {
110+
delete curlw;
109111
return false;
110112
}
111113
if (resfile["category"].getType()!=XmlRpc::XmlRpcValue::TypeString) {
112114
LOG_ERROR("No category in result");
115+
delete curlw;
113116
return false;
114117
}
115118
std::string filename=fileSystem->getSpringDir();
@@ -125,8 +128,9 @@ bool CHttpDownloader::search(std::list<IDownload*>& res, const std::string& name
125128
LOG_ERROR("Unknown Category %s", category.c_str());
126129
filename+=PATH_DELIMITER;
127130
if ((resfile["mirrors"].getType()!=XmlRpc::XmlRpcValue::TypeArray) ||
128-
(resfile["filename"].getType()!=XmlRpc::XmlRpcValue::TypeString)) {
131+
(resfile["filename"].getType()!=XmlRpc::XmlRpcValue::TypeString)) {
129132
LOG_ERROR("Invalid type in result");
133+
delete curlw;
130134
return false;
131135
}
132136
filename.append(resfile["filename"]);
@@ -165,6 +169,7 @@ bool CHttpDownloader::search(std::list<IDownload*>& res, const std::string& name
165169
}
166170
res.push_back(dl);
167171
}
172+
delete curlw;
168173
return true;
169174
}
170175

@@ -299,14 +304,14 @@ bool CHttpDownloader::setupDownload(DownloadData* piece)
299304
piece->start_piece=pieces.size() > 0 ? pieces[0] : -1;
300305
assert(piece->download->pieces.size()<=0 || piece->start_piece >=0);
301306
piece->pieces = pieces;
302-
if (piece->easy_handle==NULL) {
303-
piece->easy_handle=CurlWrapper::CurlInit();
307+
if (piece->curlw==NULL) {
308+
piece->curlw = new CurlWrapper();
304309
} else {
305-
curl_easy_cleanup(piece->easy_handle);
306-
piece->easy_handle=CurlWrapper::CurlInit();
310+
delete piece->curlw;
311+
piece->curlw = new CurlWrapper();
307312
}
308313

309-
CURL* curle= piece->easy_handle;
314+
CURL* curle = piece->curlw->GetHandle();
310315
piece->mirror=piece->download->getFastestMirror();
311316
if (piece->mirror==NULL) {
312317
LOG_ERROR("No mirror found");
@@ -351,7 +356,7 @@ bool CHttpDownloader::setupDownload(DownloadData* piece)
351356
DownloadData* CHttpDownloader::getDataByHandle(const std::vector <DownloadData*>& downloads, const CURL* easy_handle) const
352357
{
353358
for(int i=0; i<(int)downloads.size(); i++) { //search corresponding data structure
354-
if (downloads[i]->easy_handle == easy_handle) {
359+
if (downloads[i]->curlw->GetHandle() == easy_handle) {
355360
return downloads[i];
356361
}
357362
}
@@ -411,22 +416,22 @@ bool CHttpDownloader::processMessages(CURLM* curlm, std::vector <DownloadData*>&
411416
}
412417
//get speed at which this piece was downloaded + update mirror info
413418
double dlSpeed;
414-
curl_easy_getinfo(data->easy_handle, CURLINFO_SPEED_DOWNLOAD, &dlSpeed);
419+
curl_easy_getinfo(data->curlw->GetHandle(), CURLINFO_SPEED_DOWNLOAD, &dlSpeed);
415420
data->mirror->UpdateSpeed(dlSpeed);
416421
if (data->mirror->status == Mirror::STATUS_UNKNOWN) //set mirror status only when unset
417422
data->mirror->status=Mirror::STATUS_OK;
418423

419424
//remove easy handle, as its finished
420-
curl_multi_remove_handle(curlm, data->easy_handle);
421-
curl_easy_cleanup(data->easy_handle);
422-
data->easy_handle=NULL;
425+
curl_multi_remove_handle(curlm, data->curlw->GetHandle());
426+
delete data->curlw;
427+
data->curlw=NULL;
423428
LOG_INFO("piece finished");
424429
//piece finished / failed, try a new one
425430
if (!setupDownload(data)) {
426431
LOG_DEBUG("No piece found, all pieces finished / currently downloading");
427432
break;
428433
}
429-
int ret=curl_multi_add_handle(curlm, data->easy_handle);
434+
int ret=curl_multi_add_handle(curlm, data->curlw->GetHandle());
430435
if (ret!=CURLM_OK) {
431436
LOG_ERROR("curl_multi_perform_error: %d %d", ret, CURLM_BAD_EASY_HANDLE);
432437
}
@@ -474,7 +479,7 @@ bool CHttpDownloader::download(std::list<IDownload*>& download, int max_parallel
474479
}
475480
} else {
476481
downloads.push_back(dlData);
477-
curl_multi_add_handle(curlm, dlData->easy_handle);
482+
curl_multi_add_handle(curlm, dlData->curlw->GetHandle());
478483
}
479484
}
480485
}
@@ -516,7 +521,7 @@ bool CHttpDownloader::download(std::list<IDownload*>& download, int max_parallel
516521
double size=-1;
517522
for (unsigned i=0; i<downloads.size(); i++) {
518523
double tmp;
519-
curl_easy_getinfo(downloads[i]->easy_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &tmp);
524+
curl_easy_getinfo(downloads[i]->curlw->GetHandle(), CURLINFO_CONTENT_LENGTH_DOWNLOAD, &tmp);
520525
if (tmp>size) {
521526
size=tmp;
522527
}
@@ -541,7 +546,7 @@ bool CHttpDownloader::download(std::list<IDownload*>& download, int max_parallel
541546
}
542547
for (unsigned i=0; i<downloads.size(); i++) {
543548
long timestamp;
544-
if (curl_easy_getinfo(downloads[i]->easy_handle, CURLINFO_FILETIME, &timestamp) == CURLE_OK) {
549+
if (curl_easy_getinfo(downloads[i]->curlw->GetHandle(), CURLINFO_FILETIME, &timestamp) == CURLE_OK) {
545550
if (downloads[i]->download->state != IDownload::STATE_FINISHED) //decrease local timestamp if download failed to force redownload next time
546551
timestamp--;
547552
downloads[i]->download->file->SetTimestamp(timestamp);

src/Downloader/Rapid/Sdp.cpp

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -244,52 +244,54 @@ static int progress_func(CSdp& csdp, double TotalToDownload, double NowDownloade
244244

245245
bool CSdp::downloadStream(const std::string& url,std::list<FileData*> files)
246246
{
247-
CURL* curl = CurlWrapper::CurlInit();
248-
if (curl) {
249-
CURLcode res;
250-
LOG_INFO("Using rapid");
251-
LOG_INFO(url.c_str());
247+
CurlWrapper* curlw = new CurlWrapper();
248+
if (!curlw) {
249+
return false;
250+
}
251+
CURLcode res;
252+
LOG_INFO("Using rapid");
253+
LOG_INFO(url.c_str());
252254

253-
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
255+
curl_easy_setopt(curlw->GetHandle(), CURLOPT_URL, url.c_str());
254256

255-
int buflen=files.size()/8;
256-
if (files.size()%8!=0)
257-
buflen++;
258-
char* buf=(char*)malloc(buflen); //FIXME: compress blockwise and not all at once
259-
memset(buf,0,buflen);
260-
int destlen=files.size()*2;
261-
LOG_DEBUG("%d %d %d",(int)files.size(),buflen,destlen);
262-
int i=0;
263-
std::list<FileData*>::iterator it;
264-
for (it=files.begin(); it!=files.end(); ++it) {
265-
if ((*it)->download==true) {
266-
buf[i/8] |= (1<<(i%8));
267-
}
268-
i++;
257+
int buflen=files.size()/8;
258+
if (files.size()%8!=0)
259+
buflen++;
260+
char* buf=(char*)malloc(buflen); //FIXME: compress blockwise and not all at once
261+
memset(buf,0,buflen);
262+
int destlen=files.size()*2;
263+
LOG_DEBUG("%d %d %d",(int)files.size(),buflen,destlen);
264+
int i=0;
265+
std::list<FileData*>::iterator it;
266+
for (it=files.begin(); it!=files.end(); ++it) {
267+
if ((*it)->download==true) {
268+
buf[i/8] |= (1<<(i%8));
269269
}
270-
char* dest=(char*)malloc(destlen);
270+
i++;
271+
}
272+
char* dest=(char*)malloc(destlen);
271273

272-
gzip_str(buf,buflen,dest,&destlen);
274+
gzip_str(buf,buflen,dest,&destlen);
273275

274-
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_streamed_data);
275-
curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
276+
curl_easy_setopt(curlw->GetHandle(), CURLOPT_WRITEFUNCTION, write_streamed_data);
277+
curl_easy_setopt(curlw->GetHandle(), CURLOPT_WRITEDATA, this);
276278

277279

278-
globalFiles=&files;
279-
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, dest);
280-
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE,destlen);
281-
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
282-
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_func);
283-
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, this);
280+
globalFiles=&files;
281+
curl_easy_setopt(curlw->GetHandle(), CURLOPT_POSTFIELDS, dest);
282+
curl_easy_setopt(curlw->GetHandle(), CURLOPT_POSTFIELDSIZE,destlen);
283+
curl_easy_setopt(curlw->GetHandle(), CURLOPT_NOPROGRESS, 0L);
284+
curl_easy_setopt(curlw->GetHandle(), CURLOPT_PROGRESSFUNCTION, progress_func);
285+
curl_easy_setopt(curlw->GetHandle(), CURLOPT_PROGRESSDATA, this);
284286

285-
res = curl_easy_perform(curl);
286-
free(dest);
287-
/* always cleanup */
288-
curl_easy_cleanup(curl);
289-
if (res!=CURLE_OK) {
290-
LOG_ERROR("Curl cleanup error: %s",curl_easy_strerror(res));
291-
return false;
292-
}
287+
res = curl_easy_perform(curlw->GetHandle());
288+
free(dest);
289+
/* always cleanup */
290+
delete curlw;
291+
curlw = NULL;
292+
if (res != CURLE_OK) {
293+
LOG_ERROR("Curl cleanup error: %s",curl_easy_strerror(res));
294+
return false;
293295
}
294296
return true;
295297
}

0 commit comments

Comments
 (0)