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.

484 lignes
13 KiB

  1. #include "btpd.h"
  2. #include <sys/un.h>
  3. #include <iobuf.h>
  4. struct cli {
  5. int sd;
  6. struct event read;
  7. };
  8. static struct event m_cli_incoming;
  9. static int
  10. write_buffer(struct cli *cli, struct io_buffer *iob)
  11. {
  12. int err = 0;
  13. if (!iob->error) {
  14. uint32_t len = iob->off;
  15. write_fully(cli->sd, &len, sizeof(len));
  16. err = write_fully(cli->sd, iob->buf, iob->off);
  17. } else
  18. btpd_err("Out of memory.\n");
  19. buf_free(iob);
  20. return err;
  21. }
  22. static int
  23. write_code_buffer(struct cli *cli, enum ipc_err code)
  24. {
  25. struct io_buffer iob = buf_init(16);
  26. buf_print(&iob, "d4:codei%uee", code);
  27. return write_buffer(cli, &iob);
  28. }
  29. static int
  30. write_add_buffer(struct cli *cli, unsigned num)
  31. {
  32. struct io_buffer iob = buf_init(32);
  33. buf_print(&iob, "d4:codei%ue3:numi%uee", IPC_OK, num);
  34. return write_buffer(cli, &iob);
  35. }
  36. static void
  37. write_ans(struct io_buffer *iob, struct tlib *tl, enum ipc_tval val)
  38. {
  39. enum ipc_tstate ts = IPC_TSTATE_INACTIVE;
  40. switch (val) {
  41. case IPC_TVAL_CGOT:
  42. buf_print(iob, "i%dei%llde", IPC_TYPE_NUM,
  43. tl->tp == NULL ? tl->content_have : (long long)cm_content(tl->tp));
  44. return;
  45. case IPC_TVAL_CSIZE:
  46. buf_print(iob, "i%dei%llde", IPC_TYPE_NUM, tl->content_size);
  47. return;
  48. case IPC_TVAL_PCCOUNT:
  49. if (tl->tp == NULL)
  50. buf_print(iob, "i%dei%de", IPC_TYPE_ERR, IPC_ETINACTIVE);
  51. else
  52. buf_print(iob, "i%dei%lue", IPC_TYPE_NUM,
  53. (unsigned long)tl->tp->npieces);
  54. return;
  55. case IPC_TVAL_PCGOT:
  56. if (tl->tp == NULL)
  57. buf_print(iob, "i%dei%de", IPC_TYPE_ERR, IPC_ETINACTIVE);
  58. else
  59. buf_print(iob, "i%dei%lue", IPC_TYPE_NUM,
  60. (unsigned long)cm_pieces(tl->tp));
  61. return;
  62. case IPC_TVAL_PCSEEN:
  63. if (tl->tp == NULL)
  64. buf_print(iob, "i%dei%de", IPC_TYPE_NUM, 0);
  65. else {
  66. unsigned long pcseen = 0;
  67. for (unsigned long i = 0; i < tl->tp->npieces; i++)
  68. if (tl->tp->net->piece_count[i] > 0)
  69. pcseen++;
  70. buf_print(iob, "i%dei%lue", IPC_TYPE_NUM, pcseen);
  71. }
  72. return;
  73. case IPC_TVAL_RATEDWN:
  74. buf_print(iob, "i%dei%lue", IPC_TYPE_NUM,
  75. tl->tp == NULL ? 0UL : tl->tp->net->rate_dwn / RATEHISTORY);
  76. return;
  77. case IPC_TVAL_RATEUP:
  78. buf_print(iob, "i%dei%lue", IPC_TYPE_NUM,
  79. tl->tp == NULL ? 0UL : tl->tp->net->rate_up / RATEHISTORY);
  80. return;
  81. case IPC_TVAL_SESSDWN:
  82. buf_print(iob, "i%dei%llde", IPC_TYPE_NUM,
  83. tl->tp == NULL ? 0LL : tl->tp->net->downloaded);
  84. return;
  85. case IPC_TVAL_SESSUP:
  86. buf_print(iob, "i%dei%llde", IPC_TYPE_NUM,
  87. tl->tp == NULL ? 0LL : tl->tp->net->uploaded);
  88. return;
  89. case IPC_TVAL_DIR:
  90. if (tl->dir != NULL)
  91. buf_print(iob, "i%de%d:%s", IPC_TYPE_STR, (int)strlen(tl->dir),
  92. tl->dir);
  93. else
  94. buf_print(iob, "i%dei%de", IPC_TYPE_ERR, IPC_EBADTENT);
  95. return;
  96. case IPC_TVAL_NAME:
  97. if (tl->name != NULL)
  98. buf_print(iob, "i%de%d:%s", IPC_TYPE_STR, (int)strlen(tl->name),
  99. tl->name);
  100. else
  101. buf_print(iob, "i%dei%de", IPC_TYPE_ERR, IPC_EBADTENT);
  102. return;
  103. case IPC_TVAL_IHASH:
  104. buf_print(iob, "i%de20:", IPC_TYPE_BIN);
  105. buf_write(iob, tl->hash, 20);
  106. return;
  107. case IPC_TVAL_NUM:
  108. buf_print(iob, "i%dei%ue", IPC_TYPE_NUM, tl->num);
  109. return;
  110. case IPC_TVAL_PCOUNT:
  111. buf_print(iob, "i%dei%ue", IPC_TYPE_NUM,
  112. tl->tp == NULL ? 0 : tl->tp->net->npeers);
  113. return;
  114. case IPC_TVAL_STATE:
  115. buf_print(iob, "i%de", IPC_TYPE_NUM);
  116. if (tl->tp != NULL) {
  117. switch (tl->tp->state) {
  118. case T_STARTING:
  119. ts = IPC_TSTATE_START;
  120. break;
  121. case T_STOPPING:
  122. ts = IPC_TSTATE_STOP;
  123. break;
  124. case T_SEED:
  125. ts = IPC_TSTATE_SEED;
  126. break;
  127. case T_LEECH:
  128. ts = IPC_TSTATE_LEECH;
  129. break;
  130. }
  131. }
  132. buf_print(iob, "i%de", ts);
  133. return;
  134. case IPC_TVAL_TOTDWN:
  135. buf_print(iob, "i%dei%llde", IPC_TYPE_NUM, tl->tot_down +
  136. (tl->tp == NULL ? 0 : tl->tp->net->downloaded));
  137. return;
  138. case IPC_TVAL_TOTUP:
  139. buf_print(iob, "i%dei%llde", IPC_TYPE_NUM, tl->tot_up +
  140. (tl->tp == NULL ? 0 : tl->tp->net->uploaded));
  141. return;
  142. case IPC_TVAL_TRERR:
  143. buf_print(iob, "i%dei%ue", IPC_TYPE_NUM,
  144. tl->tp == NULL ? 0 : tr_errors(tl->tp));
  145. return;
  146. case IPC_TVALCOUNT:
  147. break;
  148. }
  149. buf_print(iob, "i%dei%de", IPC_TYPE_ERR, IPC_ENOKEY);
  150. }
  151. static int
  152. cmd_tget(struct cli *cli, int argc, const char *args)
  153. {
  154. if (argc != 1 || !benc_isdct(args))
  155. return IPC_COMMERR;
  156. size_t nkeys;
  157. const char *keys, *p;
  158. enum ipc_tval *opts;
  159. struct io_buffer iob;
  160. if ((keys = benc_dget_lst(args, "keys")) == NULL)
  161. return IPC_COMMERR;
  162. nkeys = benc_nelems(keys);
  163. opts = btpd_calloc(nkeys, sizeof(*opts));
  164. p = benc_first(keys);
  165. for (int i = 0; i < nkeys; i++)
  166. opts[i] = benc_int(p, &p);
  167. iob = buf_init(1 << 15);
  168. buf_swrite(&iob, "d4:codei0e6:resultl");
  169. p = benc_dget_any(args, "from");
  170. if (benc_isint(p)) {
  171. enum ipc_twc from = benc_int(p, NULL);
  172. struct tlib *tlv[tlib_count()];
  173. tlib_put_all(tlv);
  174. for (int i = 0; i < sizeof(tlv) / sizeof(tlv[0]); i++) {
  175. if ((from == IPC_TWC_ALL ||
  176. (tlv[i]->tp == NULL && from == IPC_TWC_INACTIVE) ||
  177. (tlv[i]->tp != NULL && from == IPC_TWC_ACTIVE))) {
  178. buf_swrite(&iob, "l");
  179. for (int k = 0; k < nkeys; k++)
  180. write_ans(&iob, tlv[i], opts[k]);
  181. buf_swrite(&iob, "e");
  182. }
  183. }
  184. } else if (benc_islst(p)) {
  185. for (p = benc_first(p); p != NULL; p = benc_next(p)) {
  186. struct tlib *tl = NULL;
  187. if (benc_isint(p))
  188. tl = tlib_by_num(benc_int(p, NULL));
  189. else if (benc_isstr(p) && benc_strlen(p) == 20)
  190. tl = tlib_by_hash(benc_mem(p, NULL, NULL));
  191. else {
  192. buf_free(&iob);
  193. free(opts);
  194. return IPC_COMMERR;
  195. }
  196. if (tl != NULL) {
  197. buf_swrite(&iob, "l");
  198. for (int i = 0; i < nkeys; i++)
  199. write_ans(&iob, tl, opts[i]);
  200. buf_swrite(&iob, "e");
  201. } else
  202. buf_print(&iob, "i%de", IPC_ENOTENT);
  203. }
  204. }
  205. buf_swrite(&iob, "ee");
  206. free(opts);
  207. return write_buffer(cli, &iob);
  208. }
  209. static int
  210. cmd_add(struct cli *cli, int argc, const char *args)
  211. {
  212. if (argc != 1 || !benc_isdct(args))
  213. return IPC_COMMERR;
  214. struct tlib *tl;
  215. size_t mi_size = 0, csize = 0;
  216. const char *mi, *cp;
  217. char content[PATH_MAX];
  218. uint8_t hash[20];
  219. if ((mi = benc_dget_mem(args, "torrent", &mi_size)) == NULL)
  220. return IPC_COMMERR;
  221. if (!mi_test(mi, mi_size))
  222. return write_code_buffer(cli, IPC_EBADT);
  223. if ((cp = benc_dget_mem(args, "content", &csize)) == NULL ||
  224. csize >= PATH_MAX || csize == 0)
  225. return write_code_buffer(cli, IPC_EBADCDIR);
  226. if (cp[0] != '/')
  227. return write_code_buffer(cli, IPC_EBADCDIR);
  228. bcopy(cp, content, csize);
  229. content[csize] = '\0';
  230. tl = tlib_by_hash(mi_info_hash(mi, hash));
  231. if (tl != NULL)
  232. return write_code_buffer(cli, IPC_ETENTEXIST);
  233. tl = tlib_add(hash, mi, mi_size, content,
  234. benc_dget_str(args, "name", NULL));
  235. return write_add_buffer(cli, tl->num);
  236. }
  237. static int
  238. cmd_del(struct cli *cli, int argc, const char *args)
  239. {
  240. if (argc != 1)
  241. return IPC_COMMERR;
  242. int ret;
  243. struct tlib *tl;
  244. if (benc_isstr(args) && benc_strlen(args) == 20)
  245. tl = tlib_by_hash(benc_mem(args, NULL, NULL));
  246. else if (benc_isint(args))
  247. tl = tlib_by_num(benc_int(args, NULL));
  248. else
  249. return IPC_COMMERR;
  250. if (tl == NULL)
  251. ret = write_code_buffer(cli, IPC_ENOTENT);
  252. else {
  253. ret = write_code_buffer(cli, IPC_OK);
  254. if (tl->tp != NULL)
  255. torrent_stop(tl->tp, 1);
  256. else
  257. tlib_del(tl);
  258. }
  259. return ret;
  260. }
  261. static int
  262. cmd_start(struct cli *cli, int argc, const char *args)
  263. {
  264. if (argc != 1)
  265. return IPC_COMMERR;
  266. if (btpd_is_stopping())
  267. return write_code_buffer(cli, IPC_ESHUTDOWN);
  268. struct tlib *tl;
  269. enum ipc_err code = IPC_OK;
  270. if (benc_isstr(args) && benc_strlen(args) == 20)
  271. tl = tlib_by_hash(benc_mem(args, NULL, NULL));
  272. else if (benc_isint(args))
  273. tl = tlib_by_num(benc_int(args, NULL));
  274. else
  275. return IPC_COMMERR;
  276. if (tl == NULL)
  277. code = IPC_ENOTENT;
  278. else if (tl->tp != NULL)
  279. code = IPC_ETACTIVE;
  280. else
  281. if ((code = torrent_start(tl)) == IPC_OK)
  282. active_add(tl->hash);
  283. return write_code_buffer(cli, code);
  284. }
  285. static int
  286. cmd_stop(struct cli *cli, int argc, const char *args)
  287. {
  288. if (argc != 1)
  289. return IPC_COMMERR;
  290. struct tlib *tl;
  291. if (benc_isstr(args) && benc_strlen(args) == 20)
  292. tl = tlib_by_hash(benc_mem(args, NULL, NULL));
  293. else if (benc_isint(args))
  294. tl = tlib_by_num(benc_int(args, NULL));
  295. else
  296. return IPC_COMMERR;
  297. if (tl == NULL)
  298. return write_code_buffer(cli, IPC_ENOTENT);
  299. else if (tl->tp == NULL)
  300. return write_code_buffer(cli, IPC_ETINACTIVE);
  301. else {
  302. // Stopping a torrent may trigger exit so we need to reply before.
  303. int ret = write_code_buffer(cli, IPC_OK);
  304. active_del(tl->hash);
  305. torrent_stop(tl->tp, 0);
  306. return ret;
  307. }
  308. }
  309. static int
  310. cmd_stop_all(struct cli *cli, int argc, const char *args)
  311. {
  312. struct torrent *tp;
  313. int ret = write_code_buffer(cli, IPC_OK);
  314. active_clear();
  315. BTPDQ_FOREACH(tp, torrent_get_all(), entry)
  316. if (tp->state != T_STOPPING)
  317. torrent_stop(tp, 0);
  318. return ret;
  319. }
  320. static int
  321. cmd_die(struct cli *cli, int argc, const char *args)
  322. {
  323. int err = write_code_buffer(cli, IPC_OK);
  324. if (!btpd_is_stopping()) {
  325. int grace_seconds = -1;
  326. if (argc == 1 && benc_isint(args))
  327. grace_seconds = benc_int(args, NULL);
  328. btpd_log(BTPD_L_BTPD, "Someone wants me dead.\n");
  329. btpd_shutdown(grace_seconds);
  330. }
  331. return err;
  332. }
  333. static struct {
  334. const char *name;
  335. int nlen;
  336. int (*fun)(struct cli *cli, int, const char *);
  337. } cmd_table[] = {
  338. { "add", 3, cmd_add },
  339. { "del", 3, cmd_del },
  340. { "die", 3, cmd_die },
  341. { "start", 5, cmd_start },
  342. { "stop", 4, cmd_stop },
  343. { "stop-all", 8, cmd_stop_all},
  344. { "tget", 4, cmd_tget }
  345. };
  346. static int ncmds = sizeof(cmd_table) / sizeof(cmd_table[0]);
  347. static int
  348. cmd_dispatch(struct cli *cli, const char *buf)
  349. {
  350. size_t cmdlen;
  351. const char *cmd;
  352. const char *args;
  353. cmd = benc_mem(benc_first(buf), &cmdlen, &args);
  354. for (int i = 0; i < ncmds; i++) {
  355. if ((cmdlen == cmd_table[i].nlen &&
  356. strncmp(cmd_table[i].name, cmd, cmdlen) == 0)) {
  357. return cmd_table[i].fun(cli, benc_nelems(buf) - 1, args);
  358. }
  359. }
  360. return ENOENT;
  361. }
  362. static void
  363. cli_read_cb(int sd, short type, void *arg)
  364. {
  365. struct cli *cli = arg;
  366. uint32_t cmdlen;
  367. uint8_t *msg = NULL;
  368. if (read_fully(sd, &cmdlen, sizeof(cmdlen)) != 0)
  369. goto error;
  370. msg = btpd_malloc(cmdlen);
  371. if (read_fully(sd, msg, cmdlen) != 0)
  372. goto error;
  373. if (!(benc_validate(msg, cmdlen) == 0 && benc_islst(msg) &&
  374. benc_first(msg) != NULL && benc_isstr(benc_first(msg))))
  375. goto error;
  376. if (cmd_dispatch(cli, msg) != 0)
  377. goto error;
  378. free(msg);
  379. btpd_ev_add(&cli->read, NULL);
  380. return;
  381. error:
  382. close(cli->sd);
  383. free(cli);
  384. if (msg != NULL)
  385. free(msg);
  386. }
  387. void
  388. client_connection_cb(int sd, short type, void *arg)
  389. {
  390. int nsd;
  391. if ((nsd = accept(sd, NULL, NULL)) < 0) {
  392. if (errno == EWOULDBLOCK || errno == ECONNABORTED)
  393. return;
  394. else
  395. btpd_err("client accept: %s\n", strerror(errno));
  396. }
  397. if ((errno = set_blocking(nsd)) != 0)
  398. btpd_err("set_blocking: %s.\n", strerror(errno));
  399. struct cli *cli = btpd_calloc(1, sizeof(*cli));
  400. cli->sd = nsd;
  401. event_set(&cli->read, cli->sd, EV_READ, cli_read_cb, cli);
  402. btpd_ev_add(&cli->read, NULL);
  403. }
  404. void
  405. ipc_init(void)
  406. {
  407. int sd;
  408. struct sockaddr_un addr;
  409. size_t psiz = sizeof(addr.sun_path);
  410. addr.sun_family = PF_UNIX;
  411. if (snprintf(addr.sun_path, psiz, "%s/sock", btpd_dir) >= psiz)
  412. btpd_err("'%s/sock' is too long.\n", btpd_dir);
  413. if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
  414. btpd_err("sock: %s\n", strerror(errno));
  415. if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
  416. if (errno == EADDRINUSE) {
  417. unlink(addr.sun_path);
  418. if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
  419. btpd_err("bind: %s\n", strerror(errno));
  420. } else
  421. btpd_err("bind: %s\n", strerror(errno));
  422. }
  423. if (chmod(addr.sun_path, ipcprot) == -1)
  424. btpd_err("chmod: %s (%s).\n", addr.sun_path, strerror(errno));
  425. listen(sd, 4);
  426. set_nonblocking(sd);
  427. event_set(&m_cli_incoming, sd, EV_READ | EV_PERSIST,
  428. client_connection_cb, NULL);
  429. btpd_ev_add(&m_cli_incoming, NULL);
  430. }