A clone of btpd with my configuration changes.

272 lines
6.3 KiB

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include "btpd.h"
  4. #include "benc.h"
  5. #include "subr.h"
  6. #include "http.h"
  7. #include "tracker_req.h"
  8. #define REQ_TIMEOUT (& (struct timeval) { 120, 0 })
  9. #define RETRY_WAIT (& (struct timeval) { rand_between(35, 70), 0 })
  10. enum tr_event {
  11. TR_EV_STARTED,
  12. TR_EV_STOPPED,
  13. TR_EV_COMPLETED,
  14. TR_EV_EMPTY
  15. };
  16. static const char *m_events[] = { "started", "stopped", "completed", "" };
  17. enum timer_type {
  18. TIMER_NONE,
  19. TIMER_TIMEOUT,
  20. TIMER_INTERVAL,
  21. TIMER_RETRY
  22. };
  23. struct tracker {
  24. enum timer_type ttype;
  25. enum tr_event event;
  26. int interval;
  27. unsigned nerrors;
  28. struct http *req;
  29. struct event timer;
  30. };
  31. static void tr_send(struct torrent *tp, enum tr_event event);
  32. static void
  33. maybe_connect_to(struct torrent *tp, const char *pinfo)
  34. {
  35. const char *pid;
  36. char *ip;
  37. int port;
  38. size_t len;
  39. if ((pid = benc_dget_mem(pinfo, "peer id", &len)) == NULL || len != 20)
  40. return;
  41. if (bcmp(btpd_get_peer_id(), pid, 20) == 0)
  42. return;
  43. if (net_torrent_has_peer(tp->net, pid))
  44. return;
  45. if ((ip = benc_dget_str(pinfo, "ip", NULL)) == NULL)
  46. return;
  47. port = benc_dget_int(pinfo, "port");
  48. peer_create_out(tp->net, pid, ip, port);
  49. if (ip != NULL)
  50. free(ip);
  51. }
  52. static int
  53. parse_reply(struct torrent *tp, const char *content, size_t size, int parse)
  54. {
  55. const char *buf;
  56. size_t len;
  57. const char *peers;
  58. int interval;
  59. if (benc_validate(content, size) != 0)
  60. goto bad_data;
  61. if ((buf = benc_dget_mem(content, "failure reason", &len)) != NULL) {
  62. btpd_log(BTPD_L_ERROR, "Tracker failure: '%.*s' for '%s'.\n",
  63. (int)len, buf, torrent_name(tp));
  64. return 1;
  65. }
  66. if (!parse)
  67. return 0;
  68. if (!benc_dct_chk(content, 2, BE_INT, 1, "interval", BE_ANY, 1, "peers"))
  69. goto bad_data;
  70. interval = benc_dget_int(content, "interval");
  71. if (interval < 1)
  72. goto bad_data;
  73. tp->tr->interval = interval;
  74. peers = benc_dget_any(content, "peers");
  75. if (benc_islst(peers)) {
  76. for (peers = benc_first(peers);
  77. peers != NULL && net_npeers < net_max_peers;
  78. peers = benc_next(peers))
  79. maybe_connect_to(tp, peers);
  80. } else if (benc_isstr(peers)) {
  81. peers = benc_dget_mem(content, "peers", &len);
  82. for (size_t i = 0; i < len && net_npeers < net_max_peers; i += 6)
  83. peer_create_out_compact(tp->net, peers + i);
  84. } else
  85. goto bad_data;
  86. return 0;
  87. bad_data:
  88. btpd_log(BTPD_L_ERROR, "Bad data from tracker for '%s'.\n",
  89. torrent_name(tp));
  90. return 1;
  91. }
  92. static void
  93. tr_set_stopped(struct torrent *tp)
  94. {
  95. struct tracker *tr = tp->tr;
  96. btpd_ev_del(&tr->timer);
  97. tr->ttype = TIMER_NONE;
  98. if (tr->req != NULL) {
  99. http_cancel(tr->req);
  100. tr->req = NULL;
  101. }
  102. torrent_on_tr_stopped(tp);
  103. }
  104. static void
  105. http_cb(struct http *req, struct http_res *res, void *arg)
  106. {
  107. struct torrent *tp = arg;
  108. struct tracker *tr = tp->tr;
  109. assert(tr->ttype == TIMER_TIMEOUT);
  110. tr->req = NULL;
  111. if (res->res == HRES_OK && parse_reply(tp, res->content, res->length,
  112. tr->event != TR_EV_STOPPED) == 0) {
  113. tr->nerrors = 0;
  114. tr->ttype = TIMER_INTERVAL;
  115. btpd_ev_add(&tr->timer, (& (struct timeval) { tr->interval, 0 }));
  116. } else {
  117. if (res->res == HRES_FAIL)
  118. btpd_log(BTPD_L_BTPD, "Tracker request for '%s' failed (%s).\n",
  119. torrent_name(tp), res->errmsg);
  120. tr->nerrors++;
  121. tr->ttype = TIMER_RETRY;
  122. btpd_ev_add(&tr->timer, RETRY_WAIT);
  123. }
  124. if (tr->event == TR_EV_STOPPED && (tr->nerrors == 0 || tr->nerrors >= 5))
  125. tr_set_stopped(tp);
  126. }
  127. static void
  128. timer_cb(int fd, short type, void *arg)
  129. {
  130. struct torrent *tp = arg;
  131. struct tracker *tr = tp->tr;
  132. switch (tr->ttype) {
  133. case TIMER_TIMEOUT:
  134. btpd_log(BTPD_L_ERROR, "Tracker request timed out for '%s'.\n",
  135. torrent_name(tp));
  136. tr->nerrors++;
  137. if (tr->event == TR_EV_STOPPED && tr->nerrors >= 5) {
  138. tr_set_stopped(tp);
  139. break;
  140. }
  141. case TIMER_RETRY:
  142. tr_send(tp, tr->event);
  143. break;
  144. case TIMER_INTERVAL:
  145. tr_send(tp, TR_EV_EMPTY);
  146. break;
  147. default:
  148. abort();
  149. }
  150. }
  151. static void
  152. tr_send(struct torrent *tp, enum tr_event event)
  153. {
  154. char e_hash[61], e_id[61], qc;;
  155. const uint8_t *peer_id = btpd_get_peer_id();
  156. struct tracker *tr = tp->tr;
  157. tr->event = event;
  158. if (tr->ttype == TIMER_TIMEOUT)
  159. http_cancel(tr->req);
  160. tr->ttype = TIMER_TIMEOUT;
  161. btpd_ev_add(&tr->timer, REQ_TIMEOUT);
  162. qc = (strchr(tp->meta.announce, '?') == NULL) ? '?' : '&';
  163. for (int i = 0; i < 20; i++)
  164. snprintf(e_hash + i * 3, 4, "%%%.2x", tp->meta.info_hash[i]);
  165. for (int i = 0; i < 20; i++)
  166. snprintf(e_id + i * 3, 4, "%%%.2x", peer_id[i]);
  167. http_get(&tr->req, http_cb, tp,
  168. "%s%cinfo_hash=%s&peer_id=%s&port=%d&uploaded=%llu"
  169. "&downloaded=%llu&left=%llu&compact=1%s%s",
  170. tp->meta.announce, qc, e_hash, e_id, net_port,
  171. tp->net->uploaded, tp->net->downloaded,
  172. (long long)tp->meta.total_length - cm_content(tp),
  173. event == TR_EV_EMPTY ? "" : "&event=", m_events[event]);
  174. }
  175. int
  176. tr_create(struct torrent *tp)
  177. {
  178. if (strncmp(tp->meta.announce, "http://", sizeof("http://") - 1) != 0) {
  179. btpd_log(BTPD_L_ERROR,
  180. "btpd currently has no support for the protocol specified in "
  181. "'%s'.\n", tp->meta.announce);
  182. return EINVAL;
  183. }
  184. tp->tr = btpd_calloc(1, sizeof(*tp->tr));
  185. evtimer_set(&tp->tr->timer, timer_cb, tp);
  186. return 0;
  187. }
  188. void
  189. tr_kill(struct torrent *tp)
  190. {
  191. struct tracker *tr = tp->tr;
  192. tp->tr = NULL;
  193. btpd_ev_del(&tr->timer);
  194. if (tr->req != NULL)
  195. http_cancel(tr->req);
  196. free(tr);
  197. }
  198. void
  199. tr_start(struct torrent *tp)
  200. {
  201. tr_send(tp, TR_EV_STARTED);
  202. }
  203. void
  204. tr_refresh(struct torrent *tp)
  205. {
  206. tr_send(tp, TR_EV_EMPTY);
  207. }
  208. void
  209. tr_complete(struct torrent *tp)
  210. {
  211. tr_send(tp, TR_EV_COMPLETED);
  212. }
  213. void
  214. tr_stop(struct torrent *tp)
  215. {
  216. if (tp->tr->event == TR_EV_STOPPED)
  217. tr_set_stopped(tp);
  218. else
  219. tr_send(tp, TR_EV_STOPPED);
  220. }
  221. int
  222. tr_active(struct torrent *tp)
  223. {
  224. return tp->tr->ttype != TIMER_NONE;
  225. }
  226. unsigned
  227. tr_errors(struct torrent *tp)
  228. {
  229. return tp->tr->nerrors;
  230. }