Ejemplo n.º 1
0
/**
 * 劈开ndnb名字,并把各个部分(n个)放到 components 中.
 * 貌似c会被修改. components 可以直接传null,即无所谓.
 * 参数:
 * c => 输入的 ndnb 名字
 * components => 输出
 * n => 需要留下的组件的数量. 负数代表需要remove的数量
 *
 * Chop the name down to n components.
 * @param c contains a ndnb-encoded Name
 * @param components may be NULL; if provided it must be consistent with
 *        some prefix of the name, and is updated accordingly.
 * @param n is the number or components to leave, or, if negative, specifies
 *        how many components to remove,
          e.g. -1 will remove just the last component.
 * @returns -1 for error, otherwise the new number of Components
 */
int
ndn_name_chop(struct ndn_charbuf *c, struct ndn_indexbuf *components, int n)
{
    if (components == NULL) {
        int res;
        components = ndn_indexbuf_create();
        if (components == NULL)
            return(-1);
        res = ndn_name_split(c, components);
        if (res >= 0)
            res = ndn_name_chop(c, components, n);
        ndn_indexbuf_destroy(&components);
        return(res);
    }
    /* Fix up components if needed. We could be a little smarter about this. */
    if (components->n == 0 || components->buf[components->n-1] + 1 != c->length)
        if (ndn_name_split(c, components) < 0)
            return(-1);
    if (n < 0)
        n += (components->n - 1); /* APL-style indexing */
    if (n < 0)
        return(-1);
    if (n < components->n) {
        c->length = components->buf[n];
        ndn_charbuf_append_value(c, NDN_CLOSE, 1);
        components->n = n + 1;
        return(n);
    }
    return(-1);
}
Ejemplo n.º 2
0
/**
 * Advance the last Component of a Name to the next possible value.
 * @param c contains a ndnb-encoded Name to be updated.
 * @returns -1 for error, otherwise the number of Components
 */
int
ndn_name_next_sibling(struct ndn_charbuf *c)
{
    int res = -1;
    struct ndn_indexbuf *ndx;
    unsigned char *lastcomp = NULL;
    size_t lastcompsize = 0;
    size_t i;
    int carry;
    struct ndn_charbuf *newcomp;

    ndx = ndn_indexbuf_create();
    if (ndx == NULL) goto Finish;
    res = ndn_name_split(c, ndx);
    if (res <= 0) {
        res = -1;
        goto Finish;
    }
    res = ndn_ref_tagged_BLOB(NDN_DTAG_Component, c->buf,
        ndx->buf[res-1], ndx->buf[res],
        (const unsigned char **)&lastcomp,
        &lastcompsize);
    if (res < 0) goto Finish;
    for (carry = 1, i = lastcompsize; carry && i > 0; i--) {
        carry = (((++lastcomp[i-1]) & 0xFF) == 0x00);
    }
    if (carry) {
        newcomp = ndn_charbuf_create();
        res |= ndn_charbuf_append_value(newcomp, 0, 1);
        res |= ndn_charbuf_append(newcomp, lastcomp, lastcompsize);
        res |= ndn_name_chop(c, ndx, ndx->n - 2);
        res |= ndn_name_append(c, newcomp->buf, newcomp->length);
        ndn_charbuf_destroy(&newcomp);
        if (res < 0) goto Finish;
    }
    res = ndx->n - 1;
Finish:
    ndn_indexbuf_destroy(&ndx);
    return(res);
}
Ejemplo n.º 3
0
/**
 * Extend a Name with a new version stamp
 * @param h is the the ndn handle.
 *        May be NULL.  This procedure does not use the connection.
 * @param name is a ndnb-encoded Name prefix. By default it gets extended
 *        in-place with one additional Component that conforms to the
 *        versioning profile and is based on the supplied time, unless a
 *        version component is already present.
 * @param versioning_flags modifies the default behavior:
 *        NDN_V_REPLACE causes the last component to be replaced if it
 *        appears to be a version stamp.  If NDN_V_HIGH is set as well, an
 *        attempt will be made to generate a new version stamp that is
 *        later than the existing one, or to return an error.
 *        NDN_V_NOW bases the version on the current time rather than the
 *        supplied time.
 *        NDN_V_NESTOK will allow the new version component to be appended
 *        even if there is one there (this makes no difference if NDN_V_REPLACE
 *        is also set).
 * @param secs is the desired time, in seconds since epoch
 *        (ignored if NDN_V_NOW is set).
 * @param nsecs is the number of nanoseconds.
 * @returns -1 for error, 0 for success.
 */
