A clone of btpd with my configuration changes.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

482 Zeilen
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. }