/* * 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 struct ndnr_parsed_policy * ndnr_parsed_policy_create(void) { struct ndnr_parsed_policy *pp; pp = calloc(1, sizeof(struct ndnr_parsed_policy)); pp->store = ndn_charbuf_create(); pp->namespaces = ndn_indexbuf_create(); return(pp); }
/** * 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); }
/** * Load a link to the repo policy from the repoPolicy file and load the link * target to extract the actual policy. * If a policy file does not exist a new one is created, with a link to a policy * based either on the environment variable NDNR_GLOBAL_PREFIX or the system * default value of ndn:/named-data.net/ndn/Repos, plus the system defaults for * other fields. * This routine must be called after the btree code is initialized and capable * of returning content objects. * Sets the parsed_policy field of the handle to be the new policy. */ static int load_policy(struct ndnr_handle *ndnr) { int fd; ssize_t res; struct content_entry *content = NULL; const unsigned char *content_msg = NULL; struct ndn_parsed_ContentObject pco = {0}; struct ndn_parsed_Link pl = {0}; struct ndn_indexbuf *nc = NULL; struct ndn_charbuf *basename = NULL; struct ndn_charbuf *policy = NULL; struct ndn_charbuf *policy_cob = NULL; struct ndn_charbuf *policyFileName; const char *global_prefix; const unsigned char *buf = NULL; size_t length = 0; int segment = 0; int final = 0; struct ndn_buf_decoder decoder; struct ndn_buf_decoder *d; policyFileName = ndn_charbuf_create(); ndn_charbuf_putf(policyFileName, "%s/repoPolicy", ndnr->directory); ndnr->parsed_policy = ndnr_parsed_policy_create(); fd = open(ndn_charbuf_as_string(policyFileName), O_RDONLY); if (fd >= 0) { ndnr->policy_link_cob = ndn_charbuf_create(); ndn_charbuf_reserve(ndnr->policy_link_cob, 4096); // limits the size of the policy link ndnr->policy_link_cob->length = 0; // clear the buffer res = read(fd, ndnr->policy_link_cob->buf, ndnr->policy_link_cob->limit - ndnr->policy_link_cob->length); close(fd); if (res == -1) { r_init_fail(ndnr, __LINE__, "Error reading repoPolicy file.", errno); ndn_charbuf_destroy(&ndnr->policy_link_cob); ndn_charbuf_destroy(&policyFileName); return(-1); } ndnr->policy_link_cob->length = res; nc = ndn_indexbuf_create(); res = ndn_parse_ContentObject(ndnr->policy_link_cob->buf, ndnr->policy_link_cob->length, &pco, nc); res = ndn_ref_tagged_BLOB(NDN_DTAG_Content, ndnr->policy_link_cob->buf, pco.offset[NDN_PCO_B_Content], pco.offset[NDN_PCO_E_Content], &buf, &length); d = ndn_buf_decoder_start(&decoder, buf, length); res = ndn_parse_Link(d, &pl, NULL); if (res <= 0) { ndnr_msg(ndnr, "Policy link is malformed."); goto CreateNewPolicy; } basename = ndn_charbuf_create(); ndn_charbuf_append(basename, buf + pl.offset[NDN_PL_B_Name], pl.offset[NDN_PL_E_Name] - pl.offset[NDN_PL_B_Name]); ndnr->policy_name = ndn_charbuf_create(); // to detect writes to this name ndn_charbuf_append_charbuf(ndnr->policy_name, basename); // has version ndn_name_chop(ndnr->policy_name, NULL, -1); // get rid of version policy = ndn_charbuf_create(); // if we fail to retrieve the link target, report and then create a new one do { ndn_name_append_numeric(basename, NDN_MARKER_SEQNUM, segment++); content = r_store_lookup_ndnb(ndnr, basename->buf, basename->length); if (content == NULL) { ndnr_debug_ndnb(ndnr, __LINE__, "policy lookup failed for", NULL, basename->buf, basename->length); break; } ndn_name_chop(basename, NULL, -1); content_msg = r_store_content_base(ndnr, content); if (content_msg == NULL) { ndnr_debug_ndnb(ndnr, __LINE__, "Unable to read policy object", NULL, basename->buf, basename->length); break; } res = ndn_parse_ContentObject(content_msg, r_store_content_size(ndnr, content), &pco, nc); res = ndn_ref_tagged_BLOB(NDN_DTAG_Content, content_msg, pco.offset[NDN_PCO_B_Content], pco.offset[NDN_PCO_E_Content], &buf, &length); ndn_charbuf_append(policy, buf, length); final = ndn_is_final_pco(content_msg, &pco, nc); } while (!final && segment < 100);
/** * Create a new ndnr instance * @param progname - name of program binary, used for locating helpers * @param logger - logger function * @param loggerdata - data to pass to logger function */ PUBLIC struct ndnr_handle * r_init_create(const char *progname, ndnr_logger logger, void *loggerdata) { char *sockname = NULL; const char *portstr = NULL; const char *listen_on = NULL; const char *d = NULL; struct ndnr_handle *h = NULL; struct hashtb_param param = {0}; struct ndn_charbuf *config = NULL; int res; h = calloc(1, sizeof(*h)); if (h == NULL) return(h); h->notify_after = 0; //NDNR_MAX_ACCESSION; h->logger = logger; h->loggerdata = loggerdata; h->logpid = (int)getpid(); h->progname = progname; h->debug = -1; config = r_init_read_config(h); if (config == NULL) goto Bail; r_init_parse_config(h, config, 0); /* silent pass to pick up NDNR_DEBUG */ h->debug = 1; /* so that we see any complaints */ h->debug = r_init_debug_getenv(h, "NDNR_DEBUG"); res = r_init_parse_config(h, config, 1); if (res < 0) { h->running = -1; goto Bail; } r_init_parse_config(h, config, 2); sockname = r_net_get_local_sockname(); h->skiplinks = ndn_indexbuf_create(); h->face_limit = 10; /* soft limit */ h->fdholder_by_fd = calloc(h->face_limit, sizeof(h->fdholder_by_fd[0])); param.finalize_data = h; param.finalize = &r_fwd_finalize_nameprefix; h->nameprefix_tab = hashtb_create(sizeof(struct nameprefix_entry), ¶m); param.finalize = 0; // PRUNED &r_fwd_finalize_propagating; h->propagating_tab = hashtb_create(sizeof(struct propagating_entry), ¶m); param.finalize = &r_proto_finalize_enum_state; h->enum_state_tab = hashtb_create(sizeof(struct enum_state), ¶m); h->min_stale = ~0; h->max_stale = 0; h->unsol = ndn_indexbuf_create(); h->ticktock.descr[0] = 'C'; h->ticktock.micros_per_base = 1000000; h->ticktock.gettime = &r_util_gettime; h->ticktock.data = h; h->sched = ndn_schedule_create(h, &h->ticktock); h->starttime = h->sec; h->starttime_usec = h->usec; h->oldformatcontentgrumble = 1; h->oldformatinterestgrumble = 1; h->cob_limit = 4201; h->start_write_scope_limit = r_init_confval(h, "NDNR_START_WRITE_SCOPE_LIMIT", 0, 3, 3); h->debug = 1; /* so that we see any complaints */ h->debug = r_init_debug_getenv(h, "NDNR_DEBUG"); h->syncdebug = r_init_debug_getenv(h, "NDNS_DEBUG"); portstr = getenv("NDNR_STATUS_PORT"); if (portstr == NULL || portstr[0] == 0 || strlen(portstr) > 10) portstr = ""; h->portstr = portstr; ndnr_msg(h, "NDNR_DEBUG=%d NDNR_DIRECTORY=%s NDNR_STATUS_PORT=%s", h->debug, h->directory, h->portstr); listen_on = getenv("NDNR_LISTEN_ON"); if (listen_on != NULL && listen_on[0] != 0) ndnr_msg(h, "NDNR_LISTEN_ON=%s", listen_on); if (ndnr_init_repo_keystore(h, NULL) < 0) { h->running = -1; goto Bail; } r_util_reseed(h); r_store_init(h); if (h->running == -1) goto Bail; while (h->active_in_fd >= 0) { r_dispatch_process_input(h, h->active_in_fd); r_store_trim(h, h->cob_limit); ndn_schedule_run(h->sched); } ndnr_msg(h, "Repository file is indexed"); if (h->face0 == NULL) { struct fdholder *fdholder; fdholder = calloc(1, sizeof(*fdholder)); if (dup2(open("/dev/null", O_RDONLY), 0) == -1) ndnr_msg(h, "stdin: %s", strerror(errno)); fdholder->filedesc = 0; fdholder->flags = (NDNR_FACE_GG | NDNR_FACE_NORECV); r_io_enroll_face(h, fdholder); } ndnr_direct_client_start(h); d = getenv("NDNR_SKIP_VERIFY"); #if (NDN_API_VERSION >= 4004) if (d != NULL && strcmp(d, "1") == 0) { ndnr_msg(h, "NDNR_SKIP_VERIFY=%s", d); ndn_defer_verification(h->direct_client, 1); } #endif if (ndn_connect(h->direct_client, NULL) != -1) { int af = 0; int bufsize; int flags; int fd; struct fdholder *fdholder; fd = ndn_get_connection_fd(h->direct_client); // Play a dirty trick here - if this wins, we can fix it right in the c lib later on... af = try_tcp_instead(fd); flags = NDNR_FACE_NDND; if (af == AF_INET) flags |= NDNR_FACE_INET; else if (af == AF_INET6) flags |= NDNR_FACE_INET6; else flags |= NDNR_FACE_LOCAL; fdholder = r_io_record_fd(h, fd, "NDND", 5, flags); if (fdholder == NULL) abort(); ndnr_uri_listen(h, h->direct_client, "ndn:/%C1.M.S.localhost/%C1.M.SRV/repository", &ndnr_answer_req, OP_SERVICE); ndnr_uri_listen(h, h->direct_client, "ndn:/%C1.M.S.neighborhood/%C1.M.SRV/repository", &ndnr_answer_req, OP_SERVICE); bufsize = r_init_confval(h, "NDNR_MIN_SEND_BUFSIZE", 1, 2097152, 16384); establish_min_send_bufsize(h, fd, bufsize); } else ndn_disconnect(h->direct_client); // Apparently ndn_connect error case needs work. if (1 == r_init_confval(h, "NDNS_ENABLE", 0, 1, 1)) { h->sync_plumbing = calloc(1, sizeof(struct sync_plumbing)); h->sync_plumbing->ndn = h->direct_client; h->sync_plumbing->sched = h->sched; h->sync_plumbing->client_methods = &sync_client_methods; h->sync_plumbing->client_data = h; h->sync_base = SyncNewBaseForActions(h->sync_plumbing); } if (-1 == load_policy(h)) goto Bail; r_net_listen_on(h, listen_on); ndnr_internal_client_start(h); r_proto_init(h); r_proto_activate_policy(h, h->parsed_policy); if (merge_files(h) == -1) r_init_fail(h, __LINE__, "Unable to merge additional repository data files.", errno); if (h->running == -1) goto Bail; if (h->sync_plumbing) { // Start sync running // returns < 0 if a failure occurred // returns 0 if the name updates should fully restart // returns > 0 if the name updates should restart at last fence res = h->sync_plumbing->sync_methods->sync_start(h->sync_plumbing, NULL); if (res < 0) { r_init_fail(h, __LINE__, "starting sync", res); abort(); } else if (res > 0) { // XXX: need to work out details of starting from last fence. // By examination of code, SyncActions won't take this path } } Bail: if (sockname) free(sockname); sockname = NULL; ndn_charbuf_destroy(&config); if (h->running == -1) r_init_destroy(&h); return(h); }
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); }
int main(int argc, char **argv) { char *arg = NULL; struct ndn *ndnH = NULL; struct ndn_parsed_interest interest = {0}; struct ndn_charbuf *c = ndn_charbuf_create(); struct ndn_charbuf *templ = ndn_charbuf_create(); struct ndn_indexbuf *comps = ndn_indexbuf_create(); int i; int millis = 0; int secs = 0; int opt; int pool = 0; int regflgs = (NDN_FORW_CHILD_INHERIT | NDN_FORW_ACTIVE); int res; int status = 0; int val = 0; while ((opt = getopt(argc, argv, "hv")) != -1) { switch (opt) { default: case 'h': usage(); break; case 'v': verbose++; break; } } argc -= optind; argv += optind; ndnH = ndn_create(); if (ndn_connect(ndnH, NULL) == -1) { ndn_perror(ndnH, "ndn_connect"); exit(1); } for (i = 0; i < N_POOLS; i++) { store[i].me.p = &outgoing_content; store[i].me.data = &store[i]; store[i].me.intdata = i; incoming_content_action[i].p = &incoming_content; incoming_content_action[i].intdata = i; } for (i = 0; i < argc; i++) { arg = argv[i]; if (0 == strcmp(arg, "reconnect")) { if (argv[i+1] == NULL) usage(); secs = atoi(argv[i+1]); if (secs <= 0 && strcmp(argv[i+1], "0") != 0) usage(); i++; ndn_disconnect(ndnH); sleep(secs); if (ndn_connect(ndnH, NULL) == -1) { ndn_perror(ndnH, "ndn_connect"); exit(1); } continue; } if (0 == strcmp(arg, "pool")) { if (argv[i+1] == NULL) usage(); pool = argv[i+1][0] - '0'; if (argv[i+1][1] || pool < 0 || pool >= N_POOLS) usage(); fprintf(stderr, "Pool %d\n", pool); i++; continue; } if (0 == strcmp(arg, "prefix")) { if (argv[i+1] == NULL) usage(); c->length = 0; res = ndn_name_from_uri(c, argv[i+1]); if (res < 0) usage(); fprintf(stderr, "Prefix ff=%#x %s pool %d\n", regflgs, argv[i+1], pool); if (store[pool].me.intdata != pool) { abort(); } res = ndn_set_interest_filter_with_flags(ndnH, c, &store[pool].me, regflgs); if (res < 0) { ndn_perror(ndnH, "ndn_set_interest_filter_with_flags"); status = 1; } res = ndn_run(ndnH, 2); if (res < 0) break; i++; continue; } if (0 == strcmp(arg, "flags")) { if (argv[i+1] == NULL) usage(); regflgs = atoi(argv[i+1]); if (regflgs <= 0 && strcmp(argv[i+1], "0") != 0) usage(); i++; continue; } if (0 == strcmp(arg, "mincob")) { if (argv[i+1] == NULL) usage(); val = atoi(argv[i+1]); if (val <= 0 && strcmp(argv[i+1], "0") != 0) usage(); i++; if (n_pool(pool) < val) { fprintf(stderr, "Pool %d has %d cobs, expected at least %d\n", pool, n_pool(pool), val); exit(1); } continue; } if (0 == strcmp(arg, "maxcob")) { if (argv[i+1] == NULL) usage(); val = atoi(argv[i+1]); if (val <= 0 && strcmp(argv[i+1], "0") != 0) usage(); i++; if (n_pool(pool) > val) { fprintf(stderr, "Pool %d has %d cobs, expected at most %d\n", pool, n_pool(pool), val); exit(1); } continue; } if (0 == strcmp(arg, "run")) { if (argv[i+1] == NULL) usage(); millis = atoi(argv[i+1]); if (millis <= 0 && strcmp(argv[i+1], "0") != 0) usage(); i++; res = ndn_run(ndnH, millis); if (res < 0) { ndn_perror(ndnH, "ndn_run"); exit(1); } continue; } close(0); res = open(arg, O_RDONLY); if (res != 0) { perror(arg); exit(1); } fprintf(stderr, "Reading %s ... ", arg); rawlen = read(0, rawbuf, sizeof(rawbuf)); if (rawlen < 0) { perror("skipping"); // XXX - status continue; } // XXX - Should do a skeleton check before parse res = ndn_parse_interest(rawbuf, rawlen, &interest, NULL); if (res >= 0) { size_t name_start = interest.offset[NDN_PI_B_Name]; size_t name_size = interest.offset[NDN_PI_E_Name] - name_start; templ->length = 0; ndn_charbuf_append(templ, rawbuf, rawlen); fprintf(stderr, "Expressing interest with %d name components\n", res); c->length = 0; ndn_charbuf_append(c, rawbuf + name_start, name_size); // XXX - res is currently ignored ndn_express_interest(ndnH, c, &(incoming_content_action[pool]), templ); } else { struct ndn_parsed_ContentObject obj = {0}; int try; res = ndn_parse_ContentObject(rawbuf, rawlen, &obj, comps); if (res >= 0) { for (try = 0; try < 5; try++) { res = add_to_pool(pool, rawbuf, rawlen); if (res >= 0) { fprintf(stderr, "Added to pool %d\n", pool); break; } if (try == 5) { fprintf(stderr, "No buffer for %s\n", arg); status = 1; break; } fprintf(stderr, "Pool %d full - wait for drain\n", pool); if (ndn_run(ndnH, 1000) < 0) break; } res = ndn_run(ndnH, 10); } else { fprintf(stderr, "What is that?\n"); status = 1; } } res = ndn_run(ndnH, 10); if (res < 0) { ndn_perror(ndnH, "oops"); status = 1; } } res = ndn_run(ndnH, 10); if (res < 0) status = 1; ndn_destroy(&ndnH); exit(status); }