Пример #1
0
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;
}
Пример #2
0
static void
cli_read_cb(int sd, short type, void *arg)
{
    struct cli *cli = arg;
    uint32_t cmdlen;
    uint8_t *msg = NULL;

    if (read_fully(sd, &cmdlen, sizeof(cmdlen)) != 0)
        goto error;

    msg = btpd_malloc(cmdlen);
    if (read_fully(sd, msg, cmdlen) != 0)
        goto error;

    if (!(benc_validate(msg, cmdlen) == 0 && benc_islst(msg) &&
            benc_first(msg) != NULL && benc_isstr(benc_first(msg))))
        goto error;

    if (cmd_dispatch(cli, msg) != 0)
        goto error;

    free(msg);
    return;

error:
    btpd_ev_del(&cli->read);
    close(cli->sd);
    free(cli);
    if (msg != NULL)
        free(msg);
}
Пример #3
0
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;
}
Пример #4
0
static char *
mi_filepath(const char *plst)
{
    char *res = NULL;
    const char *str;
    size_t npaths = 0, plen = 0, len;
    const char *iter = benc_first(plst);

    while (iter != NULL) {
        benc_mem(iter, &len, &iter);
        npaths++;
        plen += len;
    }

    if ((res = malloc(plen + (npaths - 1) + 1)) == NULL)
        return NULL;

    iter = benc_first(plst);
    str = benc_mem(iter, &len, &iter);
    bcopy(str, res, len);
    plen = len;
    npaths--;
    while (npaths > 0) {
        res[plen] = '/';
        plen++;
        str = benc_mem(iter, &len, &iter);
        bcopy(str, res + plen, len);
        plen += len;
        npaths--;
    }
    res[plen] = '\0';
    return res;
}
Пример #5
0
struct mi_announce *
mi_announce(const char *p)
{
    int ti, ui;
    const char *alst, *ulst, *url;
    struct mi_announce *res;

    if ((res = calloc(1, sizeof(*res))) == NULL)
        return NULL;

    if ((alst = benc_dget_lst(p, "announce-list")) != NULL) {
        res->ntiers = benc_nelems(alst);
        if ((res->tiers = calloc(res->ntiers, sizeof(*res->tiers))) == NULL)
            goto error;
        ti = 0; ulst = benc_first(alst);
        while (ulst != NULL) {
            res->tiers[ti].nurls = benc_nelems(ulst);
            res->tiers[ti].urls =
                calloc(res->tiers[ti].nurls, sizeof(*res->tiers[ti].urls));
            if (res->tiers[ti].urls == NULL)
                goto error;

            ui = 0; url = benc_first(ulst);
            while (url != NULL) {
                if ((res->tiers[ti].urls[ui] =
                        benc_str(url, NULL, NULL)) == NULL)
                    goto error;
                ui++; url = benc_next(url);
            }

            ti++; ulst = benc_next(ulst);
        }
    } else {
        res->ntiers = 1;
        if ((res->tiers = calloc(1, sizeof(*res->tiers))) == NULL)
            goto error;
        res->tiers[0].nurls = 1;
        if ((res->tiers[0].urls =
                calloc(1, sizeof(*res->tiers[0].urls))) == NULL)
            goto error;
        if ((res->tiers[0].urls[0] =
                benc_dget_str(p, "announce", NULL)) == NULL)
            goto error;
    }
    mi_shuffle_announce(res);
    return res;

error:
    if (res != NULL)
        mi_free_announce(res);
    return NULL;
}
Пример #6
0
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;
}
Пример #7
0
static int
mi_test_announce_list(const char *alst)
{
    int lstcount = 0;
    const char *t = benc_first(alst);
    while (t != NULL && benc_islst(t)) {
        int strcount = 0;
        const char *s = benc_first(t);
        while (s != NULL && benc_isstr(s)) {
            strcount++;
            s = benc_next(s);
        }
        if (strcount == 0)
            return 0;
        lstcount++;
        t = benc_next(t);
    }
    return lstcount > 0 ? 1 : 0;
}
Пример #8
0
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;
}
Пример #9
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");
}
Пример #10
0
static int
cmd_dispatch(struct cli *cli, const char *buf)
{
    size_t cmdlen;
    const char *cmd;
    const char *args;

    cmd = benc_mem(benc_first(buf), &cmdlen, &args);

    for (int i = 0; i < ARRAY_COUNT(cmd_table); i++) {
        if ((cmdlen == cmd_table[i].nlen &&
                strncmp(cmd_table[i].name, cmd, cmdlen) == 0)) {
            return cmd_table[i].fun(cli, benc_nelems(buf) - 1, args);
        }
    }
    return ENOENT;
}
Пример #11
0
static int
cmd_tget(struct cli *cli, int argc, const char *args)
{
    if (argc != 1 || !benc_isdct(args))
        return IPC_COMMERR;

    size_t nkeys;
    const char *keys, *p;
    enum ipc_tval *opts;
    struct iobuf iob;

    if ((keys = benc_dget_lst(args, "keys")) == NULL)
        return IPC_COMMERR;

    nkeys = benc_nelems(keys);
    opts = btpd_calloc(nkeys, sizeof(*opts));

    p = benc_first(keys);
    for (int i = 0; i < nkeys; i++)
        opts[i] = benc_int(p, &p);

    iob = iobuf_init(1 << 15);
    iobuf_swrite(&iob, "d4:codei0e6:resultl");
    p = benc_dget_any(args, "from");
    if (benc_isint(p)) {
        enum ipc_twc from = benc_int(p, NULL);
        struct htbl_iter it;
        struct tlib *tl;
        for (tl = tlib_iter_first(&it); tl != NULL; tl = tlib_iter_next(&it)) {
            if (!torrent_haunting(tl) && (
                    from == IPC_TWC_ALL ||
                    (!torrent_active(tl) && from == IPC_TWC_INACTIVE) ||
                    (torrent_active(tl) && from == IPC_TWC_ACTIVE))) {
                iobuf_swrite(&iob, "l");
                for (int k = 0; k < nkeys; k++)
                    write_ans(&iob, tl, opts[k]);
                iobuf_swrite(&iob, "e");
            }
        }
    } else if (benc_islst(p)) {
        for (p = benc_first(p); p != NULL; p = benc_next(p)) {
            struct tlib *tl = NULL;
            if (benc_isint(p))
                tl = tlib_by_num(benc_int(p, NULL));
            else if (benc_isstr(p) && benc_strlen(p) == 20)
                tl = tlib_by_hash(benc_mem(p, NULL, NULL));
            else {
                iobuf_free(&iob);
                free(opts);
                return IPC_COMMERR;
            }
            if (tl != NULL && !torrent_haunting(tl)) {
                iobuf_swrite(&iob, "l");
                for (int i = 0; i < nkeys; i++)
                    write_ans(&iob, tl, opts[i]);
                iobuf_swrite(&iob, "e");
            } else
                iobuf_print(&iob, "i%de", IPC_ENOTENT);
        }
    }
    iobuf_swrite(&iob, "ee");
    free(opts);
    return write_buffer(cli, &iob);
}