/** * 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); }
void r_init_fail(struct ccnr_handle *ccnr, int line, const char *culprit, int err) { if (err > 0) ccnr_msg(ccnr, "Startup failure %d %s - %s", line, culprit, strerror(err)); else { ccnr_msg(ccnr, "Startup failure %d %s - error %d", line, culprit, err); } ccnr->running = -1; }
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); }
/** * Parses content object and sets content->flatname */ static int r_store_set_flatname(struct ccnr_handle *h, struct content_entry *content, struct ccn_parsed_ContentObject *pco) { int res; struct ccn_charbuf *flatname = NULL; const unsigned char *msg = NULL; size_t size; msg = r_store_content_base(h, content); size = content->size; if (msg == NULL) goto Bail; flatname = ccn_charbuf_create(); if (flatname == NULL) goto Bail; res = ccn_parse_ContentObject(msg, size, pco, NULL); if (res < 0) { ccnr_msg(h, "error parsing ContentObject - code %d", res); goto Bail; } ccn_digest_ContentObject(msg, pco); if (pco->digest_bytes != 32) goto Bail; res = ccn_flatname_from_ccnb(flatname, msg, size); if (res < 0) goto Bail; res = ccn_flatname_append_component(flatname, pco->digest, pco->digest_bytes); if (res < 0) goto Bail; content->flatname = flatname; flatname = NULL; return(0); Bail: ccn_charbuf_destroy(&flatname); return(-1); }
/** * 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); }
/** * Make a new fdholder corresponding to the fd */ PUBLIC struct fdholder * r_io_record_fd(struct ccnr_handle *h, int fd, void *who, socklen_t wholen, int setflags) { int res; struct fdholder *fdholder = NULL; res = fcntl(fd, F_SETFL, O_NONBLOCK); if (res == -1) ccnr_msg(h, "fcntl: %s", strerror(errno)); fdholder = calloc(1, sizeof(*fdholder)); if (fdholder == NULL) return(fdholder); fdholder->name = ccn_charbuf_create(); if (fdholder->name == NULL) abort(); if (who != NULL) ccn_charbuf_append(fdholder->name, who, wholen); fdholder->filedesc = fd; init_face_flags(h, fdholder, setflags); res = r_io_enroll_face(h, fdholder); if (res == -1) { ccn_charbuf_destroy(&fdholder->name); free(fdholder); fdholder = NULL; } return(fdholder); }
/** * 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); }
/** * 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); }
/** * 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; } }
extern void SyncShutdown(struct SyncBaseStruct *bp) { char *here = "Sync.SyncShutdown"; int debug = bp->debug; if (debug >= CCNL_INFO) ccnr_msg(bp->ccnr, "%s", here); // TBD: shutdown the hearbeat // TBD: unregister the prefixes }
PUBLIC int r_store_final(struct ccnr_handle *h, int stable) { int res; res = ccn_btree_destroy(&h->btree); if (res < 0) ccnr_msg(h, "r_store_final.%d-%d Errors while closing index", __LINE__, res); if (res >= 0 && stable) res = r_store_write_stable_point(h); return(res); }
static int r_store_fatal(struct ccnr_handle *h, const char *fn, int lineno) { if (h != NULL) { ccnr_msg(h, "fatal error in %s, line %d, errno %d%s", fn, lineno, errno, strerror(errno)); } abort(); 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); }
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); }
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"); } }
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); }
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); }
static int r_init_debug_getenv(struct ccnr_handle *h, const char *envname) { const char *debugstr; int debugval; debugstr = getenv(envname); debugval = ccnr_msg_level_from_string(debugstr); /* Treat 1 and negative specially, for some backward compatibility. */ if (debugval == 1) debugval = CCNL_WARNING; if (debugval < 0) { debugval = CCNL_FINEST; if (h != NULL) ccnr_msg(h, "%s='%s' is not valid, using FINEST", envname, debugstr); } return(debugval); }
/** * 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); }
/** * Produce a ccnr debug trace entry. * Output is produced by calling ccnr_msg. * @param h the ccnr handle * @param lineno caller's source line number (usually __LINE__) * @param msg a short text tag to identify the entry * @param fdholder handle of associated fdholder; may be NULL * @param ccnb points to ccnb-encoded Interest or ContentObject * @param ccnb_size is in bytes */ void ccnr_debug_ccnb(struct ccnr_handle *h, int lineno, const char *msg, struct fdholder *fdholder, const unsigned char *ccnb, size_t ccnb_size) { struct ccn_charbuf *c; struct ccn_parsed_interest pi; const unsigned char *nonce = NULL; size_t nonce_size = 0; size_t i; if (h != NULL && h->debug == 0) return; c = ccn_charbuf_create(); ccn_charbuf_putf(c, "debug.%d %s ", lineno, msg); if (fdholder != NULL) ccn_charbuf_putf(c, "%u ", fdholder->filedesc); ccn_uri_append(c, ccnb, ccnb_size, 1); ccn_charbuf_putf(c, " (%u bytes)", (unsigned)ccnb_size); if (ccn_parse_interest(ccnb, ccnb_size, &pi, NULL) >= 0) { const char *p = ""; ccn_ref_tagged_BLOB(CCN_DTAG_Nonce, ccnb, pi.offset[CCN_PI_B_Nonce], pi.offset[CCN_PI_E_Nonce], &nonce, &nonce_size); if (nonce_size > 0) { ccn_charbuf_putf(c, " "); if (nonce_size == 12) p = "CCC-P-F-T-NN"; for (i = 0; i < nonce_size; i++) ccn_charbuf_putf(c, "%s%02X", (*p) && (*p++)=='-' ? "-" : "", nonce[i]); } } ccnr_msg(h, "%s", ccn_charbuf_as_string(c)); ccn_charbuf_destroy(&c); }
/** * Handle errors after send() or sendto(). * @returns -1 if error has been dealt with, or 0 to defer sending. */ static int handle_send_error(struct ccnr_handle *h, int errnum, struct fdholder *fdholder, const void *data, size_t size) { int res = -1; if (errnum == EAGAIN) { res = 0; } else if (errnum == EPIPE) { fdholder->flags |= CCNR_FACE_NOSEND; fdholder->outbufindex = 0; ccn_charbuf_destroy(&fdholder->outbuf); } else { ccnr_msg(h, "send/write to fd %u failed: %s (errno = %d)", fdholder->filedesc, strerror(errnum), errnum); if (errnum == EISCONN || errnum == EFBIG || errnum == ENOSPC) res = 0; } return(res); }
PUBLIC void ccnr_debug_content(struct ccnr_handle *h, int lineno, const char *msg, struct fdholder *fdholder, struct content_entry *content) { struct ccn_charbuf *c = ccn_charbuf_create(); struct ccn_charbuf *flat = content->flatname; if (c == NULL) return; ccn_charbuf_putf(c, "debug.%d %s ", lineno, msg); if (fdholder != NULL) ccn_charbuf_putf(c, "%u ", fdholder->filedesc); if (flat != NULL) ccn_uri_append_flatname(c, flat->buf, flat->length, 1); ccn_charbuf_putf(c, " (%d bytes)", content->size); ccnr_msg(h, "%s", ccn_charbuf_as_string(c)); ccn_charbuf_destroy(&c); }
/** * 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); }
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; }
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++; } } }
/** * 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); }