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.

245 lines
5.3 KiB

  1. #include <sys/types.h>
  2. #include <sys/mman.h>
  3. #include <sys/stat.h>
  4. #include <assert.h>
  5. #include <errno.h>
  6. #include <fcntl.h>
  7. #include <math.h>
  8. #include <limits.h>
  9. #include <stdarg.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <unistd.h>
  14. #include <openssl/sha.h>
  15. #include "btpd.h"
  16. #include "tracker_req.h"
  17. #include "stream.h"
  18. static int
  19. ro_fd_cb(const char *path, int *fd, void *arg)
  20. {
  21. struct torrent *tp = arg;
  22. return vopen(fd, O_RDONLY, "%s.d/%s", tp->relpath, path);
  23. }
  24. static int
  25. wo_fd_cb(const char *path, int *fd, void *arg)
  26. {
  27. struct torrent *tp = arg;
  28. return vopen(fd, O_WRONLY|O_CREAT, "%s.d/%s", tp->relpath, path);
  29. }
  30. static int
  31. torrent_load3(const char *file, struct metainfo *mi, char *mem, size_t memsiz)
  32. {
  33. struct torrent *tp = btpd_calloc(1, sizeof(*tp));
  34. tp->relpath = strdup(file);
  35. if (tp->relpath == NULL)
  36. btpd_err("Out of memory.\n");
  37. tp->piece_count = btpd_calloc(mi->npieces, sizeof(tp->piece_count[0]));
  38. BTPDQ_INIT(&tp->peers);
  39. BTPDQ_INIT(&tp->getlst);
  40. tp->imem = mem;
  41. tp->isiz = memsiz;
  42. tp->piece_field = tp->imem;
  43. tp->block_field =
  44. (uint8_t *)tp->imem + (size_t)ceil(mi->npieces / 8.0);
  45. for (uint32_t i = 0; i < mi->npieces; i++)
  46. if (has_bit(tp->piece_field, i))
  47. tp->have_npieces++;
  48. tp->meta = *mi;
  49. free(mi);
  50. BTPDQ_INSERT_TAIL(&btpd.cm_list, tp, entry);
  51. tracker_req(tp, TR_STARTED);
  52. btpd.ntorrents++;
  53. return 0;
  54. }
  55. static int
  56. torrent_load2(const char *file, struct metainfo *mi)
  57. {
  58. int error, ifd;
  59. struct stat sb;
  60. char *mem;
  61. size_t memsiz;
  62. if ((error = vopen(&ifd, O_RDWR, "%s.i", file)) != 0) {
  63. btpd_log(BTPD_L_ERROR, "Error opening %s.i: %s.\n",
  64. file, strerror(error));
  65. return error;
  66. }
  67. if (fstat(ifd, &sb) == -1) {
  68. error = errno;
  69. btpd_log(BTPD_L_ERROR, "Error stating %s.i: %s.\n",
  70. file, strerror(error));
  71. close(ifd);
  72. return error;
  73. }
  74. memsiz =
  75. ceil(mi->npieces / 8.0) +
  76. ceil(mi->npieces * mi->piece_length / (double)(1 << 17));
  77. if (sb.st_size != memsiz) {
  78. btpd_log(BTPD_L_ERROR, "File has wrong size: %s.i.\n", file);
  79. close(ifd);
  80. return EINVAL;
  81. }
  82. mem = mmap(NULL, memsiz, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0);
  83. if (mem == MAP_FAILED)
  84. btpd_err("Error mmap'ing %s.i: %s.\n", file, strerror(errno));
  85. close(ifd);
  86. if ((error = torrent_load3(file, mi, mem, memsiz) != 0)) {
  87. munmap(mem, memsiz);
  88. return error;
  89. }
  90. return 0;
  91. }
  92. int
  93. torrent_load(const char *file)
  94. {
  95. struct metainfo *mi;
  96. int error;
  97. if ((error = load_metainfo(file, -1, 0, &mi)) != 0) {
  98. btpd_log(BTPD_L_ERROR, "Couldn't load metainfo file %s: %s.\n",
  99. file, strerror(error));
  100. return error;
  101. }
  102. if (torrent_get_by_hash(mi->info_hash) != NULL) {
  103. btpd_log(BTPD_L_BTPD, "%s has same hash as an already loaded torrent.\n", file);
  104. error = EEXIST;
  105. }
  106. if (error == 0)
  107. error = torrent_load2(file, mi);
  108. if (error != 0) {
  109. clear_metainfo(mi);
  110. free(mi);
  111. }
  112. return error;
  113. }
  114. void
  115. torrent_unload(struct torrent *tp)
  116. {
  117. struct peer *peer;
  118. struct piece *piece;
  119. btpd_log(BTPD_L_BTPD, "Unloading %s.\n", tp->relpath);
  120. tracker_req(tp, TR_STOPPED);
  121. peer = BTPDQ_FIRST(&tp->peers);
  122. while (peer != NULL) {
  123. struct peer *next = BTPDQ_NEXT(peer, cm_entry);
  124. peer->flags &= ~PF_ATTACHED;
  125. peer_kill(peer);
  126. peer = next;
  127. }
  128. piece = BTPDQ_FIRST(&tp->getlst);
  129. while (piece != NULL) {
  130. struct piece *next = BTPDQ_NEXT(piece, entry);
  131. free(piece);
  132. piece = next;
  133. }
  134. free(tp->piece_count);
  135. free((void *)tp->relpath);
  136. clear_metainfo(&tp->meta);
  137. munmap(tp->imem, tp->isiz);
  138. BTPDQ_REMOVE(&btpd.cm_list, tp, entry);
  139. free(tp);
  140. btpd.ntorrents--;
  141. }
  142. off_t
  143. torrent_bytes_left(struct torrent *tp)
  144. {
  145. if (tp->have_npieces == 0)
  146. return tp->meta.total_length;
  147. else if (has_bit(tp->piece_field, tp->meta.npieces - 1)) {
  148. return tp->meta.total_length -
  149. ((tp->have_npieces - 1) * tp->meta.piece_length +
  150. tp->meta.total_length % tp->meta.piece_length);
  151. } else
  152. return tp->meta.total_length -
  153. tp->have_npieces * tp->meta.piece_length;
  154. }
  155. char *
  156. torrent_get_bytes(struct torrent *tp, off_t start, size_t len)
  157. {
  158. char *buf = btpd_malloc(len);
  159. struct bt_stream_ro *bts;
  160. if ((bts = bts_open_ro(&tp->meta, start, ro_fd_cb, tp)) == NULL)
  161. btpd_err("Out of memory.\n");
  162. if (bts_read_ro(bts, buf, len) != 0)
  163. btpd_err("Io error.\n");
  164. bts_close_ro(bts);
  165. return buf;
  166. }
  167. void
  168. torrent_put_bytes(struct torrent *tp, const char *buf, off_t start, size_t len)
  169. {
  170. int err;
  171. struct bt_stream_wo *bts;
  172. if ((bts = bts_open_wo(&tp->meta, start, wo_fd_cb, tp)) == NULL)
  173. btpd_err("Out of memory.\n");
  174. if ((err = bts_write_wo(bts, buf, len)) != 0)
  175. btpd_err("Io error1: %s\n", strerror(err));
  176. if ((err = bts_close_wo(bts)) != 0)
  177. btpd_err("Io error2: %s\n", strerror(err));
  178. }
  179. int
  180. torrent_has_peer(struct torrent *tp, const uint8_t *id)
  181. {
  182. int has = 0;
  183. struct peer *p = BTPDQ_FIRST(&tp->peers);
  184. while (p != NULL) {
  185. if (bcmp(p->id, id, 20) == 0) {
  186. has = 1;
  187. break;
  188. }
  189. p = BTPDQ_NEXT(p, cm_entry);
  190. }
  191. return has;
  192. }
  193. struct torrent *
  194. torrent_get_by_hash(const uint8_t *hash)
  195. {
  196. struct torrent *tp = BTPDQ_FIRST(&btpd.cm_list);
  197. while (tp != NULL && bcmp(hash, tp->meta.info_hash, 20) != 0)
  198. tp = BTPDQ_NEXT(tp, entry);
  199. return tp;
  200. }