1359 lines
42 KiB
C++
1359 lines
42 KiB
C++
/*
|
|
* Copyright 2006 Alon Zakai ('Kripken') <kripkensteiner@gmail.com>
|
|
*
|
|
* 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* In addition, as a special exception, the copyright holders give
|
|
* permission to link the code of portions of this program with the OpenSSL
|
|
* library.
|
|
* 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) with this
|
|
* exception, 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. If you delete this exception
|
|
* statement from all source files in the program, then also delete it here.
|
|
*
|
|
* Thank You: Some code portions were derived from BSD-licensed work by
|
|
* Arvid Norberg, and GPL-licensed work by Christophe Dumez
|
|
*/
|
|
|
|
//------------------
|
|
// TODO:
|
|
//
|
|
// The DHT capability requires UDP. We need to check that this port is in fact
|
|
// open, just like the normal TCP port for bittorrent.
|
|
//
|
|
//-----------------
|
|
#include <Python.h>
|
|
|
|
#include <boost/filesystem/exception.hpp>
|
|
#include <boost/filesystem/operations.hpp>
|
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
|
|
|
#include "libtorrent/entry.hpp"
|
|
#include "libtorrent/bencode.hpp"
|
|
#include "libtorrent/session.hpp"
|
|
#include "libtorrent/identify_client.hpp"
|
|
#include "libtorrent/alert_types.hpp"
|
|
#include "libtorrent/storage.hpp"
|
|
#include "libtorrent/hasher.hpp"
|
|
#include "libtorrent/ip_filter.hpp"
|
|
#include "libtorrent/upnp.hpp"
|
|
#include "libtorrent/file_pool.hpp"
|
|
#include "libtorrent/natpmp.hpp"
|
|
#include "libtorrent/extensions/metadata_transfer.hpp"
|
|
#include "libtorrent/extensions/ut_pex.hpp"
|
|
|
|
using namespace boost::filesystem;
|
|
using namespace libtorrent;
|
|
|
|
//----------------
|
|
// CONSTANTS
|
|
//----------------
|
|
|
|
#ifdef AMD64
|
|
#define python_long int
|
|
#else
|
|
#define python_long long
|
|
#endif
|
|
|
|
#define EVENT_NULL 0
|
|
#define EVENT_FINISHED 1
|
|
#define EVENT_PEER_ERROR 2
|
|
#define EVENT_INVALID_REQUEST 3
|
|
#define EVENT_FILE_ERROR 4
|
|
#define EVENT_HASH_FAILED_ERROR 5
|
|
#define EVENT_PEER_BAN_ERROR 6
|
|
#define EVENT_FASTRESUME_REJECTED_ERROR 8
|
|
#define EVENT_TRACKER 9
|
|
#define EVENT_OTHER 10
|
|
|
|
#define STATE_QUEUED 0
|
|
#define STATE_CHECKING 1
|
|
#define STATE_CONNECTING 2
|
|
#define STATE_DOWNLOADING_META 3
|
|
#define STATE_DOWNLOADING 4
|
|
#define STATE_FINISHED 5
|
|
#define STATE_SEEDING 6
|
|
#define STATE_ALLOCATING 7
|
|
|
|
#define DHT_ROUTER_PORT 6881
|
|
|
|
//-----------------
|
|
// TYPES
|
|
//-----------------
|
|
|
|
typedef long unique_ID_t;
|
|
typedef std::vector<bool> filter_out_t;
|
|
typedef std::string torrent_name_t;
|
|
|
|
struct torrent_t
|
|
{
|
|
torrent_handle handle;
|
|
unique_ID_t unique_ID;
|
|
};
|
|
|
|
typedef std::vector<torrent_t> torrents_t;
|
|
typedef torrents_t::iterator torrents_t_iterator;
|
|
|
|
//---------------------------
|
|
// MODULE-GLOBAL VARIABLES
|
|
//---------------------------
|
|
|
|
long M_unique_counter = 0;
|
|
session_settings *M_settings = NULL;
|
|
pe_settings *M_pe_settings = NULL;
|
|
session *M_ses = NULL;
|
|
PyObject *M_constants = NULL;
|
|
ip_filter *M_the_filter = NULL;
|
|
torrents_t *M_torrents = NULL;
|
|
|
|
//------------------------
|
|
// Exception types & macro
|
|
//------------------------
|
|
|
|
static PyObject *DelugeError = NULL;
|
|
static PyObject *InvalidEncodingError = NULL;
|
|
static PyObject *FilesystemError = NULL;
|
|
static PyObject *DuplicateTorrentError = NULL;
|
|
static PyObject *InvalidTorrentError = NULL;
|
|
|
|
#define RAISE_PTR(e,s) { printf("Raising error: %s\r\n", s); PyErr_SetString(e, s); return NULL; }
|
|
#define RAISE_INT(e,s) { printf("Raising error: %s\r\n", s); PyErr_SetString(e, s); return -1; }
|
|
|
|
//---------------------
|
|
// Internal functions
|
|
//---------------------
|
|
|
|
bool empty_name_check(const std::string & name)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
|
|
long handle_exists(torrent_handle &handle)
|
|
{
|
|
for (unsigned long i = 0; i < M_torrents->size(); i++)
|
|
if ((*M_torrents)[i].handle == handle)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
long get_torrent_index(torrent_handle &handle)
|
|
{
|
|
for (unsigned long i = 0; i < M_torrents->size(); i++)
|
|
if ((*M_torrents)[i].handle == handle)
|
|
{
|
|
// printf("Found: %li\r\n", i);
|
|
return i;
|
|
}
|
|
|
|
RAISE_INT(DelugeError, "Handle not found.");
|
|
}
|
|
|
|
|
|
long get_index_from_unique_ID(long unique_ID)
|
|
{
|
|
assert(M_handles->size() == M_unique_IDs->size());
|
|
|
|
for (unsigned long i = 0; i < M_torrents->size(); i++)
|
|
if ((*M_torrents)[i].unique_ID == unique_ID)
|
|
return i;
|
|
|
|
RAISE_INT(DelugeError, "No such unique_ID.");
|
|
}
|
|
|
|
|
|
long internal_add_torrent(std::string const& torrent_name,
|
|
float preferred_ratio,
|
|
bool compact_mode,
|
|
boost::filesystem::path const& save_path)
|
|
{
|
|
|
|
std::ifstream in(torrent_name.c_str(), std::ios_base::binary);
|
|
in.unsetf(std::ios_base::skipws);
|
|
entry e;
|
|
e = bdecode(std::istream_iterator<char>(in), std::istream_iterator<char>());
|
|
|
|
torrent_info t(e);
|
|
|
|
entry resume_data;
|
|
try
|
|
{
|
|
std::stringstream s;
|
|
s << torrent_name << ".fastresume";
|
|
boost::filesystem::ifstream resumeFile(s.str(), std::ios_base::binary);
|
|
resumeFile.unsetf(std::ios_base::skipws);
|
|
resume_data = bdecode(std::istream_iterator<char>(resumeFile),
|
|
std::istream_iterator<char>());
|
|
}
|
|
catch (invalid_encoding&)
|
|
{
|
|
}
|
|
catch (boost::filesystem::filesystem_error&) {}
|
|
|
|
// Create new torrent object
|
|
|
|
torrent_t new_torrent;
|
|
|
|
torrent_handle h = M_ses->add_torrent(t, save_path, resume_data, compact_mode, 16 * 1024);
|
|
|
|
// h.set_max_connections(60); // at some point we should use this
|
|
h.set_max_uploads(-1);
|
|
h.set_ratio(preferred_ratio);
|
|
new_torrent.handle = h;
|
|
|
|
new_torrent.unique_ID = M_unique_counter;
|
|
M_unique_counter++;
|
|
|
|
M_torrents->push_back(new_torrent);
|
|
|
|
return (new_torrent.unique_ID);
|
|
}
|
|
|
|
|
|
void internal_remove_torrent(long index)
|
|
{
|
|
assert(index < M_torrents->size());
|
|
|
|
torrent_handle& h = M_torrents->at(index).handle;
|
|
|
|
M_ses->remove_torrent(h);
|
|
|
|
torrents_t_iterator it = M_torrents->begin() + index;
|
|
M_torrents->erase(it);
|
|
}
|
|
|
|
|
|
long get_peer_index(tcp::endpoint addr, std::vector<peer_info> const& peers)
|
|
{
|
|
long index = -1;
|
|
|
|
for (unsigned long i = 0; i < peers.size(); i++)
|
|
if (peers[i].ip == addr)
|
|
index = i;
|
|
|
|
return index;
|
|
}
|
|
|
|
|
|
// The following function contains code by Christophe Dumez and Arvid Norberg
|
|
void internal_add_files(torrent_info& t,
|
|
boost::filesystem::path const& p,
|
|
boost::filesystem::path const& l)
|
|
{
|
|
// change default checker, perhaps?
|
|
boost::filesystem::path f(p / l);
|
|
if (is_directory(f))
|
|
{
|
|
for (boost::filesystem::directory_iterator i(f), end; i != end; ++i)
|
|
internal_add_files(t, p, l / i->leaf());
|
|
} else
|
|
t.add_file(l, file_size(f));
|
|
}
|
|
|
|
|
|
long count_DHT_peers(entry &state)
|
|
{
|
|
long num_peers = 0;
|
|
entry *nodes = state.find_key("nodes");
|
|
if (nodes)
|
|
{
|
|
entry::list_type &peers = nodes->list();
|
|
entry::list_type::const_iterator i;
|
|
i = peers.begin();
|
|
|
|
while (i != peers.end())
|
|
{
|
|
num_peers++;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
return num_peers;
|
|
}
|
|
|
|
|
|
//=====================
|
|
// External functions
|
|
//=====================
|
|
|
|
static PyObject *torrent_pre_init(PyObject *self, PyObject *args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, "OOOOO", &DelugeError,
|
|
&InvalidEncodingError,
|
|
&FilesystemError,
|
|
&DuplicateTorrentError,
|
|
&InvalidTorrentError))
|
|
return NULL;
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
|
|
static PyObject *torrent_init(PyObject *self, PyObject *args)
|
|
{
|
|
printf("deluge_core; using libtorrent %s. Compiled with NDEBUG value: %d\r\n",
|
|
LIBTORRENT_VERSION,
|
|
NDEBUG);
|
|
|
|
// Tell Boost that we are on *NIX, so bloody '.'s are ok inside a directory name!
|
|
boost::filesystem::path::default_name_check(empty_name_check);
|
|
|
|
char *client_ID, *user_agent;
|
|
python_long v1,v2,v3,v4;
|
|
|
|
if (!PyArg_ParseTuple(args, "siiiis", &client_ID, &v1, &v2, &v3, &v4, &user_agent))
|
|
return NULL;
|
|
|
|
M_settings = new session_settings;
|
|
M_ses = new session(fingerprint(client_ID, v1, v2, v3, v4));
|
|
|
|
M_torrents = new torrents_t;
|
|
M_torrents->reserve(10); // pretty cheap, just 10
|
|
|
|
// Init values
|
|
|
|
M_settings->user_agent = std::string(user_agent);
|
|
|
|
M_ses->set_max_half_open_connections(-1);
|
|
M_ses->set_download_rate_limit(-1);
|
|
M_ses->set_upload_rate_limit(-1);
|
|
|
|
M_ses->set_settings(*M_settings);
|
|
M_ses->set_severity_level(alert::debug);
|
|
|
|
M_ses->add_extension(&libtorrent::create_metadata_plugin);
|
|
|
|
M_constants = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i}",
|
|
"EVENT_NULL", EVENT_NULL,
|
|
"EVENT_FINISHED", EVENT_FINISHED,
|
|
"EVENT_PEER_ERROR", EVENT_PEER_ERROR,
|
|
"EVENT_INVALID_REQUEST", EVENT_INVALID_REQUEST,
|
|
"EVENT_FILE_ERROR", EVENT_FILE_ERROR,
|
|
"EVENT_HASH_FAILED_ERROR", EVENT_HASH_FAILED_ERROR,
|
|
"EVENT_PEER_BAN_ERROR", EVENT_PEER_BAN_ERROR,
|
|
"EVENT_FASTRESUME_REJECTED_ERROR", EVENT_FASTRESUME_REJECTED_ERROR,
|
|
"EVENT_TRACKER", EVENT_TRACKER,
|
|
"EVENT_OTHER", EVENT_OTHER,
|
|
"STATE_QUEUED", STATE_QUEUED,
|
|
"STATE_CHECKING", STATE_CHECKING,
|
|
"STATE_CONNECTING", STATE_CONNECTING,
|
|
"STATE_DOWNLOADING_META", STATE_DOWNLOADING_META,
|
|
"STATE_DOWNLOADING", STATE_DOWNLOADING,
|
|
"STATE_FINISHED", STATE_FINISHED,
|
|
"STATE_SEEDING", STATE_SEEDING,
|
|
"STATE_ALLOCATING", STATE_ALLOCATING);
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
};
|
|
|
|
static PyObject *torrent_quit(PyObject *self, PyObject *args)
|
|
{
|
|
M_settings->stop_tracker_timeout = 5;
|
|
M_ses->set_settings(*M_settings);
|
|
printf("core: removing torrents...\r\n");
|
|
delete M_torrents;
|
|
printf("core: removing settings...\r\n");
|
|
delete M_settings;
|
|
printf("core: shutting down session...\r\n");
|
|
delete M_ses; // 100% CPU...
|
|
Py_DECREF(M_constants);
|
|
|
|
printf("core shut down.\r\n");
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
};
|
|
|
|
static PyObject *torrent_save_fastresume(PyObject *self, PyObject *args)
|
|
{
|
|
python_long unique_ID;
|
|
const char *torrent_name;
|
|
if (!PyArg_ParseTuple(args, "is", &unique_ID, &torrent_name))
|
|
return NULL;
|
|
|
|
long index = get_index_from_unique_ID(unique_ID);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
torrent_handle& h = M_torrents->at(index).handle;
|
|
// For valid torrents, save fastresume data
|
|
if (h.is_valid() && h.has_metadata())
|
|
{
|
|
h.pause();
|
|
|
|
entry data = h.write_resume_data();
|
|
|
|
std::stringstream s;
|
|
s << torrent_name << ".fastresume";
|
|
|
|
boost::filesystem::ofstream out(s.str(), std::ios_base::binary);
|
|
|
|
out.unsetf(std::ios_base::skipws);
|
|
|
|
bencode(std::ostream_iterator<char>(out), data);
|
|
|
|
h.resume();
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
} else
|
|
RAISE_PTR(DelugeError, "Invalid handle or no metadata for fastresume.");
|
|
}
|
|
|
|
|
|
static PyObject *torrent_set_max_half_open(PyObject *self, PyObject *args)
|
|
{
|
|
python_long arg;
|
|
if (!PyArg_ParseTuple(args, "i", &arg))
|
|
return NULL;
|
|
|
|
M_ses->set_max_half_open_connections(arg);
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
|
|
static PyObject *torrent_set_download_rate_limit(PyObject *self, PyObject *args)
|
|
{
|
|
python_long arg;
|
|
if (!PyArg_ParseTuple(args, "i", &arg))
|
|
return NULL;
|
|
|
|
// printf("Capping download to %d bytes per second\r\n", (int)arg);
|
|
M_ses->set_download_rate_limit(arg);
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
|
|
static PyObject *torrent_set_upload_rate_limit(PyObject *self, PyObject *args)
|
|
{
|
|
python_long arg;
|
|
if (!PyArg_ParseTuple(args, "i", &arg))
|
|
return NULL;
|
|
|
|
// printf("Capping upload to %d bytes per second\r\n", (int)arg);
|
|
M_ses->set_upload_rate_limit(arg);
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
|
|
static PyObject *torrent_set_listen_on(PyObject *self, PyObject *args)
|
|
{
|
|
PyObject *port_vec;
|
|
if (!PyArg_ParseTuple(args, "O", &port_vec))
|
|
return NULL;
|
|
|
|
M_ses->listen_on(std::make_pair( PyInt_AsLong(PyList_GetItem(port_vec, 0)),
|
|
PyInt_AsLong(PyList_GetItem(port_vec, 1))), "");
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
|
|
static PyObject *torrent_is_listening(PyObject *self, PyObject *args)
|
|
{
|
|
long ret = (M_ses->is_listening() != 0);
|
|
|
|
return Py_BuildValue("i", ret);
|
|
}
|
|
|
|
|
|
static PyObject *torrent_listening_port(PyObject *self, PyObject *args)
|
|
{
|
|
return Py_BuildValue("i", (python_long)M_ses->listen_port());
|
|
}
|
|
|
|
|
|
static PyObject *torrent_set_max_uploads(PyObject *self, PyObject *args)
|
|
{
|
|
python_long max_up;
|
|
if (!PyArg_ParseTuple(args, "i", &max_up))
|
|
return NULL;
|
|
|
|
M_ses->set_max_uploads(max_up);
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
|
|
static PyObject *torrent_set_max_connections(PyObject *self, PyObject *args)
|
|
{
|
|
python_long max_conn;
|
|
if (!PyArg_ParseTuple(args, "i", &max_conn))
|
|
return NULL;
|
|
|
|
// printf("Setting max connections: %d\r\n", max_conn);
|
|
M_ses->set_max_connections(max_conn);
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
|
|
static PyObject *torrent_add_torrent(PyObject *self, PyObject *args)
|
|
{
|
|
const char *name, *save_dir;
|
|
python_long compact;
|
|
if (!PyArg_ParseTuple(args, "ssi", &name, &save_dir, &compact))
|
|
return NULL;
|
|
|
|
boost::filesystem::path save_dir_2 (save_dir, empty_name_check);
|
|
|
|
try
|
|
{
|
|
long ret = internal_add_torrent(name, 0, compact, save_dir_2);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
else
|
|
return Py_BuildValue("i", ret);
|
|
}
|
|
catch (invalid_encoding&)
|
|
{ RAISE_PTR(InvalidEncodingError, ""); }
|
|
catch (invalid_torrent_file&)
|
|
{ RAISE_PTR(InvalidTorrentError, ""); }
|
|
catch (boost::filesystem::filesystem_error&)
|
|
{ RAISE_PTR(FilesystemError, ""); }
|
|
catch (duplicate_torrent&)
|
|
{ RAISE_PTR(DuplicateTorrentError, "libtorrent reports this is a duplicate torrent"); }
|
|
}
|
|
|
|
|
|
static PyObject *torrent_remove_torrent(PyObject *self, PyObject *args)
|
|
{
|
|
python_long unique_ID;
|
|
if (!PyArg_ParseTuple(args, "i", &unique_ID))
|
|
return NULL;
|
|
|
|
long index = get_index_from_unique_ID(unique_ID);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
internal_remove_torrent(index);
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
|
|
static PyObject *torrent_get_num_torrents(PyObject *self, PyObject *args)
|
|
{
|
|
return Py_BuildValue("i", M_torrents->size());
|
|
}
|
|
|
|
|
|
static PyObject *torrent_reannounce(PyObject *self, PyObject *args)
|
|
{
|
|
python_long unique_ID;
|
|
if (!PyArg_ParseTuple(args, "i", &unique_ID))
|
|
return NULL;
|
|
|
|
long index = get_index_from_unique_ID(unique_ID);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
M_torrents->at(index).handle.force_reannounce();
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
|
|
static PyObject *torrent_pause(PyObject *self, PyObject *args)
|
|
{
|
|
python_long unique_ID;
|
|
if (!PyArg_ParseTuple(args, "i", &unique_ID))
|
|
return NULL;
|
|
|
|
long index = get_index_from_unique_ID(unique_ID);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
M_torrents->at(index).handle.pause();
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
|
|
static PyObject *torrent_resume(PyObject *self, PyObject *args)
|
|
{
|
|
python_long unique_ID;
|
|
if (!PyArg_ParseTuple(args, "i", &unique_ID))
|
|
return NULL;
|
|
|
|
long index = get_index_from_unique_ID(unique_ID);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
M_torrents->at(index).handle.resume();
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
|
|
static PyObject *torrent_get_torrent_state(PyObject *self, PyObject *args)
|
|
{
|
|
python_long unique_ID;
|
|
if (!PyArg_ParseTuple(args, "i", &unique_ID))
|
|
return NULL;
|
|
|
|
long index = get_index_from_unique_ID(unique_ID);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
torrent_t &t = M_torrents->at(index);
|
|
torrent_status s = t.handle.status();
|
|
const torrent_info &i = t.handle.get_torrent_info();
|
|
|
|
std::vector<peer_info> peers;
|
|
t.handle.get_peer_info(peers);
|
|
|
|
long connected_seeds = 0;
|
|
long connected_peers = 0;
|
|
long total_seeds = 0;
|
|
long total_peers = 0;
|
|
|
|
for (unsigned long i = 0; i < peers.size(); i++) {
|
|
|
|
connected_peers = s.num_peers - s.num_seeds;
|
|
|
|
connected_seeds = s.num_seeds;
|
|
|
|
total_seeds = s.num_complete != -1? s.num_complete : connected_seeds;
|
|
|
|
total_peers = s.num_incomplete != -1? s.num_incomplete : connected_peers;
|
|
}
|
|
|
|
return Py_BuildValue("{s:s,s:i,s:i,s:l,s:l,s:f,s:f,s:f,s:L,s:L,s:b,s:s,s:s,s:f,s:L,s:L,s:l,s:i,s:i,s:L,s:L,s:i,s:l,s:l,s:b,s:b,s:L,s:L,s:L}",
|
|
"name", t.handle.get_torrent_info().name().c_str(),
|
|
"num_files", t.handle.get_torrent_info().num_files(),
|
|
"state", s.state,
|
|
"num_peers", connected_peers,
|
|
"num_seeds", connected_seeds,
|
|
"distributed_copies", s.distributed_copies,
|
|
"download_rate", s.download_rate,
|
|
"upload_rate", s.upload_rate,
|
|
"total_download", s.total_download,
|
|
"total_upload", s.total_upload,
|
|
"tracker_ok", !s.current_tracker.empty(),
|
|
"next_announce", boost::posix_time::to_simple_string(s.next_announce).c_str(),
|
|
"tracker", s.current_tracker.c_str(),
|
|
"progress", s.progress,
|
|
"total_payload_download", s.total_payload_download,
|
|
"total_payload_upload", s.total_payload_upload,
|
|
"pieces", long(s.pieces), // this is really a std::vector<bool>*
|
|
"pieces_done", s.num_pieces,
|
|
"block_size", s.block_size,
|
|
"total_size", i.total_size(),
|
|
"piece_length", i.piece_length(),
|
|
"num_pieces", i.num_pieces(),
|
|
"total_peers", total_peers,
|
|
"total_seeds", total_seeds,
|
|
"is_paused", t.handle.is_paused(),
|
|
"is_seed", t.handle.is_seed(),
|
|
"total_done", s.total_done,
|
|
"total_wanted", s.total_wanted,
|
|
"total_wanted_done", s.total_wanted_done);
|
|
};
|
|
|
|
static PyObject *torrent_pop_event(PyObject *self, PyObject *args)
|
|
{
|
|
std::auto_ptr<alert> a;
|
|
|
|
a = M_ses->pop_alert();
|
|
|
|
alert *popped_alert = a.get();
|
|
|
|
if (!popped_alert)
|
|
{
|
|
Py_INCREF(Py_None); return Py_None;
|
|
} else if (dynamic_cast<torrent_finished_alert*>(popped_alert))
|
|
{
|
|
torrent_handle handle = (dynamic_cast<torrent_finished_alert*>(popped_alert))->handle;
|
|
|
|
long index = get_torrent_index(handle);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
if (handle_exists(handle))
|
|
return Py_BuildValue("{s:i,s:i}", "event_type", EVENT_FINISHED,
|
|
"unique_ID",
|
|
M_torrents->at(index).unique_ID);
|
|
else
|
|
{ Py_INCREF(Py_None); return Py_None; }
|
|
} else if (dynamic_cast<peer_error_alert*>(popped_alert))
|
|
{
|
|
peer_id peer_ID = (dynamic_cast<peer_error_alert*>(popped_alert))->pid;
|
|
std::string peer_IP =
|
|
(dynamic_cast<peer_error_alert*>(popped_alert))->ip.address().to_string();
|
|
|
|
return Py_BuildValue("{s:i,s:s,s:s,s:s}", "event_type", EVENT_PEER_ERROR,
|
|
"client_ID", identify_client(peer_ID).c_str(),
|
|
"ip", peer_IP.c_str(),
|
|
"message", a->msg().c_str());
|
|
} else if (dynamic_cast<invalid_request_alert*>(popped_alert))
|
|
{
|
|
peer_id peer_ID = (dynamic_cast<invalid_request_alert*>(popped_alert))->pid;
|
|
|
|
return Py_BuildValue("{s:i,s:s,s:s}",
|
|
"event_type", EVENT_INVALID_REQUEST,
|
|
"client_ID", identify_client(peer_ID).c_str(),
|
|
"message", a->msg().c_str());
|
|
} else if (dynamic_cast<file_error_alert*>(popped_alert))
|
|
{
|
|
torrent_handle handle = (dynamic_cast<file_error_alert*>(popped_alert))->handle;
|
|
long index = get_torrent_index(handle);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
if (handle_exists(handle))
|
|
return Py_BuildValue("{s:i,s:i,s:s}",
|
|
"event_type", EVENT_FILE_ERROR,
|
|
"unique_ID", M_torrents->at(index).unique_ID,
|
|
"message", a->msg().c_str());
|
|
else
|
|
{ Py_INCREF(Py_None); return Py_None; }
|
|
} else if (dynamic_cast<hash_failed_alert*>(popped_alert))
|
|
{
|
|
torrent_handle handle = (dynamic_cast<hash_failed_alert*>(popped_alert))->handle;
|
|
long index = get_torrent_index(handle);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
if (handle_exists(handle))
|
|
return Py_BuildValue("{s:i,s:i,s:i,s:s}",
|
|
"event_type", EVENT_HASH_FAILED_ERROR,
|
|
"unique_ID", M_torrents->at(index).unique_ID,
|
|
"piece_index",
|
|
long((dynamic_cast<hash_failed_alert*>(popped_alert))->piece_index),
|
|
"message", a->msg().c_str());
|
|
else
|
|
{ Py_INCREF(Py_None); return Py_None; }
|
|
} else if (dynamic_cast<peer_ban_alert*>(popped_alert))
|
|
{
|
|
torrent_handle handle = (dynamic_cast<peer_ban_alert*>(popped_alert))->handle;
|
|
long index = get_torrent_index(handle);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
std::string peer_IP = (dynamic_cast<peer_ban_alert*>(popped_alert))->ip.address().to_string();
|
|
|
|
if (handle_exists(handle))
|
|
return Py_BuildValue("{s:i,s:i,s:s,s:s}",
|
|
"event_type", EVENT_PEER_BAN_ERROR,
|
|
"unique_ID", M_torrents->at(index).unique_ID,
|
|
"ip", peer_IP.c_str(),
|
|
"message", a->msg().c_str());
|
|
else
|
|
{ Py_INCREF(Py_None); return Py_None; }
|
|
} else if (dynamic_cast<fastresume_rejected_alert*>(popped_alert))
|
|
{
|
|
torrent_handle handle = (dynamic_cast<fastresume_rejected_alert*>(popped_alert))->handle;
|
|
long index = get_torrent_index(handle);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
if (handle_exists(handle))
|
|
return Py_BuildValue("{s:i,s:i,s:s}",
|
|
"event_type", EVENT_FASTRESUME_REJECTED_ERROR,
|
|
"unique_ID", M_torrents->at(index).unique_ID,
|
|
"message", a->msg().c_str());
|
|
else
|
|
{ Py_INCREF(Py_None); return Py_None; }
|
|
} else if (dynamic_cast<tracker_announce_alert*>(popped_alert))
|
|
{
|
|
torrent_handle handle = (dynamic_cast<tracker_announce_alert*>(popped_alert))->handle;
|
|
long index = get_torrent_index(handle);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
if (handle_exists(handle))
|
|
return Py_BuildValue("{s:i,s:i,s:s,s:s}",
|
|
"event_type", EVENT_TRACKER,
|
|
"unique_ID",
|
|
M_torrents->at(index).unique_ID,
|
|
"tracker_status", "Announce sent",
|
|
"message", a->msg().c_str());
|
|
else
|
|
{ Py_INCREF(Py_None); return Py_None; }
|
|
} else if (dynamic_cast<tracker_alert*>(popped_alert))
|
|
{
|
|
torrent_handle handle = (dynamic_cast<tracker_alert*>(popped_alert))->handle;
|
|
long index = get_torrent_index(handle);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
if (handle_exists(handle))
|
|
return Py_BuildValue("{s:i,s:i,s:s,s:s}",
|
|
"event_type", EVENT_TRACKER,
|
|
"unique_ID",
|
|
M_torrents->at(index).unique_ID,
|
|
"tracker_status", "Bad response (status code=?)",
|
|
"message", a->msg().c_str());
|
|
else
|
|
{ Py_INCREF(Py_None); return Py_None; }
|
|
} else if (dynamic_cast<tracker_reply_alert*>(popped_alert))
|
|
{
|
|
torrent_handle handle = (dynamic_cast<tracker_reply_alert*>(popped_alert))->handle;
|
|
long index = get_torrent_index(handle);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
if (handle_exists(handle))
|
|
return Py_BuildValue("{s:i,s:i,s:s,s:s}",
|
|
"event_type", EVENT_TRACKER,
|
|
"unique_ID",
|
|
M_torrents->at(index).unique_ID,
|
|
"tracker_status", "Announce succeeded",
|
|
"message", a->msg().c_str());
|
|
else
|
|
{ Py_INCREF(Py_None); return Py_None; }
|
|
} else if (dynamic_cast<tracker_warning_alert*>(popped_alert))
|
|
{
|
|
torrent_handle handle = (dynamic_cast<tracker_warning_alert*>(popped_alert))->handle;
|
|
long index = get_torrent_index(handle);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
if (handle_exists(handle))
|
|
return Py_BuildValue("{s:i,s:i,s:s,s:s}",
|
|
"event_type", EVENT_TRACKER,
|
|
"unique_ID",
|
|
M_torrents->at(index).unique_ID,
|
|
"tracker_status", "Warning in response",
|
|
"message", a->msg().c_str());
|
|
else
|
|
{ Py_INCREF(Py_None); return Py_None; }
|
|
}
|
|
|
|
return Py_BuildValue("{s:i,s:s}", "event_type", EVENT_OTHER,
|
|
"message", a->msg().c_str() );
|
|
}
|
|
|
|
|
|
static PyObject *torrent_get_session_info(PyObject *self, PyObject *args)
|
|
{
|
|
session_status s = M_ses->status();
|
|
|
|
return Py_BuildValue("{s:l,s:f,s:f,s:f,s:f,s:l}",
|
|
"has_incoming_connections", long(s.has_incoming_connections),
|
|
"upload_rate", float(s.upload_rate),
|
|
"download_rate", float(s.download_rate),
|
|
"payload_upload_rate", float(s.payload_upload_rate),
|
|
"payload_download_rate", float(s.payload_download_rate),
|
|
"num_peers", long(s.num_peers));
|
|
}
|
|
|
|
|
|
static PyObject *torrent_get_peer_info(PyObject *self, PyObject *args)
|
|
{
|
|
python_long unique_ID;
|
|
if (!PyArg_ParseTuple(args, "i", &unique_ID))
|
|
return NULL;
|
|
|
|
long index = get_index_from_unique_ID(unique_ID);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
std::vector<peer_info> peers;
|
|
M_torrents->at(index).handle.get_peer_info(peers);
|
|
|
|
PyObject *peer_info;
|
|
PyObject *ret = PyTuple_New(peers.size());
|
|
PyObject *curr_piece, *py_pieces;
|
|
|
|
for (unsigned long i = 0; i < peers.size(); i++)
|
|
{
|
|
std::vector<bool> &pieces = peers[i].pieces;
|
|
unsigned long pieces_had = 0;
|
|
|
|
py_pieces = PyTuple_New(pieces.size());
|
|
|
|
for (unsigned long piece = 0; piece < pieces.size(); piece++)
|
|
{
|
|
if (pieces[piece])
|
|
pieces_had++;
|
|
|
|
curr_piece = Py_BuildValue("i", long(pieces[piece]));
|
|
PyTuple_SetItem(py_pieces, piece, curr_piece);
|
|
}
|
|
|
|
peer_info = Py_BuildValue(
|
|
"{s:f,s:L,s:f,s:L,s:i,s:i,s:b,s:b,s:b,s:b,s:b,s:b,s:b,s:b,s:b,s:s,s:b,s:s,s:f,s:O,s:b,s:b}",
|
|
"download_speed", peers[i].down_speed,
|
|
"total_download", peers[i].total_download,
|
|
"upload_speed", peers[i].up_speed,
|
|
"total_upload", peers[i].total_upload,
|
|
"download_queue_length", peers[i].download_queue_length,
|
|
"upload_queue_length", peers[i].upload_queue_length,
|
|
"is_interesting", ((peers[i].flags & peer_info::interesting) != 0),
|
|
"is_choked", ((peers[i].flags & peer_info::choked) != 0),
|
|
"is_remote_interested", ((peers[i].flags & peer_info::remote_interested) != 0),
|
|
"is_remote_choked", ((peers[i].flags & peer_info::remote_choked) != 0),
|
|
"supports_extensions", ((peers[i].flags & peer_info::supports_extensions) != 0),
|
|
"is_local_connection", ((peers[i].flags & peer_info::local_connection) != 0),
|
|
"is_awaiting_handshake", ((peers[i].flags & peer_info::handshake) != 0),
|
|
"is_connecting", ((peers[i].flags & peer_info::connecting) != 0),
|
|
"is_queued", ((peers[i].flags & peer_info::queued) != 0),
|
|
"client", peers[i].client.c_str(),
|
|
"is_seed", ((peers[i].flags & peer_info::seed) != 0),
|
|
"ip", peers[i].ip.address().to_string().c_str(),
|
|
"peer_has", float(float(pieces_had)*100.0/pieces.size()),
|
|
"pieces", py_pieces,
|
|
"rc4_encrypted", ((peers[i].flags & peer_info::rc4_encrypted) != 0),
|
|
"plaintext_encrypted", ((peers[i].flags & peer_info::plaintext_encrypted) != 0)
|
|
);
|
|
|
|
Py_DECREF(py_pieces); // Assuming the previous line does NOT steal the ref, then this is
|
|
// needed!
|
|
|
|
PyTuple_SetItem(ret, i, peer_info);
|
|
};
|
|
|
|
return ret;
|
|
};
|
|
|
|
static PyObject *torrent_get_file_info(PyObject *self, PyObject *args)
|
|
{
|
|
python_long unique_ID;
|
|
if (!PyArg_ParseTuple(args, "i", &unique_ID))
|
|
return NULL;
|
|
|
|
long index = get_index_from_unique_ID(unique_ID);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
std::vector<PyObject *> temp_files;
|
|
|
|
PyObject *file_info;
|
|
|
|
std::vector<float> progresses;
|
|
|
|
torrent_t &t = M_torrents->at(index);
|
|
t.handle.file_progress(progresses);
|
|
|
|
torrent_info::file_iterator start =
|
|
t.handle.get_torrent_info().begin_files();
|
|
torrent_info::file_iterator end =
|
|
t.handle.get_torrent_info().end_files();
|
|
|
|
long fileIndex = 0;
|
|
|
|
for(torrent_info::file_iterator i = start; i != end; ++i)
|
|
{
|
|
file_entry const &currFile = (*i);
|
|
|
|
file_info = Py_BuildValue(
|
|
"{s:s,s:d,s:d,s:f}",
|
|
"path", currFile.path.string().c_str(),
|
|
"offset", double(currFile.offset),
|
|
"size", double(currFile.size),
|
|
"progress", progresses[i - start]*100.0
|
|
);
|
|
|
|
fileIndex++;
|
|
|
|
temp_files.push_back(file_info);
|
|
};
|
|
|
|
PyObject *ret = PyTuple_New(temp_files.size());
|
|
|
|
for (unsigned long i = 0; i < temp_files.size(); i++)
|
|
PyTuple_SetItem(ret, i, temp_files[i]);
|
|
|
|
return ret;
|
|
};
|
|
|
|
static PyObject *torrent_set_filter_out(PyObject *self, PyObject *args)
|
|
{
|
|
python_long unique_ID;
|
|
PyObject *filter_out_object;
|
|
if (!PyArg_ParseTuple(args, "iO", &unique_ID, &filter_out_object))
|
|
return NULL;
|
|
|
|
long index = get_index_from_unique_ID(unique_ID);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
torrent_t &t = M_torrents->at(index);
|
|
long num_files = t.handle.get_torrent_info().num_files();
|
|
assert(PyList_Size(filter_out_object) == num_files);
|
|
|
|
filter_out_t filter_out(num_files);
|
|
|
|
for (long i = 0; i < num_files; i++)
|
|
{
|
|
filter_out.at(i) =
|
|
PyInt_AsLong(PyList_GetItem(filter_out_object, i));
|
|
};
|
|
|
|
t.handle.filter_files(filter_out);
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
|
|
/*static PyObject *torrent_get_unique_IDs(PyObject *self, PyObject *args)
|
|
{
|
|
PyObject *ret = PyTuple_New(M_torrents.size());
|
|
PyObject *temp;
|
|
|
|
for (unsigned long i = 0; i < M_torrents.size(); i++)
|
|
{
|
|
temp = Py_BuildValue("i", M_torrents->at(i).unique_ID)
|
|
|
|
PyTuple_SetItem(ret, i, temp);
|
|
};
|
|
|
|
return ret;
|
|
};*/
|
|
|
|
static PyObject *torrent_constants(PyObject *self, PyObject *args)
|
|
{
|
|
Py_INCREF(M_constants); return M_constants;
|
|
}
|
|
|
|
|
|
static PyObject *torrent_start_DHT(PyObject *self, PyObject *args)
|
|
{
|
|
const char *DHT_path;
|
|
if (!PyArg_ParseTuple(args, "s", &DHT_path))
|
|
return NULL;
|
|
|
|
// printf("Loading DHT state from %s\r\n", DHT_path);
|
|
|
|
boost::filesystem::path tempPath(DHT_path, empty_name_check);
|
|
boost::filesystem::ifstream DHT_state_file(tempPath, std::ios_base::binary);
|
|
DHT_state_file.unsetf(std::ios_base::skipws);
|
|
|
|
entry DHT_state;
|
|
try
|
|
{
|
|
DHT_state = bdecode(std::istream_iterator<char>(DHT_state_file),
|
|
std::istream_iterator<char>());
|
|
M_ses->start_dht(DHT_state);
|
|
// printf("DHT state recovered.\r\n");
|
|
|
|
// // Print out the state data from the FILE (not the session!)
|
|
// printf("Number of DHT peers in recovered state: %ld\r\n", count_DHT_peers(DHT_state));
|
|
|
|
}
|
|
catch (std::exception&)
|
|
{
|
|
printf("No DHT file to resume\r\n");
|
|
M_ses->start_dht();
|
|
}
|
|
|
|
M_ses->add_dht_router(std::make_pair(std::string("router.bittorrent.com"),
|
|
DHT_ROUTER_PORT));
|
|
M_ses->add_dht_router(std::make_pair(std::string("router.utorrent.com"),
|
|
DHT_ROUTER_PORT));
|
|
M_ses->add_dht_router(std::make_pair(std::string("router.bitcomet.com"),
|
|
DHT_ROUTER_PORT));
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
|
|
static PyObject *torrent_stop_DHT(PyObject *self, PyObject *args)
|
|
{
|
|
const char *DHT_path;
|
|
if (!PyArg_ParseTuple(args, "s", &DHT_path))
|
|
return NULL;
|
|
|
|
// printf("Saving DHT state to %s\r\n", DHT_path);
|
|
|
|
boost::filesystem::path tempPath = boost::filesystem::path(DHT_path, empty_name_check);
|
|
|
|
try
|
|
{
|
|
entry DHT_state = M_ses->dht_state();
|
|
|
|
// printf("Number of DHT peers in state, saving: %ld\r\n", count_DHT_peers(DHT_state));
|
|
|
|
boost::filesystem::ofstream out(tempPath, std::ios_base::binary);
|
|
out.unsetf(std::ios_base::skipws);
|
|
bencode(std::ostream_iterator<char>(out), DHT_state);
|
|
}
|
|
catch (std::exception& e)
|
|
{
|
|
printf("An error occured in saving DHT\r\n");
|
|
std::cerr << e.what() << "\n";
|
|
}
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
|
|
static PyObject *torrent_get_DHT_info(PyObject *self, PyObject *args)
|
|
{
|
|
entry DHT_state = M_ses->dht_state();
|
|
|
|
return Py_BuildValue("l", python_long(count_DHT_peers(DHT_state)));
|
|
|
|
/*
|
|
// DHT_state.print(cout);
|
|
entry *nodes = DHT_state.find_key("nodes");
|
|
if (!nodes)
|
|
return Py_BuildValue("l", -1); // No nodes - we are just starting up...
|
|
|
|
entry::list_type &peers = nodes->list();
|
|
entry::list_type::const_iterator i;
|
|
|
|
python_long num_peers = 0;
|
|
|
|
i = peers.begin();
|
|
while (i != peers.end())
|
|
{
|
|
num_peers++;
|
|
i++;
|
|
}
|
|
|
|
return Py_BuildValue("l", num_peers);
|
|
*/
|
|
}
|
|
|
|
|
|
// Create Torrents: call with something like:
|
|
// create_torrent("mytorrent.torrent", "directory or file to make a torrent out of",
|
|
// "tracker1\ntracker2\ntracker3", "no comment", 256, "Deluge");
|
|
// That makes a torrent with pieces of 256K, with "Deluge" as the creator string.
|
|
//
|
|
// The following function contains code by Christophe Dumez and Arvid Norberg
|
|
static PyObject *torrent_create_torrent(PyObject *self, PyObject *args)
|
|
{
|
|
using namespace libtorrent;
|
|
using namespace boost::filesystem;
|
|
|
|
path::default_name_check(no_check);
|
|
|
|
char *destination, *comment, *creator_str, *input, *trackers;
|
|
python_long piece_size;
|
|
if (!PyArg_ParseTuple(args, "ssssis",
|
|
&destination, &input, &trackers, &comment, &piece_size, &creator_str))
|
|
return NULL;
|
|
|
|
piece_size = piece_size * 1024;
|
|
|
|
try
|
|
{
|
|
torrent_info t;
|
|
boost::filesystem::path full_path = complete(boost::filesystem::path(input));
|
|
boost::filesystem::ofstream out(complete(boost::filesystem::path(destination)), std::ios_base::binary);
|
|
|
|
internal_add_files(t, full_path.branch_path(), full_path.leaf());
|
|
t.set_piece_size(piece_size);
|
|
|
|
file_pool fp;
|
|
boost::scoped_ptr<storage_interface> st(
|
|
default_storage_constructor(t, full_path.branch_path(), fp));
|
|
|
|
std::string stdTrackers(trackers);
|
|
unsigned long index = 0, next = stdTrackers.find("\n");
|
|
while (1 == 1)
|
|
{
|
|
t.add_tracker(stdTrackers.substr(index, next-index));
|
|
index = next + 1;
|
|
if (next >= stdTrackers.length())
|
|
break;
|
|
next = stdTrackers.find("\n", index);
|
|
if (next == std::string::npos)
|
|
break;
|
|
}
|
|
|
|
int num = t.num_pieces();
|
|
std::vector<char> buf(piece_size);
|
|
for (int i = 0; i < num; ++i)
|
|
{
|
|
st->read(&buf[0], i, 0, t.piece_size(i));
|
|
hasher h(&buf[0], t.piece_size(i));
|
|
t.set_hash(i, h.final());
|
|
}
|
|
|
|
t.set_creator(creator_str);
|
|
t.set_comment(comment);
|
|
|
|
entry e = t.create_torrent();
|
|
bencode(std::ostream_iterator<char>(out), e);
|
|
return Py_BuildValue("l", 1);
|
|
} catch (std::exception& e)
|
|
{
|
|
// std::cerr << e.what() << "\n";
|
|
// return Py_BuildValue("l", 0);
|
|
RAISE_PTR(DelugeError, e.what());
|
|
}
|
|
}
|
|
|
|
|
|
static PyObject *torrent_reset_IP_filter(PyObject *self, PyObject *args)
|
|
{
|
|
// Remove existing filter, if there is one
|
|
if (M_the_filter != NULL)
|
|
delete M_the_filter;
|
|
|
|
M_the_filter = new ip_filter();
|
|
|
|
M_ses->set_ip_filter(*M_the_filter);
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
|
|
static PyObject *torrent_add_range_to_IP_filter(PyObject *self, PyObject *args)
|
|
{
|
|
if (M_the_filter == NULL) {
|
|
RAISE_PTR(DelugeError, "No filter defined, use reset_IP_filter");
|
|
}
|
|
|
|
char *start, *end;
|
|
if (!PyArg_ParseTuple(args, "ss", &start, &end))
|
|
return NULL;
|
|
|
|
address_v4 inet_start = address_v4::from_string(start);
|
|
address_v4 inet_end = address_v4::from_string(end);
|
|
M_the_filter->add_rule(inet_start, inet_end, ip_filter::blocked);
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
static PyObject *torrent_use_upnp(PyObject *self, PyObject *args)
|
|
{
|
|
python_long action;
|
|
PyArg_ParseTuple(args, "i", &action);
|
|
|
|
if (action){
|
|
M_ses->start_upnp();
|
|
}
|
|
else{
|
|
M_ses->stop_upnp();
|
|
}
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
|
|
}
|
|
|
|
static PyObject *torrent_use_natpmp(PyObject *self, PyObject *args)
|
|
{
|
|
python_long action;
|
|
|
|
PyArg_ParseTuple(args, "i", &action);
|
|
|
|
if (action){
|
|
M_ses->start_natpmp();
|
|
}
|
|
else{
|
|
M_ses->stop_natpmp();
|
|
}
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
static PyObject *torrent_use_utpex(PyObject *self, PyObject *args)
|
|
{
|
|
python_long action;
|
|
|
|
PyArg_ParseTuple(args, "i", &action);
|
|
|
|
if (action){
|
|
M_ses->add_extension(&libtorrent::create_ut_pex_plugin);
|
|
}
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
static PyObject *torrent_pe_settings(PyObject *self, PyObject *args)
|
|
{
|
|
M_pe_settings = new pe_settings();
|
|
libtorrent::pe_settings::enc_policy out, in, prefer;
|
|
libtorrent::pe_settings::enc_level level;
|
|
|
|
PyArg_ParseTuple(args, "iiii", &out, &in, &level, &prefer);
|
|
|
|
M_pe_settings->out_enc_policy = out;
|
|
M_pe_settings->in_enc_policy = in;
|
|
M_pe_settings->allowed_enc_level = level;
|
|
M_pe_settings->prefer_rc4 = prefer;
|
|
|
|
M_ses->set_pe_settings(*M_pe_settings);
|
|
|
|
return Py_None;
|
|
}
|
|
|
|
static PyObject *torrent_set_ratio(PyObject *self, PyObject *args)
|
|
{
|
|
python_long unique_ID, num;
|
|
if (!PyArg_ParseTuple(args, "ii", &unique_ID, &num))
|
|
return NULL;
|
|
|
|
long index = get_index_from_unique_ID(unique_ID);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
M_torrents->at(index).handle.set_ratio(num);
|
|
|
|
Py_INCREF(Py_None); return Py_None;
|
|
}
|
|
|
|
|
|
//====================
|
|
// Python Module data
|
|
//====================
|
|
|
|
static PyMethodDef deluge_core_methods[] =
|
|
{
|
|
{"pe_settings", torrent_pe_settings, METH_VARARGS, "."},
|
|
{"pre_init", torrent_pre_init, METH_VARARGS, "."},
|
|
{"init", torrent_init, METH_VARARGS, "."},
|
|
{"quit", torrent_quit, METH_VARARGS, "."},
|
|
{"save_fastresume", torrent_save_fastresume, METH_VARARGS, "."},
|
|
{"set_max_half_open", torrent_set_max_half_open, METH_VARARGS, "."},
|
|
{"set_download_rate_limit", torrent_set_download_rate_limit, METH_VARARGS, "."},
|
|
{"set_upload_rate_limit", torrent_set_upload_rate_limit, METH_VARARGS, "."},
|
|
{"set_listen_on", torrent_set_listen_on, METH_VARARGS, "."},
|
|
{"is_listening", torrent_is_listening, METH_VARARGS, "."},
|
|
{"listening_port", torrent_listening_port, METH_VARARGS, "."},
|
|
{"set_max_uploads", torrent_set_max_uploads, METH_VARARGS, "."},
|
|
{"set_max_connections", torrent_set_max_connections, METH_VARARGS, "."},
|
|
{"add_torrent", torrent_add_torrent, METH_VARARGS, "."},
|
|
{"remove_torrent", torrent_remove_torrent, METH_VARARGS, "."},
|
|
{"get_num_torrents", torrent_get_num_torrents, METH_VARARGS, "."},
|
|
{"reannounce", torrent_reannounce, METH_VARARGS, "."},
|
|
{"pause", torrent_pause, METH_VARARGS, "."},
|
|
{"resume", torrent_resume, METH_VARARGS, "."},
|
|
{"get_torrent_state", torrent_get_torrent_state, METH_VARARGS, "."},
|
|
{"pop_event", torrent_pop_event, METH_VARARGS, "."},
|
|
{"get_session_info", torrent_get_session_info, METH_VARARGS, "."},
|
|
{"get_peer_info", torrent_get_peer_info, METH_VARARGS, "."},
|
|
{"get_file_info", torrent_get_file_info, METH_VARARGS, "."},
|
|
{"set_filter_out", torrent_set_filter_out, METH_VARARGS, "."},
|
|
{"constants", torrent_constants, METH_VARARGS, "."},
|
|
{"start_DHT", torrent_start_DHT, METH_VARARGS, "."},
|
|
{"stop_DHT", torrent_stop_DHT, METH_VARARGS, "."},
|
|
{"get_DHT_info", torrent_get_DHT_info, METH_VARARGS, "."},
|
|
{"create_torrent", torrent_create_torrent, METH_VARARGS, "."},
|
|
{"reset_IP_filter", torrent_reset_IP_filter, METH_VARARGS, "."},
|
|
{"add_range_to_IP_filter", torrent_add_range_to_IP_filter, METH_VARARGS, "."},
|
|
{"use_upnp", torrent_use_upnp, METH_VARARGS, "."},
|
|
{"use_natpmp", torrent_use_natpmp, METH_VARARGS, "."},
|
|
{"use_utpex", torrent_use_utpex, METH_VARARGS, "."},
|
|
{"set_ratio", torrent_set_ratio, METH_VARARGS, "."},
|
|
{NULL}
|
|
};
|
|
|
|
PyMODINIT_FUNC
|
|
initdeluge_core(void)
|
|
{
|
|
Py_InitModule("deluge_core", deluge_core_methods);
|
|
};
|