A clone of btpd with my configuration changes.
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

314 行
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. }