A clone of btpd with my configuration changes.

262 lines
6.3 KiB

  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <sys/un.h>
  4. #include <arpa/inet.h>
  5. #include <sys/stat.h>
  6. #include <inttypes.h>
  7. #include <limits.h>
  8. #include <stdarg.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <unistd.h>
  12. #include "btpd.h"
  13. #ifndef PRIu64
  14. #define PRIu64 "llu"
  15. #endif
  16. #define buf_swrite(iob, s) buf_write(iob, s, sizeof(s) - 1)
  17. static struct event m_cli_incoming;
  18. static void
  19. errdie(int error)
  20. {
  21. if (error != 0)
  22. btpd_err("io_buf: %s.\n", strerror(error));
  23. }
  24. static void
  25. cmd_stat(int argc, const char *args, FILE *fp)
  26. {
  27. struct torrent *tp;
  28. struct io_buffer iob;
  29. errdie(buf_init(&iob, (1 << 14)));
  30. errdie(buf_swrite(&iob, "d"));
  31. errdie(buf_print(&iob, "6:npeersi%ue", net_npeers));
  32. errdie(buf_print(&iob, "9:ntorrentsi%ue", btpd_get_ntorrents()));
  33. errdie(buf_print(&iob, "7:secondsi%lue", btpd_seconds));
  34. errdie(buf_swrite(&iob, "8:torrentsl"));
  35. BTPDQ_FOREACH(tp, btpd_get_torrents(), entry) {
  36. uint32_t seen_npieces = 0;
  37. for (uint32_t i = 0; i < tp->meta.npieces; i++)
  38. if (tp->piece_count[i] > 0)
  39. seen_npieces++;
  40. errdie(buf_print(&iob, "d4:downi%" PRIu64 "e", tp->downloaded));
  41. errdie(buf_swrite(&iob, "4:hash20:"));
  42. errdie(buf_write(&iob, tp->meta.info_hash, 20));
  43. errdie(buf_print(&iob, "12:have npiecesi%ue", tp->have_npieces));
  44. errdie(buf_print(&iob, "6:npeersi%ue", tp->npeers));
  45. errdie(buf_print(&iob, "7:npiecesi%ue", tp->meta.npieces));
  46. errdie(buf_print(&iob, "4:path%d:%s",
  47. (int)strlen(tp->relpath), tp->relpath));
  48. errdie(buf_print(&iob, "12:seen npiecesi%ue", seen_npieces));
  49. errdie(buf_print(&iob, "2:upi%" PRIu64 "ee", tp->uploaded));
  50. }
  51. errdie(buf_swrite(&iob, "ee"));
  52. uint32_t len = iob.buf_off;
  53. fwrite(&len, sizeof(len), 1, fp);
  54. fwrite(iob.buf, 1, iob.buf_off, fp);
  55. free(iob.buf);
  56. }
  57. static void
  58. cmd_add(int argc, const char *args, FILE *fp)
  59. {
  60. struct io_buffer iob;
  61. errdie(buf_init(&iob, (1 << 10)));
  62. errdie(buf_write(&iob, "l", 1));
  63. while (args != NULL) {
  64. size_t plen;
  65. char path[PATH_MAX];
  66. const char *pathp;
  67. if (!benc_isstr(args)) {
  68. free(iob.buf);
  69. return;
  70. }
  71. benc_str(args, &pathp, &plen, &args);
  72. if (plen >= PATH_MAX) {
  73. errdie(buf_print(&iob, "d4:codei%dee", ENAMETOOLONG));
  74. continue;
  75. }
  76. bcopy(pathp, path, plen);
  77. path[plen] = '\0';
  78. btpd_log(BTPD_L_BTPD, "add request for %s.\n", path);
  79. errdie(buf_print(&iob, "d4:codei%dee", torrent_load(path)));
  80. }
  81. errdie(buf_write(&iob, "e", 1));
  82. uint32_t len = iob.buf_off;
  83. fwrite(&len, sizeof(len), 1, fp);
  84. fwrite(iob.buf, 1, iob.buf_off, fp);
  85. free(iob.buf);
  86. }
  87. static void
  88. cmd_del(int argc, const char *args, FILE *fp)
  89. {
  90. struct io_buffer iob;
  91. errdie(buf_init(&iob, (1 << 10)));
  92. errdie(buf_swrite(&iob, "l"));
  93. while (args != NULL) {
  94. size_t len;
  95. const char *hash;
  96. struct torrent *tp;
  97. if (!benc_isstr(args) ||
  98. benc_str(args, &hash, &len, &args) != 0 || len != 20) {
  99. free(iob.buf);
  100. return;
  101. }
  102. tp = btpd_get_torrent(hash);
  103. if (tp != NULL) {
  104. btpd_log(BTPD_L_BTPD, "del request for %s.\n", tp->relpath);
  105. torrent_unload(tp);
  106. errdie(buf_swrite(&iob, "d4:codei0ee"));
  107. } else {
  108. btpd_log(BTPD_L_BTPD, "del request didn't match.\n");
  109. errdie(buf_print(&iob, "d4:codei%dee", ENOENT));
  110. }
  111. }
  112. errdie(buf_swrite(&iob, "e"));
  113. uint32_t len = iob.buf_off;
  114. fwrite(&len, sizeof(len), 1, fp);
  115. fwrite(iob.buf, 1, iob.buf_off, fp);
  116. free(iob.buf);
  117. }
  118. static void
  119. cmd_die(int argc, const char *args, FILE *fp)
  120. {
  121. char res[] = "d4:codei0ee";
  122. uint32_t len = sizeof(res) - 1;
  123. fwrite(&len, sizeof(len), 1, fp);
  124. fwrite(res, 1, len, fp);
  125. fflush(fp);
  126. btpd_log(BTPD_L_BTPD, "Someone wants me dead.\n");
  127. btpd_shutdown();
  128. }
  129. static struct {
  130. const char *name;
  131. int nlen;
  132. void (*fun)(int, const char *, FILE *);
  133. } cmd_table[] = {
  134. { "add", 3, cmd_add },
  135. { "del", 3, cmd_del },
  136. { "die", 3, cmd_die },
  137. { "stat", 4, cmd_stat }
  138. };
  139. static int ncmds = sizeof(cmd_table) / sizeof(cmd_table[0]);
  140. static void
  141. cmd_dispatch(const char *buf, FILE *fp)
  142. {
  143. size_t cmdlen;
  144. const char *cmd;
  145. const char *args;
  146. int found = 0;
  147. benc_str(benc_first(buf), &cmd, &cmdlen, &args);
  148. for (int i = 0; !found && i < ncmds; i++) {
  149. if (cmdlen == cmd_table[i].nlen &&
  150. strncmp(cmd_table[i].name, cmd, cmdlen) == 0) {
  151. cmd_table[i].fun(benc_nelems(buf) - 1, args, fp);
  152. found = 1;
  153. }
  154. }
  155. }
  156. static void
  157. do_ipc(FILE *fp)
  158. {
  159. uint32_t cmdlen, nread;
  160. char *buf;
  161. if (fread(&cmdlen, sizeof(cmdlen), 1, fp) != 1)
  162. return;
  163. buf = btpd_malloc(cmdlen);
  164. if ((nread = fread(buf, 1, cmdlen, fp)) == cmdlen) {
  165. if (benc_validate(buf, cmdlen) == 0 && benc_islst(buf) &&
  166. benc_first(buf) != NULL && benc_isstr(benc_first(buf)))
  167. cmd_dispatch(buf, fp);
  168. }
  169. free(buf);
  170. }
  171. void
  172. client_connection_cb(int sd, short type, void *arg)
  173. {
  174. int nsd;
  175. FILE *fp;
  176. if ((nsd = accept(sd, NULL, NULL)) < 0) {
  177. if (errno == EWOULDBLOCK || errno == ECONNABORTED)
  178. return;
  179. else
  180. btpd_err("client accept: %s\n", strerror(errno));
  181. }
  182. if ((errno = set_blocking(nsd)) != 0)
  183. btpd_err("set_blocking: %s.\n", strerror(errno));
  184. if ((fp = fdopen(nsd, "r+")) == NULL) {
  185. close(nsd);
  186. return;
  187. }
  188. do_ipc(fp);
  189. fclose(fp);
  190. }
  191. void
  192. ipc_init(void)
  193. {
  194. int sd;
  195. struct sockaddr_un addr;
  196. size_t psiz = sizeof(addr.sun_path);
  197. addr.sun_family = PF_UNIX;
  198. if (snprintf(addr.sun_path, psiz, "%s/sock", btpd_dir) >= psiz)
  199. btpd_err("'%s/sock' is too long.\n", btpd_dir);
  200. if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
  201. btpd_err("sock: %s\n", strerror(errno));
  202. if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
  203. if (errno == EADDRINUSE) {
  204. unlink(addr.sun_path);
  205. if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
  206. btpd_err("bind: %s\n", strerror(errno));
  207. } else
  208. btpd_err("bind: %s\n", strerror(errno));
  209. }
  210. if (chmod(addr.sun_path, 0600) == -1)
  211. btpd_err("chmod: %s (%s).\n", addr.sun_path, strerror(errno));
  212. listen(sd, 4);
  213. set_nonblocking(sd);
  214. event_set(&m_cli_incoming, sd, EV_READ | EV_PERSIST,
  215. client_connection_cb, NULL);
  216. event_add(&m_cli_incoming, NULL);
  217. }