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.

484 lines
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. }