static void parse_reply(struct torrent *tp, struct tr_response *res, const char *content, size_t size) { const char *buf; size_t len; const char *peers; const char *v6key[] = {"peers6", "peers_ipv6"}; if (benc_validate(content, size) != 0) goto bad_data; if ((buf = benc_dget_any(content, "failure reason")) != NULL) { if (!benc_isstr(buf)) goto bad_data; res->type = TR_RES_FAIL; res->mi_failure = buf; return; } buf = benc_dget_any(content, "interval"); if (buf != NULL && benc_isint(buf)) res->interval = benc_int(buf, NULL); if ((peers = benc_dget_any(content, "peers")) == NULL) goto after_peers; if (benc_islst(peers)) { for (peers = benc_first(peers); peers != NULL && net_npeers < net_max_peers; peers = benc_next(peers)) maybe_connect_to(tp, peers); } else if (benc_isstr(peers)) { if (net_ipv4) { peers = benc_dget_mem(content, "peers", &len); for (size_t i = 0; i < len && net_npeers < net_max_peers; i += 6) peer_create_out_compact(tp->net, AF_INET, peers + i); } } else goto bad_data; after_peers: if (!net_ipv6) goto after_peers6; for (int k = 0; k < 2; k++) { peers = benc_dget_any(content, v6key[k]); if (peers != NULL && benc_isstr(peers)) { peers = benc_dget_mem(content, v6key[k], &len); for (size_t i = 0; i < len && net_npeers < net_max_peers; i += 18) peer_create_out_compact(tp->net, AF_INET6, peers + i); } } after_peers6: res->type = TR_RES_OK; return; bad_data: res->type = TR_RES_BAD; }
int mi_test(const char *p, size_t size) { const char *info; const char *alst; const char *pieces; const char *files; const char *fdct; const char *name; size_t slen, npieces; off_t length = 0, piece_length; if (benc_validate(p, size) != 0 || !benc_isdct(p)) return 0; if ((alst = benc_dget_any(p, "announce-list")) != NULL) { if (!benc_islst(alst)) return 0; if (!mi_test_announce_list(alst)) return 0; } else if (benc_dget_mem(p, "announce", NULL) == NULL) return 0; if ((info = benc_dget_dct(p, "info")) == NULL) return 0; if ((name = benc_dget_mem(info, "name", &slen)) != NULL) if (!mi_test_path(name, slen)) return 0; if ((piece_length = benc_dget_int(info, "piece length")) <= 0) return 0; if ((pieces = benc_dget_mem(info, "pieces", &slen)) == NULL || slen % 20 != 0) return 0; npieces = slen / 20; if ((length = benc_dget_int(info, "length")) != 0) { if (length < 0 || benc_dget_any(info, "files") != NULL) return 0; } else { if ((files = benc_dget_lst(info, "files")) == NULL) return 0; if (!mi_test_files(files)) return 0; fdct = benc_first(files); while (fdct != NULL) { length += benc_dget_int(fdct, "length"); fdct = benc_next(fdct); } } if (length < (npieces - 1) * piece_length || length > npieces * piece_length) return 0; return 1; }
size_t mi_npieces(const char *p) { size_t plen; benc_dget_mem(benc_dget_dct(p, "info"), "pieces", &plen); return plen / 20; }
static void maybe_connect_to(struct torrent *tp, const char *pinfo) { const char *pid; char *ip; int port; size_t len; if ((pid = benc_dget_mem(pinfo, "peer id", &len)) == NULL || len != 20) return; if (bcmp(btpd_get_peer_id(), pid, 20) == 0) return; if (net_torrent_has_peer(tp->net, pid)) return; if ((ip = benc_dget_str(pinfo, "ip", NULL)) == NULL) return; port = benc_dget_int(pinfo, "port"); peer_create_out(tp->net, pid, ip, port); if (ip != NULL) free(ip); }
static int cmd_add(struct cli *cli, int argc, const char *args) { if (argc != 1 || !benc_isdct(args)) return IPC_COMMERR; struct tlib *tl; size_t mi_size = 0, csize = 0; const char *mi, *cp; char content[PATH_MAX]; uint8_t hash[20]; if ((mi = benc_dget_mem(args, "torrent", &mi_size)) == NULL) return IPC_COMMERR; if (!mi_test(mi, mi_size)) return write_code_buffer(cli, IPC_EBADT); if ((cp = benc_dget_mem(args, "content", &csize)) == NULL || csize >= PATH_MAX || csize == 0) return write_code_buffer(cli, IPC_EBADCDIR); if (cp[0] != '/') return write_code_buffer(cli, IPC_EBADCDIR); bcopy(cp, content, csize); content[csize] = '\0'; tl = tlib_by_hash(mi_info_hash(mi, hash)); if (tl != NULL && !torrent_haunting(tl)) return write_code_buffer(cli, IPC_ETENTEXIST); if (tl != NULL) { tl = tlib_readd(tl, hash, mi, mi_size, content, benc_dget_str(args, "name", NULL), benc_dget_str(args, "label", NULL)); } else { tl = tlib_add(hash, mi, mi_size, content, benc_dget_str(args, "name", NULL), benc_dget_str(args, "label", NULL)); } return write_add_buffer(cli, tl->num); }
void cmd_add(int argc, char **argv) { int ch, topdir = 0, start = 1, nfile, nloaded = 0; size_t dirlen = 0, labellen = 0; char *dir = NULL, *name = NULL, *glabel = NULL, *label; while ((ch = getopt_long(argc, argv, "NTd:l:n:", add_opts, NULL)) != -1) { switch (ch) { case 'N': start = 0; break; case 'T': topdir = 1; break; case 'd': dir = optarg; if ((dirlen = strlen(dir)) == 0) diemsg("bad option value for -d.\n"); break; case 'l': glabel = optarg; if ((labellen = strlen(dir)) == 0) diemsg("bad option value for -l.\n"); break; case 'n': name = optarg; break; default: usage_add(); } } argc -= optind; argv += optind; if (argc < 1 || dir == NULL) usage_add(); btpd_connect(); char *mi; size_t mi_size; enum ipc_err code; char dpath[PATH_MAX]; struct iobuf iob; for (nfile = 0; nfile < argc; nfile++) { if ((mi = mi_load(argv[nfile], &mi_size)) == NULL) { fprintf(stderr, "error loading '%s' (%s).\n", argv[nfile], strerror(errno)); continue; } iob = iobuf_init(PATH_MAX); iobuf_write(&iob, dir, dirlen); if (topdir && !mi_simple(mi)) { size_t tdlen; const char *td = benc_dget_mem(benc_dget_dct(mi, "info"), "name", &tdlen); iobuf_swrite(&iob, "/"); iobuf_write(&iob, td, tdlen); } iobuf_swrite(&iob, "\0"); if ((errno = make_abs_path(iob.buf, dpath)) != 0) { fprintf(stderr, "make_abs_path '%s' failed (%s).\n", dpath, strerror(errno)); iobuf_free(&iob); continue; } if(NULL == glabel) label = benc_dget_str(mi, "announce", NULL); else label = glabel; code = btpd_add(ipc, mi, mi_size, dpath, name, label); if ((code == IPC_OK) && start) { struct ipc_torrent tspec; tspec.by_hash = 1; mi_info_hash(mi, tspec.u.hash); code = btpd_start(ipc, &tspec); } if (code != IPC_OK) { fprintf(stderr, "command failed for '%s' (%s).\n", argv[nfile], ipc_strerror(code)); } else { nloaded++; } iobuf_free(&iob); } if (nloaded != nfile) { diemsg("error loaded %d of %d files.\n", nloaded, nfile); } }