A clone of btpd with my configuration changes.
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

186 lines
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. }