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.

286 lignes
7.4 KiB

  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <sys/un.h>
  4. #include <arpa/inet.h>
  5. #include <sys/stat.h>
  6. #include <inttypes.h>
  7. #include <limits.h>
  8. #include <stdarg.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <unistd.h>
  12. #include "btpd.h"
  13. #include "tracker_req.h"
  14. struct cli {
  15. int sd;
  16. struct event read;
  17. };
  18. static struct event m_cli_incoming;
  19. enum ipc_code { // XXX: Same as in cli/btpd_if.h
  20. IPC_OK,
  21. IPC_FAIL,
  22. IPC_ERROR,
  23. IPC_COMMERR
  24. };
  25. static int
  26. write_buffer(struct cli *cli, struct io_buffer *iob)
  27. {
  28. int err = 0;
  29. if (!iob->error) {
  30. uint32_t len = iob->buf_off;
  31. write_fully(cli->sd, &len, sizeof(len));
  32. err = write_fully(cli->sd, iob->buf, iob->buf_off);
  33. } else
  34. btpd_err("Out of memory.\n");
  35. if (iob->buf != NULL)
  36. free(iob->buf);
  37. return err;
  38. }
  39. static int
  40. write_code_buffer(struct cli *cli, enum ipc_code code)
  41. {
  42. struct io_buffer iob;
  43. buf_init(&iob, 16);
  44. buf_print(&iob, "d4:codei%uee", code);
  45. return write_buffer(cli, &iob);
  46. }
  47. static int
  48. cmd_stat(struct cli *cli, int argc, const char *args)
  49. {
  50. struct torrent *tp;
  51. struct io_buffer iob;
  52. buf_init(&iob, (1 << 14));
  53. buf_swrite(&iob, "d");
  54. buf_swrite(&iob, "4:codei0e");
  55. buf_print(&iob, "6:npeersi%ue", net_npeers);
  56. buf_print(&iob, "9:ntorrentsi%ue", torrent_count());
  57. buf_swrite(&iob, "8:torrentsl");
  58. BTPDQ_FOREACH(tp, torrent_get_all(), entry) {
  59. const char *name = torrent_name(tp);
  60. uint32_t seen_npieces = 0;
  61. for (uint32_t i = 0; i < tp->meta.npieces; i++)
  62. if (tp->net->piece_count[i] > 0)
  63. seen_npieces++;
  64. buf_swrite(&iob, "d");
  65. buf_print(&iob, "11:content goti%llde", (long long)cm_content(tp));
  66. buf_print(&iob, "12:content sizei%llde",
  67. (long long)tp->meta.total_length);
  68. buf_print(&iob, "10:downloadedi%llde", tp->net->downloaded);
  69. buf_swrite(&iob, "9:info hash20:");
  70. buf_write(&iob, tp->meta.info_hash, 20);
  71. buf_print(&iob, "4:name%d:%s", (int)strlen(name), name);
  72. buf_print(&iob, "5:peersi%ue", tp->net->npeers);
  73. buf_print(&iob, "10:pieces goti%ue", cm_pieces(tp));
  74. buf_print(&iob, "11:pieces seeni%ue", seen_npieces);
  75. buf_print(&iob, "9:rate downi%lue", tp->net->rate_dwn);
  76. buf_print(&iob, "7:rate upi%lue", tp->net->rate_up);
  77. buf_print(&iob, "5:statei%ue", tp->state);
  78. buf_print(&iob, "14:torrent piecesi%ue", tp->meta.npieces);
  79. buf_print(&iob, "14:tracker errorsi%ue", tr_errors(tp));
  80. buf_print(&iob, "8:uploadedi%llde", tp->net->uploaded);
  81. buf_swrite(&iob, "e");
  82. }
  83. buf_swrite(&iob, "ee");
  84. return write_buffer(cli, &iob);
  85. }
  86. static int
  87. cmd_add(struct cli *cli, int argc, const char *args)
  88. {
  89. if (argc != 1)
  90. return EINVAL;
  91. if (btpd_is_stopping())
  92. return write_code_buffer(cli, IPC_FAIL);
  93. size_t hlen;
  94. struct torrent *tp;
  95. enum ipc_code code = IPC_OK;
  96. const uint8_t *hash = benc_dget_mem(args, "hash", &hlen);
  97. char *content = benc_dget_str(args, "content", NULL);
  98. char *torrent = benc_dget_str(args, "torrent", NULL);
  99. if (!(hlen == 20 && content != NULL && torrent != NULL)) {
  100. code = IPC_COMMERR;
  101. goto out;
  102. }
  103. if ((tp = torrent_get(hash)) != NULL) {
  104. code = tp->state == T_STOPPING ? IPC_FAIL : IPC_OK;
  105. goto out;
  106. }
  107. if (torrent_set_links(hash, torrent, content) != 0) {
  108. code = IPC_ERROR;
  109. goto out;
  110. }
  111. if (torrent_start(hash) != 0)
  112. code = IPC_ERROR;
  113. out:
  114. if (content != NULL)
  115. free(content);
  116. if (torrent != NULL)
  117. free(torrent);
  118. if (code == IPC_COMMERR)
  119. return EINVAL;
  120. else
  121. return write_code_buffer(cli, code);
  122. }
  123. static int
  124. cmd_del(struct cli *cli, int argc, const char *args)
  125. {
  126. if (argc != 1 || !benc_isstr(args))
  127. return EINVAL;
  128. size_t hlen;
  129. uint8_t *hash = (uint8_t *)benc_mem(args, &hlen, NULL);
  130. if (hlen != 20)
  131. return EINVAL;
  132. // Stopping a torrent may trigger exit so we need to reply before.
  133. int ret = write_code_buffer(cli, IPC_OK);
  134. struct torrent *tp = torrent_get(hash);
  135. if (tp != NULL)
  136. torrent_stop(tp);
  137. return ret;
  138. }
  139. static int
  140. cmd_die(struct cli *cli, int argc, const char *args)
  141. {
  142. int err = write_code_buffer(cli, IPC_OK);
  143. if (!btpd_is_stopping()) {
  144. int grace_seconds = -1;
  145. if (argc == 1 && benc_isint(args))
  146. grace_seconds = benc_int(args, NULL);
  147. btpd_log(BTPD_L_BTPD, "Someone wants me dead.\n");
  148. btpd_shutdown(grace_seconds);
  149. }
  150. return err;
  151. }
  152. static struct {
  153. const char *name;
  154. int nlen;
  155. int (*fun)(struct cli *cli, int, const char *);
  156. } cmd_table[] = {
  157. { "add", 3, cmd_add },
  158. { "del", 3, cmd_del },
  159. { "die", 3, cmd_die },
  160. { "stat", 4, cmd_stat }
  161. };
  162. static int ncmds = sizeof(cmd_table) / sizeof(cmd_table[0]);
  163. static int
  164. cmd_dispatch(struct cli *cli, const char *buf)
  165. {
  166. size_t cmdlen;
  167. const char *cmd;
  168. const char *args;
  169. cmd = benc_mem(benc_first(buf), &cmdlen, &args);
  170. for (int i = 0; i < ncmds; i++) {
  171. if ((cmdlen == cmd_table[i].nlen &&
  172. strncmp(cmd_table[i].name, cmd, cmdlen) == 0)) {
  173. return cmd_table[i].fun(cli, benc_nelems(buf) - 1, args);
  174. }
  175. }
  176. return ENOENT;
  177. }
  178. static void
  179. cli_read_cb(int sd, short type, void *arg)
  180. {
  181. struct cli *cli = arg;
  182. uint32_t cmdlen;
  183. uint8_t *msg = NULL;
  184. if (read_fully(sd, &cmdlen, sizeof(cmdlen)) != 0)
  185. goto error;
  186. msg = btpd_malloc(cmdlen);
  187. if (read_fully(sd, msg, cmdlen) != 0)
  188. goto error;
  189. if (!(benc_validate(msg, cmdlen) == 0 && benc_islst(msg) &&
  190. benc_first(msg) != NULL && benc_isstr(benc_first(msg))))
  191. goto error;
  192. if (cmd_dispatch(cli, msg) != 0)
  193. goto error;
  194. free(msg);
  195. event_add(&cli->read, NULL);
  196. return;
  197. error:
  198. close(cli->sd);
  199. free(cli);
  200. if (msg != NULL)
  201. free(msg);
  202. }
  203. void
  204. client_connection_cb(int sd, short type, void *arg)
  205. {
  206. int nsd;
  207. if ((nsd = accept(sd, NULL, NULL)) < 0) {
  208. if (errno == EWOULDBLOCK || errno == ECONNABORTED)
  209. return;
  210. else
  211. btpd_err("client accept: %s\n", strerror(errno));
  212. }
  213. if ((errno = set_blocking(nsd)) != 0)
  214. btpd_err("set_blocking: %s.\n", strerror(errno));
  215. struct cli *cli = btpd_calloc(1, sizeof(*cli));
  216. cli->sd = nsd;
  217. event_set(&cli->read, cli->sd, EV_READ, cli_read_cb, cli);
  218. event_add(&cli->read, NULL);
  219. }
  220. void
  221. ipc_init(void)
  222. {
  223. int sd;
  224. struct sockaddr_un addr;
  225. size_t psiz = sizeof(addr.sun_path);
  226. addr.sun_family = PF_UNIX;
  227. if (snprintf(addr.sun_path, psiz, "%s/sock", btpd_dir) >= psiz)
  228. btpd_err("'%s/sock' is too long.\n", btpd_dir);
  229. if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
  230. btpd_err("sock: %s\n", strerror(errno));
  231. if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
  232. if (errno == EADDRINUSE) {
  233. unlink(addr.sun_path);
  234. if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
  235. btpd_err("bind: %s\n", strerror(errno));
  236. } else
  237. btpd_err("bind: %s\n", strerror(errno));
  238. }
  239. if (chmod(addr.sun_path, 0600) == -1)
  240. btpd_err("chmod: %s (%s).\n", addr.sun_path, strerror(errno));
  241. listen(sd, 4);
  242. set_nonblocking(sd);
  243. event_set(&m_cli_incoming, sd, EV_READ | EV_PERSIST,
  244. client_connection_cb, NULL);
  245. event_add(&m_cli_incoming, NULL);
  246. }