A clone of btpd with my configuration changes.
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

255 rindas
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. }