Example #1
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);
}
Example #2
0
/**
 * Resolve the version, based on existing ccn content.
 * @param h is the the ccn handle; it may be NULL, but it is preferable to
 *        use the handle that the client probably already has.
 * @param name is a ccnb-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 CCN_V_HIGH or CCN_V_HIGHEST,
 *        possibly combined with CCN_V_NESTOK.  If CCN_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 applied per
 *        fetch attempt, so the total time may be longer by a factor that
 *        depends on the number of (ccn) hops to the source(s).
 * @returns -1 for error, 0 if name could not be extended, 1 if was.
 */
int
ccn_resolve_version(struct ccn *h, struct ccn_charbuf *name,
                    int versioning_flags, int timeout_ms)
{
    int res;
    int myres = -1;
    struct ccn_parsed_ContentObject pco_space = { 0 };
    struct ccn_charbuf *templ = NULL;
    struct ccn_charbuf *prefix = ccn_charbuf_create();
    struct ccn_charbuf *cobj = ccn_charbuf_create();
    struct ccn_parsed_ContentObject *pco = &pco_space;
    struct ccn_indexbuf *ndx = ccn_indexbuf_create();
    const unsigned char *vers = NULL;
    size_t vers_size = 0;
    int n;
    struct ccn_indexbuf *nix = ccn_indexbuf_create();
    unsigned char lowtime[7] = {CCN_MARKER_VERSION, 0, FF, FF, FF, FF, FF};
    
    if ((versioning_flags & ~CCN_V_NESTOK & ~CCN_V_EST) != CCN_V_HIGH) {
        ccn_seterror(h, EINVAL);
        ccn_perror(h, "ccn_resolve_version is only implemented for versioning_flags = CCN_V_HIGH(EST)");
        goto Finish;
    }
    n = ccn_name_split(name, nix);
    if (n < 0)
        goto Finish;
    if ((versioning_flags & CCN_V_NESTOK) == 0) {
        res = ccn_name_comp_get(name->buf, nix, n - 1, &vers, &vers_size);
        if (res >= 0 && vers_size == 7 && vers[0] == CCN_MARKER_VERSION) {
            myres = 0;
            goto Finish;
        }    
    }
    templ = resolve_templ(templ, lowtime, sizeof(lowtime));
    ccn_charbuf_append(prefix, name->buf, name->length); /* our copy */
    cobj->length = 0;
    res = ccn_get(h, prefix, templ, timeout_ms, cobj, pco, ndx, 0);
    while (cobj->length != 0) {
        if (pco->type == CCN_CONTENT_NACK) // XXX - also check for number of components
            break;
        res = ccn_name_comp_get(cobj->buf, ndx, n, &vers, &vers_size);
        if (res < 0)
            break;
        if (vers_size == 7 && vers[0] == CCN_MARKER_VERSION) {
            /* Looks like we have versions. */
            name->length = 0;
            ccn_charbuf_append(name, prefix->buf, prefix->length);
            ccn_name_append(name, vers, vers_size);
            myres = 0;
            if ((versioning_flags & CCN_V_EST) == 0)
                break;
            templ = resolve_templ(templ, vers, vers_size);
            if (templ == NULL) break;
            cobj->length = 0;
            res = ccn_get(h, prefix, templ, timeout_ms, cobj, pco, ndx,
                          CCN_GET_NOKEYWAIT);
        }
        else break;
    }
Finish:
    ccn_charbuf_destroy(&prefix);
    ccn_charbuf_destroy(&cobj);
    ccn_indexbuf_destroy(&ndx);
    ccn_indexbuf_destroy(&nix);
    ccn_charbuf_destroy(&templ);
    return(myres);
}