A clone of btpd with my configuration changes.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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