A clone of btpd with my configuration changes.
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

467 líneas
12 KiB

  1. #include "btpd.h"
  2. #include <sys/mman.h>
  3. #include <dirent.h>
  4. #include <iobuf.h>
  5. HTBL_TYPE(numtbl, tlib, unsigned, num, nchain);
  6. HTBL_TYPE(hashtbl, tlib, uint8_t, hash, hchain);
  7. static unsigned m_nextnum;
  8. static unsigned m_ntlibs;
  9. static struct numtbl *m_numtbl;
  10. static struct hashtbl *m_hashtbl;
  11. unsigned
  12. tlib_count(void)
  13. {
  14. return m_ntlibs;
  15. }
  16. struct tlib *
  17. tlib_by_num(unsigned num)
  18. {
  19. return numtbl_find(m_numtbl, &num);
  20. }
  21. struct tlib *
  22. tlib_by_hash(const uint8_t *hash)
  23. {
  24. return hashtbl_find(m_hashtbl, hash);
  25. }
  26. void
  27. tlib_kill(struct tlib *tl)
  28. {
  29. numtbl_remove(m_numtbl, &tl->num);
  30. hashtbl_remove(m_hashtbl, tl->hash);
  31. if (tl->name != NULL)
  32. free(tl->name);
  33. if (tl->dir != NULL)
  34. free(tl->dir);
  35. free(tl);
  36. m_ntlibs--;
  37. }
  38. struct tlib *
  39. tlib_create(const uint8_t *hash)
  40. {
  41. struct tlib *tl = btpd_calloc(1, sizeof(*tl));
  42. char hex[SHAHEXSIZE];
  43. bin2hex(hash, hex, 20);
  44. tl->num = m_nextnum;
  45. bcopy(hash, tl->hash, 20);
  46. m_nextnum++;
  47. m_ntlibs++;
  48. numtbl_insert(m_numtbl, tl);
  49. hashtbl_insert(m_hashtbl, tl);
  50. return tl;
  51. }
  52. int
  53. tlib_del(struct tlib *tl)
  54. {
  55. char relpath[RELPATH_SIZE];
  56. char path[PATH_MAX];
  57. DIR *dir;
  58. struct dirent *de;
  59. assert(tl->tp == NULL);
  60. snprintf(path, PATH_MAX, "torrents/%s", bin2hex(tl->hash, relpath, 20));
  61. if ((dir = opendir(path)) != NULL) {
  62. while ((de = readdir(dir)) != NULL) {
  63. if (strcmp(".", de->d_name) == 0 || strcmp("..", de->d_name) == 0)
  64. continue;
  65. snprintf(path, PATH_MAX, "torrents/%s/%s", relpath, de->d_name);
  66. remove(path);
  67. }
  68. closedir(dir);
  69. }
  70. snprintf(path, PATH_MAX, "torrents/%s", relpath);
  71. remove(path);
  72. tlib_kill(tl);
  73. return 0;
  74. }
  75. static void
  76. dct_subst_save(FILE *fp, const char *dct1, const char *dct2)
  77. {
  78. fprintf(fp, "d");
  79. const char *k1 = benc_first(dct1), *k2 = benc_first(dct2);
  80. const char *val, *str, *rest;
  81. size_t len;
  82. while (k1 != NULL && k2 != NULL) {
  83. int test = benc_strcmp(k1, k2);
  84. if (test < 0) {
  85. str = benc_mem(k1, &len, &val);
  86. fprintf(fp, "%d:%.*s", (int)len, (int)len, str);
  87. fwrite(val, 1, benc_length(val), fp);
  88. k1 = benc_next(val);
  89. } else {
  90. str = benc_mem(k2, &len, &val);
  91. fprintf(fp, "%d:%.*s", (int)len, (int)len, str);
  92. fwrite(val, 1, benc_length(val), fp);
  93. k2 = benc_next(val);
  94. if (test == 0)
  95. k1 = benc_next(benc_next(k1));
  96. }
  97. }
  98. rest = k1 != NULL ? k1 : k2;
  99. while (rest != NULL) {
  100. str = benc_mem(rest, &len, &val);
  101. fprintf(fp, "%d:%.*s", (int)len, (int)len, str);
  102. fwrite(val, 1, benc_length(val), fp);
  103. rest = benc_next(val);
  104. }
  105. fprintf(fp, "e");
  106. }
  107. static int
  108. valid_info(char *buf, size_t len)
  109. {
  110. size_t slen;
  111. const char *info;
  112. if (benc_validate(buf, len) != 0)
  113. return 0;
  114. if ((info = benc_dget_dct(buf, "info")) == NULL)
  115. return 0;
  116. if (benc_dget_mem(info, "name", &slen) == NULL || slen == 0)
  117. return 0;
  118. if ((benc_dget_mem(info, "dir", &slen) == NULL ||
  119. (slen == 0 || slen >= PATH_MAX)))
  120. return 0;
  121. return 1;
  122. }
  123. static void
  124. load_info(struct tlib *tl, const char *path)
  125. {
  126. size_t size = 1 << 14;
  127. char buf[size];
  128. const char *info;
  129. if (read_file(path, buf, &size) == NULL) {
  130. btpd_log(BTPD_L_ERROR, "couldn't load '%s' (%s).\n", path,
  131. strerror(errno));
  132. return;
  133. }
  134. if (!valid_info(buf, size)) {
  135. btpd_log(BTPD_L_ERROR, "bad info file '%s'.\n", path);
  136. return;
  137. }
  138. info = benc_dget_dct(buf, "info");
  139. tl->name = benc_dget_str(info, "name", NULL);
  140. tl->dir = benc_dget_str(info, "dir", NULL);
  141. tl->tot_up = benc_dget_int(info, "total upload");
  142. tl->tot_down = benc_dget_int(info, "total download");
  143. tl->content_size = benc_dget_int(info, "content size");
  144. tl->content_have = benc_dget_int(info, "content have");
  145. if (tl->name == NULL || tl->dir == NULL)
  146. btpd_err("Out of memory.\n");
  147. }
  148. static void
  149. save_info(struct tlib *tl)
  150. {
  151. FILE *fp;
  152. char relpath[SHAHEXSIZE], path[PATH_MAX], wpath[PATH_MAX];
  153. struct iobuf iob = iobuf_init(1 << 10);
  154. iobuf_print(&iob,
  155. "d4:infod"
  156. "12:content havei%llde12:content sizei%llde"
  157. "3:dir%d:%s4:name%d:%s"
  158. "14:total downloadi%llde12:total uploadi%llde"
  159. "ee",
  160. (long long)tl->content_have, (long long)tl->content_size,
  161. (int)strlen(tl->dir), tl->dir, (int)strlen(tl->name), tl->name,
  162. tl->tot_down, tl->tot_up);
  163. if (iob.error)
  164. btpd_err("Out of memory.\n");
  165. bin2hex(tl->hash, relpath, 20);
  166. snprintf(path, PATH_MAX, "torrents/%s/info", relpath);
  167. snprintf(wpath, PATH_MAX, "%s.write", path);
  168. if ((fp = fopen(wpath, "w")) == NULL)
  169. btpd_err("failed to open '%s' (%s).\n", wpath, strerror(errno));
  170. dct_subst_save(fp, "de", iob.buf);
  171. iobuf_free(&iob);
  172. if ((fflush(fp) == EOF || fsync(fileno(fp)) != 0
  173. || ferror(fp) || fclose(fp) != 0))
  174. btpd_err("failed to write '%s'.\n", wpath);
  175. if (rename(wpath, path) != 0)
  176. btpd_err("failed to rename: '%s' -> '%s' (%s).\n", wpath, path,
  177. strerror(errno));
  178. }
  179. void
  180. tlib_update_info(struct tlib *tl, int only_file)
  181. {
  182. struct tlib tmp;
  183. assert(tl->tp != NULL);
  184. if (only_file) {
  185. tmp = *tl;
  186. tl = &tmp;
  187. }
  188. tl->tot_down += tl->tp->net->downloaded;
  189. tl->tot_up += tl->tp->net->uploaded;
  190. tl->content_have = cm_content(tl->tp);
  191. tl->content_size = tl->tp->total_length;
  192. save_info(tl);
  193. }
  194. static void
  195. write_torrent(const char *mi, size_t mi_size, const char *path)
  196. {
  197. FILE *fp;
  198. if ((fp = fopen(path, "w")) == NULL)
  199. goto err;
  200. if (fwrite(mi, mi_size, 1, fp) != 1) {
  201. errno = EIO;
  202. goto err;
  203. }
  204. if (fclose(fp) != 0)
  205. goto err;
  206. return;
  207. err:
  208. btpd_err("failed to write metainfo '%s' (%s).\n", path, strerror(errno));
  209. }
  210. struct tlib *
  211. tlib_add(const uint8_t *hash, const char *mi, size_t mi_size,
  212. const char *content, char *name)
  213. {
  214. struct tlib *tl = tlib_create(hash);
  215. char relpath[RELPATH_SIZE], file[PATH_MAX];
  216. bin2hex(hash, relpath, 20);
  217. if (name == NULL)
  218. if ((name = mi_name(mi)) == NULL)
  219. btpd_err("out of memory.\n");
  220. tl->content_size = mi_total_length(mi);
  221. tl->name = name;
  222. tl->dir = strdup(content);
  223. if (tl->name == NULL || tl->dir == NULL)
  224. btpd_err("out of memory.\n");
  225. snprintf(file, PATH_MAX, "torrents/%s", relpath);
  226. if (mkdir(file, 0777) != 0)
  227. btpd_err("failed to create dir '%s' (%s).\n", file, strerror(errno));
  228. snprintf(file, PATH_MAX, "torrents/%s/torrent", relpath);
  229. write_torrent(mi, mi_size, file);
  230. save_info(tl);
  231. return tl;
  232. }
  233. static int
  234. num_test(const void *k1, const void *k2)
  235. {
  236. return *(const unsigned *)k1 == *(const unsigned *)k2;
  237. }
  238. static uint32_t
  239. num_hash(const void *k)
  240. {
  241. return *(const unsigned *)k;
  242. }
  243. static int
  244. id_test(const void *k1, const void *k2)
  245. {
  246. return bcmp(k1, k2, 20) == 0;
  247. }
  248. static uint32_t
  249. id_hash(const void *k)
  250. {
  251. return dec_be32(k + 16);
  252. }
  253. void
  254. tlib_put_all(struct tlib **v)
  255. {
  256. hashtbl_tov(m_hashtbl, v);
  257. }
  258. void
  259. tlib_init(void)
  260. {
  261. DIR *dirp;
  262. struct dirent *dp;
  263. uint8_t hash[20];
  264. char file[PATH_MAX];
  265. m_numtbl = numtbl_create(num_test, num_hash);
  266. m_hashtbl = hashtbl_create(id_test, id_hash);
  267. if (m_numtbl == NULL || m_hashtbl == NULL)
  268. btpd_err("Out of memory.\n");
  269. if ((dirp = opendir("torrents")) == NULL)
  270. btpd_err("couldn't open the torrents directory.\n");
  271. while ((dp = readdir(dirp)) != NULL) {
  272. if (strlen(dp->d_name) == 40 && ishex(dp->d_name)) {
  273. struct tlib * tl = tlib_create(hex2bin(dp->d_name, hash, 20));
  274. snprintf(file, PATH_MAX, "torrents/%s/info", dp->d_name);
  275. load_info(tl, file);
  276. }
  277. }
  278. closedir(dirp);
  279. }
  280. void
  281. tlib_read_hash(struct tlib *tl, size_t off, uint32_t piece, uint8_t *hash)
  282. {
  283. int fd;
  284. ssize_t nread;
  285. char relpath[RELPATH_SIZE];
  286. bin2hex(tl->hash, relpath, 20);
  287. if ((errno = vopen(&fd, O_RDONLY, "torrents/%s/torrent", relpath)) != 0)
  288. btpd_err("failed to open 'torrents/%s/torrent' (%s).\n",
  289. relpath, strerror(errno));
  290. lseek(fd, off + piece * 20, SEEK_SET);
  291. if ((nread = read(fd, hash, 20)) != 20) {
  292. if (nread == -1)
  293. btpd_err("failed to read 'torrents/%s/torrent' (%s).\n", relpath,
  294. strerror(errno));
  295. else
  296. btpd_err("corrupt file: 'torrents/%s/torrent'.\n", relpath);
  297. }
  298. close(fd);
  299. }
  300. int
  301. tlib_load_mi(struct tlib *tl, char **res)
  302. {
  303. char file[PATH_MAX];
  304. char relpath[RELPATH_SIZE];
  305. char *mi;
  306. bin2hex(tl->hash, relpath, 20);
  307. snprintf(file, sizeof(file), "torrents/%s/torrent", relpath);
  308. if ((mi = mi_load(file, NULL)) == NULL) {
  309. btpd_log(BTPD_L_ERROR,
  310. "torrent '%s': failed to load metainfo (%s).\n",
  311. tl->name, strerror(errno));
  312. return errno;
  313. }
  314. *res = mi;
  315. return 0;
  316. }
  317. struct resume_data {
  318. void *base;
  319. size_t size;
  320. uint8_t *pc_field;
  321. uint8_t *blk_field;
  322. };
  323. static void *
  324. resume_file_size(struct resume_data *resd, int i)
  325. {
  326. return resd->base + 8 + 16 * i;
  327. }
  328. static void *
  329. resume_file_time(struct resume_data *resd, int i)
  330. {
  331. return resd->base + 16 + 16 * i;
  332. }
  333. static void
  334. init_resume(int fd, size_t size)
  335. {
  336. char buf[1024];
  337. uint32_t ver;
  338. bzero(buf, sizeof(buf));
  339. enc_be32(&ver, 2);
  340. if (write(fd, "RESD", 4) == -1 || write(fd, &ver, 4) == -1)
  341. goto fatal;
  342. size -= 8;
  343. while (size > 0) {
  344. ssize_t nw = write(fd, buf, min(sizeof(buf), size));
  345. if (nw < 1)
  346. goto fatal;
  347. size -= nw;
  348. }
  349. return;
  350. fatal:
  351. btpd_err("failed to initialize resume file (%s).\n", strerror(errno));
  352. }
  353. struct resume_data *
  354. tlib_open_resume(struct tlib *tl, unsigned nfiles, size_t pfsize,
  355. size_t bfsize)
  356. {
  357. int fd;
  358. char relpath[RELPATH_SIZE];
  359. struct stat sb;
  360. struct resume_data *resd = btpd_calloc(1, sizeof(*resd));
  361. bin2hex(tl->hash, relpath, 20);
  362. resd->size = 8 + nfiles * 16 + pfsize + bfsize;
  363. if ((errno =
  364. vopen(&fd, O_RDWR|O_CREAT, "torrents/%s/resume", relpath)) != 0)
  365. goto fatal;
  366. if (fstat(fd, &sb) != 0)
  367. goto fatal;
  368. if (sb.st_size != resd->size) {
  369. if (sb.st_size != 0 && ftruncate(fd, 0) != 0)
  370. goto fatal;
  371. init_resume(fd, resd->size);
  372. }
  373. resd->base =
  374. mmap(NULL, resd->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  375. if (resd->base == MAP_FAILED)
  376. goto fatal;
  377. if (bcmp(resd->base, "RESD", 4) != 0 || dec_be32(resd->base + 4) != 2)
  378. init_resume(fd, resd->size);
  379. close(fd);
  380. resd->pc_field = resd->base + 8 + nfiles * 16;
  381. resd->blk_field = resd->pc_field + pfsize;
  382. return resd;
  383. fatal:
  384. btpd_err("file operation failed on 'torrents/%s/resume' (%s).\n",
  385. relpath, strerror(errno));
  386. }
  387. uint8_t *
  388. resume_piece_field(struct resume_data *resd)
  389. {
  390. return resd->pc_field;
  391. }
  392. uint8_t *
  393. resume_block_field(struct resume_data *resd)
  394. {
  395. return resd->blk_field;
  396. }
  397. void
  398. resume_set_fts(struct resume_data *resd, int i, struct file_time_size *fts)
  399. {
  400. enc_be64(resume_file_size(resd, i), (uint64_t)fts->size);
  401. enc_be64(resume_file_time(resd, i), (uint64_t)fts->mtime);
  402. }
  403. void
  404. resume_get_fts(struct resume_data *resd, int i, struct file_time_size *fts)
  405. {
  406. fts->size = dec_be64(resume_file_size(resd, i));
  407. fts->mtime = dec_be64(resume_file_time(resd, i));
  408. }
  409. void
  410. tlib_close_resume(struct resume_data *resd)
  411. {
  412. munmap(resd->base, resd->size);
  413. free(resd);
  414. }