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.

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