PUBLIC int r_store_commit_content(struct ccnr_handle *h, struct content_entry *content) { // XXX - here we need to check if this is something we *should* be storing, according to our policy if ((r_store_content_flags(content) & CCN_CONTENT_ENTRY_STABLE) == 0) { r_store_send_content(h, r_io_fdholder_from_fd(h, h->active_out_fd), content); r_store_content_change_flags(content, CCN_CONTENT_ENTRY_STABLE, 0); } return(0); }
/** * Shutdown all open fds. */ PUBLIC void r_io_shutdown_all(struct ccnr_handle *h) { int i; for (i = 1; i < h->face_limit; i++) { if (r_io_fdholder_from_fd(h, i) != NULL) r_io_shutdown_client_fd(h, i); } ccnr_internal_client_stop(h); r_io_shutdown_client_fd(h, 0); }
/** * 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 void r_match_consume_interest(struct ccnr_handle *h, struct propagating_entry *pe) { struct fdholder *fdholder = NULL; ccn_indexbuf_destroy(&pe->outbound); if (pe->interest_msg != NULL) { free(pe->interest_msg); pe->interest_msg = NULL; fdholder = r_io_fdholder_from_fd(h, pe->filedesc); if (fdholder != NULL) fdholder->pending_interests -= 1; } if (pe->next != NULL) { pe->next->prev = pe->prev; pe->prev->next = pe->next; pe->next = pe->prev = NULL; } pe->usec = 0; }
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); } }
/** * Log a bit if we are taking a while to re-index. */ static int r_store_reindexing(struct ccn_schedule *sched, void *clienth, struct ccn_scheduled_event *ev, int flags) { struct ccnr_handle *h = clienth; struct fdholder *in = NULL; unsigned pct; if ((flags & CCN_SCHEDULE_CANCEL) != 0) return(0); in = r_io_fdholder_from_fd(h, h->active_in_fd); if (in == NULL) return(0); pct = ccnr_meter_total(in->meter[FM_BYTI]) / ((h->startupbytes / 100) + 1); if (pct >= 100) return(0); ccnr_msg(h, "indexing %u%% complete", pct); return(2000000); }
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); }
/** * 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); }
/** * Looks up a fdholder based on its filedesc. */ PUBLIC struct fdholder * ccnr_r_io_fdholder_from_fd(struct ccnr_handle *h, unsigned filedesc) { return(r_io_fdholder_from_fd(h, filedesc)); }
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); }
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); }