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.

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