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.

544 lignes
14 KiB

  1. #include "btpd.h"
  2. #include <openssl/sha.h>
  3. #include <stream.h>
  4. struct content {
  5. enum { CM_INACTIVE, CM_STARTING, CM_ACTIVE } state;
  6. int error;
  7. uint32_t npieces_got;
  8. off_t ncontent_bytes;
  9. size_t bppbf; // bytes per piece block field
  10. uint8_t *piece_field;
  11. uint8_t *block_field;
  12. uint8_t *pos_field;
  13. struct bt_stream *rds;
  14. struct bt_stream *wrs;
  15. struct resume_data *resd;
  16. };
  17. #define ZEROBUFLEN (1 << 14)
  18. static const uint8_t m_zerobuf[ZEROBUFLEN];
  19. static int
  20. fd_cb_rd(const char *path, int *fd, void *arg)
  21. {
  22. struct torrent *tp = arg;
  23. return vopen(fd, O_RDONLY, "%s/%s", tp->tl->dir, path);
  24. }
  25. static int
  26. fd_cb_wr(const char *path, int *fd, void *arg)
  27. {
  28. struct torrent *tp = arg;
  29. return vopen(fd, O_RDWR, "%s/%s", tp->tl->dir, path);
  30. }
  31. struct start_test_data {
  32. struct torrent *tp;
  33. struct file_time_size *fts;
  34. uint32_t start;
  35. BTPDQ_ENTRY(start_test_data) entry;
  36. };
  37. BTPDQ_HEAD(std_tq, start_test_data);
  38. static struct std_tq m_startq = BTPDQ_HEAD_INITIALIZER(m_startq);
  39. static struct timeout m_workev;
  40. #define READBUFLEN (1 << 14)
  41. static int
  42. test_hash(struct torrent *tp, uint8_t *hash, uint32_t piece)
  43. {
  44. char piece_hash[SHA_DIGEST_LENGTH];
  45. tlib_read_hash(tp->tl, tp->pieces_off, piece, piece_hash);
  46. return bcmp(hash, piece_hash, SHA_DIGEST_LENGTH);
  47. }
  48. static int
  49. test_piece(struct torrent *tp, uint32_t piece, int *ok)
  50. {
  51. int err;
  52. uint8_t hash[SHA_DIGEST_LENGTH];
  53. if ((err = bts_sha(tp->cm->rds, piece * tp->piece_length,
  54. torrent_piece_size(tp, piece), hash)) != 0) {
  55. btpd_log(BTPD_L_ERROR, "io error on '%s' (%s).\n",
  56. bts_filename(tp->cm->rds), strerror(err));
  57. return err;;
  58. }
  59. *ok = test_hash(tp, hash, piece) == 0;
  60. return 0;
  61. }
  62. static int test_hash(struct torrent *tp, uint8_t *hash, uint32_t piece);
  63. static void startup_test_run(void);
  64. void
  65. worker_cb(int fd, short type, void *arg)
  66. {
  67. startup_test_run();
  68. }
  69. void
  70. cm_kill(struct torrent *tp)
  71. {
  72. struct content *cm = tp->cm;
  73. tlib_close_resume(cm->resd);
  74. free(cm->pos_field);
  75. free(cm);
  76. tp->cm = NULL;
  77. }
  78. static int stat_and_adjust(struct torrent *tp, struct file_time_size ret[]);
  79. void
  80. cm_save(struct torrent *tp)
  81. {
  82. struct file_time_size fts[tp->nfiles];
  83. stat_and_adjust(tp, fts);
  84. for (int i = 0; i < tp->nfiles; i++)
  85. resume_set_fts(tp->cm->resd, i, fts + i);
  86. }
  87. static void
  88. cm_on_error(struct torrent *tp)
  89. {
  90. if (!tp->cm->error) {
  91. tp->cm->error = 1;
  92. cm_stop(tp);
  93. }
  94. }
  95. static void
  96. cm_write_done(struct torrent *tp)
  97. {
  98. int err;
  99. struct content *cm = tp->cm;
  100. err = bts_close(cm->wrs);
  101. cm->wrs = NULL;
  102. if (err && !cm->error) {
  103. btpd_log(BTPD_L_ERROR, "error closing write stream for '%s' (%s).\n",
  104. torrent_name(tp), strerror(err));
  105. cm_on_error(tp);
  106. }
  107. if (!cm->error)
  108. cm_save(tp);
  109. }
  110. void
  111. cm_stop(struct torrent *tp)
  112. {
  113. struct content *cm = tp->cm;
  114. if (cm->state != CM_STARTING && cm->state != CM_ACTIVE)
  115. return;
  116. if (cm->state == CM_STARTING) {
  117. struct start_test_data *std;
  118. BTPDQ_FOREACH(std, &m_startq, entry)
  119. if (std->tp == tp) {
  120. BTPDQ_REMOVE(&m_startq, std, entry);
  121. free(std->fts);
  122. free(std);
  123. break;
  124. }
  125. }
  126. if (cm->rds != NULL)
  127. bts_close(cm->rds);
  128. if (cm->wrs != NULL)
  129. cm_write_done(tp);
  130. cm->state = CM_INACTIVE;
  131. }
  132. int
  133. cm_active(struct torrent *tp)
  134. {
  135. struct content *cm = tp->cm;
  136. return cm->state != CM_INACTIVE;
  137. }
  138. int
  139. cm_error(struct torrent *tp)
  140. {
  141. return tp->cm->error;
  142. }
  143. int
  144. cm_started(struct torrent *tp)
  145. {
  146. struct content *cm = tp->cm;
  147. return cm->state == CM_ACTIVE;
  148. }
  149. void
  150. cm_create(struct torrent *tp, const char *mi)
  151. {
  152. size_t pfield_size = ceil(tp->npieces / 8.0);
  153. struct content *cm = btpd_calloc(1, sizeof(*cm));
  154. cm->bppbf = ceil((double)tp->piece_length / (1 << 17));
  155. cm->pos_field = btpd_calloc(pfield_size, 1);
  156. cm->resd = tlib_open_resume(tp->tl, tp->nfiles, pfield_size,
  157. cm->bppbf * tp->npieces);
  158. cm->piece_field = resume_piece_field(cm->resd);
  159. cm->block_field = resume_block_field(cm->resd);
  160. tp->cm = cm;
  161. }
  162. int
  163. cm_get_bytes(struct torrent *tp, uint32_t piece, uint32_t begin, size_t len,
  164. uint8_t **buf)
  165. {
  166. if (tp->cm->error)
  167. return EIO;
  168. *buf = btpd_malloc(len);
  169. int err =
  170. bts_get(tp->cm->rds, piece * tp->piece_length + begin, *buf, len);
  171. if (err != 0) {
  172. btpd_log(BTPD_L_ERROR, "io error on '%s' (%s).\n",
  173. bts_filename(tp->cm->rds), strerror(err));
  174. cm_on_error(tp);
  175. }
  176. return err;
  177. }
  178. void
  179. cm_prealloc(struct torrent *tp, uint32_t piece)
  180. {
  181. struct content *cm = tp->cm;
  182. if (cm_alloc_size <= 0)
  183. set_bit(cm->pos_field, piece);
  184. }
  185. void
  186. cm_test_piece(struct torrent *tp, uint32_t piece)
  187. {
  188. int ok;
  189. struct content *cm = tp->cm;
  190. if ((errno = test_piece(tp, piece, &ok)) != 0)
  191. cm_on_error(tp);
  192. else if (ok) {
  193. assert(cm->npieces_got < tp->npieces);
  194. cm->npieces_got++;
  195. set_bit(cm->piece_field, piece);
  196. if (net_active(tp))
  197. dl_on_ok_piece(tp->net,piece);
  198. if (cm_full(tp))
  199. cm_write_done(tp);
  200. } else {
  201. cm->ncontent_bytes -= torrent_piece_size(tp,piece);
  202. bzero(cm->block_field + piece * cm->bppbf, cm->bppbf);
  203. if (net_active(tp))
  204. dl_on_bad_piece(tp->net, piece);
  205. }
  206. }
  207. int
  208. cm_put_bytes(struct torrent *tp, uint32_t piece, uint32_t begin,
  209. const uint8_t *buf, size_t len)
  210. {
  211. int err;
  212. struct content *cm = tp->cm;
  213. if (cm->error)
  214. return EIO;
  215. uint8_t *bf = cm->block_field + piece * cm->bppbf;
  216. assert(!has_bit(bf, begin / PIECE_BLOCKLEN));
  217. assert(!has_bit(cm->piece_field, piece));
  218. if (!has_bit(cm->pos_field, piece)) {
  219. unsigned npieces = ceil((double)cm_alloc_size / tp->piece_length);
  220. uint32_t start = piece - piece % npieces;
  221. uint32_t end = min(start + npieces, tp->npieces);
  222. while (start < end) {
  223. if (!has_bit(cm->pos_field, start)) {
  224. assert(!has_bit(cm->piece_field, start));
  225. off_t len = torrent_piece_size(tp, start);
  226. off_t off = tp->piece_length * start;
  227. while (len > 0) {
  228. size_t wlen = min(ZEROBUFLEN, len);
  229. if ((err = bts_put(cm->wrs, off, m_zerobuf, wlen)) != 0) {
  230. btpd_log(BTPD_L_ERROR, "io error on '%s' (%s).\n",
  231. bts_filename(cm->wrs), strerror(errno));
  232. cm_on_error(tp);
  233. return err;
  234. }
  235. len -= wlen;
  236. off += wlen;
  237. }
  238. set_bit(cm->pos_field, start);
  239. }
  240. start++;
  241. }
  242. }
  243. err = bts_put(cm->wrs, piece * tp->piece_length + begin, buf, len);
  244. if (err != 0) {
  245. btpd_log(BTPD_L_ERROR, "io error on '%s' (%s)\n",
  246. bts_filename(cm->wrs), strerror(err));
  247. cm_on_error(tp);
  248. return err;
  249. }
  250. cm->ncontent_bytes += len;
  251. set_bit(bf, begin / PIECE_BLOCKLEN);
  252. return 0;
  253. }
  254. int
  255. cm_full(struct torrent *tp)
  256. {
  257. return tp->cm->npieces_got == tp->npieces;
  258. }
  259. off_t
  260. cm_content(struct torrent *tp)
  261. {
  262. return tp->cm->ncontent_bytes;
  263. }
  264. uint32_t
  265. cm_pieces(struct torrent *tp)
  266. {
  267. return tp->cm->npieces_got;
  268. }
  269. uint8_t *
  270. cm_get_piece_field(struct torrent *tp)
  271. {
  272. return tp->cm->piece_field;
  273. }
  274. uint8_t *
  275. cm_get_block_field(struct torrent *tp, uint32_t piece)
  276. {
  277. return tp->cm->block_field + piece * tp->cm->bppbf;
  278. }
  279. int
  280. cm_has_piece(struct torrent *tp, uint32_t piece)
  281. {
  282. return has_bit(tp->cm->piece_field, piece);
  283. }
  284. int
  285. stat_and_adjust(struct torrent *tp, struct file_time_size ret[])
  286. {
  287. int fd;
  288. char path[PATH_MAX];
  289. struct stat sb;
  290. for (int i = 0; i < tp->nfiles; i++) {
  291. snprintf(path, PATH_MAX, "%s/%s", tp->tl->dir, tp->files[i].path);
  292. again:
  293. if (stat(path, &sb) == -1) {
  294. if (errno == ENOENT) {
  295. errno = vopen(&fd, O_CREAT|O_RDWR, "%s", path);
  296. if (errno != 0 || close(fd) != 0) {
  297. btpd_log(BTPD_L_ERROR, "failed to create '%s' (%s).\n",
  298. path, strerror(errno));
  299. return errno;
  300. }
  301. goto again;
  302. } else {
  303. btpd_log(BTPD_L_ERROR, "failed to stat '%s' (%s).\n",
  304. path, strerror(errno));
  305. return errno;
  306. }
  307. } else if (sb.st_size > tp->files[i].length) {
  308. if (truncate(path, tp->files[i].length) != 0) {
  309. btpd_log(BTPD_L_ERROR, "failed to truncate '%s' (%s).\n",
  310. path, strerror(errno));
  311. return errno;
  312. }
  313. goto again;
  314. } else {
  315. ret[i].mtime = sb.st_mtime;
  316. ret[i].size = sb.st_size;
  317. }
  318. }
  319. return 0;
  320. }
  321. void
  322. startup_test_end(struct torrent *tp, int unclean)
  323. {
  324. struct content *cm = tp->cm;
  325. bzero(cm->pos_field, ceil(tp->npieces / 8.0));
  326. for (uint32_t piece = 0; piece < tp->npieces; piece++) {
  327. if (cm_has_piece(tp, piece)) {
  328. cm->ncontent_bytes += torrent_piece_size(tp, piece);
  329. cm->npieces_got++;
  330. set_bit(cm->pos_field, piece);
  331. continue;
  332. }
  333. uint8_t *bf = cm->block_field + cm->bppbf * piece;
  334. uint32_t nblocks = torrent_piece_blocks(tp, piece);
  335. uint32_t nblocks_got = 0;
  336. for (uint32_t i = 0; i < nblocks; i++) {
  337. if (has_bit(bf, i)) {
  338. nblocks_got++;
  339. cm->ncontent_bytes +=
  340. torrent_block_size(tp, piece, nblocks, i);
  341. }
  342. }
  343. if (nblocks_got == nblocks) {
  344. bzero(bf, cm->bppbf);
  345. cm->ncontent_bytes -= torrent_piece_size(tp, piece);
  346. } else if (nblocks_got > 0)
  347. set_bit(cm->pos_field, piece);
  348. }
  349. if (unclean) {
  350. struct start_test_data *std = BTPDQ_FIRST(&m_startq);
  351. BTPDQ_REMOVE(&m_startq, std, entry);
  352. for (int i = 0; i < tp->nfiles; i++)
  353. resume_set_fts(cm->resd, i, std->fts + i);
  354. free(std->fts);
  355. free(std);
  356. }
  357. if (!cm_full(tp)) {
  358. int err;
  359. if ((err = bts_open(&cm->wrs, tp->nfiles, tp->files,
  360. fd_cb_wr, tp)) != 0) {
  361. btpd_log(BTPD_L_ERROR,
  362. "failed to open write stream for '%s' (%s).\n",
  363. torrent_name(tp), strerror(err));
  364. cm_on_error(tp);
  365. return;
  366. }
  367. }
  368. cm->state = CM_ACTIVE;
  369. }
  370. void
  371. startup_test_run(void)
  372. {
  373. int ok;
  374. struct torrent *tp;
  375. struct content *cm;
  376. struct start_test_data * std = BTPDQ_FIRST(&m_startq);
  377. uint32_t this;
  378. if (std == NULL)
  379. return;
  380. tp = std->tp;
  381. cm = tp->cm;
  382. if (test_piece(std->tp, std->start, &ok) != 0) {
  383. cm_on_error(std->tp);
  384. return;
  385. }
  386. if (ok)
  387. set_bit(cm->piece_field, std->start);
  388. else
  389. clear_bit(cm->piece_field, std->start);
  390. this = std->start;
  391. do
  392. std->start++;
  393. while (std->start < tp->npieces && !has_bit(cm->pos_field, std->start));
  394. if (std->start >= tp->npieces)
  395. startup_test_end(tp, 1);
  396. if (!BTPDQ_EMPTY(&m_startq))
  397. btpd_timer_add(&m_workev, (& (struct timespec) { 0, 0 }));
  398. }
  399. void
  400. startup_test_begin(struct torrent *tp, struct file_time_size *fts)
  401. {
  402. uint32_t piece = 0;
  403. struct content *cm = tp->cm;
  404. while (piece < tp->npieces && !has_bit(cm->pos_field, piece))
  405. piece++;
  406. if (piece < tp->npieces) {
  407. struct start_test_data *std = btpd_calloc(1, sizeof(*std));
  408. std->tp = tp;
  409. std->start = piece;
  410. std->fts = fts;
  411. BTPDQ_INSERT_TAIL(&m_startq, std, entry);
  412. if (std == BTPDQ_FIRST(&m_startq))
  413. btpd_timer_add(&m_workev, (& (struct timespec) { 0, 0 }));
  414. } else {
  415. free(fts);
  416. startup_test_end(tp, 0);
  417. }
  418. }
  419. void
  420. cm_start(struct torrent *tp, int force_test)
  421. {
  422. int err, run_test = force_test;
  423. struct file_time_size *fts;
  424. struct content *cm = tp->cm;
  425. cm->state = CM_STARTING;
  426. if ((errno =
  427. bts_open(&cm->rds, tp->nfiles, tp->files, fd_cb_rd, tp)) != 0) {
  428. btpd_log(BTPD_L_ERROR, "failed to open stream for '%s' (%s).\n",
  429. torrent_name(tp), strerror(errno));
  430. cm_on_error(tp);
  431. return;
  432. }
  433. fts = btpd_calloc(tp->nfiles, sizeof(*fts));
  434. if ((err = stat_and_adjust(tp, fts)) != 0) {
  435. free(fts);
  436. cm_on_error(tp);
  437. return;
  438. }
  439. for (int i = 0; i < tp->nfiles; i++) {
  440. struct file_time_size rfts;
  441. resume_get_fts(cm->resd, i, &rfts);
  442. if ((fts[i].mtime != rfts.mtime || fts[i].size != rfts.size)) {
  443. run_test = 1;
  444. break;
  445. }
  446. }
  447. if (run_test) {
  448. memset(cm->pos_field, 0xff, ceil(tp->npieces / 8.0));
  449. off_t off = 0;
  450. for (int i = 0; i < tp->nfiles; i++) {
  451. if (fts[i].size != tp->files[i].length) {
  452. uint32_t start, end;
  453. end = (off + tp->files[i].length - 1)
  454. / tp->piece_length;
  455. start = (off + fts[i].size) / tp->piece_length;
  456. while (start <= end) {
  457. clear_bit(cm->pos_field, start);
  458. clear_bit(cm->piece_field, start);
  459. bzero(cm->block_field + start * cm->bppbf, cm->bppbf);
  460. start++;
  461. }
  462. }
  463. off += tp->files[i].length;
  464. }
  465. }
  466. startup_test_begin(tp, fts);
  467. }
  468. void
  469. cm_init(void)
  470. {
  471. timer_init(&m_workev, worker_cb, NULL);
  472. }