A clone of btpd with my configuration changes.

524 строки
14 KiB

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