/** * Basic tests of ndn_btree_io_from_directory() and its methods. * * Assumes TEST_DIRECTORY has been set. */ static int test_btree_io(void) { int res; struct ndn_btree_node nodespace = {0}; struct ndn_btree_node *node = &nodespace; struct ndn_btree_io *io = NULL; /* Open it up. */ io = ndn_btree_io_from_directory(getenv("TEST_DIRECTORY"), NULL); CHKPTR(io); node->buf = ndn_charbuf_create(); CHKPTR(node->buf); node->nodeid = 12345; res = io->btopen(io, node); CHKSYS(res); FAILIF(node->iodata == NULL); ndn_charbuf_putf(node->buf, "smoke"); res = io->btwrite(io, node); CHKSYS(res); node->buf->length = 0; ndn_charbuf_putf(node->buf, "garbage"); res = io->btread(io, node, 500000); CHKSYS(res); FAILIF(node->buf->length != 5); FAILIF(node->buf->limit > 10000); node->clean = 5; ndn_charbuf_putf(node->buf, "r"); res = io->btwrite(io, node); CHKSYS(res); node->buf->length--; ndn_charbuf_putf(node->buf, "d"); res = io->btread(io, node, 1000); CHKSYS(res); FAILIF(0 != strcmp("smoker", ndn_charbuf_as_string(node->buf))); node->buf->length--; res = io->btwrite(io, node); CHKSYS(res); node->buf->length = 0; ndn_charbuf_putf(node->buf, "garbage"); node->clean = 0; res = io->btread(io, node, 1000); CHKSYS(res); res = io->btclose(io, node); CHKSYS(res); FAILIF(node->iodata != NULL); FAILIF(0 != strcmp("smoke", ndn_charbuf_as_string(node->buf))); res = io->btdestroy(&io); CHKSYS(res); ndn_charbuf_destroy(&node->buf); return(res); }
/** * Read the contents of the repository config file * * Calls r_init_fail and returns NULL in case of error. * @returns unparsed content of config file in a newly allocated charbuf */ struct ndn_charbuf * r_init_read_config(struct ndnr_handle *h) { struct ndn_charbuf *path = NULL; struct ndn_charbuf *contents = NULL; size_t sz = 800; ssize_t sres = -1; int fd; h->directory = getenv("NDNR_DIRECTORY"); if (h->directory == NULL || h->directory[0] == 0) h->directory = "."; path = ndn_charbuf_create(); contents = ndn_charbuf_create(); if (path == NULL || contents == NULL) return(NULL); ndn_charbuf_putf(path, "%s/config", h->directory); fd = open(ndn_charbuf_as_string(path), O_RDONLY); if (fd == -1) { if (errno == ENOENT) sres = 0; else r_init_fail(h, __LINE__, ndn_charbuf_as_string(path), errno); } else { for (;;) { sres = read(fd, ndn_charbuf_reserve(contents, sz), sz); if (sres == 0) break; if (sres < 0) { r_init_fail(h, __LINE__, "Read failed reading config", errno); break; } contents->length += sres; if (contents->length > 999999) { r_init_fail(h, __LINE__, "config file too large", 0); sres = -1; break; } } close(fd); } ndn_charbuf_destroy(&path); if (sres < 0) ndn_charbuf_destroy(&contents); return(contents); }
static int merge_files(struct ndnr_handle *h) { int i, last_file; int res; struct ndn_charbuf *filename = ndn_charbuf_create(); // first parse the file(s) making sure there are no errors for (i = 2;; i++) { filename->length = 0; ndn_charbuf_putf(filename, "repoFile%d", i); res = r_init_map_and_process_file(h, filename, 0); if (res == 1) break; if (res < 0) { ndnr_msg(h, "Error parsing repository file %s", ndn_charbuf_as_string(filename)); return (-1); } } last_file = i - 1; for (i = 2; i <= last_file; i++) { filename->length = 0; ndn_charbuf_putf(filename, "repoFile%d", i); res = r_init_map_and_process_file(h, filename, 1); if (res < 0) { ndnr_msg(h, "Error in phase 2 incorporating repository file %s", ndn_charbuf_as_string(filename)); return (-1); } } for (i = last_file; i > 1; --i) { filename->length = 0; ndn_charbuf_putf(filename, "%s/repoFile%d", h->directory, i); if (NDNSHOULDLOG(h, LM_128, NDNL_INFO)) ndnr_msg(h, "unlinking %s", ndn_charbuf_as_string(filename)); unlink(ndn_charbuf_as_string(filename)); } ndn_charbuf_destroy(&filename); return (0); }
/** * Use standard mkdtemp() to create a subdirectory of the * current working directory, and set the TEST_DIRECTORY environment * variable with its name. */ static int test_directory_creation(void) { int res; struct ndn_charbuf *dirbuf; char *temp; dirbuf = ndn_charbuf_create(); CHKPTR(dirbuf); res = ndn_charbuf_putf(dirbuf, "./%s", "_bt_XXXXXX"); CHKSYS(res); temp = mkdtemp(ndn_charbuf_as_string(dirbuf)); CHKPTR(temp); res = ndn_charbuf_putf(dirbuf, "/%s", "_test"); CHKSYS(res); res = mkdir(ndn_charbuf_as_string(dirbuf), 0777); CHKSYS(res); printf("Created directory %s\n", ndn_charbuf_as_string(dirbuf)); setenv("TEST_DIRECTORY", ndn_charbuf_as_string(dirbuf), 1); ndn_charbuf_destroy(&dirbuf); return(res); }
struct hash_store* hash_store_ctor(struct ndnr_handle* h) { struct hash_store* self = calloc(1, sizeof(*self)); self->h = h; h->hashstore = self; // open btree with disk IO struct ndn_charbuf* path = ndn_charbuf_create(); ndn_charbuf_putf(path, "%s/hashstore", h->directory); int res = mkdir(ndn_charbuf_as_string(path), 0700); if (res != 0 && errno != EEXIST) { free(self); ndn_charbuf_destroy(&path); return NULL; } self->btree = ndn_btree_create(); self->btree->io = ndn_btree_io_from_directory(ndn_charbuf_as_string(path), NULL); if (self->btree->io == NULL) { free(self); ndn_charbuf_destroy(&path); ndn_btree_destroy(&self->btree); return NULL; } ndn_charbuf_destroy(&path); struct ndn_btree_node* node = ndn_btree_getnode(self->btree, 1, 0); self->btree->nextnodeid = self->btree->io->maxnodeid + 1; if (node->buf->length == 0) { res = ndn_btree_init_node(node, 0, 'R', 0); } LOG("hash_store_ctor\n"); return self; }
/* returns * res >= 0 res characters remaining to be processed from data * decoder state will be set appropriately */ static size_t process_data(struct ndn_skeleton_decoder *d, unsigned char *data, size_t n, struct ndn_charbuf *c) { size_t s; retry: s = ndn_skeleton_decode(d, data, n); if (d->state < 0) return (0); if (NDN_FINAL_DSTATE(d->state)) { c->length = 0; ndn_uri_append(c, data, s, 1); printf("%s\n", ndn_charbuf_as_string(c)); data += s; n -= s; if (n > 0) goto retry; } return(n); }
/** * 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);
int r_init_map_and_process_file(struct ndnr_handle *h, struct ndn_charbuf *filename, int add_content) { int res = 0; int dres; struct stat statbuf; unsigned char *mapped_file = MAP_FAILED; unsigned char *msg; size_t size; int fd = -1; struct content_entry *content; struct ndn_skeleton_decoder *d; struct fdholder *fdholder; fd = r_io_open_repo_data_file(h, ndn_charbuf_as_string(filename), 0); if (fd == -1) // Normal exit return(1); res = fstat(fd, &statbuf); if (res != 0) { ndnr_msg(h, "stat failed for %s (fd=%d), %s (errno=%d)", ndn_charbuf_as_string(filename), fd, strerror(errno), errno); res = -errno; goto Bail; } if (statbuf.st_size == 0) goto Bail; mapped_file = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0); if (mapped_file == MAP_FAILED) { ndnr_msg(h, "mmap failed for %s (fd=%d), %s (errno=%d)", ndn_charbuf_as_string(filename), fd, strerror(errno), errno); res = -errno; goto Bail; } fdholder = r_io_fdholder_from_fd(h, fd); d = &fdholder->decoder; msg = mapped_file; size = statbuf.st_size; while (d->index < size) { dres = ndn_skeleton_decode(d, msg + d->index, size - d->index); if (!NDN_FINAL_DSTATE(d->state)) break; if (add_content) { content = process_incoming_content(h, fdholder, msg + d->index - dres, dres, NULL); if (content != NULL) r_store_commit_content(h, content); } } if (d->index != size || !NDN_FINAL_DSTATE(d->state)) { ndnr_msg(h, "protocol error on fdholder %u (state %d), discarding %d bytes", fdholder->filedesc, d->state, (int)(size - d->index)); res = -1; goto Bail; } Bail: if (mapped_file != MAP_FAILED) munmap(mapped_file, statbuf.st_size); r_io_shutdown_client_fd(h, fd); return (res); }
/** * Parse the buffered configuration found in config * * The pass argument controls what is done with the result: * 0 - silent check for syntax errors; * 1 - check for syntax errors and warnings, logging the results, * 2 - incorporate settings into environ. * * @returns -1 if an error is found, otherwise the count of warnings. */ int r_init_parse_config(struct ndnr_handle *h, struct ndn_charbuf *config, int pass) { struct ndn_charbuf *key = NULL; struct ndn_charbuf *value = NULL; const unsigned char *b; int line; size_t i; size_t sol; /* start of line */ size_t len; /* config->len */ size_t ndx; /* temp for column report*/ int ch; int warns = 0; int errors = 0; int use_it = 0; static const char pclegal[] = "~@%-+=:,./[]" "abcdefghijklmnopqrstuvwxyz" "0123456789" "_" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const char *klegal = strchr(pclegal, 'a'); int flags; /* for reporting */ b = config->buf; len = config->length; if (len == 0) return(0); ndn_charbuf_as_string(config); key = ndn_charbuf_create(); value = ndn_charbuf_create(); if (key == NULL || value == NULL) return(-1); /* Ensure there is null termination in the buffered config */ if (ndn_charbuf_as_string(config) == NULL) return(-1); for (line = 1, i = 0, ch = b[0], sol = 0; i < len;) { flags = pass; use_it = 0; if (ch > ' ' && ch != '#') { key->length = value->length = 0; /* parse key */ while (i < len && ch != '\n' && ch != '=') { ndn_charbuf_append_value(key, ch, 1); ch = b[++i]; } if (ch == '=') ch = b[++i]; else { r_init_config_msg(h, flags, line, key->length, "missing '='"); flags |= NDNR_CONFIG_IGNORELINE; warns++; ch = '\n'; } /* parse value */ while (i < len && ch > ' ') { ndn_charbuf_append_value(value, ch, 1); ch = b[++i]; } /* See if it might be one of ours */ if (key->length < 5 || (memcmp(key->buf, "NDNR_", 5) != 0 && memcmp(key->buf, "NDNS_", 5) != 0)) { r_init_config_msg(h, flags, line, 0, "ignoring unrecognized key"); flags |= NDNR_CONFIG_IGNORELINE; warns++; use_it = 0; } else use_it = 1; /* Check charset of key */ ndx = strspn(ndn_charbuf_as_string(key), klegal); if (ndx != key->length) { errors += use_it; r_init_config_msg(h, (flags | NDNR_CONFIG_ERR), line, ndx, "unexpected character in key"); flags |= NDNR_CONFIG_IGNORELINE; warns++; } /* Check charset of value */ ndx = strspn(ndn_charbuf_as_string(value), pclegal); if (ndx != value->length) { errors += use_it; r_init_config_msg(h, (flags | NDNR_CONFIG_ERR), line, key->length + 1 + ndx, "unexpected character in value"); flags |= NDNR_CONFIG_IGNORELINE; warns++; } } if (ch == '#') { /* a comment line or error recovery. */ while (i < len && ch != '\n') ch = b[++i]; } while (i < len && ch <= ' ') { if (ch == '\n') { line++; sol = i; break; } if (memchr("\r\t ", ch, 3) == NULL) { r_init_config_msg(h, pass, line, i - sol, "non-whitespace control char at end of line"); warns++; } ch = b[++i]; } if (i == len) { r_init_config_msg(h, flags, line, i - sol, "missing newline at end of file"); warns++; ch = '\n'; } else if (ch == '\n') ch = b[++i]; else { r_init_config_msg(h, flags, line, i - sol, "junk at end of line"); flags |= NDNR_CONFIG_IGNORELINE; warns++; ch = '#'; } if (flags == 0 && strcmp(ndn_charbuf_as_string(key), "NDNR_DEBUG") == 0) { /* Set this on pass 0 so that it takes effect sooner. */ h->debug = 1; setenv("NDNR_DEBUG", ndn_charbuf_as_string(value), 1); h->debug = r_init_debug_getenv(h, "NDNR_DEBUG"); } if (pass == 2 && use_it) { if (NDNSHOULDLOG(h, mmm, NDNL_FINEST)) ndnr_msg(h, "config: %s=%s", ndn_charbuf_as_string(key), ndn_charbuf_as_string(value)); setenv(ndn_charbuf_as_string(key), ndn_charbuf_as_string(value), 1); } } ndn_charbuf_destroy(&key); ndn_charbuf_destroy(&value); return(errors ? -1 : warns); }
/* * This upcall gets called for each piece of incoming content that * matches one of our interests. We need to issue a new interest that * excludes another component at the current level, and perhaps also * and interest to start exploring the next level. Thus if the matched * interest is * /a/b/c exclude {d,e,f,i,j,k} * and we get * /a/b/c/g/h * we would issue a new interest * /a/b/c exclude {d,e,f,g,i,j,k} * to continue exploring the current level, plus a simple interest * /a/b/c/g * to start exploring the next level as well. * * This does end up fetching each piece of content multiple times, once for * each level in the name. The repeated requests will be answered from the local * content store, though, and so should not generate extra network traffic. * There is a lot of unanswerable interest generated, though. * * To prevent the interests from becoming too huge, we may need to split them. * Thus if the first new interest above were deemed too large, we could instead * issue the two interests * /a/b/c exclude {d,e,f,g,*} * /a/b/c exclude {*,g,i,j,k} * where * stands for a Bloom filter that excludes anything. Note the * repetition of g to ensure that these two interests cover disjoint portions * of the hierarchy. We need to keep track of the endpoint conditions * as well as the excluded set in our upcall data. * When a split happens, we need a new closure to track it, as we do when * we start exploring a new level. */ static enum ndn_upcall_res incoming_content( struct ndn_closure *selfp, enum ndn_upcall_kind kind, struct ndn_upcall_info *info) { struct ndn_charbuf *c = NULL; struct ndn_charbuf *comp = NULL; struct ndn_charbuf *uri = NULL; const unsigned char *ndnb = NULL; size_t ndnb_size = 0; struct ndn_indexbuf *comps = NULL; int matched_comps = 0; int res; int i; struct ndn_traversal *data = get_my_data(selfp); if (kind == NDN_UPCALL_FINAL) { for (i = 0; i < data->n_excl; i++) ndn_charbuf_destroy(&(data->excl[i])); if (data->excl != NULL) free(data->excl); free(data); free(selfp); return(0); } if (kind == NDN_UPCALL_INTEREST_TIMED_OUT) return(0); if (kind == NDN_UPCALL_CONTENT_BAD) return(0); if (kind == NDN_UPCALL_CONTENT_UNVERIFIED) { if ((data->flags & MUST_VERIFY) != 0) return(NDN_UPCALL_RESULT_VERIFY); } if (kind != NDN_UPCALL_CONTENT && kind != NDN_UPCALL_CONTENT_UNVERIFIED) abort(); ndnb = info->content_ndnb; ndnb_size = info->pco->offset[NDN_PCO_E]; comps = info->content_comps; matched_comps = info->pi->prefix_comps; c = ndn_charbuf_create(); uri = ndn_charbuf_create(); if (matched_comps + 1 > comps->n) { ndn_uri_append(c, ndnb, ndnb_size, 1); fprintf(stderr, "How did this happen? %s\n", ndn_charbuf_as_string(uri)); exit(1); } data->counter[0]++; /* Tell main that something new came in */ /* Recover the same prefix as before */ ndn_name_init(c); ndn_name_append_components(c, ndnb, comps->buf[0], comps->buf[matched_comps]); comp = ndn_charbuf_create(); ndn_name_init(comp); if (matched_comps + 1 == comps->n) { /* Reconstruct the implicit content digest component */ ndn_digest_ContentObject(ndnb, info->pco); ndn_name_append(comp, info->pco->digest, info->pco->digest_bytes); } else { ndn_name_append_components(comp, ndnb, comps->buf[matched_comps], comps->buf[matched_comps + 1]); } data->excl = realloc(data->excl, (data->n_excl + 1) * sizeof(data->excl[0])); data->excl[data->n_excl++] = comp; comp = NULL; qsort(data->excl, data->n_excl, sizeof(data->excl[0]), &namecompare); res = express_my_interest(info->h, selfp, c); if (res == -1) { struct ndn_closure *high = split_my_excludes(selfp); if (high == NULL) abort(); express_my_interest(info->h, selfp, c); express_my_interest(info->h, high, c); } /* Explore the next level, if there is one. */ if (matched_comps + 2 < comps->n) { struct ndn_traversal *newdat = NULL; struct ndn_closure *cl; newdat = calloc(1, sizeof(*newdat)); newdat->magic = 68955871; newdat->warn = 1492; newdat->counter = data->counter; newdat->flags = data->flags & ~(EXCLUDE_LOW | EXCLUDE_HIGH); newdat->n_excl = 0; newdat->excl = NULL; cl = calloc(1, sizeof(*cl)); cl->p = &incoming_content; cl->data = newdat; ndn_name_init(c); ndn_name_append_components(c, ndnb, comps->buf[0], comps->buf[matched_comps + 1]); express_my_interest(info->h, cl, c); } else { res = ndn_uri_append(uri, info->content_ndnb, info->pco->offset[NDN_PCO_E], 1); if (res < 0) fprintf(stderr, "*** Error: ndn_traverse line %d res=%d\n", __LINE__, res); else printf("%s\n", ndn_charbuf_as_string(uri)); } ndn_charbuf_destroy(&c); ndn_charbuf_destroy(&uri); return(0); }
int main(int argc, char **argv) { const char *progname = argv[0]; struct ndn *ndn = NULL; struct ndn_charbuf *name = NULL; struct ndn_charbuf *pname = NULL; struct ndn_charbuf *temp = NULL; struct ndn_charbuf *extopt = NULL; long expire = -1; int versioned = 0; size_t blocksize = 8*1024; int status = 0; int res; ssize_t read_res; unsigned char *buf = NULL; enum ndn_content_type content_type = NDN_CONTENT_DATA; struct ndn_closure in_interest = {.p=&incoming_interest}; const char *postver = NULL; const char *key_uri = NULL; int force = 0; int verbose = 0; int timeout = -1; int setfinal = 0; int prefixcomps = -1; int fd; struct ndn_signing_params sp = NDN_SIGNING_PARAMS_INIT; while ((res = getopt(argc, argv, "e:fhk:lvV:p:t:w:x:")) != -1) { switch (res) { case 'e': if (extopt == NULL) extopt = ndn_charbuf_create(); fd = open(optarg, O_RDONLY); if (fd < 0) { perror(optarg); exit(1); } for (;;) { read_res = read(fd, ndn_charbuf_reserve(extopt, 64), 64); if (read_res <= 0) break; extopt->length += read_res; } if (read_res < 0) perror(optarg); close(fd); break; case 'f': force = 1; break; case 'l': setfinal = 1; // set FinalBlockID to last comp of name break; case 'k': key_uri = optarg; break; case 'p': prefixcomps = atoi(optarg); if (prefixcomps < 0) usage(progname); break; case 'x': expire = atol(optarg); if (expire <= 0) usage(progname); break; case 'v': verbose = 1; break; case 'V': versioned = 1; postver = optarg; if (0 == memcmp(postver, "%00", 3)) setfinal = 1; break; case 'w': timeout = atol(optarg); if (timeout <= 0) usage(progname); timeout *= 1000; break; case 't': if (0 == strcasecmp(optarg, "DATA")) { content_type = NDN_CONTENT_DATA; break; } if (0 == strcasecmp(optarg, "ENCR")) { content_type = NDN_CONTENT_ENCR; break; } if (0 == strcasecmp(optarg, "GONE")) { content_type = NDN_CONTENT_GONE; break; } if (0 == strcasecmp(optarg, "KEY")) { content_type = NDN_CONTENT_KEY; break; } if (0 == strcasecmp(optarg, "LINK")) { content_type = NDN_CONTENT_LINK; break; } if (0 == strcasecmp(optarg, "NACK")) { content_type = NDN_CONTENT_NACK; break; } content_type = atoi(optarg); if (content_type > 0 && content_type <= 0xffffff) break; fprintf(stderr, "Unknown content type %s\n", optarg); /* FALLTHRU */ default: case 'h': usage(progname); break; } } argc -= optind; argv += optind; if (argv[0] == NULL) usage(progname); name = ndn_charbuf_create(); res = ndn_name_from_uri(name, argv[0]); if (res < 0) { fprintf(stderr, "%s: bad ndn URI: %s\n", progname, argv[0]); exit(1); } if (argv[1] != NULL) fprintf(stderr, "%s warning: extra arguments ignored\n", progname); /* Preserve the original prefix, in case we add versioning, * but trim it down if requested for the interest filter registration */ pname = ndn_charbuf_create(); ndn_charbuf_append(pname, name->buf, name->length); if (prefixcomps >= 0) { res = ndn_name_chop(pname, NULL, prefixcomps); if (res < 0) { fprintf(stderr, "%s: unable to trim name to %d component%s.\n", progname, prefixcomps, prefixcomps == 1 ? "" : "s"); exit(1); } } /* Connect to ndnd */ ndn = ndn_create(); if (ndn_connect(ndn, NULL) == -1) { perror("Could not connect to ndnd"); exit(1); } /* Read the actual user data from standard input */ buf = calloc(1, blocksize); read_res = read_full(0, buf, blocksize); if (read_res < 0) { perror("read"); read_res = 0; status = 1; } /* Tack on the version component if requested */ if (versioned) { res = ndn_create_version(ndn, name, NDN_V_REPLACE | NDN_V_NOW | NDN_V_HIGH, 0, 0); if (res < 0) { fprintf(stderr, "%s: ndn_create_version() failed\n", progname); exit(1); } if (postver != NULL) { res = ndn_name_from_uri(name, postver); if (res < 0) { fprintf(stderr, "-V %s: invalid name suffix\n", postver); exit(0); } } } temp = ndn_charbuf_create(); /* Ask for a FinalBlockID if appropriate. */ if (setfinal) sp.sp_flags |= NDN_SP_FINAL_BLOCK; if (res < 0) { fprintf(stderr, "Failed to create signed_info (res == %d)\n", res); exit(1); } /* Set content type */ sp.type = content_type; /* Set freshness */ if (expire >= 0) { if (sp.template_ndnb == NULL) { sp.template_ndnb = ndn_charbuf_create(); ndn_charbuf_append_tt(sp.template_ndnb, NDN_DTAG_SignedInfo, NDN_DTAG); } else if (sp.template_ndnb->length > 0) { sp.template_ndnb->length--; } ndnb_tagged_putf(sp.template_ndnb, NDN_DTAG_FreshnessSeconds, "%ld", expire); sp.sp_flags |= NDN_SP_TEMPL_FRESHNESS; ndn_charbuf_append_closer(sp.template_ndnb); } /* Set key locator, if supplied */ if (key_uri != NULL) { struct ndn_charbuf *c = ndn_charbuf_create(); res = ndn_name_from_uri(c, key_uri); if (res < 0) { fprintf(stderr, "%s is not a valid ndnx URI\n", key_uri); exit(1); } if (sp.template_ndnb == NULL) { sp.template_ndnb = ndn_charbuf_create(); ndn_charbuf_append_tt(sp.template_ndnb, NDN_DTAG_SignedInfo, NDN_DTAG); } else if (sp.template_ndnb->length > 0) { sp.template_ndnb->length--; } ndn_charbuf_append_tt(sp.template_ndnb, NDN_DTAG_KeyLocator, NDN_DTAG); ndn_charbuf_append_tt(sp.template_ndnb, NDN_DTAG_KeyName, NDN_DTAG); ndn_charbuf_append(sp.template_ndnb, c->buf, c->length); ndn_charbuf_append_closer(sp.template_ndnb); ndn_charbuf_append_closer(sp.template_ndnb); sp.sp_flags |= NDN_SP_TEMPL_KEY_LOCATOR; ndn_charbuf_append_closer(sp.template_ndnb); ndn_charbuf_destroy(&c); } if (extopt != NULL && extopt->length > 0) { if (sp.template_ndnb == NULL) { sp.template_ndnb = ndn_charbuf_create(); ndn_charbuf_append_tt(sp.template_ndnb, NDN_DTAG_SignedInfo, NDN_DTAG); } else if (sp.template_ndnb->length > 0) { sp.template_ndnb->length--; } ndnb_append_tagged_blob(sp.template_ndnb, NDN_DTAG_ExtOpt, extopt->buf, extopt->length); sp.sp_flags |= NDN_SP_TEMPL_EXT_OPT; ndn_charbuf_append_closer(sp.template_ndnb); } /* Create the signed content object, ready to go */ temp->length = 0; res = ndn_sign_content(ndn, temp, name, &sp, buf, read_res); if (res != 0) { fprintf(stderr, "Failed to encode ContentObject (res == %d)\n", res); exit(1); } if (read_res == blocksize) { read_res = read_full(0, buf, 1); if (read_res == 1) { fprintf(stderr, "%s: warning - truncated data\n", argv[0]); status = 1; } } free(buf); buf = NULL; if (force) { /* At user request, send without waiting to see an interest */ res = ndn_put(ndn, temp->buf, temp->length); if (res < 0) { fprintf(stderr, "ndn_put failed (res == %d)\n", res); exit(1); } } else { in_interest.data = temp; /* Set up a handler for interests */ res = ndn_set_interest_filter(ndn, pname, &in_interest); if (res < 0) { fprintf(stderr, "Failed to register interest (res == %d)\n", res); exit(1); } res = ndn_run(ndn, timeout); if (in_interest.intdata == 0) { if (verbose) fprintf(stderr, "Nobody's interested\n"); exit(1); } } if (verbose) { struct ndn_charbuf *uri = ndn_charbuf_create(); uri->length = 0; ndn_uri_append(uri, name->buf, name->length, 1); printf("wrote %s\n", ndn_charbuf_as_string(uri)); ndn_charbuf_destroy(&uri); } ndn_destroy(&ndn); ndn_charbuf_destroy(&name); ndn_charbuf_destroy(&pname); ndn_charbuf_destroy(&temp); ndn_charbuf_destroy(&sp.template_ndnb); ndn_charbuf_destroy(&extopt); exit(status); }