/** * 劈开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); }
/** * 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); }
/** * 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); }
/** * 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); }