/** * 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); }
PyObject * _pyccn_cmd_digest_contentobject(PyObject *UNUSED(self), PyObject *args) { PyObject *py_content_object; struct ccn_charbuf *content_object; struct ccn_parsed_ContentObject *parsed_content_object; PyObject *py_digest; if (!PyArg_ParseTuple(args, "O", &py_content_object)) return NULL; if (!CCNObject_IsValid(CONTENT_OBJECT, py_content_object)) { PyErr_SetString(PyExc_TypeError, "Expected CCN ContentObject"); return NULL; } content_object = CCNObject_Get(CONTENT_OBJECT, py_content_object); parsed_content_object = _pyccn_content_object_get_pco(py_content_object); if (!parsed_content_object) return NULL; /* * sanity check (sigh, I guess pco and comps should be carried in * capsule's context, since they're very closely related) */ if (content_object->length != parsed_content_object->offset[CCN_PCO_E]) { PyErr_SetString(PyExc_ValueError, "ContentObject size doesn't match" " the size reported by pco"); return NULL; } ccn_digest_ContentObject(content_object->buf, parsed_content_object); py_digest = PyBytes_FromStringAndSize( (char *) parsed_content_object->digest, parsed_content_object->digest_bytes); return py_digest; }
/* * This upcall gets called for each piece of incoming content that * matches one of our interests. We need to issue a new interest that * excludes another component at the current level, and perhaps also * and interest to start exploring the next level. Thus if the matched * interest is * /a/b/c exclude {d,e,f,i,j,k} * and we get * /a/b/c/g/h * we would issue a new interest * /a/b/c exclude {d,e,f,g,i,j,k} * to continue exploring the current level, plus a simple interest * /a/b/c/g * to start exploring the next level as well. * * This does end up fetching each piece of content multiple times, once for * each level in the name. The repeated requests will be answered from the local * content store, though, and so should not generate extra network traffic. * There is a lot of unanswerable interest generated, though. * * To prevent the interests from becoming too huge, we may need to split them. * Thus if the first new interest above were deemed too large, we could instead * issue the two interests * /a/b/c exclude {d,e,f,g,*} * /a/b/c exclude {*,g,i,j,k} * where * stands for a Bloom filter that excludes anything. Note the * repetition of g to ensure that these two interests cover disjoint portions * of the hierarchy. We need to keep track of the endpoint conditions * as well as the excluded set in our upcall data. * When a split happens, we need a new closure to track it, as we do when * we start exploring a new level. */ static enum ccn_upcall_res incoming_content( struct ccn_closure *selfp, enum ccn_upcall_kind kind, struct ccn_upcall_info *info) { struct ccn_charbuf *c = NULL; struct ccn_charbuf *comp = NULL; struct ccn_charbuf *uri = NULL; const unsigned char *ccnb = NULL; size_t ccnb_size = 0; struct ccn_indexbuf *comps = NULL; int matched_comps = 0; int res; int i; struct ccn_traversal *data = get_my_data(selfp); if (kind == CCN_UPCALL_FINAL) { for (i = 0; i < data->n_excl; i++) ccn_charbuf_destroy(&(data->excl[i])); if (data->excl != NULL) free(data->excl); free(data); free(selfp); return(0); } if (kind == CCN_UPCALL_INTEREST_TIMED_OUT) return(0); if (kind == CCN_UPCALL_CONTENT_BAD) return(0); if (kind == CCN_UPCALL_CONTENT_UNVERIFIED) { if ((data->flags & MUST_VERIFY) != 0) return(CCN_UPCALL_RESULT_VERIFY); } if (kind != CCN_UPCALL_CONTENT && kind != CCN_UPCALL_CONTENT_UNVERIFIED) abort(); ccnb = info->content_ccnb; ccnb_size = info->pco->offset[CCN_PCO_E]; comps = info->content_comps; matched_comps = info->pi->prefix_comps; c = ccn_charbuf_create(); uri = ccn_charbuf_create(); if (matched_comps + 1 > comps->n) { ccn_uri_append(c, ccnb, ccnb_size, 1); fprintf(stderr, "How did this happen? %s\n", ccn_charbuf_as_string(uri)); exit(1); } data->counter[0]++; /* Tell main that something new came in */ /* Recover the same prefix as before */ ccn_name_init(c); ccn_name_append_components(c, ccnb, comps->buf[0], comps->buf[matched_comps]); comp = ccn_charbuf_create(); ccn_name_init(comp); if (matched_comps + 1 == comps->n) { /* Reconstruct the implicit content digest component */ ccn_digest_ContentObject(ccnb, info->pco); ccn_name_append(comp, info->pco->digest, info->pco->digest_bytes); } else { ccn_name_append_components(comp, ccnb, comps->buf[matched_comps], comps->buf[matched_comps + 1]); } data->excl = realloc(data->excl, (data->n_excl + 1) * sizeof(data->excl[0])); data->excl[data->n_excl++] = comp; comp = NULL; qsort(data->excl, data->n_excl, sizeof(data->excl[0]), &namecompare); res = express_my_interest(info->h, selfp, c); if (res == -1) { struct ccn_closure *high = split_my_excludes(selfp); if (high == NULL) abort(); express_my_interest(info->h, selfp, c); express_my_interest(info->h, high, c); } /* Explore the next level, if there is one. */ if (matched_comps + 2 < comps->n) { struct ccn_traversal *newdat = NULL; struct ccn_closure *cl; newdat = calloc(1, sizeof(*newdat)); newdat->magic = 68955871; newdat->warn = 1492; newdat->counter = data->counter; newdat->flags = data->flags & ~(EXCLUDE_LOW | EXCLUDE_HIGH); newdat->n_excl = 0; newdat->excl = NULL; cl = calloc(1, sizeof(*cl)); cl->p = &incoming_content; cl->data = newdat; ccn_name_init(c); ccn_name_append_components(c, ccnb, comps->buf[0], comps->buf[matched_comps + 1]); express_my_interest(info->h, cl, c); } else { res = ccn_uri_append(uri, info->content_ccnb, info->pco->offset[CCN_PCO_E], 1); if (res < 0) fprintf(stderr, "*** Error: ccn_traverse line %d res=%d\n", __LINE__, res); else printf("%s\n", ccn_charbuf_as_string(uri)); } ccn_charbuf_destroy(&c); ccn_charbuf_destroy(&uri); return(0); }
enum ccn_upcall_res incoming_content( struct ccn_closure *selfp, enum ccn_upcall_kind kind, struct ccn_upcall_info *info) { struct ccn_charbuf *c = NULL; struct ccn_charbuf *comp = NULL; struct ccn_charbuf *uri = NULL; struct ccn_charbuf *templ = NULL; const unsigned char *ccnb = NULL; size_t ccnb_size = 0; struct ccn_indexbuf *comps = NULL; int matched_comps = 0; int res; int i; struct upcalldata *data = selfp->data; if (data->magic != 856372) abort(); if (kind == CCN_UPCALL_FINAL) return(CCN_UPCALL_RESULT_OK); if (kind == CCN_UPCALL_INTEREST_TIMED_OUT) return(CCN_UPCALL_RESULT_REEXPRESS); if (kind == CCN_UPCALL_CONTENT_UNVERIFIED) { if ((data->option & MUST_VERIFY) != 0) return(CCN_UPCALL_RESULT_VERIFY); } else if (kind != CCN_UPCALL_CONTENT) abort(); ccnb = info->content_ccnb; ccnb_size = info->pco->offset[CCN_PCO_E]; comps = info->content_comps; matched_comps = info->pi->prefix_comps; c = ccn_charbuf_create(); uri = ccn_charbuf_create(); templ = ccn_charbuf_create(); /* note that comps->n is 1 greater than the number of explicit components */ if (matched_comps > comps->n) { ccn_uri_append(c, ccnb, ccnb_size, 1); fprintf(stderr, "How did this happen? %s\n", ccn_charbuf_as_string(uri)); exit(1); } data->counter[0]++; /* Recover the same prefix as before */ ccn_name_init(c); res = ccn_name_append_components(c, info->interest_ccnb, info->interest_comps->buf[0], info->interest_comps->buf[matched_comps]); if (res < 0) abort(); comp = ccn_charbuf_create(); ccn_name_init(comp); if (matched_comps + 1 == comps->n) { /* Reconstruct the implicit ContentObject digest component */ ccn_digest_ContentObject(ccnb, info->pco); ccn_name_append(comp, info->pco->digest, info->pco->digest_bytes); } else if (matched_comps < comps->n) { ccn_name_append_components(comp, ccnb, comps->buf[matched_comps], comps->buf[matched_comps + 1]); } res = ccn_uri_append(uri, comp->buf, comp->length, 0); if (res < 0 || uri->length < 1) fprintf(stderr, "*** Error: ccnls line %d res=%d\n", __LINE__, res); else { if (uri->length == 1) ccn_charbuf_append(uri, ".", 1); printf("%s%s\n", ccn_charbuf_as_string(uri) + 1, kind == CCN_UPCALL_CONTENT ? " [verified]" : " [unverified]"); } ccn_charbuf_append_tt(templ, CCN_DTAG_Interest, CCN_DTAG); ccn_charbuf_append(templ, c->buf, c->length); /* Name */ if (matched_comps == comps->n) { /* The interest supplied the digest component */ ccn_charbuf_destroy(&comp); /* * We can't rely on the Exclude filter to keep from seeing this, so * say that we need at least one more name component. */ ccn_charbuf_append_tt(templ, CCN_DTAG_MinSuffixComponents, CCN_DTAG); ccn_charbuf_append_tt(templ, 1, CCN_UDATA); ccn_charbuf_append(templ, "1", 1); ccn_charbuf_append_closer(templ); /* </MinSuffixComponents> */ } else { data->excl = realloc(data->excl, (data->n_excl + 1) * sizeof(data->excl[0])); data->excl[data->n_excl++] = comp; comp = NULL; } qsort(data->excl, data->n_excl, sizeof(data->excl[0]), &namecompare); ccn_charbuf_append_tt(templ, CCN_DTAG_Exclude, CCN_DTAG); for (i = 0; i < data->n_excl; i++) { comp = data->excl[i]; if (comp->length < 4) abort(); ccn_charbuf_append(templ, comp->buf + 1, comp->length - 2); } comp = NULL; ccn_charbuf_append_closer(templ); /* </Exclude> */ ccnb_tagged_putf(templ, CCN_DTAG_AnswerOriginKind, "%d", CCN_AOK_CS); if (data->scope > -1) ccnb_tagged_putf(templ, CCN_DTAG_Scope, "%d", data->scope); ccn_charbuf_append_closer(templ); /* </Interest> */ if (templ->length > data->warn) { fprintf(stderr, "*** Interest packet is %d bytes\n", (int)templ->length); data->warn = data->warn * 8 / 5; } ccn_express_interest(info->h, c, selfp, templ); ccn_charbuf_destroy(&templ); ccn_charbuf_destroy(&c); ccn_charbuf_destroy(&uri); return(CCN_UPCALL_RESULT_OK); }
/** * Test for a match between a ContentObject and an Interest * * @param content_object ccnb-encoded ContentObject * @param content_object_size its size in bytes * @param implicit_content_digest boolean indicating whether the * final name component is implicit (as in * the on-wire format) or explicit (as within * ccnd's content store). * @param pc Valid parse information may be provided to * speed things up. If NULL it will be * reconstructed internally. * @param interest_msg ccnb-encoded Interest * @param interest_msg_size its size in bytes * @param pi see _pc_ * * @result 1 if the ccnb-encoded content_object matches the * ccnb-encoded interest_msg, otherwise 0. */ int ccn_content_matches_interest(const unsigned char *content_object, size_t content_object_size, int implicit_content_digest, struct ccn_parsed_ContentObject *pc, const unsigned char *interest_msg, size_t interest_msg_size, const struct ccn_parsed_interest *pi) { struct ccn_parsed_ContentObject pc_store; struct ccn_parsed_interest pi_store; int res; int ncomps; int prefixstart; int prefixbytes; int namecompstart; int namecompbytes; int checkdigest = 0; struct ccn_buf_decoder decoder; struct ccn_buf_decoder *d; const unsigned char *nextcomp; size_t nextcomp_size = 0; const unsigned char *comp; size_t comp_size = 0; const unsigned char *bloom; size_t bloom_size = 0; unsigned char match_any[2] = "-"; if (pc == NULL) { res = ccn_parse_ContentObject(content_object, content_object_size, &pc_store, NULL); if (res < 0) return(0); pc = &pc_store; } if (pi == NULL) { res = ccn_parse_interest(interest_msg, interest_msg_size, &pi_store, NULL); if (res < 0) return(0); pi = &pi_store; } if (!ccn_pubid_matches(content_object, pc, interest_msg, pi)) return(0); ncomps = pc->name_ncomps + (implicit_content_digest ? 1 : 0); if (ncomps < pi->prefix_comps + pi->min_suffix_comps) return(0); if (ncomps > pi->prefix_comps + pi->max_suffix_comps) return(0); prefixstart = pi->offset[CCN_PI_B_Component0]; prefixbytes = pi->offset[CCN_PI_E_LastPrefixComponent] - prefixstart; namecompstart = pc->offset[CCN_PCO_B_Component0]; namecompbytes = pc->offset[CCN_PCO_E_ComponentLast] - namecompstart; if (prefixbytes > namecompbytes) { /* * The only way for this to be a match is if the implicit * content digest name component comes into play. */ if (implicit_content_digest && pi->offset[CCN_PI_B_LastPrefixComponent] - prefixstart == namecompbytes && (pi->offset[CCN_PI_E_LastPrefixComponent] - pi->offset[CCN_PI_B_LastPrefixComponent]) == 1 + 2 + 32 + 1) { prefixbytes = namecompbytes; checkdigest = 1; } else return(0); } if (0 != memcmp(interest_msg + prefixstart, content_object + namecompstart, prefixbytes)) return(0); if (checkdigest) { /* * The Exclude by next component is not relevant in this case, * since there is no next component present. */ ccn_digest_ContentObject(content_object, pc); d = ccn_buf_decoder_start(&decoder, interest_msg + pi->offset[CCN_PI_B_LastPrefixComponent], (pi->offset[CCN_PI_E_LastPrefixComponent] - pi->offset[CCN_PI_B_LastPrefixComponent])); comp_size = 0; if (ccn_buf_match_dtag(d, CCN_DTAG_Component)) { ccn_buf_advance(d); ccn_buf_match_blob(d, &comp, &comp_size); } if (comp_size != pc->digest_bytes) abort(); if (0 != memcmp(comp, pc->digest, comp_size)) return(0); } else if (pi->offset[CCN_PI_E_Exclude] > pi->offset[CCN_PI_B_Exclude]) { if (prefixbytes < namecompbytes) { /* pick out the next component in the content object name */ d = ccn_buf_decoder_start(&decoder, content_object + (namecompstart + prefixbytes), pc->offset[CCN_PCO_E_ComponentLast] - (namecompstart + prefixbytes)); if (ccn_buf_match_dtag(d, CCN_DTAG_Component)) { ccn_buf_advance(d); ccn_buf_match_blob(d, &nextcomp, &nextcomp_size); } else return(0); } else if (!implicit_content_digest) goto exclude_checked; else if (prefixbytes == namecompbytes) { /* use the digest name as the next component */ ccn_digest_ContentObject(content_object, pc); nextcomp_size = pc->digest_bytes; nextcomp = pc->digest; } else abort(); /* bug - should have returned already */ 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]); if (!ccn_buf_match_dtag(d, CCN_DTAG_Exclude)) abort(); ccn_buf_advance(d); bloom = NULL; bloom_size = 0; if (ccn_buf_match_dtag(d, CCN_DTAG_Any)) { ccn_buf_advance(d); bloom = match_any; ccn_buf_check_close(d); } else if (ccn_buf_match_dtag(d, CCN_DTAG_Bloom)) { ccn_buf_advance(d); if (ccn_buf_match_blob(d, &bloom, &bloom_size)) ccn_buf_advance(d); ccn_buf_check_close(d); } while (ccn_buf_match_dtag(d, CCN_DTAG_Component)) { ccn_buf_advance(d); comp_size = 0; if (ccn_buf_match_blob(d, &comp, &comp_size)) ccn_buf_advance(d); ccn_buf_check_close(d); if (comp_size > nextcomp_size) break; if (comp_size == nextcomp_size) { res = memcmp(comp, nextcomp, comp_size); if (res == 0) return(0); /* One of the explicit excludes */ if (res > 0) break; } bloom = NULL; bloom_size = 0; if (ccn_buf_match_dtag(d, CCN_DTAG_Any)) { ccn_buf_advance(d); bloom = match_any; ccn_buf_check_close(d); } else if (ccn_buf_match_dtag(d, CCN_DTAG_Bloom)) { ccn_buf_advance(d); if (ccn_buf_match_blob(d, &bloom, &bloom_size)) ccn_buf_advance(d); ccn_buf_check_close(d); } } /* * Now we have isolated the applicable filter (Any or Bloom or none). */ if (bloom == match_any) return(0); else if (bloom_size != 0) { const struct ccn_bloom_wire *f = ccn_bloom_validate_wire(bloom, bloom_size); /* If not a valid filter, treat like a false positive */ if (f == NULL) return(0); if (ccn_bloom_match_wire(f, nextcomp, nextcomp_size)) return(0); } exclude_checked: {} } /* * At this point the prefix matches and exclude-by-next-component is done. */ // test any other qualifiers here return(1); }