A clone of btpd with my configuration changes.
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

256 行
5.3 KiB

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