A clone of btpd with my configuration changes.

269 lines
6.2 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. event_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. event_add(&tr->timer, (& (struct timeval) { tr->interval, 0 }));
  116. } else {
  117. tr->nerrors++;
  118. tr->ttype = TIMER_RETRY;
  119. event_add(&tr->timer, RETRY_WAIT);
  120. }
  121. if (tr->event == TR_EV_STOPPED && (tr->nerrors == 0 || tr->nerrors >= 5))
  122. tr_set_stopped(tp);
  123. }
  124. static void
  125. timer_cb(int fd, short type, void *arg)
  126. {
  127. struct torrent *tp = arg;
  128. struct tracker *tr = tp->tr;
  129. switch (tr->ttype) {
  130. case TIMER_TIMEOUT:
  131. btpd_log(BTPD_L_ERROR, "Tracker request timed out for '%s'.\n",
  132. torrent_name(tp));
  133. tr->nerrors++;
  134. if (tr->event == TR_EV_STOPPED && tr->nerrors >= 5) {
  135. tr_set_stopped(tp);
  136. break;
  137. }
  138. case TIMER_RETRY:
  139. tr_send(tp, tr->event);
  140. break;
  141. case TIMER_INTERVAL:
  142. tr_send(tp, TR_EV_EMPTY);
  143. break;
  144. default:
  145. abort();
  146. }
  147. }
  148. static void
  149. tr_send(struct torrent *tp, enum tr_event event)
  150. {
  151. char e_hash[61], e_id[61], qc;;
  152. const uint8_t *peer_id = btpd_get_peer_id();
  153. struct tracker *tr = tp->tr;
  154. tr->event = event;
  155. if (tr->ttype == TIMER_TIMEOUT)
  156. http_cancel(tr->req);
  157. tr->ttype = TIMER_TIMEOUT;
  158. event_add(&tr->timer, REQ_TIMEOUT);
  159. qc = (strchr(tp->meta.announce, '?') == NULL) ? '?' : '&';
  160. for (int i = 0; i < 20; i++)
  161. snprintf(e_hash + i * 3, 4, "%%%.2x", tp->meta.info_hash[i]);
  162. for (int i = 0; i < 20; i++)
  163. snprintf(e_id + i * 3, 4, "%%%.2x", peer_id[i]);
  164. http_get(&tr->req, http_cb, tp,
  165. "%s%cinfo_hash=%s&peer_id=%s&port=%d&uploaded=%ju"
  166. "&downloaded=%ju&left=%ju&compact=1%s%s",
  167. tp->meta.announce, qc, e_hash, e_id, net_port,
  168. (intmax_t)tp->net->uploaded, (intmax_t)tp->net->downloaded,
  169. (intmax_t)tp->meta.total_length - cm_get_size(tp),
  170. event == TR_EV_EMPTY ? "" : "&event=", m_events[event]);
  171. }
  172. int
  173. tr_create(struct torrent *tp)
  174. {
  175. if (strncmp(tp->meta.announce, "http://", sizeof("http://") - 1) != 0) {
  176. btpd_log(BTPD_L_ERROR,
  177. "btpd currently has no support for the protocol specified in "
  178. "'%s'.\n", tp->meta.announce);
  179. return EINVAL;
  180. }
  181. tp->tr = btpd_calloc(1, sizeof(*tp->tr));
  182. evtimer_set(&tp->tr->timer, timer_cb, tp);
  183. return 0;
  184. }
  185. void
  186. tr_kill(struct torrent *tp)
  187. {
  188. struct tracker *tr = tp->tr;
  189. tp->tr = NULL;
  190. event_del(&tr->timer);
  191. if (tr->req != NULL)
  192. http_cancel(tr->req);
  193. free(tr);
  194. }
  195. void
  196. tr_start(struct torrent *tp)
  197. {
  198. tr_send(tp, TR_EV_STARTED);
  199. }
  200. void
  201. tr_refresh(struct torrent *tp)
  202. {
  203. tr_send(tp, TR_EV_EMPTY);
  204. }
  205. void
  206. tr_complete(struct torrent *tp)
  207. {
  208. tr_send(tp, TR_EV_COMPLETED);
  209. }
  210. void
  211. tr_stop(struct torrent *tp)
  212. {
  213. if (tp->tr->event == TR_EV_STOPPED)
  214. tr_set_stopped(tp);
  215. else
  216. tr_send(tp, TR_EV_STOPPED);
  217. }
  218. int
  219. tr_active(struct torrent *tp)
  220. {
  221. return tp->tr->ttype != TIMER_NONE;
  222. }
  223. unsigned
  224. tr_errors(struct torrent *tp)
  225. {
  226. return tp->tr->nerrors;
  227. }