2007-09-29 12:00:14 +04:00
|
|
|
/*
|
|
|
|
* Bittorrent Client using Qt4 and libtorrent.
|
|
|
|
* Copyright (C) 2006 Christophe Dumez
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
2009-04-05 21:00:55 +04:00
|
|
|
* In addition, as a special exception, the copyright holders give permission to
|
|
|
|
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
|
|
|
* modified versions of it that use the same license as the "OpenSSL" library),
|
|
|
|
* and distribute the linked executables. You must obey the GNU General Public
|
|
|
|
* License in all respects for all of the code used other than "OpenSSL". If you
|
|
|
|
* modify file(s), you may extend this exception to your version of the file(s),
|
|
|
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
|
|
|
* exception statement from your version.
|
|
|
|
*
|
2007-09-29 12:00:14 +04:00
|
|
|
* Contact : chris@qbittorrent.org
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "downloadThread.h"
|
|
|
|
#include <iostream>
|
2007-11-22 01:30:33 +03:00
|
|
|
#include <QSettings>
|
2007-11-24 01:57:49 +03:00
|
|
|
#include <stdio.h>
|
2007-09-29 12:00:14 +04:00
|
|
|
|
2008-07-27 20:13:57 +04:00
|
|
|
#define MAX_THREADS 3
|
|
|
|
|
2007-11-24 01:57:49 +03:00
|
|
|
// http://curl.rtin.bz/libcurl/c/libcurl-errors.html
|
|
|
|
QString subDownloadThread::errorCodeToString(CURLcode status) {
|
2007-09-29 12:00:14 +04:00
|
|
|
switch(status){
|
2007-11-24 02:06:38 +03:00
|
|
|
case CURLE_FTP_CANT_GET_HOST:
|
2007-11-24 01:57:49 +03:00
|
|
|
case CURLE_COULDNT_RESOLVE_HOST:
|
2007-09-29 12:00:14 +04:00
|
|
|
return tr("Host is unreachable");
|
2007-11-24 01:57:49 +03:00
|
|
|
case CURLE_READ_ERROR:
|
|
|
|
case CURLE_FILE_COULDNT_READ_FILE:
|
2007-09-29 12:00:14 +04:00
|
|
|
return tr("File was not found (404)");
|
2007-11-24 02:06:38 +03:00
|
|
|
case CURLE_FTP_ACCESS_DENIED:
|
2007-11-24 01:57:49 +03:00
|
|
|
case CURLE_LOGIN_DENIED:
|
2007-11-24 02:06:38 +03:00
|
|
|
case CURLE_FTP_USER_PASSWORD_INCORRECT:
|
2007-09-29 12:00:14 +04:00
|
|
|
return tr("Connection was denied");
|
2007-11-24 01:57:49 +03:00
|
|
|
case CURLE_URL_MALFORMAT:
|
2007-09-29 12:00:14 +04:00
|
|
|
return tr("Url is invalid");
|
2007-11-24 01:57:49 +03:00
|
|
|
case CURLE_COULDNT_RESOLVE_PROXY:
|
|
|
|
return tr("Could not resolve proxy");
|
|
|
|
//case 5:
|
|
|
|
// return tr("Connection forbidden (403)");
|
|
|
|
//case 6:
|
|
|
|
// return tr("Connection was not authorized (401)");
|
|
|
|
//case 7:
|
|
|
|
// return tr("Content has moved (301)");
|
|
|
|
case CURLE_COULDNT_CONNECT:
|
2007-09-29 12:00:14 +04:00
|
|
|
return tr("Connection failure");
|
2007-11-24 01:57:49 +03:00
|
|
|
case CURLE_OPERATION_TIMEOUTED:
|
2007-09-29 12:00:14 +04:00
|
|
|
return tr("Connection was timed out");
|
2007-11-24 01:57:49 +03:00
|
|
|
case CURLE_INTERFACE_FAILED:
|
2007-09-29 12:00:14 +04:00
|
|
|
return tr("Incorrect network interface");
|
|
|
|
default:
|
|
|
|
return tr("Unknown error");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-24 01:57:49 +03:00
|
|
|
subDownloadThread::subDownloadThread(QObject *parent, QString url) : QThread(parent), url(url), abort(false){}
|
2007-09-29 12:00:14 +04:00
|
|
|
|
|
|
|
subDownloadThread::~subDownloadThread(){
|
|
|
|
abort = true;
|
|
|
|
wait();
|
|
|
|
}
|
|
|
|
|
|
|
|
void subDownloadThread::run(){
|
|
|
|
// XXX: Trick to get a unique filename
|
|
|
|
QString filePath;
|
|
|
|
QTemporaryFile *tmpfile = new QTemporaryFile();
|
|
|
|
if (tmpfile->open()) {
|
|
|
|
filePath = tmpfile->fileName();
|
|
|
|
}
|
|
|
|
delete tmpfile;
|
2009-07-12 12:13:00 +04:00
|
|
|
FILE *f = fopen(filePath.toLocal8Bit().data(), "wb");
|
2007-11-24 01:57:49 +03:00
|
|
|
if(!f) {
|
|
|
|
std::cerr << "couldn't open destination file" << "\n";
|
2007-09-29 12:00:14 +04:00
|
|
|
return;
|
|
|
|
}
|
2007-11-24 01:57:49 +03:00
|
|
|
CURL *curl;
|
2008-12-26 19:43:55 +03:00
|
|
|
CURLcode res = (CURLcode)-1;
|
2007-11-24 01:57:49 +03:00
|
|
|
curl = curl_easy_init();
|
|
|
|
if(curl) {
|
2009-07-12 12:13:00 +04:00
|
|
|
std::string c_url = url.toLocal8Bit().data();
|
2007-11-24 01:57:49 +03:00
|
|
|
curl_easy_setopt(curl, CURLOPT_URL, c_url.c_str());
|
2007-11-24 02:06:38 +03:00
|
|
|
// SSL support
|
|
|
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
|
|
|
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
|
2007-11-24 01:57:49 +03:00
|
|
|
// PROXY SUPPORT
|
|
|
|
QSettings settings("qBittorrent", "qBittorrent");
|
2008-09-27 13:12:41 +04:00
|
|
|
int intValue = settings.value(QString::fromUtf8("Preferences/Connection/HTTPProxyType"), 0).toInt();
|
2007-11-24 01:57:49 +03:00
|
|
|
if(intValue > 0) {
|
|
|
|
// Proxy enabled
|
2008-09-27 13:12:41 +04:00
|
|
|
QString IP = settings.value(QString::fromUtf8("Preferences/Connection/HTTPProxy/IP"), "0.0.0.0").toString();
|
|
|
|
QString port = settings.value(QString::fromUtf8("Preferences/Connection/HTTPProxy/Port"), 8080).toString();
|
2009-07-12 12:13:00 +04:00
|
|
|
qDebug("Using proxy: %s", (IP+QString(":")+port).toLocal8Bit().data());
|
|
|
|
curl_easy_setopt(curl, CURLOPT_PROXYPORT, (IP+QString(":")+port).toLocal8Bit().data());
|
2007-11-24 01:57:49 +03:00
|
|
|
// Default proxy type is HTTP, we must change if it is SOCKS5
|
|
|
|
if(intValue%2==0) {
|
|
|
|
qDebug("Proxy is SOCKS5, not HTTP");
|
|
|
|
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
|
|
|
|
}
|
|
|
|
// Authentication?
|
|
|
|
if(intValue > 2) {
|
|
|
|
qDebug("Proxy requires authentication, authenticating");
|
2008-09-27 13:12:41 +04:00
|
|
|
QString username = settings.value(QString::fromUtf8("Preferences/Connection/HTTPProxy/Username"), QString()).toString();
|
|
|
|
QString password = settings.value(QString::fromUtf8("Preferences/Connection/HTTPProxy/Password"), QString()).toString();
|
2009-07-12 12:13:00 +04:00
|
|
|
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, (username+QString(":")+password).toLocal8Bit().data());
|
2007-11-24 01:57:49 +03:00
|
|
|
}
|
|
|
|
}
|
2007-11-30 19:05:20 +03:00
|
|
|
// We have to define CURLOPT_WRITEFUNCTION or it will crash on windows
|
|
|
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
|
2007-11-24 01:57:49 +03:00
|
|
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, f);
|
2007-12-11 23:20:43 +03:00
|
|
|
// Verbose
|
2007-12-13 01:20:36 +03:00
|
|
|
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
|
2007-12-11 23:20:43 +03:00
|
|
|
// No progress info (we don't use it)
|
|
|
|
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
|
|
|
|
// Redirections
|
|
|
|
curl_easy_setopt(curl, CURLOPT_AUTOREFERER, 1);
|
|
|
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
|
|
|
|
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, -1);
|
2009-07-12 12:13:00 +04:00
|
|
|
qDebug("Downloading %s", url.toLocal8Bit().data());
|
2008-12-26 19:43:55 +03:00
|
|
|
if(!abort)
|
|
|
|
res = curl_easy_perform(curl);
|
2007-11-24 01:57:49 +03:00
|
|
|
/* always cleanup */
|
|
|
|
curl_easy_cleanup(curl);
|
|
|
|
fclose(f);
|
2008-12-26 19:43:55 +03:00
|
|
|
if(abort)
|
|
|
|
return;
|
2007-11-24 01:57:49 +03:00
|
|
|
if(res) {
|
|
|
|
emit downloadFailureST(this, url, errorCodeToString(res));
|
|
|
|
} else {
|
|
|
|
emit downloadFinishedST(this, url, filePath);
|
2007-09-29 12:00:14 +04:00
|
|
|
}
|
2007-11-24 01:57:49 +03:00
|
|
|
} else {
|
|
|
|
std::cerr << "Could not initialize CURL" << "\n";
|
2007-09-29 12:00:14 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Download Thread **/
|
|
|
|
|
|
|
|
downloadThread::downloadThread(QObject* parent) : QThread(parent), abort(false){}
|
|
|
|
|
|
|
|
downloadThread::~downloadThread(){
|
|
|
|
mutex.lock();
|
|
|
|
abort = true;
|
|
|
|
condition.wakeOne();
|
|
|
|
mutex.unlock();
|
2009-08-23 12:10:56 +04:00
|
|
|
qDebug("downloadThread deleting subthreads...");
|
2007-09-29 12:00:14 +04:00
|
|
|
qDeleteAll(subThreads);
|
2009-08-23 12:10:56 +04:00
|
|
|
qDebug("downloadThread deleted subthreads");
|
2007-09-29 12:00:14 +04:00
|
|
|
wait();
|
|
|
|
}
|
|
|
|
|
|
|
|
void downloadThread::downloadUrl(QString url){
|
|
|
|
QMutexLocker locker(&mutex);
|
2008-07-27 20:23:00 +04:00
|
|
|
urls_queue.enqueue(url);
|
2007-09-29 12:00:14 +04:00
|
|
|
if(!isRunning()){
|
|
|
|
start();
|
|
|
|
}else{
|
|
|
|
condition.wakeOne();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void downloadThread::run(){
|
|
|
|
forever{
|
2009-08-23 12:10:56 +04:00
|
|
|
if(abort) {
|
|
|
|
qDebug("DownloadThread aborting...");
|
2007-09-29 12:00:14 +04:00
|
|
|
return;
|
2009-08-23 12:10:56 +04:00
|
|
|
}
|
2007-09-29 12:00:14 +04:00
|
|
|
mutex.lock();
|
2008-07-27 20:23:00 +04:00
|
|
|
if(!urls_queue.empty() && subThreads.size() < MAX_THREADS){
|
|
|
|
QString url = urls_queue.dequeue();
|
2007-09-29 12:00:14 +04:00
|
|
|
mutex.unlock();
|
2009-08-23 12:10:56 +04:00
|
|
|
qDebug("DownloadThread downloading %s...", url.toLocal8Bit().data());
|
2007-09-29 12:00:14 +04:00
|
|
|
subDownloadThread *st = new subDownloadThread(0, url);
|
|
|
|
subThreads << st;
|
|
|
|
connect(st, SIGNAL(downloadFinishedST(subDownloadThread*, QString, QString)), this, SLOT(propagateDownloadedFile(subDownloadThread*, QString, QString)));
|
|
|
|
connect(st, SIGNAL(downloadFailureST(subDownloadThread*, QString, QString)), this, SLOT(propagateDownloadFailure(subDownloadThread*, QString, QString)));
|
|
|
|
st->start();
|
|
|
|
}else{
|
2009-08-23 12:10:56 +04:00
|
|
|
qDebug("DownloadThread sleeping...");
|
2007-09-29 12:00:14 +04:00
|
|
|
condition.wait(&mutex);
|
2009-08-23 12:10:56 +04:00
|
|
|
qDebug("DownloadThread woke up");
|
2007-09-29 12:00:14 +04:00
|
|
|
mutex.unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void downloadThread::propagateDownloadedFile(subDownloadThread* st, QString url, QString path){
|
2009-08-23 12:10:56 +04:00
|
|
|
qDebug("Downloading %s was successful", url.toLocal8Bit().data());
|
2009-08-22 18:06:05 +04:00
|
|
|
mutex.lock();
|
2007-09-29 12:00:14 +04:00
|
|
|
int index = subThreads.indexOf(st);
|
|
|
|
Q_ASSERT(index != -1);
|
|
|
|
subThreads.removeAt(index);
|
2009-08-22 18:06:05 +04:00
|
|
|
mutex.unlock();
|
2007-09-29 12:00:14 +04:00
|
|
|
delete st;
|
|
|
|
emit downloadFinished(url, path);
|
|
|
|
mutex.lock();
|
2008-07-27 20:23:00 +04:00
|
|
|
if(!urls_queue.empty()) {
|
2008-07-27 20:13:57 +04:00
|
|
|
condition.wakeOne();
|
|
|
|
}
|
2007-09-29 12:00:14 +04:00
|
|
|
mutex.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void downloadThread::propagateDownloadFailure(subDownloadThread* st, QString url, QString reason){
|
2009-08-23 12:10:56 +04:00
|
|
|
qDebug("Downloading %s failed", url.toLocal8Bit().data());
|
2009-08-22 18:06:05 +04:00
|
|
|
mutex.lock();
|
2007-09-29 12:00:14 +04:00
|
|
|
int index = subThreads.indexOf(st);
|
|
|
|
Q_ASSERT(index != -1);
|
|
|
|
subThreads.removeAt(index);
|
2009-08-22 18:06:05 +04:00
|
|
|
mutex.unlock();
|
2007-09-29 12:00:14 +04:00
|
|
|
delete st;
|
|
|
|
emit downloadFailure(url, reason);
|
|
|
|
mutex.lock();
|
2008-07-27 20:23:00 +04:00
|
|
|
if(!urls_queue.empty()) {
|
2008-07-27 20:13:57 +04:00
|
|
|
condition.wakeOne();
|
|
|
|
}
|
2007-09-29 12:00:14 +04:00
|
|
|
mutex.unlock();
|
|
|
|
}
|