struct mi_file * mi_files(const char *p) { struct mi_file *fi; const char *info = benc_dget_dct(p, "info"); const char *files = benc_dget_lst(info, "files"); if (files != NULL) { int i = 0; unsigned nfiles = benc_nelems(files); const char *fdct = benc_first(files); if ((fi = calloc(nfiles, sizeof(*fi))) == NULL) return NULL; for (fdct = benc_first(files); fdct != NULL; fdct = benc_next(fdct)) { fi[i].length = benc_dget_int(fdct, "length"); fi[i].path = mi_filepath(benc_dget_lst(fdct, "path")); if (fi[i].path == NULL) { mi_free_files(nfiles, fi); return NULL; } i++; } } else { if ((fi = calloc(1, sizeof(*fi))) == NULL) return NULL; fi[0].length = benc_dget_int(info, "length"); fi[0].path = benc_dget_str(info, "name", NULL); if (fi[0].path == NULL) { free(fi); return NULL; } } return fi; }
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; }
static int mi_test_files(const char *files) { int fcount = 0; const char *fdct = benc_first(files); while (fdct != NULL) { const char *plst; const char *path; int pcount = 0; if (!benc_isdct(fdct)) return 0; if (benc_dget_int(fdct, "length") < 0) return 0; if ((plst = benc_dget_lst(fdct, "path")) == NULL) return 0; path = benc_first(plst); while (path != NULL) { size_t plen; const char *pstr = benc_mem(path, &plen, &path); if (pstr == NULL || !mi_test_path(pstr, plen)) return 0; pcount++; } if (pcount == 0) return 0; fcount++; fdct = benc_next(fdct); } return fcount > 0 ? 1 : 0; }
off_t mi_total_length(const char *p) { const char *info = benc_dget_dct(p, "info"); const char *files = benc_dget_lst(info, "files"); if (files != NULL) { off_t length = 0; const char *fdct = benc_first(files); while (fdct != NULL) { length += benc_dget_int(fdct, "length"); fdct = benc_next(fdct); } return length; } else return benc_dget_int(info, "length"); }
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); }
off_t mi_piece_length(const char *p) { return benc_dget_int(benc_dget_dct(p, "info"), "piece length"); }