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.

186 lignes
4.8 KiB

  1. #include <arpa/inet.h>
  2. #include <netinet/in.h>
  3. #include <string.h>
  4. #include "btpd.h"
  5. #include "tracker_req.h"
  6. #include "http_client.h"
  7. #define MAX_DOWNLOAD (1 << 18) // 256kB
  8. static const char *m_tr_events[] = { "started", "stopped", "completed", "" };
  9. struct http_tr_req {
  10. struct torrent *tp;
  11. struct http_req *req;
  12. struct evbuffer *buf;
  13. enum tr_event event;
  14. };
  15. static void
  16. http_tr_free(struct http_tr_req *treq)
  17. {
  18. evbuffer_free(treq->buf);
  19. free(treq);
  20. }
  21. static void
  22. maybe_connect_to(struct torrent *tp, const char *pinfo)
  23. {
  24. const char *pid;
  25. char *ip;
  26. int port;
  27. size_t len;
  28. if ((pid = benc_dget_mem(pinfo, "peer id", &len)) == NULL || len != 20)
  29. return;
  30. if (bcmp(btpd_get_peer_id(), pid, 20) == 0)
  31. return;
  32. if (net_torrent_has_peer(tp->net, pid))
  33. return;
  34. if ((ip = benc_dget_str(pinfo, "ip", NULL)) == NULL)
  35. return;
  36. port = benc_dget_int(pinfo, "port");
  37. peer_create_out(tp->net, pid, ip, port);
  38. if (ip != NULL)
  39. free(ip);
  40. }
  41. static int
  42. parse_reply(struct torrent *tp, const char *content, size_t size, int parse,
  43. int *interval)
  44. {
  45. const char *buf;
  46. size_t len;
  47. const char *peers;
  48. if (benc_validate(content, size) != 0)
  49. goto bad_data;
  50. if ((buf = benc_dget_mem(content, "failure reason", &len)) != NULL) {
  51. btpd_log(BTPD_L_ERROR, "Tracker failure: '%.*s' for '%s'.\n",
  52. (int)len, buf, torrent_name(tp));
  53. return 1;
  54. }
  55. if (!parse) {
  56. *interval = -1;
  57. return 0;
  58. }
  59. if (!benc_dct_chk(content, 2, BE_INT, 1, "interval", BE_ANY, 1, "peers"))
  60. goto bad_data;
  61. *interval = benc_dget_int(content, "interval");
  62. if (*interval < 1)
  63. goto bad_data;
  64. peers = benc_dget_any(content, "peers");
  65. if (benc_islst(peers)) {
  66. for (peers = benc_first(peers);
  67. peers != NULL && net_npeers < net_max_peers;
  68. peers = benc_next(peers))
  69. maybe_connect_to(tp, peers);
  70. } else if (benc_isstr(peers)) {
  71. peers = benc_dget_mem(content, "peers", &len);
  72. for (size_t i = 0; i < len && net_npeers < net_max_peers; i += 6)
  73. peer_create_out_compact(tp->net, peers + i);
  74. } else
  75. goto bad_data;
  76. return 0;
  77. bad_data:
  78. btpd_log(BTPD_L_ERROR, "Bad data from tracker for '%s'.\n",
  79. torrent_name(tp));
  80. return 1;
  81. }
  82. static void
  83. http_cb(struct http_req *req, struct http_response *res, void *arg)
  84. {
  85. int interval;
  86. struct http_tr_req *treq = arg;
  87. switch (res->type) {
  88. case HTTP_T_ERR:
  89. btpd_log(BTPD_L_ERROR, "http request failed for '%s'.\n",
  90. torrent_name(treq->tp));
  91. tr_result(treq->tp, TR_RES_FAIL, -1);
  92. http_tr_free(treq);
  93. break;
  94. case HTTP_T_DATA:
  95. if (treq->buf->off + res->v.data.l > MAX_DOWNLOAD) {
  96. tr_result(treq->tp, TR_RES_FAIL, -1);
  97. http_tr_cancel(treq);
  98. break;
  99. }
  100. if (evbuffer_add(treq->buf, res->v.data.p, res->v.data.l) != 0)
  101. btpd_err("Out of memory.\n");
  102. break;
  103. case HTTP_T_DONE:
  104. if (parse_reply(treq->tp, treq->buf->buffer, treq->buf->off,
  105. treq->event != TR_EV_STOPPED, &interval) == 0)
  106. tr_result(treq->tp, TR_RES_OK, interval);
  107. else
  108. tr_result(treq->tp, TR_RES_FAIL, -1);
  109. http_tr_free(treq);
  110. break;
  111. default:
  112. break;
  113. }
  114. }
  115. struct http_tr_req *
  116. http_tr_req(struct torrent *tp, enum tr_event event, const char *aurl)
  117. {
  118. char e_hash[61], e_id[61], ip_arg[INET_ADDRSTRLEN + 4], url[512], qc;
  119. const uint8_t *peer_id = btpd_get_peer_id();
  120. qc = (strchr(aurl, '?') == NULL) ? '?' : '&';
  121. for (int i = 0; i < 20; i++)
  122. snprintf(e_hash + i * 3, 4, "%%%.2x", tp->tl->hash[i]);
  123. for (int i = 0; i < 20; i++)
  124. snprintf(e_id + i * 3, 4, "%%%.2x", peer_id[i]);
  125. if (tr_ip_arg == INADDR_ANY)
  126. ip_arg[0] = '\0';
  127. else {
  128. bcopy("&ip=", ip_arg, 4);
  129. inet_ntop(AF_INET, &tr_ip_arg, ip_arg + 4, sizeof(ip_arg) - 4);
  130. }
  131. snprintf(url, sizeof(url),
  132. "%s%cinfo_hash=%s&peer_id=%s&key=%ld%s&port=%d&uploaded=%llu"
  133. "&downloaded=%llu&left=%llu&compact=1%s%s",
  134. aurl, qc, e_hash, e_id, tr_key, ip_arg, net_port,
  135. tp->net->uploaded, tp->net->downloaded,
  136. (long long)tp->total_length - cm_content(tp),
  137. event == TR_EV_EMPTY ? "" : "&event=", m_tr_events[event]);
  138. struct http_tr_req *treq = btpd_calloc(1, sizeof(*treq));
  139. if (!http_get(&treq->req, url, "User-Agent: " BTPD_VERSION "\r\n",
  140. http_cb, treq)) {
  141. free(treq);
  142. return NULL;
  143. }
  144. if ((treq->buf = evbuffer_new()) == NULL)
  145. btpd_err("Out of memory.\n");
  146. treq->tp = tp;
  147. treq->event = event;
  148. return treq;
  149. }
  150. void
  151. http_tr_cancel(struct http_tr_req *treq)
  152. {
  153. http_cancel(treq->req);
  154. http_tr_free(treq);
  155. }