A clone of btpd with my configuration changes.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

260 lignes
5.4 KiB

  1. #include <string.h>
  2. #include "btpd.h"
  3. #include "subr.h"
  4. #include "tracker_req.h"
  5. #define REQ_DELAY 1
  6. #define STOP_ERRORS 5
  7. #define REQ_TIMEOUT (& (struct timeval) { 120, 0 })
  8. #define RETRY_WAIT (& (struct timeval) { rand_between(35, 70), 0 })
  9. long tr_key;
  10. static long m_tlast_req, m_tnext_req;
  11. enum timer_type {
  12. TIMER_NONE,
  13. TIMER_TIMEOUT,
  14. TIMER_INTERVAL,
  15. TIMER_RETRY
  16. };
  17. struct tracker {
  18. enum timer_type ttype;
  19. enum tr_event event;
  20. int interval;
  21. unsigned nerrors;
  22. int tier, url;
  23. struct mi_announce *ann;
  24. void *req;
  25. struct event timer;
  26. };
  27. typedef struct _dummy *(*request_fun_t)(struct torrent *, enum tr_event,
  28. const char *);
  29. typedef void (*cancel_fun_t)(struct _dummy *);
  30. struct tr_op {
  31. int len;
  32. const char *scheme;
  33. request_fun_t request;
  34. cancel_fun_t cancel;
  35. };
  36. static struct tr_op m_http_op = {
  37. 7, "http://", (request_fun_t)http_tr_req, (cancel_fun_t)http_tr_cancel
  38. };
  39. static struct tr_op *m_tr_ops[] = {
  40. &m_http_op, NULL
  41. };
  42. static char *
  43. get_url(struct tracker *tr)
  44. {
  45. return tr->ann->tiers[tr->tier].urls[tr->url];
  46. }
  47. static void
  48. good_url(struct tracker *tr)
  49. {
  50. char *set = tr->ann->tiers[tr->tier].urls[tr->url], *hold;
  51. for (int i = 0; i <= tr->url; i++) {
  52. hold = tr->ann->tiers[tr->tier].urls[i];
  53. tr->ann->tiers[tr->tier].urls[i] = set;
  54. set = hold;
  55. }
  56. tr->tier = 0;
  57. tr->url = 0;
  58. }
  59. static void
  60. next_url(struct tracker *tr)
  61. {
  62. tr->url = (tr->url + 1) % tr->ann->tiers[tr->tier].nurls;
  63. if (tr->url == 0)
  64. tr->tier = (tr->tier + 1) % tr->ann->ntiers;
  65. }
  66. struct tr_op *
  67. get_op(struct tracker *tr)
  68. {
  69. struct tr_op **opp;
  70. char *url = get_url(tr);
  71. for (opp = m_tr_ops; *opp != NULL; opp++)
  72. if (strncasecmp((*opp)->scheme, url, (*opp)->len) == 0)
  73. return *opp;
  74. return NULL;
  75. }
  76. static void
  77. tr_cancel(struct tracker *tr)
  78. {
  79. struct tr_op *op = get_op(tr);
  80. assert(op != NULL);
  81. op->cancel(tr->req);
  82. tr->req = NULL;
  83. }
  84. static void
  85. tr_set_stopped(struct torrent *tp)
  86. {
  87. struct tracker *tr = tp->tr;
  88. btpd_ev_del(&tr->timer);
  89. tr->ttype = TIMER_NONE;
  90. if (tr->req != NULL)
  91. tr_cancel(tr);
  92. }
  93. static void
  94. tr_send(struct torrent *tp, enum tr_event event)
  95. {
  96. struct tracker *tr = tp->tr;
  97. struct tr_op *op = get_op(tr);
  98. tr->event = event;
  99. if (tr->req != NULL)
  100. tr_cancel(tr);
  101. if (m_tlast_req > btpd_seconds - REQ_DELAY) {
  102. m_tnext_req = max(m_tnext_req, m_tlast_req) + REQ_DELAY;
  103. tr->ttype = TIMER_RETRY;
  104. btpd_ev_add(&tr->timer,
  105. (& (struct timeval) { m_tnext_req - btpd_seconds, 0 }));
  106. return;
  107. }
  108. if ((op == NULL ||
  109. (tr->req = op->request(tp, event, get_url(tr))) == NULL)) {
  110. tr->nerrors++;
  111. if (tr->event == TR_EV_STOPPED && tr->nerrors >= STOP_ERRORS) {
  112. tr_set_stopped(tp);
  113. return;
  114. }
  115. next_url(tr);
  116. tr->ttype = TIMER_RETRY;
  117. btpd_ev_add(&tr->timer, (& (struct timeval) { 5, 0 }));
  118. } else {
  119. m_tlast_req = btpd_seconds;
  120. tr->ttype = TIMER_TIMEOUT;
  121. btpd_ev_add(&tr->timer, REQ_TIMEOUT);
  122. }
  123. }
  124. void
  125. tr_result(struct torrent *tp, enum tr_res res, int interval)
  126. {
  127. struct tracker *tr = tp->tr;
  128. tr->req = NULL;
  129. if (tr->event == TR_EV_STOPPED &&
  130. (res == TR_RES_OK || tr->nerrors >= STOP_ERRORS - 1))
  131. tr_set_stopped(tp);
  132. else if (res == TR_RES_OK) {
  133. good_url(tr);
  134. tr->interval = interval;
  135. tr->nerrors = 0;
  136. tr->ttype = TIMER_INTERVAL;
  137. btpd_ev_add(&tr->timer, (& (struct timeval) { tr->interval, 0}));
  138. } else {
  139. tr->nerrors++;
  140. tr->ttype = TIMER_RETRY;
  141. btpd_ev_add(&tr->timer, RETRY_WAIT);
  142. next_url(tr);
  143. }
  144. }
  145. static void
  146. timer_cb(int fd, short type, void *arg)
  147. {
  148. struct torrent *tp = arg;
  149. struct tracker *tr = tp->tr;
  150. switch (tr->ttype) {
  151. case TIMER_TIMEOUT:
  152. btpd_log(BTPD_L_ERROR, "Tracker request timed out for '%s'.\n",
  153. torrent_name(tp));
  154. tr->nerrors++;
  155. if (tr->event == TR_EV_STOPPED && tr->nerrors >= STOP_ERRORS) {
  156. tr_set_stopped(tp);
  157. break;
  158. }
  159. tr_cancel(tr);
  160. next_url(tr);
  161. case TIMER_RETRY:
  162. tr_send(tp, tr->event);
  163. break;
  164. case TIMER_INTERVAL:
  165. tr_send(tp, TR_EV_EMPTY);
  166. break;
  167. default:
  168. abort();
  169. }
  170. }
  171. int
  172. tr_create(struct torrent *tp, const char *mi)
  173. {
  174. tp->tr = btpd_calloc(1, sizeof(*tp->tr));
  175. if ((tp->tr->ann = mi_announce(mi)) == NULL)
  176. btpd_err("Out of memory.\n");
  177. evtimer_set(&tp->tr->timer, timer_cb, tp);
  178. return 0;
  179. }
  180. void
  181. tr_kill(struct torrent *tp)
  182. {
  183. struct tracker *tr = tp->tr;
  184. tp->tr = NULL;
  185. btpd_ev_del(&tr->timer);
  186. if (tr->req != NULL)
  187. tr_cancel(tr);
  188. mi_free_announce(tr->ann);
  189. free(tr);
  190. }
  191. void
  192. tr_start(struct torrent *tp)
  193. {
  194. tr_send(tp, TR_EV_STARTED);
  195. }
  196. void
  197. tr_refresh(struct torrent *tp)
  198. {
  199. tr_send(tp, TR_EV_EMPTY);
  200. }
  201. void
  202. tr_complete(struct torrent *tp)
  203. {
  204. tr_send(tp, TR_EV_COMPLETED);
  205. }
  206. void
  207. tr_stop(struct torrent *tp)
  208. {
  209. if (tp->tr->event == TR_EV_STOPPED)
  210. tr_set_stopped(tp);
  211. else
  212. tr_send(tp, TR_EV_STOPPED);
  213. }
  214. int
  215. tr_active(struct torrent *tp)
  216. {
  217. return tp->tr->ttype != TIMER_NONE;
  218. }
  219. unsigned
  220. tr_errors(struct torrent *tp)
  221. {
  222. return tp->tr->nerrors;
  223. }
  224. void
  225. tr_init(void)
  226. {
  227. tr_key = random();
  228. }