int
ndn_create_version(struct ndn *h, struct ndn_charbuf *name,
                   int versioning_flags, intmax_t secs, int nsecs)
{
    size_t i;
    size_t j;
    size_t lc = 0;
    size_t oc = 0;
    int n;
    struct ndn_indexbuf *nix = NULL;
    int myres = -1;
    int already_versioned = 0;
    int ok_flags = (NDN_V_REPLACE | NDN_V_HIGH | NDN_V_NOW | NDN_V_NESTOK);
    // XXX - right now we ignore h, but in the future we may use it to try to avoid non-monotonicies in the versions.
    
    nix = ndn_indexbuf_create();
    n = ndn_name_split(name, nix);
    if (n < 0)
        goto Finish;
    if ((versioning_flags & ~ok_flags) != 0)
        goto Finish;        
    /* Check for existing version component */
    if (n >= 1) {
        oc = nix->buf[n-1];
        lc = nix->buf[n] - oc;
        if (lc <= 11 && lc >= 6 && name->buf[oc + 2] == NDN_MARKER_VERSION)
            already_versioned = 1;
    }
    myres = 0;
    if (already_versioned &&
        (versioning_flags & (NDN_V_REPLACE | NDN_V_NESTOK)) == 0)
        goto Finish;
    name->length -= 1; /* Strip name closer */
    i = name->length;
    myres |= ndn_charbuf_append_tt(name, NDN_DTAG_Component, NDN_DTAG);
    if ((versioning_flags & NDN_V_NOW) != 0)
        myres |= ndnb_append_now_blob(name, NDN_MARKER_VERSION);
    else {
        myres |= ndnb_append_timestamp_blob(name, NDN_MARKER_VERSION, secs, nsecs);
    }
    myres |= ndn_charbuf_append_closer(name); /* </Component> */
    if (myres < 0) {
        name->length = i;
        goto CloseName;
    }
    j = name->length;
    if (already_versioned && (versioning_flags & NDN_V_REPLACE) != 0) {
        oc = nix->buf[n-1];
        lc = nix->buf[n] - oc;
        if ((versioning_flags & NDN_V_HIGH) != 0 &&
            memcmp(name->buf + oc, name->buf + i, j - i) > 0) {
            /* Supplied version is in the future. */
            name->length = i;
            // XXX - we could try harder to make this work, for now just error out
            myres = -1;
            goto CloseName;
        }
        memmove(name->buf + oc, name->buf + i, j - i);
        name->length -= lc;
    }
CloseName:
    myres |= ndn_charbuf_append_closer(name); /* </Name> */
Finish:
    myres = (myres < 0) ? -1 : 0;
    ndn_indexbuf_destroy(&nix);
    return(myres);
}
Ejemplo n.º 4
0
/**
 * Resolve the version, based on existing ndn content.
 * @param h is the the ndn handle; it may be NULL, but it is preferable to
 *        use the handle that the client probably already has.
 * @param name is a ndnb-encoded Name prefix. It gets extended in-place with
 *        one additional Component such that it names highest extant
 *        version that can be found, subject to the supplied timeout.
 * @param versioning_flags presently must be NDN_V_HIGH or NDN_V_HIGHEST,
 *        possibly combined with NDN_V_NESTOK.  If NDN_V_NESTOK is not present
 *        and the ending component appears to be a version, the routine
 *        returns 0 immediately, on the assumption that an explicit
 *        version has already been provided.
 * @param timeout_ms is a time value in milliseconds. This is the total time
 *        that the caller can wait.
 * @returns -1 for error, 0 if name was not extended, 1 if was.
 */
