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.

314 lignes
6.9 KiB

  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <netinet/in.h>
  4. #include <netdb.h>
  5. #include <sys/wait.h>
  6. #include <sys/mman.h>
  7. #include <stdio.h>
  8. #include <errno.h>
  9. #include <stdlib.h>
  10. #include <unistd.h>
  11. #include <string.h>
  12. #include <inttypes.h>
  13. #include <curl/curl.h>
  14. #include "btpd.h"
  15. #include "tracker_req.h"
  16. #ifndef PRIu64
  17. #define PRIu64 "llu"
  18. #endif
  19. #define REQ_SIZE (getpagesize() * 2)
  20. struct tracker_req {
  21. enum tr_event tr_event;
  22. uint8_t info_hash[20];
  23. struct io_buffer *res;
  24. };
  25. static void
  26. maybe_connect_to(struct torrent *tp, const char *pinfo)
  27. {
  28. const char *pid = NULL;
  29. char *ip = NULL;
  30. int64_t port;
  31. size_t len;
  32. if (!benc_isdct(pinfo))
  33. return;
  34. if (benc_dget_str(pinfo, "peer id", &pid, &len) != 0 || len != 20)
  35. return;
  36. if (bcmp(btpd_get_peer_id(), pid, 20) == 0)
  37. return;
  38. if (torrent_has_peer(tp, pid))
  39. return;
  40. if (benc_dget_strz(pinfo, "ip", &ip, NULL) != 0)
  41. goto out;
  42. if (benc_dget_int64(pinfo, "port", &port) != 0)
  43. goto out;
  44. peer_create_out(tp, pid, ip, port);
  45. out:
  46. if (ip != NULL)
  47. free(ip);
  48. }
  49. static void
  50. tracker_done(pid_t pid, void *arg)
  51. {
  52. struct tracker_req *req = arg;
  53. int failed = 0;
  54. char *buf;
  55. const char *peers;
  56. uint32_t interval;
  57. struct torrent *tp;
  58. if ((tp = btpd_get_torrent(req->info_hash)) == NULL)
  59. goto out;
  60. if (benc_validate(req->res->buf, req->res->buf_off) != 0
  61. || !benc_isdct(req->res->buf)) {
  62. if (req->res->buf_off != 0) {
  63. fwrite(req->res->buf, 1, req->res->buf_off, (stdout));
  64. putchar('\n');
  65. }
  66. btpd_log(BTPD_L_ERROR, "Bad data from tracker.\n");
  67. failed = 1;
  68. goto out;
  69. }
  70. if ((benc_dget_strz(req->res->buf, "failure reason", &buf, NULL)) == 0) {
  71. btpd_log(BTPD_L_ERROR, "Tracker failure: %s.\n", buf);
  72. free(buf);
  73. failed = 1;
  74. goto out;
  75. }
  76. if ((benc_dget_uint32(req->res->buf, "interval", &interval)) != 0) {
  77. btpd_log(BTPD_L_ERROR, "Bad data from tracker.\n");
  78. failed = 1;
  79. goto out;
  80. }
  81. tp->tracker_time = btpd_seconds + interval;
  82. int error = 0;
  83. size_t length;
  84. if ((error = benc_dget_lst(req->res->buf, "peers", &peers)) == 0) {
  85. for (peers = benc_first(peers);
  86. peers != NULL && net_npeers < net_max_peers;
  87. peers = benc_next(peers))
  88. maybe_connect_to(tp, peers);
  89. }
  90. if (error == EINVAL) {
  91. error = benc_dget_str(req->res->buf, "peers", &peers, &length);
  92. if (error == 0 && length % 6 == 0) {
  93. size_t i;
  94. for (i = 0; i < length && net_npeers < net_max_peers; i += 6)
  95. peer_create_out_compact(tp, peers + i);
  96. }
  97. }
  98. if (error != 0) {
  99. btpd_log(BTPD_L_ERROR, "Bad data from tracker.\n");
  100. failed = 1;
  101. goto out;
  102. }
  103. out:
  104. if (failed) {
  105. if (req->tr_event == TR_STARTED) {
  106. btpd_log(BTPD_L_BTPD,
  107. "Start request failed for %s.\n", tp->relpath);
  108. torrent_unload(tp);
  109. } else
  110. tp->tracker_time = btpd_seconds + 10;
  111. }
  112. munmap(req->res, REQ_SIZE);
  113. free(req);
  114. }
  115. static const char *
  116. event2str(enum tr_event ev)
  117. {
  118. switch (ev) {
  119. case TR_STARTED:
  120. return "started";
  121. case TR_STOPPED:
  122. return "stopped";
  123. case TR_COMPLETED:
  124. return "completed";
  125. case TR_EMPTY:
  126. return "";
  127. default:
  128. btpd_err("Bad tracker event %d.\n", ev);
  129. return ""; // Shut GCC up!
  130. }
  131. }
  132. static int
  133. create_url(struct tracker_req *req, struct torrent *tp, char **url)
  134. {
  135. char e_hash[61], e_id[61];
  136. const uint8_t *peer_id = btpd_get_peer_id();
  137. char qc;
  138. int i;
  139. uint64_t left;
  140. const char *event;
  141. event = event2str(req->tr_event);
  142. qc = (strchr(tp->meta.announce, '?') == NULL) ? '?' : '&';
  143. for (i = 0; i < 20; i++)
  144. snprintf(e_hash + i * 3, 4, "%%%.2x", tp->meta.info_hash[i]);
  145. for (i = 0; i < 20; i++)
  146. snprintf(e_id + i * 3, 4, "%%%.2x", peer_id[i]);
  147. left = torrent_bytes_left(tp);
  148. i = asprintf(url, "%s%cinfo_hash=%s"
  149. "&peer_id=%s"
  150. "&port=%d"
  151. "&uploaded=%" PRIu64
  152. "&downloaded=%" PRIu64
  153. "&left=%" PRIu64
  154. "&compact=1"
  155. "%s%s",
  156. tp->meta.announce, qc, e_hash, e_id, net_port,
  157. tp->uploaded, tp->downloaded, left,
  158. req->tr_event == TR_EMPTY ? "" : "&event=",
  159. event);
  160. if (i < 0)
  161. return ENOMEM;
  162. return 0;
  163. }
  164. static size_t
  165. http_cb(void *ptr, size_t size, size_t nmemb, void *stream)
  166. {
  167. struct tracker_req *req = (struct tracker_req *)stream;
  168. size_t nbytes = size * nmemb;
  169. if (nbytes <= req->res->buf_len - req->res->buf_off) {
  170. memcpy(req->res->buf + req->res->buf_off, ptr, nbytes);
  171. req->res->buf_off += nbytes;
  172. return nbytes;
  173. }
  174. else
  175. return 0;
  176. }
  177. static void
  178. http_helper(struct tracker_req *req, struct torrent *tp)
  179. {
  180. char cerror[CURL_ERROR_SIZE];
  181. char fr[] = "failure reason";
  182. CURL *handle;
  183. char *url;
  184. int err;
  185. if (create_url(req, tp, &url) != 0)
  186. goto memory_error;
  187. if (curl_global_init(0) != 0)
  188. goto libcurl_error;
  189. if ((handle = curl_easy_init()) == NULL)
  190. goto libcurl_error;
  191. err = curl_easy_setopt(handle, CURLOPT_URL, url);
  192. if (err == 0)
  193. err = curl_easy_setopt(handle, CURLOPT_USERAGENT, BTPD_VERSION);
  194. if (err == 0)
  195. err = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, http_cb);
  196. if (err == 0)
  197. err = curl_easy_setopt(handle, CURLOPT_WRITEDATA, req);
  198. if (err == 0)
  199. err = curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, cerror);
  200. if (err != 0) {
  201. strncpy(cerror, curl_easy_strerror(err), CURL_ERROR_SIZE - 1);
  202. goto handle_error;
  203. }
  204. req->res->buf_off = 0;
  205. if (curl_easy_perform(handle) != 0)
  206. goto handle_error;
  207. #if 0
  208. curl_easy_cleanup(handle);
  209. curl_global_cleanup();
  210. free(url);
  211. #endif
  212. exit(0);
  213. memory_error:
  214. strncpy(cerror, "Out of memory", CURL_ERROR_SIZE - 1);
  215. goto handle_error;
  216. libcurl_error:
  217. strncpy(cerror, "Generic libcurl error", CURL_ERROR_SIZE - 1);
  218. goto handle_error;
  219. handle_error:
  220. req->res->buf_off =
  221. snprintf(req->res->buf, req->res->buf_len,
  222. "d%d:%s%d:%se", (int)strlen(fr), fr, (int)strlen(cerror), cerror);
  223. if (req->res->buf_off >= req->res->buf_len)
  224. req->res->buf_off = 0;
  225. exit(1);
  226. }
  227. void
  228. tracker_req(struct torrent *tp, enum tr_event tr_event)
  229. {
  230. struct tracker_req *req;
  231. pid_t pid;
  232. btpd_log(BTPD_L_TRACKER,
  233. "request for %s, event: %s.\n",
  234. tp->relpath, event2str(tr_event));
  235. req = (struct tracker_req *)btpd_calloc(1, sizeof(*req));
  236. req->res = mmap(NULL, REQ_SIZE, PROT_READ | PROT_WRITE,
  237. MAP_ANON | MAP_SHARED, -1, 0);
  238. if (req->res == MAP_FAILED)
  239. btpd_err("Failed mmap: %s\n", strerror(errno));
  240. req->res->buf_len = REQ_SIZE - sizeof(*req->res);
  241. req->res->buf_off = 0;
  242. req->res->buf = (char *)req->res + sizeof(*req->res);
  243. req->tr_event = tr_event;
  244. bcopy(tp->meta.info_hash, req->info_hash, 20);
  245. fflush(NULL);
  246. pid = fork();
  247. if (pid < 0) {
  248. btpd_err("Couldn't fork (%s).\n", strerror(errno));
  249. } else if (pid == 0) { // Child
  250. int nfiles = getdtablesize();
  251. for (int i = 0; i < nfiles; i++)
  252. close(i);
  253. http_helper(req, tp);
  254. } else
  255. btpd_add_child(pid, tracker_done, req);
  256. }