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.

255 lignes
6.8 KiB

  1. #include "btpd.h"
  2. #include <http_client.h>
  3. #include <iobuf.h>
  4. #define MAX_DOWNLOAD (1 << 18) // 256kB
  5. static const char *m_tr_events[] = { "started", "stopped", "completed", "" };
  6. struct httptr_req {
  7. struct torrent *tp;
  8. struct tr_tier *tr;
  9. struct http_req *req;
  10. struct iobuf buf;
  11. struct fdev ioev;
  12. struct timeout timer;
  13. nameconn_t nc;
  14. int sd;
  15. enum tr_event event;
  16. };
  17. static void
  18. httptr_free(struct httptr_req *treq)
  19. {
  20. if (treq->sd != -1) {
  21. btpd_ev_del(&treq->ioev);
  22. close(treq->sd);
  23. }
  24. btpd_timer_del(&treq->timer);
  25. iobuf_free(&treq->buf);
  26. free(treq);
  27. }
  28. static void
  29. maybe_connect_to(struct torrent *tp, const char *pinfo)
  30. {
  31. const char *pid;
  32. char *ip;
  33. int port;
  34. size_t len;
  35. if ((pid = benc_dget_mem(pinfo, "peer id", &len)) == NULL || len != 20)
  36. return;
  37. if (bcmp(btpd_get_peer_id(), pid, 20) == 0)
  38. return;
  39. if (net_torrent_has_peer(tp->net, pid))
  40. return;
  41. if ((ip = benc_dget_str(pinfo, "ip", NULL)) == NULL)
  42. return;
  43. port = benc_dget_int(pinfo, "port");
  44. peer_create_out(tp->net, pid, ip, port);
  45. if (ip != NULL)
  46. free(ip);
  47. }
  48. static void
  49. parse_reply(struct torrent *tp, struct tr_response *res, const char *content,
  50. size_t size)
  51. {
  52. const char *buf;
  53. size_t len;
  54. const char *peers;
  55. const char *v6key[] = {"peers6", "peers_ipv6"};
  56. if (benc_validate(content, size) != 0)
  57. goto bad_data;
  58. if ((buf = benc_dget_any(content, "failure reason")) != NULL) {
  59. if (!benc_isstr(buf))
  60. goto bad_data;
  61. res->type = TR_RES_FAIL;
  62. res->mi_failure = buf;
  63. return;
  64. }
  65. buf = benc_dget_any(content, "interval");
  66. if (buf != NULL && benc_isint(buf))
  67. res->interval = benc_int(buf, NULL);
  68. if ((peers = benc_dget_any(content, "peers")) == NULL)
  69. goto after_peers;
  70. if (benc_islst(peers)) {
  71. for (peers = benc_first(peers);
  72. peers != NULL && net_npeers < net_max_peers;
  73. peers = benc_next(peers))
  74. maybe_connect_to(tp, peers);
  75. } else if (benc_isstr(peers)) {
  76. if (net_ipv4) {
  77. peers = benc_dget_mem(content, "peers", &len);
  78. for (size_t i = 0; i < len && net_npeers < net_max_peers; i += 6)
  79. peer_create_out_compact(tp->net, AF_INET, peers + i);
  80. }
  81. } else
  82. goto bad_data;
  83. after_peers:
  84. if (!net_ipv6)
  85. goto after_peers6;
  86. for (int k = 0; k < 2; k++) {
  87. peers = benc_dget_any(content, v6key[k]);
  88. if (peers != NULL && benc_isstr(peers)) {
  89. peers = benc_dget_mem(content, v6key[k], &len);
  90. for (size_t i = 0; i < len && net_npeers < net_max_peers; i += 18)
  91. peer_create_out_compact(tp->net, AF_INET6, peers + i);
  92. }
  93. }
  94. after_peers6:
  95. res->type = TR_RES_OK;
  96. return;
  97. bad_data:
  98. res->type = TR_RES_BAD;
  99. }
  100. static void
  101. http_cb(struct http_req *req, struct http_response *res, void *arg)
  102. {
  103. struct httptr_req *treq = arg;
  104. struct tr_response tres = {0, NULL, -1 };
  105. switch (res->type) {
  106. case HTTP_T_ERR:
  107. tres.type = TR_RES_BAD;
  108. tr_result(treq->tr, &tres);
  109. httptr_free(treq);
  110. break;
  111. case HTTP_T_DATA:
  112. if (treq->buf.off + res->v.data.l > MAX_DOWNLOAD) {
  113. tres.type = TR_RES_BAD;
  114. tr_result(treq->tr, &tres);
  115. httptr_cancel(treq);
  116. break;
  117. }
  118. if (!iobuf_write(&treq->buf, res->v.data.p, res->v.data.l))
  119. btpd_err("Out of memory.\n");
  120. break;
  121. case HTTP_T_DONE:
  122. if (treq->event == TR_EV_STOPPED) {
  123. tres.type = TR_RES_OK;
  124. tr_result(treq->tr, &tres);
  125. } else {
  126. parse_reply(treq->tp, &tres, treq->buf.buf, treq->buf.off);
  127. tr_result(treq->tr, &tres);
  128. }
  129. httptr_free(treq);
  130. break;
  131. default:
  132. break;
  133. }
  134. }
  135. static void
  136. httptr_io_cb(int sd, short type, void *arg)
  137. {
  138. struct tr_response res;
  139. struct httptr_req *treq = arg;
  140. switch (type) {
  141. case EV_READ:
  142. if (http_read(treq->req, sd) && !http_want_read(treq->req))
  143. btpd_ev_disable(&treq->ioev, EV_READ);
  144. break;
  145. case EV_WRITE:
  146. if (http_write(treq->req, sd) && !http_want_write(treq->req))
  147. btpd_ev_disable(&treq->ioev, EV_WRITE);
  148. break;
  149. case EV_TIMEOUT:
  150. res.type = TR_RES_CONN;
  151. tr_result(treq->tr, &res);
  152. httptr_cancel(treq);
  153. break;
  154. default:
  155. abort();
  156. }
  157. }
  158. static void
  159. httptr_nc_cb(void *arg, int error, int sd)
  160. {
  161. struct tr_response res;
  162. struct httptr_req *treq = arg;
  163. if (error) {
  164. res.type = TR_RES_CONN;
  165. tr_result(treq->tr, &res);
  166. http_cancel(treq->req);
  167. httptr_free(treq);
  168. } else {
  169. treq->sd = sd;
  170. uint16_t flags =
  171. (http_want_read(treq->req) ? EV_READ : 0) |
  172. (http_want_write(treq->req) ? EV_WRITE : 0);
  173. btpd_ev_new(&treq->ioev, sd, flags, httptr_io_cb, treq);
  174. btpd_timer_add(&treq->timer, (& (struct timespec) { 30, 0 }));
  175. }
  176. }
  177. struct httptr_req *
  178. httptr_req(struct torrent *tp, struct tr_tier *tr, const char *aurl,
  179. enum tr_event event)
  180. {
  181. char e_hash[61], e_id[61], url[512], qc;
  182. const uint8_t *peer_id = btpd_get_peer_id();
  183. struct http_url *http_url;
  184. qc = (strchr(aurl, '?') == NULL) ? '?' : '&';
  185. for (int i = 0; i < 20; i++)
  186. snprintf(e_hash + i * 3, 4, "%%%.2x", tp->tl->hash[i]);
  187. for (int i = 0; i < 20; i++)
  188. snprintf(e_id + i * 3, 4, "%%%.2x", peer_id[i]);
  189. snprintf(url, sizeof(url),
  190. "%s%cinfo_hash=%s&peer_id=%s&key=%ld%s%s&port=%d&uploaded=%llu"
  191. "&downloaded=%llu&left=%llu&compact=1%s%s",
  192. aurl, qc, e_hash, e_id, tr_key,
  193. tr_ip_arg == NULL ? "" : "&ip=", tr_ip_arg == NULL ? "" : tr_ip_arg,
  194. net_port, tp->net->uploaded, tp->net->downloaded,
  195. (long long)tp->total_length - cm_content(tp),
  196. event == TR_EV_EMPTY ? "" : "&event=", m_tr_events[event]);
  197. struct httptr_req *treq = btpd_calloc(1, sizeof(*treq));
  198. if (!http_get(&treq->req, url, "User-Agent: " BTPD_VERSION "\r\n",
  199. http_cb, treq)) {
  200. free(treq);
  201. return NULL;
  202. }
  203. treq->tp = tp;
  204. treq->tr = tr;
  205. treq->event = event;
  206. treq->buf = iobuf_init(4096);
  207. if (treq->buf.error)
  208. btpd_err("Out of memory.\n");
  209. treq->tr = tr;
  210. treq->sd = -1;
  211. http_url = http_url_get(treq->req);
  212. treq->nc = btpd_name_connect(http_url->host, http_url->port,
  213. httptr_nc_cb, treq);
  214. evtimer_init(&treq->timer, httptr_io_cb, treq);
  215. btpd_timer_add(&treq->timer, (& (struct timespec) { 60, 0 }));
  216. return treq;
  217. }
  218. void
  219. httptr_cancel(struct httptr_req *treq)
  220. {
  221. if (treq->sd == -1)
  222. btpd_name_connect_cancel(treq->nc);
  223. http_cancel(treq->req);
  224. httptr_free(treq);
  225. }