A clone of btpd with my configuration changes.

350 lines
8.2 KiB

  1. #include "btpd.h"
  2. #include "http_client.h"
  3. #define REQ_DELAY 1
  4. #define DEFAULT_INTERVAL rand_between(25 * 60, 30 * 60)
  5. #define RETRY1_TIMEOUT (& (struct timespec) {240 + rand_between(0, 120), 0})
  6. #define RETRY2_TIMEOUT (& (struct timespec) {900 + rand_between(0, 300), 0})
  7. long tr_key;
  8. static long m_tlast_req, m_tnext_req;
  9. struct tr_entry {
  10. BTPDQ_ENTRY(tr_entry) entry;
  11. char *failure;
  12. char *url;
  13. enum tr_type type;
  14. };
  15. BTPDQ_HEAD(tr_entry_tq, tr_entry);
  16. struct tr_tier {
  17. struct torrent *tp;
  18. struct tr_entry *cur;
  19. struct tr_entry_tq trackers;
  20. struct timeout timer;
  21. BTPDQ_ENTRY(tr_tier) entry;
  22. void *req;
  23. int interval;
  24. int bad_conns;
  25. int active;
  26. int has_responded;
  27. enum tr_event event;
  28. };
  29. BTPDQ_HEAD(tr_tier_tq, tr_tier);
  30. struct trackers {
  31. struct tr_tier_tq trackers;
  32. };
  33. static struct tr_entry *
  34. first_nonfailed(struct tr_tier *t)
  35. {
  36. struct tr_entry *e;
  37. BTPDQ_FOREACH(e, &t->trackers, entry)
  38. if (e->failure == NULL)
  39. return e;
  40. abort();
  41. }
  42. static int
  43. all_failed(struct tr_tier *t)
  44. {
  45. struct tr_entry *e;
  46. BTPDQ_FOREACH(e, &t->trackers, entry)
  47. if (e->failure == NULL)
  48. return 0;
  49. return 1;
  50. }
  51. static void *
  52. req_send(struct tr_tier *t)
  53. {
  54. btpd_log(BTPD_L_TR, "sending event %d to '%s' for '%s'.\n",
  55. t->event, t->cur->url, torrent_name(t->tp));
  56. switch (t->cur->type) {
  57. case TR_HTTP:
  58. return httptr_req(t->tp, t, t->cur->url, t->event);
  59. default:
  60. abort();
  61. }
  62. }
  63. static void
  64. req_cancel(struct tr_tier *t)
  65. {
  66. switch (t->cur->type) {
  67. case TR_HTTP:
  68. httptr_cancel(t->req);
  69. break;
  70. default:
  71. abort();
  72. }
  73. t->req = NULL;
  74. }
  75. static void
  76. entry_send(struct tr_tier *t, struct tr_entry *e, enum tr_event event)
  77. {
  78. if (t->req != NULL)
  79. req_cancel(t);
  80. t->event = event;
  81. t->cur = e;
  82. if (m_tlast_req > btpd_seconds - REQ_DELAY) {
  83. m_tnext_req = max(m_tnext_req, m_tlast_req) + REQ_DELAY;
  84. btpd_timer_add(&t->timer,
  85. (& (struct timespec) { m_tnext_req - btpd_seconds, 0 }));
  86. return;
  87. }
  88. btpd_timer_del(&t->timer);
  89. if ((t->req = req_send(t)) == NULL)
  90. btpd_err("failed to create tracker message to '%s' (%s).",
  91. e->url, strerror(errno));
  92. m_tlast_req = btpd_seconds;
  93. }
  94. static int
  95. tier_active(struct tr_tier *t)
  96. {
  97. return t->active;
  98. }
  99. static void
  100. tier_timer_cb(int fd, short type, void *arg)
  101. {
  102. struct tr_tier *t = arg;
  103. assert(tier_active(t) && !all_failed(t));
  104. entry_send(t, first_nonfailed(t), t->event);
  105. }
  106. static void
  107. tier_start(struct tr_tier *t)
  108. {
  109. struct tr_entry *e;
  110. assert(!tier_active(t) || t->event == TR_EV_STOPPED);
  111. BTPDQ_FOREACH(e, &t->trackers, entry)
  112. if (e->failure != NULL) {
  113. free(e->failure);
  114. e->failure = NULL;
  115. }
  116. t->has_responded = 0;
  117. t->bad_conns = 0;
  118. t->active = 1;
  119. entry_send(t, BTPDQ_FIRST(&t->trackers), TR_EV_STARTED);
  120. }
  121. static void
  122. tier_stop(struct tr_tier *t)
  123. {
  124. if (!tier_active(t) || t->event == TR_EV_STOPPED)
  125. return;
  126. if (!t->has_responded && t->bad_conns > 1) {
  127. btpd_timer_del(&t->timer);
  128. if (t->req != NULL)
  129. req_cancel(t);
  130. t->active = 0;
  131. } else
  132. entry_send(t, first_nonfailed(t), TR_EV_STOPPED);
  133. }
  134. static void
  135. tier_complete(struct tr_tier *t)
  136. {
  137. if (tier_active(t) && t->event == TR_EV_EMPTY)
  138. entry_send(t, BTPDQ_FIRST(&t->trackers), TR_EV_COMPLETED);
  139. }
  140. static void
  141. add_tracker(struct tr_tier *t, const char *url)
  142. {
  143. struct tr_entry *e;
  144. struct http_url *hu;
  145. if ((hu = http_url_parse(url)) != NULL) {
  146. http_url_free(hu);
  147. e = btpd_calloc(1, sizeof(*e));
  148. if ((e->url = strdup(url)) == NULL)
  149. btpd_err("Out of memory.\n");
  150. e->type = TR_HTTP;
  151. } else {
  152. btpd_log(BTPD_L_TR, "skipping unsupported tracker '%s' for '%s'.\n",
  153. url, torrent_name(t->tp));
  154. return;
  155. }
  156. BTPDQ_INSERT_TAIL(&t->trackers, e, entry);
  157. }
  158. static struct tr_tier *
  159. tier_create(struct torrent *tp, struct mi_tier *tier)
  160. {
  161. struct tr_tier *t = btpd_calloc(1, sizeof(*t));
  162. t->tp = tp;
  163. BTPDQ_INIT(&t->trackers);
  164. for (int i = 0; i < tier->nurls; i++)
  165. add_tracker(t, tier->urls[i]);
  166. if (!BTPDQ_EMPTY(&t->trackers)) {
  167. t->interval = -1;
  168. t->event = TR_EV_STOPPED;
  169. evtimer_init(&t->timer, tier_timer_cb, t);
  170. return t;
  171. } else {
  172. free(t);
  173. return NULL;
  174. }
  175. }
  176. static void
  177. tier_kill(struct tr_tier *t)
  178. {
  179. struct tr_entry *e, *next;
  180. btpd_timer_del(&t->timer);
  181. if (t->req != NULL)
  182. req_cancel(t);
  183. BTPDQ_FOREACH_MUTABLE(e, &t->trackers, entry , next) {
  184. if (e->failure != NULL)
  185. free(e->failure);
  186. free(e->url);
  187. free(e);
  188. }
  189. free(t);
  190. }
  191. void
  192. tr_create(struct torrent *tp, const char *mi)
  193. {
  194. int i;
  195. struct tr_tier *t;
  196. struct mi_announce *ann;
  197. tp->tr = btpd_calloc(1, sizeof(*tp->tr));
  198. BTPDQ_INIT(&tp->tr->trackers);
  199. if ((ann = mi_announce(mi)) == NULL)
  200. btpd_err("Out of memory.\n");
  201. for (i = 0; i < ann->ntiers; i++)
  202. if ((t = tier_create(tp, &ann->tiers[i])) != NULL)
  203. BTPDQ_INSERT_TAIL(&tp->tr->trackers, t, entry);
  204. mi_free_announce(ann);
  205. }
  206. void
  207. tr_kill(struct torrent *tp)
  208. {
  209. struct tr_tier *t, *next;
  210. BTPDQ_FOREACH_MUTABLE(t, &tp->tr->trackers, entry, next)
  211. tier_kill(t);
  212. free(tp->tr);
  213. tp->tr = NULL;
  214. }
  215. void
  216. tr_start(struct torrent *tp)
  217. {
  218. struct tr_tier *t;
  219. BTPDQ_FOREACH(t, &tp->tr->trackers, entry)
  220. tier_start(t);
  221. }
  222. void
  223. tr_stop(struct torrent *tp)
  224. {
  225. struct tr_tier *t;
  226. BTPDQ_FOREACH(t, &tp->tr->trackers, entry)
  227. tier_stop(t);
  228. }
  229. void
  230. tr_complete(struct torrent *tp)
  231. {
  232. struct tr_tier *t;
  233. BTPDQ_FOREACH(t, &tp->tr->trackers, entry)
  234. tier_complete(t);
  235. }
  236. int
  237. tr_active(struct torrent *tp)
  238. {
  239. struct tr_tier *t;
  240. BTPDQ_FOREACH(t, &tp->tr->trackers, entry)
  241. if (tier_active(t))
  242. return 1;
  243. return 0;
  244. }
  245. int
  246. tr_good_count(struct torrent *tp)
  247. {
  248. int count = 0;
  249. struct tr_tier *t;
  250. BTPDQ_FOREACH(t, &tp->tr->trackers, entry)
  251. if (tier_active(t) && t->bad_conns == 0)
  252. count++;
  253. return count;
  254. }
  255. void
  256. tr_result(struct tr_tier *t, struct tr_response *res)
  257. {
  258. struct tr_entry *e;
  259. t->req = NULL;
  260. switch (res->type) {
  261. case TR_RES_FAIL:
  262. t->cur->failure = benc_str(res->mi_failure, NULL, NULL);
  263. btpd_log(BTPD_L_ERROR, "tracker at '%s' failed (%s).\n",
  264. t->cur->url, t->cur->failure);
  265. if (all_failed(t)) {
  266. t->active = 0;
  267. break;
  268. }
  269. case TR_RES_CONN:
  270. btpd_log(BTPD_L_TR, "connection to '%s' failed for '%s'.\n",
  271. t->cur->url, torrent_name(t->tp));
  272. e = t->cur;
  273. while ((e = BTPDQ_NEXT(e, entry)) != NULL && e->failure != NULL)
  274. ;
  275. if (e != NULL) {
  276. entry_send(t, e, t->event);
  277. break;
  278. }
  279. t->bad_conns++;
  280. if (t->event == TR_EV_STOPPED && t->bad_conns > 1)
  281. t->active = 0;
  282. else if (t->bad_conns == 1)
  283. entry_send(t, BTPDQ_FIRST(&t->trackers), t->event);
  284. else if (t->bad_conns == 2)
  285. btpd_timer_add(&t->timer, RETRY1_TIMEOUT);
  286. else
  287. btpd_timer_add(&t->timer, RETRY2_TIMEOUT);
  288. break;
  289. case TR_RES_BAD:
  290. btpd_log(BTPD_L_ERROR, "bad data from tracker '%s' for '%s'.\n",
  291. t->cur->url, torrent_name(t->tp));
  292. case TR_RES_OK:
  293. if (TR_RES_OK)
  294. btpd_log(BTPD_L_TR, "response from '%s' for '%s'.\n",
  295. t->cur->url, torrent_name(t->tp));
  296. if (t->event == TR_EV_STOPPED)
  297. t->active = 0;
  298. else {
  299. t->event = TR_EV_EMPTY;
  300. if (res->interval > 0)
  301. t->interval = res->interval;
  302. btpd_timer_add(&t->timer, (& (struct timespec) {
  303. t->interval > 0 ? t->interval : DEFAULT_INTERVAL, 0 }));
  304. }
  305. t->bad_conns = 0;
  306. t->has_responded = 1;
  307. BTPDQ_REMOVE(&t->trackers, t->cur, entry);
  308. BTPDQ_INSERT_HEAD(&t->trackers, t->cur, entry);
  309. break;
  310. default:
  311. abort();
  312. }
  313. }
  314. void
  315. tr_init(void)
  316. {
  317. tr_key = random();
  318. }