/** * Destroy the ndnr instance, releasing all associated resources. */ PUBLIC void r_init_destroy(struct ndnr_handle **pndnr) { struct ndnr_handle *h = *pndnr; int stable; if (h == NULL) return; stable = h->active_in_fd == -1 ? 1 : 0; r_io_shutdown_all(h); ndnr_direct_client_stop(h); ndn_schedule_destroy(&h->sched); hashtb_destroy(&h->propagating_tab); hashtb_destroy(&h->nameprefix_tab); hashtb_destroy(&h->enum_state_tab); hashtb_destroy(&h->content_by_accession_tab); // SyncActions sync_stop method should be shutting down heartbeat if (h->sync_plumbing) { h->sync_plumbing->sync_methods->sync_stop(h->sync_plumbing, NULL); free(h->sync_plumbing); h->sync_plumbing = NULL; h->sync_base = NULL; // freed by sync_stop ? } r_store_final(h, stable); if (h->fds != NULL) { free(h->fds); h->fds = NULL; h->nfds = 0; } if (h->fdholder_by_fd != NULL) { free(h->fdholder_by_fd); h->fdholder_by_fd = NULL; h->face_limit = h->face_gen = 0; } if (h->content_by_cookie != NULL) { free(h->content_by_cookie); h->content_by_cookie = NULL; h->cookie_limit = 1; } ndn_charbuf_destroy(&h->scratch_charbuf); ndn_indexbuf_destroy(&h->skiplinks); ndn_indexbuf_destroy(&h->scratch_indexbuf); ndn_indexbuf_destroy(&h->unsol); if (h->parsed_policy != NULL) { ndn_indexbuf_destroy(&h->parsed_policy->namespaces); ndn_charbuf_destroy(&h->parsed_policy->store); free(h->parsed_policy); h->parsed_policy = NULL; } ndn_charbuf_destroy(&h->policy_name); ndn_charbuf_destroy(&h->policy_link_cob); ndn_charbuf_destroy(&h->ndnr_keyid); free(h); *pndnr = NULL; }
/* * deliver_content is used to deliver a previously-buffered * ContentObject to the client. */ static enum ndn_upcall_res deliver_content(struct ndn *h, struct bulkdata *b) { struct ndn_upcall_info info = {0}; struct ndn_parsed_ContentObject obj = {0}; struct pending *p = b->first; int res; enum ndn_upcall_res ans; assert(p != NULL && p->x == b->next_expected && p->content_ndnb != NULL); info.pco = &obj; info.content_comps = ndn_indexbuf_create(); res = ndn_parse_ContentObject(p->content_ndnb, p->content_size, &obj, info.content_comps); assert(res >= 0); info.content_ndnb = p->content_ndnb; info.matched_comps = info.content_comps->n - 2; /* XXX - we have no matched interest to present */ ans = (*b->client->p)(b->client, NDN_UPCALL_CONTENT, &info); // XXX - check for refusal info.content_ndnb = NULL; free(p->content_ndnb); p->content_ndnb = NULL; p->content_size = 0; ndn_indexbuf_destroy(&info.content_comps); if (ans == NDN_UPCALL_RESULT_OK) { struct ndn_closure *old = &p->closure; if ((--(old->refcount)) == 0) { info.pco = NULL; (old->p)(old, NDN_UPCALL_FINAL, &info); } } return(ans); }
/** * 劈开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); }
PUBLIC void ndnr_parsed_policy_destroy(struct ndnr_parsed_policy **ppp) { struct ndnr_parsed_policy *pp; if (*ppp == NULL) return; pp = *ppp; ndn_charbuf_destroy(&pp->store); ndn_indexbuf_destroy(&pp->namespaces); free(pp); *ppp = NULL; }
/** * 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); }
int main (int argc, char *argv[]) { struct ndn *ndn = NULL; struct ndn_closure *action; struct ndn_charbuf *namebuf = NULL; struct ndn_charbuf *interestnamebuf = NULL; struct ndn_charbuf *interesttemplatebuf = NULL; struct ndn_buf_decoder decoder; struct ndn_buf_decoder *d; struct handlerstate *state; char *filename; char rawbuf[1024 * 1024]; ssize_t rawlen; int i, n, res; int fd = -1; ndn = ndn_create(); if (ndn_connect(ndn, NULL) == -1) { perror("ndn_connect"); exit(1); } state = calloc(1, sizeof(struct handlerstate)); action = calloc(1, sizeof(struct ndn_closure)); action->p = interest_handler; namebuf = ndn_charbuf_create(); if (namebuf == NULL) { fprintf(stderr, "ndn_charbuf_create\n"); exit(1); } res = ndn_name_init(namebuf); if (res < 0) { fprintf(stderr, "ndn_name_init\n"); exit(1); } interestnamebuf = ndn_charbuf_create(); interesttemplatebuf = ndn_charbuf_create(); if (interestnamebuf == NULL || interesttemplatebuf == NULL) { fprintf(stderr, "ndn_charbuf_create\n"); exit(1); } res = ndn_name_init(interestnamebuf); if (res < 0) { fprintf(stderr, "ndn_name_init\n"); exit(1); } n = 0; for (i = 1; i < argc; i++) { if (fd != -1) close(fd); filename = argv[i]; if (0 == strcmp(filename, "-d")) { options.logging++; continue; } if (0 == strcmp(filename, "-nointerest")) { options.nointerest = 1; continue; } if (0 == strcmp(filename, "-reconnect")) { options.reconnect = 1; continue; } if (options.logging > 0) fprintf(stderr, "Processing %s ", filename); fd = open(filename, O_RDONLY); if (fd == -1) { perror("- open"); continue; } rawlen = read(fd, rawbuf, sizeof(rawbuf)); if (rawlen <= 0) { perror("- read"); continue; } d = ndn_buf_decoder_start(&decoder, (unsigned char *)rawbuf, rawlen); if (ndn_buf_match_dtag(d, NDN_DTAG_ContentObject)) { state->items = realloc(state->items, (n + 1) * sizeof(*(state->items))); if (state->items == NULL) { perror(" - realloc failed"); exit(1); } memset(&(state->items[n]), 0, sizeof(*(state->items))); state->items[n].components = ndn_indexbuf_create(); res = ndn_parse_ContentObject((unsigned char *)rawbuf, rawlen, &(state->items[n].x), state->items[n].components); if (res < 0) { if (options.logging > 0) fprintf(stderr, "Processing %s ", filename); fprintf(stderr, "- skipping: ContentObject error %d\n", res); ndn_indexbuf_destroy(&state->items[n].components); continue; } if (options.logging > 0) fprintf(stderr, "- ok\n"); state->items[n].filename = filename; state->items[n].contents = malloc(rawlen); state->items[n].size = rawlen; memcpy(state->items[n].contents, rawbuf, rawlen); n++; } else if (ndn_buf_match_dtag(d, NDN_DTAG_Interest)) { struct ndn_parsed_interest interest = {0}; if (options.nointerest == 0) { size_t name_start; size_t name_size; interestnamebuf->length = 0; interesttemplatebuf->length = 0; res = ndn_parse_interest((unsigned char *)rawbuf, rawlen, &interest, NULL); name_start = interest.offset[NDN_PI_B_Name]; name_size = interest.offset[NDN_PI_E_Name] - name_start; ndn_charbuf_append(interestnamebuf, rawbuf + name_start, name_size); ndn_charbuf_append(interesttemplatebuf, rawbuf, rawlen); res = ndn_express_interest(ndn, interestnamebuf, action, interesttemplatebuf); } } else { if (options.logging == 0) fprintf(stderr, "Processing %s ", filename); fprintf(stderr, "- skipping: unknown type\n"); } } state->count = n; action->data = state; if (ndn_name_init(namebuf) == -1) { fprintf(stderr, "ndn_name_init\n"); exit(1); } res = ndn_set_interest_filter(ndn, namebuf, action); for (;;) { res = ndn_run(ndn, -1); ndn_disconnect(ndn); if (!options.reconnect) break; sleep(2); ndn_connect(ndn, NULL); } ndn_destroy(&ndn); exit(0); }
enum ndn_upcall_res interest_handler(struct ndn_closure *selfp, enum ndn_upcall_kind upcall_kind, struct ndn_upcall_info *info) { int i, c, mc, match, res; struct handlerstateitem item; struct handlerstate *state; size_t ndnb_size = 0; state = selfp->data; switch(upcall_kind) { case NDN_UPCALL_FINAL: fprintf(stderr, "Upcall final\n"); return (0); case NDN_UPCALL_INTEREST_TIMED_OUT: fprintf(stderr, "refresh\n"); return (NDN_UPCALL_RESULT_REEXPRESS); case NDN_UPCALL_CONTENT: case NDN_UPCALL_CONTENT_UNVERIFIED: ndnb_size = info->pco->offset[NDN_PCO_E]; c = state->count; for (i = 0; i < c; i++) { if (info->content_comps->n == state->items[i].components->n) { mc = match_components((unsigned char *)info->content_ndnb, info->content_comps, state->items[i].contents, state->items[i].components); if (mc == (info->content_comps->n - 1)) { fprintf(stderr, "Duplicate content\n"); return (0); } } } fprintf(stderr, "Storing content item %d ", c); state->items = realloc(state->items, (c + 1) * sizeof(*(state->items))); if (state->items == NULL) { perror("realloc failed"); exit(1); } memset(&(state->items[c]), 0, sizeof(*(state->items))); state->items[c].components = ndn_indexbuf_create(); /* XXX: probably should not have to do this re-parse of the content object */ res = ndn_parse_ContentObject(info->content_ndnb, ndnb_size, &(state->items[c].x), state->items[c].components); if (res < 0) { fprintf(stderr, "- skipping: Not a ContentObject\n"); ndn_indexbuf_destroy(&state->items[c].components); return (-1); } fprintf(stderr, "- ok\n"); state->items[c].filename = "ephemeral"; state->items[c].contents = malloc(ndnb_size); state->items[c].size = ndnb_size; memcpy(state->items[c].contents, info->content_ndnb, ndnb_size); state->count = c + 1; return (0); case NDN_UPCALL_CONTENT_BAD: fprintf(stderr, "Content signature verification failed! Discarding.\n"); return (-1); case NDN_UPCALL_CONSUMED_INTEREST: fprintf(stderr, "Upcall consumed interest\n"); return (-1); /* no data */ case NDN_UPCALL_INTEREST: c = state->count; for (i = 0; i < c; i++) { match = ndn_content_matches_interest(state->items[i].contents, state->items[i].size, 1, NULL, info->interest_ndnb, info->pi->offset[NDN_PI_E], info->pi); if (match) { ndn_put(info->h, state->items[i].contents, state->items[i].size); fprintf(stderr, "Sending %s\n", state->items[i].filename); if (i < c - 1) { item = state->items[i]; memmove(&(state->items[i]), &(state->items[i+1]), sizeof(item) * ((c - 1) - i)); state->items[c - 1] = item; } return (1); } } return(0); case NDN_UPCALL_CONTENT_KEYMISSING: case NDN_UPCALL_CONTENT_RAW: /* should not happen */ return (-1); } return (-1); }