2022-01-20 18:27:56 +00:00
|
|
|
// This file Copyright © 2008-2022 Mnemosyne LLC.
|
|
|
|
// It may be used under GPLv2 (SPDX: GPL-2.0), GPLv3 (SPDX: GPL-3.0),
|
|
|
|
// or any future license endorsed by Mnemosyne LLC.
|
|
|
|
// License text can be found in the licenses/ folder.
|
2008-06-07 21:26:41 +00:00
|
|
|
|
2021-09-19 20:41:35 +00:00
|
|
|
#include <algorithm>
|
2021-09-27 19:28:11 +00:00
|
|
|
#include <set>
|
2022-01-13 02:13:58 +00:00
|
|
|
#include <string>
|
2021-12-15 21:25:42 +00:00
|
|
|
#include <string_view>
|
2021-11-09 03:30:03 +00:00
|
|
|
#include <vector>
|
2008-06-07 21:26:41 +00:00
|
|
|
|
2010-12-20 02:07:51 +00:00
|
|
|
#include <event2/buffer.h>
|
2011-01-06 01:00:21 +00:00
|
|
|
#include <event2/event.h>
|
2008-06-07 21:26:41 +00:00
|
|
|
|
|
|
|
#include "transmission.h"
|
2021-11-09 03:30:03 +00:00
|
|
|
|
2011-03-03 18:33:24 +00:00
|
|
|
#include "bandwidth.h"
|
2011-01-06 01:00:21 +00:00
|
|
|
#include "cache.h"
|
|
|
|
#include "peer-mgr.h"
|
2008-06-07 21:26:41 +00:00
|
|
|
#include "torrent.h"
|
2017-04-21 07:40:57 +00:00
|
|
|
#include "trevent.h" /* tr_runInEventThread() */
|
2008-06-07 21:26:41 +00:00
|
|
|
#include "utils.h"
|
2021-11-09 03:30:03 +00:00
|
|
|
#include "web-utils.h"
|
2008-06-07 21:26:41 +00:00
|
|
|
#include "web.h"
|
|
|
|
#include "webseed.h"
|
|
|
|
|
2021-10-07 13:33:55 +00:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
|
|
|
struct tr_webseed;
|
|
|
|
|
2011-01-06 01:00:21 +00:00
|
|
|
struct tr_webseed_task
|
2008-06-07 21:26:41 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
bool dead;
|
|
|
|
struct evbuffer* content;
|
|
|
|
struct tr_webseed* webseed;
|
|
|
|
tr_session* session;
|
|
|
|
tr_block_index_t block;
|
|
|
|
tr_piece_index_t piece_index;
|
|
|
|
uint32_t piece_offset;
|
|
|
|
uint32_t length;
|
|
|
|
tr_block_index_t blocks_done;
|
|
|
|
uint32_t block_size;
|
|
|
|
struct tr_web_task* web_task;
|
|
|
|
long response_code;
|
2011-01-06 01:00:21 +00:00
|
|
|
};
|
2008-06-07 21:26:41 +00:00
|
|
|
|
2021-10-07 13:33:55 +00:00
|
|
|
auto constexpr TR_IDLE_TIMER_MSEC = 2000;
|
|
|
|
|
|
|
|
auto constexpr FAILURE_RETRY_INTERVAL = 150;
|
|
|
|
|
|
|
|
auto constexpr MAX_CONSECUTIVE_FAILURES = 5;
|
|
|
|
|
|
|
|
auto constexpr MAX_WEBSEED_CONNECTIONS = 4;
|
|
|
|
|
|
|
|
void webseed_timer_func(evutil_socket_t fd, short what, void* vw);
|
|
|
|
|
|
|
|
struct tr_webseed : public tr_peer
|
2011-01-06 01:00:21 +00:00
|
|
|
{
|
2021-10-07 13:33:55 +00:00
|
|
|
public:
|
|
|
|
tr_webseed(struct tr_torrent* tor, std::string_view url, tr_peer_callback callback_in, void* callback_data_in)
|
|
|
|
: tr_peer{ tor }
|
|
|
|
, torrent_id{ tr_torrentId(tor) }
|
|
|
|
, base_url{ url }
|
|
|
|
, callback{ callback_in }
|
|
|
|
, callback_data{ callback_data_in }
|
2021-10-09 12:52:09 +00:00
|
|
|
, bandwidth(tor->bandwidth)
|
2022-01-23 22:47:41 +00:00
|
|
|
, timer(evtimer_new(session->event_base, webseed_timer_func, this))
|
2021-10-07 13:33:55 +00:00
|
|
|
{
|
|
|
|
// init parent bits
|
2021-10-24 20:43:36 +00:00
|
|
|
have.setHasAll();
|
2021-10-07 13:33:55 +00:00
|
|
|
tr_peerUpdateProgress(tor, this);
|
|
|
|
|
2021-12-06 21:26:04 +00:00
|
|
|
file_urls.resize(tor->fileCount());
|
2021-10-07 13:33:55 +00:00
|
|
|
|
|
|
|
tr_timerAddMsec(timer, TR_IDLE_TIMER_MSEC);
|
|
|
|
}
|
|
|
|
|
|
|
|
~tr_webseed() override
|
|
|
|
{
|
|
|
|
// flag all the pending tasks as dead
|
|
|
|
std::for_each(std::begin(tasks), std::end(tasks), [](auto* task) { task->dead = true; });
|
|
|
|
tasks.clear();
|
|
|
|
|
|
|
|
event_free(timer);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_transferring_pieces(uint64_t now, tr_direction direction, unsigned int* setme_Bps) const override
|
|
|
|
{
|
|
|
|
unsigned int Bps = 0;
|
|
|
|
bool is_active = false;
|
|
|
|
|
|
|
|
if (direction == TR_DOWN)
|
|
|
|
{
|
|
|
|
is_active = !std::empty(tasks);
|
2021-10-12 06:04:22 +00:00
|
|
|
Bps = bandwidth.getPieceSpeedBytesPerSecond(now, direction);
|
2021-10-07 13:33:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (setme_Bps != nullptr)
|
|
|
|
{
|
|
|
|
*setme_Bps = Bps;
|
|
|
|
}
|
|
|
|
|
|
|
|
return is_active;
|
|
|
|
}
|
|
|
|
|
|
|
|
int const torrent_id;
|
|
|
|
std::string const base_url;
|
|
|
|
tr_peer_callback const callback;
|
|
|
|
void* const callback_data;
|
|
|
|
|
2021-10-10 01:12:03 +00:00
|
|
|
Bandwidth bandwidth;
|
2021-09-27 19:28:11 +00:00
|
|
|
std::set<tr_webseed_task*> tasks;
|
2022-01-23 22:47:41 +00:00
|
|
|
struct event* const timer;
|
2021-10-07 13:33:55 +00:00
|
|
|
int consecutive_failures = 0;
|
|
|
|
int retry_tickcount = 0;
|
|
|
|
int retry_challenge = 0;
|
|
|
|
int idle_connections = 0;
|
|
|
|
int active_transfers = 0;
|
|
|
|
std::vector<std::string> file_urls;
|
2011-07-10 15:24:51 +00:00
|
|
|
};
|
|
|
|
|
2021-10-07 13:33:55 +00:00
|
|
|
} // namespace
|
2011-01-06 15:12:12 +00:00
|
|
|
|
2021-12-07 18:11:28 +00:00
|
|
|
tr_webseed_view tr_webseedView(tr_peer const* peer)
|
|
|
|
{
|
|
|
|
auto const* w = dynamic_cast<tr_webseed const*>(peer);
|
|
|
|
if (w == nullptr)
|
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
auto bytes_per_second = unsigned{ 0 };
|
|
|
|
auto const is_downloading = peer->is_transferring_pieces(tr_time_msec(), TR_DOWN, &bytes_per_second);
|
|
|
|
return { w->base_url.c_str(), is_downloading, bytes_per_second };
|
|
|
|
}
|
|
|
|
|
2008-06-07 21:26:41 +00:00
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static void publish(tr_webseed* w, tr_peer_event* e)
|
2008-06-07 21:26:41 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
if (w->callback != nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2021-10-07 13:33:55 +00:00
|
|
|
(*w->callback)(w, e, w->callback_data);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2009-02-11 16:34:35 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static void fire_client_got_rejs(tr_torrent* tor, tr_webseed* w, tr_block_index_t block, tr_block_index_t count)
|
2008-06-07 21:26:41 +00:00
|
|
|
{
|
2021-09-12 17:41:49 +00:00
|
|
|
auto e = tr_peer_event{};
|
2017-04-19 12:04:45 +00:00
|
|
|
e.eventType = TR_PEER_CLIENT_GOT_REJ;
|
|
|
|
tr_torrentGetBlockLocation(tor, block, &e.pieceIndex, &e.offset, &e.length);
|
|
|
|
|
2017-05-13 22:38:31 +00:00
|
|
|
for (tr_block_index_t i = 1; i <= count; i++)
|
2013-02-04 16:23:33 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
if (i == count)
|
|
|
|
{
|
2021-11-26 19:33:56 +00:00
|
|
|
e.length = tor->blockSize(block + count - 1);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
publish(w, &e);
|
|
|
|
e.offset += e.length;
|
2011-07-10 15:24:51 +00:00
|
|
|
}
|
2011-02-03 04:17:48 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static void fire_client_got_blocks(tr_torrent* tor, tr_webseed* w, tr_block_index_t block, tr_block_index_t count)
|
2011-02-03 04:17:48 +00:00
|
|
|
{
|
2021-09-12 17:41:49 +00:00
|
|
|
auto e = tr_peer_event{};
|
2017-04-19 12:04:45 +00:00
|
|
|
e.eventType = TR_PEER_CLIENT_GOT_BLOCK;
|
|
|
|
tr_torrentGetBlockLocation(tor, block, &e.pieceIndex, &e.offset, &e.length);
|
|
|
|
|
2017-05-13 22:38:31 +00:00
|
|
|
for (tr_block_index_t i = 1; i <= count; i++)
|
2013-02-04 16:23:33 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
if (i == count)
|
|
|
|
{
|
2021-11-26 19:33:56 +00:00
|
|
|
e.length = tor->blockSize(block + count - 1);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
publish(w, &e);
|
|
|
|
e.offset += e.length;
|
2011-07-10 15:24:51 +00:00
|
|
|
}
|
2008-06-07 21:26:41 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static void fire_client_got_piece_data(tr_webseed* w, uint32_t length)
|
2008-06-07 21:26:41 +00:00
|
|
|
{
|
2021-09-12 17:41:49 +00:00
|
|
|
auto e = tr_peer_event{};
|
2017-04-19 12:04:45 +00:00
|
|
|
e.eventType = TR_PEER_CLIENT_GOT_PIECE_DATA;
|
|
|
|
e.length = length;
|
|
|
|
publish(w, &e);
|
2008-06-07 21:26:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
|
|
|
|
2011-09-12 21:46:15 +00:00
|
|
|
struct write_block_data
|
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_session* session;
|
|
|
|
int torrent_id;
|
|
|
|
struct tr_webseed* webseed;
|
|
|
|
struct evbuffer* content;
|
|
|
|
tr_piece_index_t piece_index;
|
|
|
|
tr_block_index_t block_index;
|
|
|
|
tr_block_index_t count;
|
|
|
|
uint32_t block_offset;
|
2011-09-12 21:46:15 +00:00
|
|
|
};
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static void write_block_func(void* vdata)
|
2011-07-10 15:24:51 +00:00
|
|
|
{
|
2021-10-15 17:27:12 +00:00
|
|
|
auto* const data = static_cast<struct write_block_data*>(vdata);
|
|
|
|
struct tr_webseed* const w = data->webseed;
|
|
|
|
struct evbuffer* const buf = data->content;
|
2011-07-10 15:24:51 +00:00
|
|
|
|
2021-10-15 17:27:12 +00:00
|
|
|
auto* const tor = tr_torrentFindFromId(data->session, data->torrent_id);
|
2021-09-15 00:18:09 +00:00
|
|
|
if (tor != nullptr)
|
2011-07-10 15:24:51 +00:00
|
|
|
{
|
2022-01-07 19:13:37 +00:00
|
|
|
uint32_t const block_size = tor->blockSize();
|
2017-04-19 12:04:45 +00:00
|
|
|
uint32_t len = evbuffer_get_length(buf);
|
2017-04-20 16:02:19 +00:00
|
|
|
uint32_t const offset_end = data->block_offset + len;
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_cache* cache = data->session->cache;
|
2017-04-20 16:02:19 +00:00
|
|
|
tr_piece_index_t const piece = data->piece_index;
|
2011-07-10 15:24:51 +00:00
|
|
|
|
2021-11-25 18:26:51 +00:00
|
|
|
if (!tor->hasPiece(piece))
|
2011-07-10 15:24:51 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
while (len > 0)
|
2015-07-05 07:54:46 +00:00
|
|
|
{
|
2021-09-19 20:41:35 +00:00
|
|
|
uint32_t const bytes_this_pass = std::min(len, block_size);
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_cacheWriteBlock(cache, tor, piece, offset_end - len, bytes_this_pass, buf);
|
|
|
|
len -= bytes_this_pass;
|
2015-07-05 07:54:46 +00:00
|
|
|
}
|
2011-09-12 21:46:15 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
fire_client_got_blocks(tor, w, data->block_index, data->count);
|
2015-07-05 07:54:46 +00:00
|
|
|
}
|
2011-07-10 15:24:51 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
evbuffer_free(buf);
|
|
|
|
tr_free(data);
|
2011-07-10 15:24:51 +00:00
|
|
|
}
|
|
|
|
|
2011-09-12 21:46:15 +00:00
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
|
|
|
|
|
|
|
struct connection_succeeded_data
|
|
|
|
{
|
2021-12-10 00:49:30 +00:00
|
|
|
tr_webseed* webseed = nullptr;
|
|
|
|
std::string real_url;
|
|
|
|
tr_piece_index_t piece_index = 0;
|
|
|
|
uint32_t piece_offset = 0;
|
2011-09-12 21:46:15 +00:00
|
|
|
};
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static void connection_succeeded(void* vdata)
|
2011-07-10 15:24:51 +00:00
|
|
|
{
|
2021-09-12 17:41:49 +00:00
|
|
|
auto* data = static_cast<struct connection_succeeded_data*>(vdata);
|
2017-04-19 12:04:45 +00:00
|
|
|
struct tr_webseed* w = data->webseed;
|
2011-07-10 15:24:51 +00:00
|
|
|
|
2017-04-30 16:25:26 +00:00
|
|
|
if (++w->active_transfers >= w->retry_challenge && w->retry_challenge != 0)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
/* the server seems to be accepting more connections now */
|
|
|
|
w->consecutive_failures = w->retry_tickcount = w->retry_challenge = 0;
|
|
|
|
}
|
2011-07-10 15:24:51 +00:00
|
|
|
|
2021-12-10 00:49:30 +00:00
|
|
|
if (!std::empty(data->real_url))
|
2011-07-10 15:24:51 +00:00
|
|
|
{
|
2020-11-09 03:31:02 +00:00
|
|
|
tr_torrent const* const tor = tr_torrentFindFromId(w->session, w->torrent_id);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (tor != nullptr)
|
2019-03-17 06:09:08 +00:00
|
|
|
{
|
2021-12-24 06:39:55 +00:00
|
|
|
auto const file_index = tor->fileOffset(data->piece_index, data->piece_offset).index;
|
2021-10-07 13:33:55 +00:00
|
|
|
w->file_urls[file_index].assign(data->real_url);
|
2019-03-17 06:09:08 +00:00
|
|
|
}
|
2011-07-10 15:24:51 +00:00
|
|
|
}
|
2013-02-04 16:23:33 +00:00
|
|
|
|
2021-12-10 00:49:30 +00:00
|
|
|
delete data;
|
2011-07-10 15:24:51 +00:00
|
|
|
}
|
|
|
|
|
2011-09-12 21:46:15 +00:00
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
static void on_content_changed(struct evbuffer* buf, struct evbuffer_cb_info const* info, void* vtask)
|
2008-06-07 21:26:41 +00:00
|
|
|
{
|
2017-04-20 16:02:19 +00:00
|
|
|
size_t const n_added = info->n_added;
|
2021-09-12 17:41:49 +00:00
|
|
|
auto* task = static_cast<struct tr_webseed_task*>(vtask);
|
2021-10-07 13:33:55 +00:00
|
|
|
auto* session = task->session;
|
2021-11-20 21:20:45 +00:00
|
|
|
auto const lock = session->unique_lock();
|
2011-07-10 15:24:51 +00:00
|
|
|
|
2017-04-30 16:25:26 +00:00
|
|
|
if (!task->dead && n_added > 0)
|
2011-01-06 01:00:21 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
struct tr_webseed* w = task->webseed;
|
2011-07-10 15:24:51 +00:00
|
|
|
|
2021-10-09 12:52:09 +00:00
|
|
|
w->bandwidth.notifyBandwidthConsumed(TR_DOWN, n_added, true, tr_time_msec());
|
2017-04-19 12:04:45 +00:00
|
|
|
fire_client_got_piece_data(w, n_added);
|
2021-10-15 17:27:12 +00:00
|
|
|
uint32_t const len = evbuffer_get_length(buf);
|
2011-09-12 05:39:27 +00:00
|
|
|
|
2017-04-30 16:25:26 +00:00
|
|
|
if (task->response_code == 0)
|
2013-02-04 16:23:33 +00:00
|
|
|
{
|
2020-08-27 23:41:26 +00:00
|
|
|
task->response_code = tr_webGetTaskResponseCode(task->web_task);
|
2013-02-04 16:23:33 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
if (task->response_code == 206)
|
2013-02-04 16:23:33 +00:00
|
|
|
{
|
2021-12-10 00:49:30 +00:00
|
|
|
auto const* real_url = tr_webGetTaskRealUrl(task->web_task);
|
2013-02-04 16:23:33 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
/* processing this uses a tr_torrent pointer,
|
|
|
|
so push the work to the libevent thread... */
|
2021-12-10 00:49:30 +00:00
|
|
|
tr_runInEventThread(
|
|
|
|
session,
|
|
|
|
connection_succeeded,
|
|
|
|
new connection_succeeded_data{ w,
|
|
|
|
real_url ? real_url : "",
|
|
|
|
task->piece_index,
|
|
|
|
task->piece_offset + task->blocks_done * task->block_size + len - 1 });
|
2013-02-04 16:23:33 +00:00
|
|
|
}
|
|
|
|
}
|
2011-07-10 15:24:51 +00:00
|
|
|
|
2017-04-30 16:25:26 +00:00
|
|
|
if (task->response_code == 206 && len >= task->block_size)
|
2011-09-12 21:46:15 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
/* once we've got at least one full block, save it */
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
uint32_t const block_size = task->block_size;
|
|
|
|
tr_block_index_t const completed = len / block_size;
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2021-10-15 17:27:12 +00:00
|
|
|
auto* const data = tr_new(struct write_block_data, 1);
|
2017-04-19 12:04:45 +00:00
|
|
|
data->webseed = task->webseed;
|
|
|
|
data->piece_index = task->piece_index;
|
|
|
|
data->block_index = task->block + task->blocks_done;
|
|
|
|
data->count = completed;
|
|
|
|
data->block_offset = task->piece_offset + task->blocks_done * block_size;
|
|
|
|
data->content = evbuffer_new();
|
|
|
|
data->torrent_id = w->torrent_id;
|
|
|
|
data->session = w->session;
|
|
|
|
|
|
|
|
/* we don't use locking on this evbuffer so we must copy out the data
|
|
|
|
that will be needed when writing the block in a different thread */
|
2020-09-11 21:07:45 +00:00
|
|
|
evbuffer_remove_buffer(task->content, data->content, (size_t)block_size * (size_t)completed);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
tr_runInEventThread(w->session, write_block_func, data);
|
|
|
|
task->blocks_done += completed;
|
2011-07-10 15:24:51 +00:00
|
|
|
}
|
|
|
|
}
|
2008-06-07 21:26:41 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static void task_request_next_chunk(struct tr_webseed_task* task);
|
2008-06-07 21:26:41 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static void on_idle(tr_webseed* w)
|
2008-06-07 21:26:41 +00:00
|
|
|
{
|
2021-10-15 17:27:12 +00:00
|
|
|
auto want = int{};
|
2021-09-27 19:28:11 +00:00
|
|
|
int const running_tasks = std::size(w->tasks);
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_torrent* tor = tr_torrentFindFromId(w->session, w->torrent_id);
|
2011-07-10 15:24:51 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
if (w->consecutive_failures >= MAX_CONSECUTIVE_FAILURES)
|
2013-02-04 16:23:33 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
want = w->idle_connections;
|
2011-07-10 15:24:51 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
if (w->retry_tickcount >= FAILURE_RETRY_INTERVAL)
|
2013-02-04 16:23:33 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
/* some time has passed since our connection attempts failed. try again */
|
|
|
|
++want;
|
|
|
|
/* if this challenge is fulfilled we will reset consecutive_failures */
|
|
|
|
w->retry_challenge = running_tasks + want;
|
2011-07-10 15:24:51 +00:00
|
|
|
}
|
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
else
|
2008-06-07 21:26:41 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
want = MAX_WEBSEED_CONNECTIONS - running_tasks;
|
|
|
|
w->retry_challenge = running_tasks + w->idle_connections + 1;
|
2008-06-07 21:26:41 +00:00
|
|
|
}
|
2013-02-04 16:23:33 +00:00
|
|
|
|
2021-12-15 07:04:26 +00:00
|
|
|
if (tor != nullptr && tor->isRunning && !tor->isDone() && want > 0)
|
2008-06-07 21:26:41 +00:00
|
|
|
{
|
2021-11-19 18:37:38 +00:00
|
|
|
auto n_tasks = size_t{};
|
2011-07-10 15:24:51 +00:00
|
|
|
|
2021-11-25 18:26:51 +00:00
|
|
|
for (auto const span : tr_peerMgrGetNextRequests(tor, w, want))
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2021-11-25 18:26:51 +00:00
|
|
|
auto const [begin, end] = span;
|
2021-11-19 18:37:38 +00:00
|
|
|
auto* const task = tr_new0(tr_webseed_task, 1);
|
2017-04-19 12:04:45 +00:00
|
|
|
task->session = tor->session;
|
|
|
|
task->webseed = w;
|
2021-11-25 18:26:51 +00:00
|
|
|
task->block = begin;
|
|
|
|
task->piece_index = tor->pieceForBlock(begin);
|
2022-01-07 19:13:37 +00:00
|
|
|
task->piece_offset = tor->blockSize() * begin - tor->pieceSize() * task->piece_index;
|
|
|
|
task->length = (end - 1 - begin) * tor->blockSize() + tor->blockSize(end - 1);
|
2017-04-19 12:04:45 +00:00
|
|
|
task->blocks_done = 0;
|
|
|
|
task->response_code = 0;
|
2022-01-07 19:13:37 +00:00
|
|
|
task->block_size = tor->blockSize();
|
2017-04-19 12:04:45 +00:00
|
|
|
task->content = evbuffer_new();
|
|
|
|
evbuffer_add_cb(task->content, on_content_changed, task);
|
2021-09-27 19:28:11 +00:00
|
|
|
w->tasks.insert(task);
|
2017-04-19 12:04:45 +00:00
|
|
|
task_request_next_chunk(task);
|
2021-11-19 18:37:38 +00:00
|
|
|
|
|
|
|
--w->idle_connections;
|
|
|
|
++n_tasks;
|
2021-11-25 18:26:51 +00:00
|
|
|
tr_peerMgrClientSentRequests(tor, w, span);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
|
|
|
|
2021-11-19 18:37:38 +00:00
|
|
|
if (w->retry_tickcount >= FAILURE_RETRY_INTERVAL && n_tasks > 0)
|
|
|
|
{
|
|
|
|
w->retry_tickcount = 0;
|
|
|
|
}
|
2008-06-07 21:26:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-15 09:41:48 +00:00
|
|
|
static void web_response_func(
|
|
|
|
tr_session* session,
|
2021-10-24 16:41:54 +00:00
|
|
|
bool /*did_connect*/,
|
|
|
|
bool /*did_timeout*/,
|
2021-08-15 09:41:48 +00:00
|
|
|
long response_code,
|
2021-11-15 18:10:18 +00:00
|
|
|
std::string_view /*response*/,
|
2021-08-15 09:41:48 +00:00
|
|
|
void* vtask)
|
2008-06-07 21:26:41 +00:00
|
|
|
{
|
2021-09-12 17:41:49 +00:00
|
|
|
auto* t = static_cast<struct tr_webseed_task*>(vtask);
|
2019-07-14 12:40:41 +00:00
|
|
|
bool const success = response_code == 206;
|
2013-02-04 16:23:33 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
if (t->dead)
|
2013-02-04 16:23:33 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
evbuffer_free(t->content);
|
|
|
|
tr_free(t);
|
|
|
|
return;
|
2013-02-04 16:23:33 +00:00
|
|
|
}
|
2008-11-08 22:24:07 +00:00
|
|
|
|
2021-09-12 17:41:49 +00:00
|
|
|
tr_webseed* w = t->webseed;
|
|
|
|
tr_torrent* tor = tr_torrentFindFromId(session, w->torrent_id);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (tor != nullptr)
|
2008-11-08 22:24:07 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
/* active_transfers was only increased if the connection was successful */
|
|
|
|
if (t->response_code == 206)
|
|
|
|
{
|
|
|
|
--w->active_transfers;
|
|
|
|
}
|
2011-07-10 15:24:51 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
if (!success)
|
2011-01-06 01:00:21 +00:00
|
|
|
{
|
2022-01-07 19:13:37 +00:00
|
|
|
tr_block_index_t const blocks_remain = (t->length + tor->blockSize() - 1) / tor->blockSize() - t->blocks_done;
|
2011-07-10 15:24:51 +00:00
|
|
|
|
2017-04-30 16:25:26 +00:00
|
|
|
if (blocks_remain != 0)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
fire_client_got_rejs(tor, w, t->block + t->blocks_done, blocks_remain);
|
|
|
|
}
|
2011-07-10 15:24:51 +00:00
|
|
|
|
2017-04-30 16:25:26 +00:00
|
|
|
if (t->blocks_done != 0)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
++w->idle_connections;
|
|
|
|
}
|
2017-04-30 16:25:26 +00:00
|
|
|
else if (++w->consecutive_failures >= MAX_CONSECUTIVE_FAILURES && w->retry_tickcount == 0)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
/* now wait a while until retrying to establish a connection */
|
|
|
|
++w->retry_tickcount;
|
|
|
|
}
|
2011-01-06 01:00:21 +00:00
|
|
|
|
2021-09-27 19:28:11 +00:00
|
|
|
w->tasks.erase(t);
|
2017-04-19 12:04:45 +00:00
|
|
|
evbuffer_free(t->content);
|
|
|
|
tr_free(t);
|
2011-02-03 04:17:48 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-01-07 19:13:37 +00:00
|
|
|
uint32_t const bytes_done = t->blocks_done * tor->blockSize();
|
2017-04-20 16:02:19 +00:00
|
|
|
uint32_t const buf_len = evbuffer_get_length(t->content);
|
2011-07-10 15:24:51 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
if (bytes_done + buf_len < t->length)
|
2011-02-03 04:17:48 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
/* request finished successfully but there's still data missing. that
|
|
|
|
means we've reached the end of a file and need to request the next one */
|
|
|
|
t->response_code = 0;
|
|
|
|
task_request_next_chunk(t);
|
2011-02-03 04:17:48 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-11-25 18:26:51 +00:00
|
|
|
if (buf_len != 0 && !tor->hasPiece(t->piece_index))
|
2013-02-04 16:23:33 +00:00
|
|
|
{
|
2017-04-21 07:40:57 +00:00
|
|
|
/* on_content_changed() will not write a block if it is smaller than
|
2017-04-19 12:04:45 +00:00
|
|
|
the torrent's block size, i.e. the torrent's very last block */
|
|
|
|
tr_cacheWriteBlock(session->cache, tor, t->piece_index, t->piece_offset + bytes_done, buf_len, t->content);
|
|
|
|
|
|
|
|
fire_client_got_blocks(tor, t->webseed, t->block + t->blocks_done, 1);
|
2011-07-10 15:24:51 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
++w->idle_connections;
|
2011-02-03 04:17:48 +00:00
|
|
|
|
2021-09-27 19:28:11 +00:00
|
|
|
w->tasks.erase(t);
|
2017-04-19 12:04:45 +00:00
|
|
|
evbuffer_free(t->content);
|
|
|
|
tr_free(t);
|
2011-02-03 04:17:48 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
on_idle(w);
|
2011-02-03 04:17:48 +00:00
|
|
|
}
|
2011-01-06 01:00:21 +00:00
|
|
|
}
|
2008-11-08 22:24:07 +00:00
|
|
|
}
|
2008-06-07 21:26:41 +00:00
|
|
|
}
|
|
|
|
|
2022-01-02 01:25:25 +00:00
|
|
|
static std::string make_url(tr_webseed* w, std::string_view name)
|
2008-06-07 21:26:41 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
struct evbuffer* buf = evbuffer_new();
|
2008-06-07 21:26:41 +00:00
|
|
|
|
2021-10-07 13:33:55 +00:00
|
|
|
evbuffer_add(buf, std::data(w->base_url), std::size(w->base_url));
|
2011-01-06 01:00:21 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
/* if url ends with a '/', add the torrent name */
|
2022-01-02 01:25:25 +00:00
|
|
|
if (*std::rbegin(w->base_url) == '/' && !std::empty(name))
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2021-11-28 03:17:47 +00:00
|
|
|
tr_http_escape(buf, name, false);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2011-01-06 01:00:21 +00:00
|
|
|
|
2021-10-17 21:09:58 +00:00
|
|
|
auto url = std::string{ (char const*)evbuffer_pullup(buf, -1), evbuffer_get_length(buf) };
|
2021-10-07 13:33:55 +00:00
|
|
|
evbuffer_free(buf);
|
|
|
|
return url;
|
2011-01-06 01:00:21 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static void task_request_next_chunk(struct tr_webseed_task* t)
|
2011-01-06 01:00:21 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_webseed* w = t->webseed;
|
|
|
|
tr_torrent* tor = tr_torrentFindFromId(w->session, w->torrent_id);
|
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (tor != nullptr)
|
2008-06-07 21:26:41 +00:00
|
|
|
{
|
2021-10-07 13:33:55 +00:00
|
|
|
auto& urls = t->webseed->file_urls;
|
2013-02-04 16:23:33 +00:00
|
|
|
|
2021-12-16 08:49:04 +00:00
|
|
|
auto const piece_size = tor->pieceSize();
|
2022-01-07 19:13:37 +00:00
|
|
|
uint64_t const remain = t->length - t->blocks_done * tor->blockSize() - evbuffer_get_length(t->content);
|
2013-02-04 16:23:33 +00:00
|
|
|
|
2021-12-26 17:25:51 +00:00
|
|
|
auto const total_offset = tor->offset(t->piece_index, t->piece_offset, t->length - remain);
|
2021-12-16 08:49:04 +00:00
|
|
|
tr_piece_index_t const step_piece = total_offset / piece_size;
|
|
|
|
uint64_t const step_piece_offset = total_offset - uint64_t(piece_size) * step_piece;
|
2013-02-04 16:23:33 +00:00
|
|
|
|
2021-12-24 06:39:55 +00:00
|
|
|
auto const [file_index, file_offset] = tor->fileOffset(step_piece, step_piece_offset);
|
2022-01-02 01:25:25 +00:00
|
|
|
uint64_t this_pass = std::min(remain, tor->fileSize(file_index) - file_offset);
|
2013-02-04 16:23:33 +00:00
|
|
|
|
2021-10-07 13:33:55 +00:00
|
|
|
if (std::empty(urls[file_index]))
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-01-02 01:25:25 +00:00
|
|
|
urls[file_index] = make_url(t->webseed, tor->fileSubpath(file_index));
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2013-02-04 16:23:33 +00:00
|
|
|
|
2021-10-07 13:33:55 +00:00
|
|
|
char range[64];
|
2017-05-20 16:29:23 +00:00
|
|
|
tr_snprintf(range, sizeof(range), "%" PRIu64 "-%" PRIu64, file_offset, file_offset + this_pass - 1);
|
2013-04-13 20:25:28 +00:00
|
|
|
|
2021-10-07 13:33:55 +00:00
|
|
|
t->web_task = tr_webRunWebseed(tor, urls[file_index].c_str(), range, web_response_func, t, t->content);
|
2011-01-06 01:00:21 +00:00
|
|
|
}
|
2008-06-07 21:26:41 +00:00
|
|
|
}
|
|
|
|
|
2013-02-04 16:23:33 +00:00
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
2008-06-10 02:36:52 +00:00
|
|
|
|
2021-10-07 13:33:55 +00:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
2021-10-24 16:41:54 +00:00
|
|
|
void webseed_timer_func(evutil_socket_t /*fd*/, short /*what*/, void* vw)
|
2008-06-10 01:38:12 +00:00
|
|
|
{
|
2021-09-12 17:41:49 +00:00
|
|
|
auto* w = static_cast<tr_webseed*>(vw);
|
2013-02-04 16:23:33 +00:00
|
|
|
|
2017-04-30 16:25:26 +00:00
|
|
|
if (w->retry_tickcount != 0)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
++w->retry_tickcount;
|
|
|
|
}
|
2013-02-04 16:23:33 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
on_idle(w);
|
2013-02-04 16:23:33 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_timerAddMsec(w->timer, TR_IDLE_TIMER_MSEC);
|
2008-06-10 01:38:12 +00:00
|
|
|
}
|
|
|
|
|
2021-10-07 13:33:55 +00:00
|
|
|
} // unnamed namespace
|
2013-02-04 16:23:33 +00:00
|
|
|
|
2021-10-07 13:33:55 +00:00
|
|
|
tr_peer* tr_webseedNew(struct tr_torrent* torrent, std::string_view url, tr_peer_callback callback, void* callback_data)
|
2011-01-06 01:00:21 +00:00
|
|
|
{
|
2021-10-07 13:33:55 +00:00
|
|
|
return new tr_webseed(torrent, url, callback, callback_data);
|
2008-06-07 21:26:41 +00:00
|
|
|
}
|