/** * 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); }
/** * 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); }
/** * 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);
PUBLIC void r_store_init(struct ccnr_handle *h) { struct ccn_btree *btree = NULL; struct ccn_btree_node *node = NULL; struct hashtb_param param = {0}; int i; int j; int res; struct ccn_charbuf *path = NULL; struct ccn_charbuf *msgs = NULL; off_t offset; path = ccn_charbuf_create(); param.finalize_data = h; param.finalize = 0; h->cob_limit = r_init_confval(h, "CCNR_CONTENT_CACHE", 16, 2000000, 4201); h->cookie_limit = choose_limit(h->cob_limit, (ccnr_cookie)(~0U)); h->content_by_cookie = calloc(h->cookie_limit, sizeof(h->content_by_cookie[0])); CHKPTR(h->content_by_cookie); h->content_by_accession_tab = hashtb_create(sizeof(struct content_by_accession_entry), NULL); CHKPTR(h->content_by_accession_tab); h->btree = btree = ccn_btree_create(); CHKPTR(btree); FAILIF(btree->nextnodeid != 1); ccn_charbuf_putf(path, "%s/index", h->directory); res = mkdir(ccn_charbuf_as_string(path), 0700); if (res != 0 && errno != EEXIST) r_init_fail(h, __LINE__, ccn_charbuf_as_string(path), errno); else { msgs = ccn_charbuf_create(); btree->io = ccn_btree_io_from_directory(ccn_charbuf_as_string(path), msgs); if (btree->io == NULL) res = errno; if (msgs->length != 0 && CCNSHOULDLOG(h, sffdsdf, CCNL_WARNING)) { ccnr_msg(h, "while initializing %s - %s", ccn_charbuf_as_string(path), ccn_charbuf_as_string(msgs)); } ccn_charbuf_destroy(&msgs); if (btree->io == NULL) r_init_fail(h, __LINE__, ccn_charbuf_as_string(path), res); } node = ccn_btree_getnode(btree, 1, 0); if (btree->io != NULL) btree->nextnodeid = btree->io->maxnodeid + 1; CHKPTR(node); if (node->buf->length == 0) { res = ccn_btree_init_node(node, 0, 'R', 0); CHKSYS(res); } ccn_charbuf_destroy(&path); if (h->running == -1) return; r_store_read_stable_point(h); h->active_in_fd = -1; h->active_out_fd = r_io_open_repo_data_file(h, "repoFile1", 1); /* output */ offset = lseek(h->active_out_fd, 0, SEEK_END); h->startupbytes = offset; if (offset != h->stable || node->corrupt != 0) { ccnr_msg(h, "Index not current - resetting"); ccn_btree_init_node(node, 0, 'R', 0); node = NULL; ccn_btree_destroy(&h->btree); path = ccn_charbuf_create(); /* Remove old index files to avoid confusion */ for (i = 1, j = 0; i > 0 && j < 3; i++) { path->length = 0; res = ccn_charbuf_putf(path, "%s/index/%d", h->directory, i); if (res >= 0) res = unlink(ccn_charbuf_as_string(path)); if (res < 0) j++; } h->btree = btree = ccn_btree_create(); path->length = 0; ccn_charbuf_putf(path, "%s/index", h->directory); btree->io = ccn_btree_io_from_directory(ccn_charbuf_as_string(path), msgs); CHKPTR(btree->io); btree->io->maxnodeid = 0; btree->nextnodeid = 1; node = ccn_btree_getnode(btree, 1, 0); btree->nextnodeid = btree->io->maxnodeid + 1; ccn_btree_init_node(node, 0, 'R', 0); h->stable = 0; h->active_in_fd = r_io_open_repo_data_file(h, "repoFile1", 0); /* input */ ccn_charbuf_destroy(&path); if (CCNSHOULDLOG(h, dfds, CCNL_INFO)) ccn_schedule_event(h->sched, 50000, r_store_reindexing, NULL, 0); } if (CCNSHOULDLOG(h, weuyg, CCNL_FINEST)) { FILE *dumpfile = NULL; path = ccn_charbuf_create(); ccn_charbuf_putf(path, "%s/index/btree_check.out", h->directory); dumpfile = fopen(ccn_charbuf_as_string(path), "w"); res = ccn_btree_check(btree, dumpfile); if (dumpfile != NULL) { fclose(dumpfile); dumpfile = NULL; } else path->length = 0; ccnr_msg(h, "ccn_btree_check returned %d (%s)", res, ccn_charbuf_as_string(path)); ccn_charbuf_destroy(&path); if (res < 0) r_init_fail(h, __LINE__, "index is corrupt", res); } btree->full = r_init_confval(h, "CCNR_BTREE_MAX_FANOUT", 4, 9999, 1999); btree->full0 = r_init_confval(h, "CCNR_BTREE_MAX_LEAF_ENTRIES", 4, 9999, 1999); btree->nodebytes = r_init_confval(h, "CCNR_BTREE_MAX_NODE_BYTES", 1024, 8388608, 2097152); btree->nodepool = r_init_confval(h, "CCNR_BTREE_NODE_POOL", 16, 2000000, 512); if (h->running != -1) r_store_index_needs_cleaning(h); }