/** * Write a file named index/stable that contains the size of * repoFile1 when the repository is shut down. */ static int r_store_write_stable_point(struct ccnr_handle *h) { struct ccn_charbuf *path = NULL; struct ccn_charbuf *cb = NULL; int fd; path = ccn_charbuf_create(); cb = ccn_charbuf_create(); ccn_charbuf_putf(path, "%s/index/stable", h->directory); unlink(ccn_charbuf_as_string(path)); /* Should not exist, but just in case. */ fd = open(ccn_charbuf_as_string(path), O_CREAT | O_EXCL | O_WRONLY | O_TRUNC, 0666); if (fd == -1) { ccnr_msg(h, "cannot write stable mark %s: %s", ccn_charbuf_as_string(path), strerror(errno)); unlink(ccn_charbuf_as_string(path)); } else { ccn_charbuf_putf(cb, "%ju", (uintmax_t)(h->stable)); write(fd, cb->buf, cb->length); close(fd); if (CCNSHOULDLOG(h, dfsdf, CCNL_INFO)) ccnr_msg(h, "Index marked stable - %s", ccn_charbuf_as_string(cb)); } ccn_charbuf_destroy(&path); ccn_charbuf_destroy(&cb); return(0); }
/** * Get the specified numerical config value, subject to limits. */ intmax_t r_init_confval(struct ccnr_handle *h, const char *key, intmax_t lo, intmax_t hi, intmax_t deflt) { const char *s; intmax_t v; char *ep; if (!(lo <= deflt && deflt <= hi)) abort(); s = getenv(key); if (s != NULL && s[0] != 0) { ep = "x"; v = strtoimax(s, &ep, 10); if (v != 0 || ep[0] == 0) { if (v > hi) v = hi; if (v < lo) v = lo; if (CCNSHOULDLOG(h, mmm, CCNL_FINEST)) ccnr_msg(h, "Using %s=%jd", key, v); return(v); } } return (deflt); }
/** * Get the base address of the content object * * This may involve reading the object in. Caller should not assume that * the address will stay valid after it relinquishes control, either by * returning or by calling routines that might invalidate objects. * */ PUBLIC const unsigned char * r_store_content_base(struct ccnr_handle *h, struct content_entry *content) { const unsigned char *ans = NULL; if (content->cob != NULL && content->cob->length == content->size) { ans = content->cob->buf; goto Finish; } if (content->accession == CCNR_NULL_ACCESSION) goto Finish; ans = r_store_content_mapped(h, content); if (ans != NULL) goto Finish; ans = r_store_content_read(h, content); Finish: if (ans != NULL) { /* Sanity check - make sure first 2 and last 2 bytes are good */ if (content->size < 5 || ans[0] != 0x04 || ans[1] != 0x82 || ans[content->size - 1] != 0 || ans[content->size - 2] != 0) { bogon = ans; /* for debugger */ ans = NULL; } } if (ans == NULL || CCNSHOULDLOG(h, xxxx, CCNL_FINEST)) ccnr_msg(h, "r_store_content_base.%d returning %p (acc=0x%jx, cookie=%u)", __LINE__, ans, ccnr_accession_encode(h, content->accession), (unsigned)content->cookie); return(ans); }
PUBLIC int r_sendq_face_send_queue_insert(struct ccnr_handle *h, struct fdholder *fdholder, struct content_entry *content) { int ans = -1; int delay; enum cq_delay_class c; struct content_queue *q; if (fdholder == NULL || content == NULL || (fdholder->flags & CCNR_FACE_NOSEND) != 0) return(-1); c = choose_content_delay_class(h, fdholder->filedesc, r_store_content_flags(content)); if (fdholder->q[c] == NULL) fdholder->q[c] = content_queue_create(h, fdholder, c); q = fdholder->q[c]; if (q == NULL) return(-1); ans = ccn_indexbuf_set_insert(q->send_queue, r_store_content_cookie(h, content)); if (q->sender == NULL) { delay = randomize_content_delay(h, q); q->ready = q->send_queue->n; q->sender = ccn_schedule_event(h->sched, delay, content_sender, q, fdholder->filedesc); if (CCNSHOULDLOG(h, LM_8, CCNL_FINER)) ccnr_msg(h, "fdholder %u q %d delay %d usec", fdholder->filedesc, c, delay); } return (ans); }
/** * Evict recoverable content from in-memory buffers */ PUBLIC void r_store_trim(struct ccnr_handle *h, unsigned long limit) { struct content_entry *content = NULL; int checklimit; unsigned before; unsigned rover; unsigned mask; r_store_index_needs_cleaning(h); before = h->cob_count; if (before <= limit) return; checklimit = h->cookie_limit; mask = h->cookie_limit - 1; for (rover = (h->trim_rover & mask); checklimit > 0 && h->cob_count > limit; checklimit--, rover = (rover + 1) & mask) { content = h->content_by_cookie[rover]; if (content != NULL) r_store_content_trim(h, content); } h->trim_rover = rover; if (CCNSHOULDLOG(h, sdf, CCNL_FINER)) ccnr_msg(h, "trimmed %u cobs", before - h->cob_count); }
PUBLIC struct content_entry * process_incoming_content(struct ccnr_handle *h, struct fdholder *fdholder, unsigned char *msg, size_t size) { struct ccn_parsed_ContentObject obj = {0}; int res; struct content_entry *content = NULL; ccnr_accession accession = CCNR_NULL_ACCESSION; content = calloc(1, sizeof(*content)); if (content == NULL) goto Bail; content->cob = ccn_charbuf_create(); if (content->cob == NULL) goto Bail; res = ccn_charbuf_append(content->cob, msg, size); if (res < 0) goto Bail; content->size = size; res = r_store_set_flatname(h, content, &obj); if (res < 0) goto Bail; ccnr_meter_bump(h, fdholder->meter[FM_DATI], 1); content->accession = CCNR_NULL_ACCESSION; r_store_enroll_content(h, content); if (CCNSHOULDLOG(h, LM_4, CCNL_FINE)) ccnr_debug_content(h, __LINE__, "content_from", fdholder, content); res = r_store_content_btree_insert(h, content, &obj, &accession); if (res < 0) goto Bail; if (res == 0) { /* Content was there, with an accession */ if (CCNSHOULDLOG(h, LM_4, CCNL_FINER)) ccnr_debug_content(h, __LINE__, "content_duplicate", fdholder, content); h->content_dups_recvd++; r_store_forget_content(h, &content); content = r_store_content_from_accession(h, accession); if (content == NULL) goto Bail; } r_store_set_content_timer(h, content, &obj); r_match_match_interests(h, content, &obj, NULL, fdholder); return(content); Bail: r_store_forget_content(h, &content); return(content); }
PUBLIC void r_store_send_content(struct ccnr_handle *h, struct fdholder *fdholder, struct content_entry *content) { const unsigned char *content_msg = NULL; off_t offset; if (CCNSHOULDLOG(h, LM_4, CCNL_FINE)) ccnr_debug_content(h, __LINE__, "content_to", fdholder, content); content_msg = r_store_content_base(h, content); r_link_stuff_and_send(h, fdholder, content_msg, content->size, NULL, 0, &offset); if (offset != (off_t)-1 && content->accession == CCNR_NULL_ACCESSION) { int res; res = r_store_set_accession_from_offset(h, content, fdholder, offset); if (res == 0) if (CCNSHOULDLOG(h, LM_4, CCNL_FINE)) ccnr_debug_content(h, __LINE__, "content_stored", r_io_fdholder_from_fd(h, h->active_out_fd), content); } }
PUBLIC int r_io_open_repo_data_file(struct ccnr_handle *h, const char *name, int output) { struct ccn_charbuf *temp = NULL; int fd = -1; struct fdholder *fdholder = NULL; temp = ccn_charbuf_create(); ccn_charbuf_putf(temp, "%s/%s", h->directory, name); fd = open(ccn_charbuf_as_string(temp), output ? (O_CREAT | O_WRONLY | O_APPEND) : O_RDONLY, 0666); if (fd == -1) { if (CCNSHOULDLOG(h, sdf, CCNL_FINE)) ccnr_msg(h, "open(%s): %s", ccn_charbuf_as_string(temp), strerror(errno)); ccn_charbuf_destroy(&temp); return(-1); } fdholder = r_io_record_fd(h, fd, temp->buf, temp->length, CCNR_FACE_REPODATA | (output ? CCNR_FACE_NORECV : CCNR_FACE_NOSEND)); if (fdholder == NULL) close_fd(&fd); else { if (!output) { /* Use a larger buffer for indexing an existing repo file */ if (fdholder->inbuf == NULL) { fdholder->inbuf = ccn_charbuf_create(); fdholder->bufoffset = 0; } if (fdholder->inbuf != NULL) ccn_charbuf_reserve(fdholder->inbuf, 256 * 1024); } if (CCNSHOULDLOG(h, sdf, CCNL_INFO)) ccnr_msg(h, "opened fd=%d file=%s", fd, ccn_charbuf_as_string(temp)); } ccn_charbuf_destroy(&temp); return(fd); }
/** * Close an open file descriptor, and grumble about it. */ /* unused */ void ccnr_close_fd(struct ccnr_handle *h, unsigned filedesc, int *pfd) { int res; if (*pfd != -1) { int linger = 0; setsockopt(*pfd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)); res = close(*pfd); if (res == -1) ccnr_msg(h, "close failed for fdholder %u fd=%d: %s (errno=%d)", filedesc, *pfd, strerror(errno), errno); else if (CCNSHOULDLOG(h, io, CCNL_FINE)) ccnr_msg(h, "closing fd %d while finalizing fdholder %u", *pfd, filedesc); *pfd = -1; } }
/** * Message helper for r_init_parse_config() */ static void r_init_config_msg(struct ccnr_handle *h, int flags, int line, int chindex, const char *msg) { const char *problem = "Problem"; int log_at = CCNL_WARNING; log_at = CCNL_WARNING; if ((flags & CCNR_CONFIG_ERR) != 0) { problem = "Error"; log_at = CCNL_ERROR; } if ((flags & (CCNR_CONFIG_IGNORELINE|CCNR_CONFIG_PASSMASK)) == 1 && CCNSHOULDLOG(h, mmm, log_at)) { ccnr_msg(h, "%s in config file %s/config - line %d column %d: %s", problem, h->directory, line, chindex + 1, msg); } }
/** * Remove internal representation of a content object */ PUBLIC void r_store_forget_content(struct ccnr_handle *h, struct content_entry **pentry) { unsigned i; struct content_entry *entry = *pentry; if (entry == NULL) return; *pentry = NULL; if ((entry->flags & CCN_CONTENT_ENTRY_STALE) != 0) h->n_stale--; if (CCNSHOULDLOG(h, LM_4, CCNL_FINER)) ccnr_debug_content(h, __LINE__, "remove", NULL, entry); /* Remove the cookie reference */ i = entry->cookie & (h->cookie_limit - 1); if (h->content_by_cookie[i] == entry) h->content_by_cookie[i] = NULL; entry->cookie = 0; /* Remove the accession reference */ if (entry->accession != CCNR_NULL_ACCESSION) { struct hashtb_enumerator ee; struct hashtb_enumerator *e = ⅇ hashtb_start(h->content_by_accession_tab, e); if (hashtb_seek(e, &entry->accession, sizeof(entry->accession), 0) == HT_NEW_ENTRY) { ccnr_msg(h, "orphaned content %llu", (unsigned long long)(entry->accession)); hashtb_delete(e); hashtb_end(e); return; } hashtb_delete(e); hashtb_end(e); entry->accession = CCNR_NULL_ACCESSION; } /* Clean up allocated subfields */ ccn_charbuf_destroy(&entry->flatname); if (entry->cob != NULL) { h->cob_count--; ccn_charbuf_destroy(&entry->cob); } free(entry); }
PUBLIC struct content_entry * r_store_content_from_accession(struct ccnr_handle *h, ccnr_accession accession) { struct ccn_parsed_ContentObject obj = {0}; struct content_entry *content = NULL; struct content_by_accession_entry *entry; const unsigned char *content_base = NULL; int res; ccnr_accession acc; if (accession == CCNR_NULL_ACCESSION) return(NULL); entry = hashtb_lookup(h->content_by_accession_tab, &accession, sizeof(accession)); if (entry != NULL) { h->content_from_accession_hits++; return(entry->content); } h->content_from_accession_misses++; content = calloc(1, sizeof(*content)); CHKPTR(content); content->cookie = 0; content->accession = accession; content->cob = NULL; content->size = 0; content_base = r_store_content_base(h, content); if (content_base == NULL || content->size == 0) goto Bail; res = r_store_set_flatname(h, content, &obj); if (res < 0) goto Bail; r_store_enroll_content(h, content); res = r_store_content_btree_insert(h, content, &obj, &acc); if (res < 0) goto Bail; if (res == 1 || CCNSHOULDLOG(h, sdf, CCNL_FINEST)) ccnr_debug_content(h, __LINE__, "content/accession", NULL, content); return(content); Bail: ccnr_msg(h, "r_store_content_from_accession.%d failed 0x%jx", __LINE__, ccnr_accession_encode(h, accession)); r_store_forget_content(h, &content); return(content); }
static int merge_files(struct ccnr_handle *h) { int i, last_file; int res; struct ccn_charbuf *filename = ccn_charbuf_create(); // first parse the file(s) making sure there are no errors for (i = 2;; i++) { filename->length = 0; ccn_charbuf_putf(filename, "repoFile%d", i); res = r_init_map_and_process_file(h, filename, 0); if (res == 1) break; if (res < 0) { ccnr_msg(h, "Error parsing repository file %s", ccn_charbuf_as_string(filename)); return (-1); } } last_file = i - 1; for (i = 2; i <= last_file; i++) { filename->length = 0; ccn_charbuf_putf(filename, "repoFile%d", i); res = r_init_map_and_process_file(h, filename, 1); if (res < 0) { ccnr_msg(h, "Error in phase 2 incorporating repository file %s", ccn_charbuf_as_string(filename)); return (-1); } } for (i = last_file; i > 1; --i) { filename->length = 0; ccn_charbuf_putf(filename, "%s/repoFile%d", h->directory, i); if (CCNSHOULDLOG(h, LM_128, CCNL_INFO)) ccnr_msg(h, "unlinking %s", ccn_charbuf_as_string(filename)); unlink(ccn_charbuf_as_string(filename)); } ccn_charbuf_destroy(&filename); return (0); }
/** * Read the former size of repoFile1 from index/stable, and remove * the latter. */ static void r_store_read_stable_point(struct ccnr_handle *h) { struct ccn_charbuf *path = NULL; struct ccn_charbuf *cb = NULL; int fd; int i; ssize_t rres; uintmax_t val; unsigned char c; path = ccn_charbuf_create(); cb = ccn_charbuf_create(); ccn_charbuf_putf(path, "%s/index/stable", h->directory); fd = open(ccn_charbuf_as_string(path), O_RDONLY, 0666); if (fd != -1) { rres = read(fd, ccn_charbuf_reserve(cb, 80), 80); if (rres > 0) cb->length = rres; close(fd); if (CCNSHOULDLOG(h, dfsdf, CCNL_INFO)) ccnr_msg(h, "Last stable at %s", ccn_charbuf_as_string(cb)); } for (val = 0, i = 0; i < cb->length; i++) { c = cb->buf[i]; if ('0' <= c && c <= '9') val = val * 10 + (c - '0'); else break; } if (i == 0 || i < cb->length) { ccnr_msg(h, "Bad stable mark - %s", ccn_charbuf_as_string(cb)); h->stable = 0; } else { h->stable = val; unlink(ccn_charbuf_as_string(path)); } ccn_charbuf_destroy(&path); ccn_charbuf_destroy(&cb); }
PUBLIC void r_store_index_needs_cleaning(struct ccnr_handle *h) { int k; if (h->btree != NULL && h->btree->io != NULL && h->btree->cleanreq > 0) { if (h->index_cleaner == NULL) { h->index_cleaner = ccn_schedule_event(h->sched, CCN_BT_CLEAN_TICK_MICROS, r_store_index_cleaner, NULL, 0); if (CCNSHOULDLOG(h, sdfsdffd, CCNL_FINER)) ccnr_msg(h, "index cleaner started"); } /* If necessary, clean in a hurry. */ for (k = 30; /* Backstop to make sure we do not loop here */ k > 0 && h->index_cleaner != NULL && h->btree->io->openfds > CCN_BT_OPEN_NODES_LIMIT - 2; k--) r_store_index_cleaner(h->sched, h, h->index_cleaner, 0); if (k == 0) ccnr_msg(h, "index cleaner is in trouble"); } }
static int ccnr_direct_client_refresh(struct ccn_schedule *sched, void *clienth, struct ccn_scheduled_event *ev, int flags) { struct ccnr_handle *ccnr = clienth; int microsec = 0; if ((flags & CCN_SCHEDULE_CANCEL) == 0 && ccnr->direct_client != NULL && ccnr->direct_client_refresh == ev) { microsec = ccn_process_scheduled_operations(ccnr->direct_client); // XXX - This is not really right, since an incoming request can cause us to need to reschedule this event. if CCNSHOULDLOG(ccnr, refresh, CCNL_FINEST) ccnr_msg(ccnr, "direct_client_refresh %d in %d usec", ccn_get_connection_fd(ccnr->direct_client), microsec); if (microsec > ev->evint) microsec = ev->evint; if (microsec == 0) microsec = CCN_INTEREST_LIFETIME_MICROSEC; }
PUBLIC struct content_entry * r_store_next_child_at_level(struct ccnr_handle *h, struct content_entry *content, int level) { struct content_entry *next = NULL; struct ccn_charbuf *name; struct ccn_charbuf *flatname = NULL; int res; if (content == NULL) return(NULL); name = ccn_charbuf_create(); ccn_name_init(name); res = ccn_name_append_flatname(name, content->flatname->buf, content->flatname->length, 0, level + 1); if (res < level) goto Bail; if (res == level) res = ccn_name_append(name, NULL, 0); else if (res == level + 1) res = ccn_name_next_sibling(name); // XXX - would be nice to have a flatname version of this if (res < 0) goto Bail; if (CCNSHOULDLOG(h, LM_8, CCNL_FINER)) ccnr_debug_ccnb(h, __LINE__, "child_successor", NULL, name->buf, name->length); flatname = ccn_charbuf_create(); ccn_flatname_from_ccnb(flatname, name->buf, name->length); next = r_store_look(h, flatname->buf, flatname->length); if (next == content) { // XXX - I think this case should not occur, but just in case, avoid a loop. ccnr_debug_content(h, __LINE__, "urp", NULL, next); next = NULL; } Bail: ccn_charbuf_destroy(&name); ccn_charbuf_destroy(&flatname); return(next); }
PUBLIC void r_io_shutdown_client_fd(struct ccnr_handle *h, int fd) { struct fdholder *fdholder = NULL; enum cq_delay_class c; int m; int res; fdholder = r_io_fdholder_from_fd(h, fd); if (fdholder == NULL) { ccnr_msg(h, "no fd holder for fd %d", fd); return; } if (fdholder == h->face0) (res = 0, h->face0 = NULL); else if ((fdholder->flags & CCNR_FACE_CCND)) res = ccn_disconnect(h->direct_client); else res = close(fd); if (CCNSHOULDLOG(h, sdfdf, CCNL_INFO)) ccnr_msg(h, "shutdown client fd=%d", fd); ccn_charbuf_destroy(&fdholder->inbuf); ccn_charbuf_destroy(&fdholder->outbuf); for (c = 0; c < CCN_CQ_N; c++) r_sendq_content_queue_destroy(h, &(fdholder->q[c])); for (m = 0; m < CCNR_FACE_METER_N; m++) ccnr_meter_destroy(&fdholder->meter[m]); if (h->fdholder_by_fd[fd] != fdholder) abort(); h->fdholder_by_fd[fd] = NULL; ccn_charbuf_destroy(&fdholder->name); free(fdholder); if (h->active_in_fd == fd) h->active_in_fd = -1; if (h->active_out_fd == fd) h->active_out_fd = -1; if (h->repofile1_fd == fd) h->repofile1_fd = -1; // r_fwd_reap_needed(h, 250000); }
/** * Accept an incoming DGRAM_STREAM connection, creating a new fdholder. * @returns fd of new socket, or -1 for an error. */ PUBLIC int r_io_accept_connection(struct ccnr_handle *h, int listener_fd) { struct sockaddr_storage who; socklen_t wholen = sizeof(who); int fd; struct fdholder *fdholder; fd = accept(listener_fd, (struct sockaddr *)&who, &wholen); if (fd == -1) { ccnr_msg(h, "accept: %s", strerror(errno)); return(-1); } fdholder = r_io_record_fd(h, fd, (struct sockaddr *)&who, wholen, CCNR_FACE_UNDECIDED); if (fdholder == NULL) close_fd(&fd); else if (CCNSHOULDLOG(h, io, CCNL_INFO)) ccnr_msg(h, "accepted client fd=%d id=%u", fd, fdholder->filedesc); return(fd); }
/** * Consume matching interests * given a nameprefix_entry and a piece of content. * * If fdholder is not NULL, pay attention only to interests from that fdholder. * It is allowed to pass NULL for pc, but if you have a (valid) one it * will avoid a re-parse. * @returns number of matches found. */ PUBLIC int r_match_consume_matching_interests(struct ccnr_handle *h, struct nameprefix_entry *npe, struct content_entry *content, struct ccn_parsed_ContentObject *pc, struct fdholder *fdholder) { int matches = 0; struct propagating_entry *head; struct propagating_entry *next; struct propagating_entry *p; const unsigned char *content_msg; size_t content_size; struct fdholder *f; head = &npe->pe_head; // XXX - i do not think this is called in practice content_msg = r_store_content_base(h, content); content_size = r_store_content_size(h, content); f = fdholder; for (p = head->next; p != head; p = next) { next = p->next; if (p->interest_msg != NULL && ((fdholder == NULL && (f = r_io_fdholder_from_fd(h, p->filedesc)) != NULL) || (fdholder != NULL && p->filedesc == fdholder->filedesc))) { if (ccn_content_matches_interest(content_msg, content_size, 1, pc, p->interest_msg, p->size, NULL)) { r_sendq_face_send_queue_insert(h, f, content); if (CCNSHOULDLOG(h, (32 | 8), CCNL_FINE)) ccnr_debug_ccnb(h, __LINE__, "consume", f, p->interest_msg, p->size); matches += 1; r_match_consume_interest(h, p); } } } return(matches); }
static int establish_min_send_bufsize(struct ccnr_handle *h, int fd, int minsize) { int res; int bufsize; int obufsize; socklen_t bufsize_sz; bufsize_sz = sizeof(bufsize); res = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bufsize, &bufsize_sz); if (res == -1) return (res); obufsize = bufsize; if (bufsize < minsize) { bufsize = minsize; res = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)); if (res == -1) return(res); } if (CCNSHOULDLOG(h, sdfdsf, CCNL_INFO)) ccnr_msg(h, "SO_SNDBUF for fd %d is %d (was %d)", fd, bufsize, obufsize); return(bufsize); }
/** * Set up the array of fd descriptors for the poll(2) call. * */ PUBLIC void r_io_prepare_poll_fds(struct ccnr_handle *h) { int i, j, nfds; for (i = 1, nfds = 0; i < h->face_limit; i++) if (r_io_fdholder_from_fd(h, i) != NULL) nfds++; if (nfds != h->nfds) { h->nfds = nfds; h->fds = realloc(h->fds, h->nfds * sizeof(h->fds[0])); memset(h->fds, 0, h->nfds * sizeof(h->fds[0])); } for (i = 1, j = 0; i < h->face_limit; i++) { struct fdholder *fdholder = r_io_fdholder_from_fd(h, i); if (fdholder != NULL) { h->fds[j].fd = fdholder->filedesc; h->fds[j].events = 0; if ((fdholder->flags & (CCNR_FACE_NORECV|CCNR_FACE_REPODATA)) == 0) h->fds[j].events |= POLLIN; if (fdholder->filedesc == h->active_in_fd) h->fds[j].events |= POLLIN; if (((fdholder->flags & CCNR_FACE_REPODATA) == 0) && ((fdholder->outbuf != NULL || (fdholder->flags & CCNR_FACE_CLOSING) != 0))) h->fds[j].events |= POLLOUT; if ((fdholder->flags & CCNR_FACE_CCND) != 0) { if (ccn_output_is_pending(h->direct_client)) { if (CCNSHOULDLOG(h, xxx, CCNL_FINEST)) ccnr_msg(h, "including direct client in poll set"); h->fds[j].events |= POLLOUT; } } j++; } } }
PUBLIC struct content_entry * r_store_find_first_match_candidate(struct ccnr_handle *h, const unsigned char *interest_msg, const struct ccn_parsed_interest *pi) { int res; size_t start = pi->offset[CCN_PI_B_Name]; size_t end = pi->offset[CCN_PI_E_Name]; struct ccn_charbuf *namebuf = NULL; struct ccn_charbuf *flatname = NULL; struct content_entry *content = NULL; flatname = ccn_charbuf_create(); ccn_flatname_from_ccnb(flatname, interest_msg, pi->offset[CCN_PI_E]); if (pi->offset[CCN_PI_B_Exclude] < pi->offset[CCN_PI_E_Exclude]) { /* Check for <Exclude><Any/><Component>... fast case */ struct ccn_buf_decoder decoder; struct ccn_buf_decoder *d; size_t ex1start; size_t ex1end; d = ccn_buf_decoder_start(&decoder, interest_msg + pi->offset[CCN_PI_B_Exclude], pi->offset[CCN_PI_E_Exclude] - pi->offset[CCN_PI_B_Exclude]); ccn_buf_advance(d); if (ccn_buf_match_dtag(d, CCN_DTAG_Any)) { ccn_buf_advance(d); ccn_buf_check_close(d); if (ccn_buf_match_dtag(d, CCN_DTAG_Component)) { ex1start = pi->offset[CCN_PI_B_Exclude] + d->decoder.token_index; ccn_buf_advance_past_element(d); ex1end = pi->offset[CCN_PI_B_Exclude] + d->decoder.token_index; if (d->decoder.state >= 0) { namebuf = ccn_charbuf_create(); ccn_charbuf_append(namebuf, interest_msg + start, end - start); namebuf->length--; ccn_charbuf_append(namebuf, interest_msg + ex1start, ex1end - ex1start); ccn_charbuf_append_closer(namebuf); res = ccn_flatname_append_from_ccnb(flatname, interest_msg + ex1start, ex1end - ex1start, 0, 1); if (res != 1) ccnr_debug_ccnb(h, __LINE__, "fastex_bug", NULL, namebuf->buf, namebuf->length); if (CCNSHOULDLOG(h, LM_8, CCNL_FINER)) ccnr_debug_ccnb(h, __LINE__, "fastex", NULL, namebuf->buf, namebuf->length); } } } } content = r_store_look(h, flatname->buf, flatname->length); ccn_charbuf_destroy(&namebuf); ccn_charbuf_destroy(&flatname); return(content); }
static int r_store_index_cleaner(struct ccn_schedule *sched, void *clienth, struct ccn_scheduled_event *ev, int flags) { struct ccnr_handle *h = clienth; struct hashtb_enumerator ee; struct hashtb_enumerator *e = ⅇ struct ccn_btree_node *node = NULL; int k; int res; int overquota; (void)(sched); (void)(ev); if ((flags & CCN_SCHEDULE_CANCEL) != 0 || h->btree == NULL || h->btree->io == NULL) { h->index_cleaner = NULL; ccn_indexbuf_destroy(&h->toclean); return(0); } /* First, work on cleaning the things we already know need cleaning */ if (h->toclean != NULL) { for (k = 0; k < CCN_BT_CLEAN_BATCH && h->toclean->n > 0; k++) { node = ccn_btree_rnode(h->btree, h->toclean->buf[--h->toclean->n]); if (node != NULL && node->iodata != NULL) { res = ccn_btree_chknode(node); /* paranoia */ if (res < 0 || CCNSHOULDLOG(h, sdfsdffd, CCNL_FINER)) ccnr_msg(h, "write index node %u (err %d)", (unsigned)node->nodeid, node->corrupt); if (res >= 0) { if (node->clean != node->buf->length) res = h->btree->io->btwrite(h->btree->io, node); if (res < 0) ccnr_msg(h, "failed to write index node %u", (unsigned)node->nodeid); else node->clean = node->buf->length; } if (res >= 0 && node->iodata != NULL && node->activity == 0) { if (CCNSHOULDLOG(h, sdfsdffd, CCNL_FINER)) ccnr_msg(h, "close index node %u", (unsigned)node->nodeid); res = ccn_btree_close_node(h->btree, node); } } } if (h->toclean->n > 0) return(nrand48(h->seed) % (2U * CCN_BT_CLEAN_TICK_MICROS) + 500); } /* Sweep though and find the nodes that still need cleaning */ overquota = 0; if (h->btree->nodepool >= 16) overquota = hashtb_n(h->btree->resident) - h->btree->nodepool; hashtb_start(h->btree->resident, e); for (node = e->data; node != NULL; node = e->data) { if (overquota > 0 && node->activity == 0 && node->iodata == NULL && node->clean == node->buf->length) { overquota -= 1; if (CCNSHOULDLOG(h, sdfsdffd, CCNL_FINEST)) ccnr_msg(h, "prune index node %u", (unsigned)node->nodeid); hashtb_delete(e); continue; } node->activity /= 2; /* Age the node's activity */ if (node->clean != node->buf->length || (node->iodata != NULL && node->activity == 0)) { if (h->toclean == NULL) { h->toclean = ccn_indexbuf_create(); if (h->toclean == NULL) break; } ccn_indexbuf_append_element(h->toclean, node->nodeid); } hashtb_next(e); } hashtb_end(e); /* If nothing to do, shut down cleaner */ if ((h->toclean == NULL || h->toclean->n == 0) && overquota <= 0 && h->btree->io->openfds <= CCN_BT_OPEN_NODES_IDLE) { h->btree->cleanreq = 0; h->index_cleaner = NULL; ccn_indexbuf_destroy(&h->toclean); if (CCNSHOULDLOG(h, sdfsdffd, CCNL_FINE)) ccnr_msg(h, "index btree nodes all clean"); return(0); } return(nrand48(h->seed) % (2U * CCN_BT_CLEAN_TICK_MICROS) + 500); }
/** * Send data to the fdholder. * * No direct error result is provided; the fdholder state is updated as needed. */ PUBLIC void r_io_send(struct ccnr_handle *h, struct fdholder *fdholder, const void *data, size_t size, off_t *offsetp) { ssize_t res; off_t offset = -1; if (offsetp != NULL) *offsetp = (off_t)-1; if ((fdholder->flags & CCNR_FACE_NOSEND) != 0) return; if (fdholder->outbuf != NULL) { ccn_charbuf_append(fdholder->outbuf, data, size); return; } if (fdholder == h->face0) { ccnr_meter_bump(h, fdholder->meter[FM_BYTO], size); ccn_dispatch_message(h->internal_client, (void *)data, size); r_dispatch_process_internal_client_buffer(h); return; } if ((fdholder->flags & CCNR_FACE_CCND) != 0) { /* Writes here need to go via the direct client's handle. */ ccnr_meter_bump(h, fdholder->meter[FM_BYTO], size); res = ccn_put(h->direct_client, data, size); if (res < 0 && CCNSHOULDLOG(h, r_io_send, CCNL_WARNING)) ccnr_msg(h, "ccn_put failed"); if (res == 1 && CCNSHOULDLOG(h, r_io_send, CCNL_FINEST)) ccnr_msg(h, "ccn_put deferred output for later send"); return; } if ((fdholder->flags & CCNR_FACE_REPODATA) != 0) { offset = lseek(fdholder->filedesc, 0, SEEK_END); if (offset == (off_t)-1) { ccnr_msg(h, "lseek(%d): %s", fdholder->filedesc, strerror(errno)); return; } if (offsetp != NULL) *offsetp = offset; if (fdholder->filedesc == h->active_out_fd) { if (offset != h->stable && h->stable != 0) ccnr_msg(h, "expected file size %ju, found %ju", (uintmax_t)h->stable, (uintmax_t)offset); h->stable = offset + size; } } if ((fdholder->flags & CCNR_FACE_DGRAM) == 0) res = write(fdholder->filedesc, data, size); else res = sendto(sending_fd(h, fdholder), data, size, 0, (struct sockaddr *)fdholder->name->buf, fdholder->name->length); if (res > 0) ccnr_meter_bump(h, fdholder->meter[FM_BYTO], res); if (res == size) return; if (res == -1) { res = handle_send_error(h, errno, fdholder, data, size); if (res == -1) return; } if ((fdholder->flags & CCNR_FACE_DGRAM) != 0) { ccnr_msg(h, "sendto short"); return; } if ((fdholder->flags & CCNR_FACE_REPODATA) != 0) { // need to truncate back to last known good object then exit. ccnr_msg(h, "Unrecoverable write error writing to repository. Content NOT stored."); ftruncate(fdholder->filedesc, offset); h->running = 0; return; } fdholder->outbufindex = 0; fdholder->outbuf = ccn_charbuf_create(); if (fdholder->outbuf == NULL) { ccnr_msg(h, "do_write: %s", strerror(errno)); return; } ccn_charbuf_append(fdholder->outbuf, ((const unsigned char *)data) + res, size - res); }
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); }
PUBLIC struct content_entry * r_store_lookup(struct ccnr_handle *h, const unsigned char *msg, const struct ccn_parsed_interest *pi, struct ccn_indexbuf *comps) { struct content_entry *content = NULL; struct ccn_btree_node *leaf = NULL; ccnr_cookie last_match = 0; ccnr_accession last_match_acc = CCNR_NULL_ACCESSION; struct ccn_charbuf *scratch = NULL; size_t size = pi->offset[CCN_PI_E]; int ndx; int res; int try; content = r_store_find_first_match_candidate(h, msg, pi); if (content != NULL && CCNSHOULDLOG(h, LM_8, CCNL_FINER)) ccnr_debug_content(h, __LINE__, "first_candidate", NULL, content); if (content != NULL && !r_store_content_matches_interest_prefix(h, content, msg, size)) { if (CCNSHOULDLOG(h, LM_8, CCNL_FINER)) ccnr_debug_ccnb(h, __LINE__, "prefix_mismatch", NULL, msg, size); content = NULL; } scratch = ccn_charbuf_create(); for (try = 0; content != NULL; try++) { res = ccn_btree_lookup(h->btree, content->flatname->buf, content->flatname->length, &leaf); if (CCN_BT_SRCH_FOUND(res) == 0) { ccnr_debug_content(h, __LINE__, "impossible", NULL, content); content = NULL; break; } ndx = CCN_BT_SRCH_INDEX(res); res = ccn_btree_match_interest(leaf, ndx, msg, pi, scratch); if (res == -1) { ccnr_debug_ccnb(h, __LINE__, "match_error", NULL, msg, size); content = NULL; break; } if (res == 1) { if ((pi->orderpref & 1) == 0) // XXX - should be symbolic break; last_match = content->cookie; last_match_acc = content->accession; content = r_store_next_child_at_level(h, content, comps->n - 1); } else content = r_store_content_next(h, content); if (content != NULL && !r_store_content_matches_interest_prefix(h, content, msg, size)) content = NULL; } if (last_match != 0) { content = r_store_content_from_cookie(h, last_match); if (content == NULL) content = r_store_content_from_accession(h, last_match_acc); } ccn_charbuf_destroy(&scratch); return(content); } /** * Find the first content handle that matches the prefix given by the namish, * which may be a Name, Interest, ContentObject, ... * * Does not check the other parts of namish, in particular, does not generate * the digest component of a ContentObject. */ PUBLIC struct content_entry * r_store_lookup_ccnb(struct ccnr_handle *h, const unsigned char *namish, size_t size) { struct content_entry *content = NULL; struct ccn_charbuf *flatname = NULL; int res; flatname = ccn_charbuf_create(); if (flatname == NULL) goto Bail; res = ccn_flatname_from_ccnb(flatname, namish, size); if (res < 0) goto Bail; content = r_store_look(h, flatname->buf, flatname->length); if (content != NULL) { res = ccn_flatname_charbuf_compare(flatname, content->flatname); if (res == 0 || res == -9999) { /* prefix matches */ } else content = NULL; } Bail: ccn_charbuf_destroy(&flatname); return(content); } /** * Mark content as stale */ PUBLIC void r_store_mark_stale(struct ccnr_handle *h, struct content_entry *content) { ccnr_cookie cookie = content->cookie; if ((content->flags & CCN_CONTENT_ENTRY_STALE) != 0) return; if (CCNSHOULDLOG(h, LM_4, CCNL_FINE)) ccnr_debug_content(h, __LINE__, "stale", NULL, content); content->flags |= CCN_CONTENT_ENTRY_STALE; h->n_stale++; if (cookie < h->min_stale) h->min_stale = cookie; if (cookie > h->max_stale) h->max_stale = cookie; } /** * Scheduled event that makes content stale when its FreshnessSeconds * has expired. */ static int expire_content(struct ccn_schedule *sched, void *clienth, struct ccn_scheduled_event *ev, int flags) { struct ccnr_handle *h = clienth; ccnr_cookie cookie = ev->evint; struct content_entry *content = NULL; if ((flags & CCN_SCHEDULE_CANCEL) != 0) return(0); content = r_store_content_from_cookie(h, cookie); if (content != NULL) r_store_mark_stale(h, content); return(0); } /** * Schedules content expiration based on its FreshnessSeconds. * */ PUBLIC void r_store_set_content_timer(struct ccnr_handle *h, struct content_entry *content, struct ccn_parsed_ContentObject *pco) { int seconds = 0; int microseconds = 0; size_t start = pco->offset[CCN_PCO_B_FreshnessSeconds]; size_t stop = pco->offset[CCN_PCO_E_FreshnessSeconds]; const unsigned char *content_msg = NULL; if (start == stop) return; content_msg = r_store_content_base(h, content); seconds = ccn_fetch_tagged_nonNegativeInteger( CCN_DTAG_FreshnessSeconds, content_msg, start, stop); if (seconds <= 0) return; if (seconds > ((1U<<31) / 1000000)) { ccnr_debug_content(h, __LINE__, "FreshnessSeconds_too_large", NULL, content); return; } microseconds = seconds * 1000000; ccn_schedule_event(h->sched, microseconds, &expire_content, NULL, content->cookie); }
int ccnr_init_repo_keystore(struct ccnr_handle *ccnr, struct ccn *h) { struct ccn_charbuf *temp = NULL; struct ccn_charbuf *culprit = NULL; struct stat statbuf; int res = -1; char *keystore_path = NULL; struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT; temp = ccn_charbuf_create(); culprit = temp; ccn_charbuf_putf(temp, "%s/", ccnr->directory); res = stat(ccn_charbuf_as_string(temp), &statbuf); if (res == -1) goto Finish; if ((statbuf.st_mode & S_IFDIR) == 0) { res = -1; errno = ENOTDIR; goto Finish; } ccn_charbuf_putf(temp, "ccnx_repository_keystore"); keystore_path = strdup(ccn_charbuf_as_string(temp)); res = stat(keystore_path, &statbuf); if (res == 0 && h != NULL) res = ccn_load_default_key(h, keystore_path, CCNR_KEYSTORE_PASS); if (res >= 0) { culprit = NULL; goto Finish; } /* No stored keystore that we can access. Create one if we can.*/ res = ccn_keystore_file_init(keystore_path, CCNR_KEYSTORE_PASS, "Repository", 0, 0); if (res != 0) { res = -1; goto Finish; } if (CCNSHOULDLOG(ccnr, keystore, CCNL_WARNING)) ccnr_msg(ccnr, "New repository private key saved in %s", keystore_path); if (h != NULL) res = ccn_load_default_key(h, keystore_path, CCNR_KEYSTORE_PASS); Finish: if (res >= 0 && h != NULL) res = ccn_chk_signing_params(h, NULL, &sp, NULL, NULL, NULL, NULL); if (res >= 0 && h != NULL) { memcpy(ccnr->ccnr_id, sp.pubid, sizeof(ccnr->ccnr_id)); if (ccnr->ccnr_keyid == NULL) ccnr->ccnr_keyid = ccn_charbuf_create(); else ccnr->ccnr_keyid->length = 0; ccn_charbuf_append_value(ccnr->ccnr_keyid, CCN_MARKER_CONTROL, 1); ccn_charbuf_append_string(ccnr->ccnr_keyid, ".M.K"); ccn_charbuf_append_value(ccnr->ccnr_keyid, 0, 1); ccn_charbuf_append(ccnr->ccnr_keyid, ccnr->ccnr_id, sizeof(ccnr->ccnr_id)); } if (res < 0) { ccnr->running = -1; /* Make note of init failure */ if (culprit != NULL) ccnr_msg(ccnr, "Error accessing keystore - %s: %s\n", strerror(errno), ccn_charbuf_as_string(temp)); } ccn_charbuf_destroy(&temp); if (keystore_path != NULL) free(keystore_path); return(res); }
/** * Common interest handler */ PUBLIC enum ccn_upcall_res ccnr_answer_req(struct ccn_closure *selfp, enum ccn_upcall_kind kind, struct ccn_upcall_info *info) { struct ccn_charbuf *msg = NULL; struct ccn_charbuf *name = NULL; struct ccn_charbuf *keylocator = NULL; struct ccn_charbuf *signed_info = NULL; struct ccn_charbuf *reply_body = NULL; struct ccnr_handle *ccnr = NULL; int res = 0; int morecomps = 0; const unsigned char *final_comp = NULL; size_t final_size = 0; switch (kind) { case CCN_UPCALL_FINAL: free(selfp); return(CCN_UPCALL_RESULT_OK); case CCN_UPCALL_INTEREST: break; case CCN_UPCALL_CONSUMED_INTEREST: return(CCN_UPCALL_RESULT_OK); default: return(CCN_UPCALL_RESULT_ERR); } ccnr = (struct ccnr_handle *)selfp->data; if (CCNSHOULDLOG(ccnr, LM_128, CCNL_FINE)) ccnr_debug_ccnb(ccnr, __LINE__, "ccnr_answer_req", NULL, info->interest_ccnb, info->pi->offset[CCN_PI_E]); morecomps = selfp->intdata & MORECOMPS_MASK; if ((info->pi->answerfrom & CCN_AOK_NEW) == 0 && selfp->intdata != OP_SERVICE) return(CCN_UPCALL_RESULT_OK); if (info->matched_comps >= info->interest_comps->n) goto Bail; if ((selfp->intdata & OPER_MASK) != OP_SERVICE && info->pi->prefix_comps != info->matched_comps + morecomps) goto Bail; if (morecomps == 1) { res = ccn_name_comp_get(info->interest_ccnb, info->interest_comps, info->matched_comps, &final_comp, &final_size); if (res < 0) goto Bail; } if ((selfp->intdata & MUST_VERIFY) != 0) { struct ccn_parsed_ContentObject pco = {0}; // XXX - probably should check for message origin BEFORE verify res = ccn_parse_ContentObject(final_comp, final_size, &pco, NULL); if (res < 0) { ccnr_debug_ccnb(ccnr, __LINE__, "co_parse_failed", NULL, info->interest_ccnb, info->pi->offset[CCN_PI_E]); goto Bail; } res = ccn_verify_content(info->h, final_comp, &pco); if (res != 0) { ccnr_debug_ccnb(ccnr, __LINE__, "co_verify_failed", NULL, info->interest_ccnb, info->pi->offset[CCN_PI_E]); goto Bail; } } switch (selfp->intdata & OPER_MASK) { case OP_SERVICE: if (ccnr->service_ccnb == NULL) ccnr->service_ccnb = ccnr_init_service_ccnb(ccnr, info->h, CCNRID_LOCAL_URI, 600); if (ccn_content_matches_interest( ccnr->service_ccnb->buf, ccnr->service_ccnb->length, 1, NULL, info->interest_ccnb, info->pi->offset[CCN_PI_E], info->pi )) { ccn_put(info->h, ccnr->service_ccnb->buf, ccnr->service_ccnb->length); res = CCN_UPCALL_RESULT_INTEREST_CONSUMED; goto Finish; } // XXX this needs refactoring. if (ccnr->neighbor_ccnb == NULL) ccnr->neighbor_ccnb = ccnr_init_service_ccnb(ccnr, info->h, CCNRID_NEIGHBOR_URI, 5); if (ccn_content_matches_interest( ccnr->neighbor_ccnb->buf, ccnr->neighbor_ccnb->length, 1, NULL, info->interest_ccnb, info->pi->offset[CCN_PI_E], info->pi )) { ccn_put(info->h, ccnr->neighbor_ccnb->buf, ccnr->neighbor_ccnb->length); res = CCN_UPCALL_RESULT_INTEREST_CONSUMED; goto Finish; } if (ccn_content_matches_interest( ccnr->policy_link_cob->buf, ccnr->policy_link_cob->length, 1, NULL, info->interest_ccnb, info->pi->offset[CCN_PI_E], info->pi )) { ccn_put(info->h, ccnr->policy_link_cob->buf, ccnr->policy_link_cob->length); res = CCN_UPCALL_RESULT_INTEREST_CONSUMED; goto Finish; } goto Bail; break; default: // No other OP_xxx are supported here goto Bail; } Bail: res = CCN_UPCALL_RESULT_ERR; Finish: ccn_charbuf_destroy(&msg); ccn_charbuf_destroy(&name); ccn_charbuf_destroy(&keylocator); ccn_charbuf_destroy(&reply_body); ccn_charbuf_destroy(&signed_info); return(res); }
static int content_sender(struct ccn_schedule *sched, void *clienth, struct ccn_scheduled_event *ev, int flags) { int i, j; int delay; int nsec; int burst_nsec; int burst_max; struct ccnr_handle *h = clienth; struct content_entry *content = NULL; unsigned filedesc = ev->evint; struct fdholder *fdholder = NULL; struct content_queue *q = ev->evdata; (void)sched; if ((flags & CCN_SCHEDULE_CANCEL) != 0) goto Bail; fdholder = r_io_fdholder_from_fd(h, filedesc); if (fdholder == NULL) goto Bail; if (q->send_queue == NULL) goto Bail; if ((fdholder->flags & CCNR_FACE_NOSEND) != 0) goto Bail; /* Send the content at the head of the queue */ if (q->ready > q->send_queue->n || (q->ready == 0 && q->nrun >= 12 && q->nrun < 120)) q->ready = q->send_queue->n; nsec = 0; burst_nsec = q->burst_nsec; burst_max = 2; if (q->ready < burst_max) burst_max = q->ready; if (burst_max == 0) q->nrun = 0; for (i = 0; i < burst_max && nsec < 1000000; i++) { content = r_store_content_from_cookie(h, q->send_queue->buf[i]); if (content == NULL) q->nrun = 0; else { r_link_send_content(h, fdholder, content); /* fdholder may have vanished, bail out if it did */ if (r_io_fdholder_from_fd(h, filedesc) == NULL) goto Bail; // nsec += burst_nsec * (unsigned)((content->size + 1023) / 1024); q->nrun++; } } if (q->ready < i) abort(); q->ready -= i; /* Update queue */ for (j = 0; i < q->send_queue->n; i++, j++) q->send_queue->buf[j] = q->send_queue->buf[i]; q->send_queue->n = j; /* Do a poll before going on to allow others to preempt send. */ delay = (nsec + 499) / 1000 + 1; if (q->ready > 0) { return(delay); } q->ready = j; if (q->nrun >= 12 && q->nrun < 120) { /* We seem to be a preferred provider, forgo the randomized delay */ if (j == 0) delay += burst_nsec / 50; return(delay); } /* Determine when to run again */ for (i = 0; i < q->send_queue->n; i++) { content = r_store_content_from_cookie(h, q->send_queue->buf[i]); if (content != NULL) { q->nrun = 0; delay = randomize_content_delay(h, q); if (CCNSHOULDLOG(h, LM_8, CCNL_FINER)) ccnr_msg(h, "fdholder %u queued %u delay %i", (unsigned)ev->evint, q->ready, delay); return(delay); } } q->send_queue->n = q->ready = 0; Bail: q->sender = NULL; return(0); }