int
ndn_resolve_version(struct ndn *h, struct ndn_charbuf *name,
                    int versioning_flags, int timeout_ms)
{
    int res;
    int myres = -1;
    struct ndn_parsed_ContentObject pco_space = { 0 };
    struct ndn_charbuf *templ = NULL;
    struct ndn_charbuf *prefix = ndn_charbuf_create();
    struct ndn_charbuf *cobj = ndn_charbuf_create();
    struct ndn_parsed_ContentObject *pco = &pco_space;
    struct ndn_indexbuf *ndx = ndn_indexbuf_create();
    const unsigned char *vers = NULL;
    size_t vers_size = 0;
    struct timeval start, prev, now;
    int n;
    int rtt_max = 0;
    int rtt;
    int ttimeout;
    struct ndn_indexbuf *nix = ndn_indexbuf_create();
    unsigned char lowtime[7] = {NDN_MARKER_VERSION, 0, FF, FF, FF, FF, FF};
    
    if ((versioning_flags & ~NDN_V_NESTOK & ~NDN_V_EST) != NDN_V_HIGH) {
        ndn_seterror(h, EINVAL);
        ndn_perror(h, "ndn_resolve_version is only implemented for versioning_flags = NDN_V_HIGH(EST)");
        goto Finish;
    }
    n = ndn_name_split(name, nix);
    if (n < 0)
        goto Finish;
    if ((versioning_flags & NDN_V_NESTOK) == 0) {
        res = ndn_name_comp_get(name->buf, nix, n - 1, &vers, &vers_size);
        if (res >= 0 && vers_size == 7 && vers[0] == NDN_MARKER_VERSION) {
            myres = 0;
            goto Finish;
        }    
    }
    templ = resolve_templ(templ, lowtime, sizeof(lowtime),
                          ms_to_tu(timeout_ms) * 7 / 8, versioning_flags);
    ndn_charbuf_append(prefix, name->buf, name->length); /* our copy */
    cobj->length = 0;
    gettimeofday(&start, NULL);
    prev = start;
    /*
     * the algorithm for NDN_V_HIGHEST is to send the initial Interest with
     * a lifetime that will ensure 1 resend before the timeout, and to keep
     * keep sending an Interest, excluding earlier versions, tracking the
     * maximum round trip time and using a timeout of 4*RTT, and an interest
     * lifetime that should get a retransmit.   If there is no response,
     * return the highest version found so far.
     */
    myres = 0;
    res = ndn_get(h, prefix, templ, timeout_ms, cobj, pco, ndx, 0);
    while (cobj->length != 0) {
        if (pco->type == NDN_CONTENT_NACK) // XXX - also check for number of components
            break;
        res = ndn_name_comp_get(cobj->buf, ndx, n, &vers, &vers_size);
        if (res < 0)
            break;
        if (vers_size == 7 && vers[0] == NDN_MARKER_VERSION) {
            /* Looks like we have versions. */
            name->length = 0;
            ndn_charbuf_append(name, prefix->buf, prefix->length);
            ndn_name_append(name, vers, vers_size);
            myres = 1;
            if ((versioning_flags & NDN_V_EST) == 0)
                break;
            gettimeofday(&now, NULL);
            rtt = (now.tv_sec - prev.tv_sec) * 1000000 + (now.tv_usec - prev.tv_usec);
            if (rtt > rtt_max) rtt_max = rtt;
            prev = now;
            timeout_ms -= (now.tv_sec - start.tv_sec) * 1000 + (now.tv_usec - start.tv_usec) / 1000;
            if (timeout_ms <= 0)
                break;
            ttimeout = timeout_ms < (rtt_max/250) ? timeout_ms : (rtt_max/250);
            templ = resolve_templ(templ, vers, vers_size, ms_to_tu(ttimeout) * 7 / 8, versioning_flags);
            if (templ == NULL) break;
            cobj->length = 0;
            res = ndn_get(h, prefix, templ, ttimeout, cobj, pco, ndx,
                          NDN_GET_NOKEYWAIT);
        }
        else break;
    }
Finish:
    ndn_charbuf_destroy(&prefix);
    ndn_charbuf_destroy(&cobj);
    ndn_indexbuf_destroy(&ndx);
    ndn_indexbuf_destroy(&nix);
    ndn_charbuf_destroy(&templ);
    return(myres);
}