A clone of btpd with my configuration changes.

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