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.

467 lignes
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. }