/* * Utility routine to set the topo and prefix fields to copies of the * passed in charbufs */ int ccns_slice_set_topo_prefix(struct ccns_slice *s, struct ccn_charbuf *t, struct ccn_charbuf *p) { int res = 0; if (t != NULL) { ccn_charbuf_reset(s->topo); res |= ccn_charbuf_append_charbuf(s->topo, t); } if (p != NULL) { ccn_charbuf_reset(s->prefix); res |= ccn_charbuf_append_charbuf(s->prefix, p); } return(res); }
/** * Append to a charbuf the versioned ccnb-encoded Name that will be used for * this stream. * * @param w the seqwriter for which the name is requested * @param nv the charbuf to which the name will be appended * @returns 0 for success, -1 for failure */ int ccn_seqw_get_name(struct ccn_seqwriter *w, struct ccn_charbuf *nv) { if (nv == NULL || w == NULL) return (-1); return (ccn_charbuf_append_charbuf(nv, w->nv)); }
/* * Utility routine to add a clause to a ccns_slice structure */ int ccns_slice_add_clause(struct ccns_slice *s, struct ccn_charbuf *c) { struct ccn_charbuf **clauses = NULL; struct ccn_charbuf *clause; clause = ccn_charbuf_create_n(c->length); if (clause == NULL) return(-1); if (s->clauses == NULL) { s->clauses = calloc(1, sizeof(s->clauses[0])); if (s->clauses == NULL) goto Cleanup; } else { clauses = realloc(s->clauses, (s->nclauses + 1) * sizeof(s->clauses[0])); if (clauses == NULL) goto Cleanup; s->clauses = clauses; } ccn_charbuf_append_charbuf(clause, c); s->clauses[s->nclauses++] = clause; return (0); Cleanup: ccn_charbuf_destroy(&clause); return (-1); }
/** * Post an interests to the CCN network, and maintains the state information * * This will create the name used to express the interest on the network. It takes * the given segment and includes it in the name. It will then manage the state information * we keep in the context to allow us to deliver segments in order, as oppose to how * they may be presented to us from the network. * * \param me context holding the array of interest states and other ccn information * \param seg the segment to express interest in * \return status value from the express call made to CCN */ static gint request_segment (Gstccnxsrc * me, uintmax_t seg) { struct ccn_charbuf *nm = NULL; gint rc = 0; if (NULL == me) return -1; // nm = sequenced_name(me->p_name, seg); nm = ccn_charbuf_create (); rc |= ccn_charbuf_append_charbuf (nm, me->p_name); rc |= ccn_name_append_numeric (nm, CCN_MARKER_SEQNUM, seg); GST_INFO ("reqseg - name for interest..."); // hDump(nm->buf, nm->length); rc |= ccn_express_interest (me->ccn, nm, me->ccn_closure, me->p_template); ccn_charbuf_destroy (&nm); if (rc < 0) { return rc; } GST_DEBUG ("interest sent for segment %d\n", seg); return rc; }
int andana_server_connect(struct andana_server *server) { int res; res = ccn_proxy_connect(server->proxy); if (res != 0) { return(res); } struct ccn_charbuf *session_namespace = ccn_charbuf_create(); ccn_charbuf_append_charbuf(session_namespace, server->proxy->filter); ccn_name_append_str(session_namespace, "CREATESESSION"); server->session_handler.p = &andana_server_session_listener; server->session_handler.data = server; res = ccn_set_interest_filter(server->proxy->handle, session_namespace, &(server->session_handler)); ccn_charbuf_destroy(&session_namespace); return(res); }
/** * Write a ccns_slice object to a repository. * @param h is the ccn_handle on which to write. * @param slice is a pointer to a ccns_slice object to be written. * @param name, if non-NULL, is a pointer to a charbuf which will be filled * in with the name of the slice that was written. * @returns 0 on success, -1 otherwise. */ int ccns_write_slice(struct ccn *h, struct ccns_slice *slice, struct ccn_charbuf *name) { struct ccn_charbuf *n = NULL; int res; // calculate versioned and segmented name for the slice n = ccn_charbuf_create(); if (n == NULL) return(-1); res = ccns_slice_name(n, slice); if (res < 0) goto Cleanup; res |= ccn_create_version(h, n, CCN_V_NOW, 0, 0); if (name != NULL) { ccn_charbuf_reset(name); res |= ccn_charbuf_append_charbuf(name, n); } res |= ccn_name_append_numeric(n, CCN_MARKER_SEQNUM, 0); if (res < 0) goto Cleanup; res = write_slice(h, slice, n); Cleanup: ccn_charbuf_destroy(&n); return (res); }
static void setCurrentHash(struct SyncRootStruct *root, struct SyncHashCacheEntry *ce) { struct ccn_charbuf *hash = root->currentHash; hash->length = 0; if (ce != NULL) ccn_charbuf_append_charbuf(hash, ce->hash); }
static struct ccn_charbuf * ccnr_init_service_ccnb(struct ccnr_handle *ccnr, struct ccn *h, const char *baseuri, int freshness) { struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT; struct ccn_charbuf *name = ccn_charbuf_create(); struct ccn_charbuf *pubid = ccn_charbuf_create(); struct ccn_charbuf *pubkey = ccn_charbuf_create(); struct ccn_charbuf *keyid = ccn_charbuf_create(); struct ccn_charbuf *cob = ccn_charbuf_create(); int res; res = ccn_get_public_key(h, NULL, pubid, pubkey); if (res < 0) abort(); ccn_name_from_uri(name, baseuri); ccn_charbuf_append_value(keyid, CCN_MARKER_CONTROL, 1); ccn_charbuf_append_string(keyid, ".M.K"); ccn_charbuf_append_value(keyid, 0, 1); ccn_charbuf_append_charbuf(keyid, pubid); ccn_name_append(name, keyid->buf, keyid->length); ccn_create_version(h, name, 0, ccnr->starttime, ccnr->starttime_usec * 1000); sp.template_ccnb = ccn_charbuf_create(); ccnb_element_begin(sp.template_ccnb, CCN_DTAG_SignedInfo); ccnb_element_begin(sp.template_ccnb, CCN_DTAG_KeyLocator); ccnb_element_begin(sp.template_ccnb, CCN_DTAG_KeyName); ccn_charbuf_append_charbuf(sp.template_ccnb, name); ccnb_element_end(sp.template_ccnb); // ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_PublisherPublicKeyDigest, // CCN_DTAG); // ccn_charbuf_append_charbuf(sp.template_ccnb, pubid); // ccnb_element_end(sp.template_ccnb); ccnb_element_end(sp.template_ccnb); ccnb_element_end(sp.template_ccnb); sp.sp_flags |= CCN_SP_TEMPL_KEY_LOCATOR; ccn_name_from_uri(name, "%00"); sp.sp_flags |= CCN_SP_FINAL_BLOCK; sp.type = CCN_CONTENT_KEY; sp.freshness = freshness; res = ccn_sign_content(h, cob, name, &sp, pubkey->buf, pubkey->length); if (res != 0) abort(); ccn_charbuf_destroy(&name); ccn_charbuf_destroy(&pubid); ccn_charbuf_destroy(&pubkey); ccn_charbuf_destroy(&keyid); ccn_charbuf_destroy(&sp.template_ccnb); return(cob); }
static struct ccn_charbuf * sequenced_name(struct ccn_charbuf *basename, seg_t seq) { // creates a new struct ccn_charbuf *, appending the sequence number to the basename struct ccn_charbuf *name = ccn_charbuf_create(); ccn_charbuf_append_charbuf(name, basename); if (seq >= 0) ccn_name_append_numeric(name, CCN_MARKER_SEQNUM, seq); return(name); }
/* * utility, may need to be exported, to append the encoding of a * slice to a charbuf */ static int append_slice(struct ccn_charbuf *c, struct ccns_slice *s) { int res = 0; int i; res |= ccnb_element_begin(c, CCN_DTAG_SyncConfigSlice); res |= ccnb_tagged_putf(c, CCN_DTAG_SyncVersion, "%u", SLICE_VERSION); res |= ccn_charbuf_append_charbuf(c, s->topo); res |= ccn_charbuf_append_charbuf(c, s->prefix); res |= ccnb_element_begin(c, CCN_DTAG_SyncConfigSliceList); for (i = 0; i < s->nclauses ; i++) { res |= ccnb_tagged_putf(c, CCN_DTAG_SyncConfigSliceOp, "%u", 0); res |= ccn_charbuf_append_charbuf(c, s->clauses[i]); } res |= ccnb_element_end(c); res |= ccnb_element_end(c); return (res); }
static struct andana_server_pair * andana_server_pair_init(struct ccn_charbuf *name, struct ccn_pkey *symkey) { struct andana_server_pair *p = calloc(1, sizeof(struct andana_server_pair)); p->name = ccn_charbuf_create(); ccn_charbuf_append_charbuf(p->name, name); p->symkey = ccn_crypto_symkey_copy(symkey); return(p); }
/** * Append a representation of a Link to a charbuf. * @param buf is the output buffer where encoded link is written. * @param name is the ccnb-encoded name from ccn_name_init and friends. * @param label is a UTF-8 string in a ccn_charbuf. * @param linkAuthenticator is the ccnb-encoded LinkAuthenticator. * @returns 0 for success or -1 for error. */ int ccnb_append_Link(struct ccn_charbuf *buf, const struct ccn_charbuf *name, const char *label, const struct ccn_charbuf *linkAuthenticator ) { int res = 0; res |= ccn_charbuf_append_tt(buf, CCN_DTAG_Link, CCN_DTAG); res |= ccn_charbuf_append_charbuf(buf, name); if (label != NULL) { res |= ccn_charbuf_append_tt(buf, CCN_DTAG_Label, CCN_DTAG); res |= ccn_charbuf_append_tt(buf, strlen(label), CCN_UDATA); res |= ccn_charbuf_append_string(buf, label); res |= ccn_charbuf_append_closer(buf); } if (linkAuthenticator != NULL) { res |= ccn_charbuf_append_charbuf(buf, linkAuthenticator); } res |= ccn_charbuf_append_closer(buf); return(res == 0 ? 0 : -1); }
/** * should probably return a new cob, rather than reusing one. * should publish link as: * CCNRID_POLICY_URI("ccnx:/%C1.M.S.localhost/%C1.M.SRV/repository/POLICY)/%C1.M.K--pubid--/--version--/%00 * should have key locator which is the key name of the repository */ PUBLIC struct ccn_charbuf * ccnr_init_policy_link_cob(struct ccnr_handle *ccnr, struct ccn *h, struct ccn_charbuf *targetname) { struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT; struct ccn_charbuf *name = ccn_charbuf_create(); struct ccn_charbuf *pubid = ccn_charbuf_create(); struct ccn_charbuf *pubkey = ccn_charbuf_create(); struct ccn_charbuf *keyid = ccn_charbuf_create(); struct ccn_charbuf *content = ccn_charbuf_create(); struct ccn_charbuf *cob = ccn_charbuf_create(); struct ccn_charbuf *answer = NULL; int res; res = ccn_get_public_key(h, NULL, pubid, pubkey); if (res < 0) goto Bail; if (ccn_name_from_uri(name, CCNRID_POLICY_URI) < 0) goto Bail; res |= ccn_charbuf_append_value(keyid, CCN_MARKER_CONTROL, 1); res |= ccn_charbuf_append_string(keyid, ".M.K"); res |= ccn_charbuf_append_value(keyid, 0, 1); res |= ccn_charbuf_append_charbuf(keyid, pubid); res |= ccn_name_append(name, keyid->buf, keyid->length); res |= ccn_create_version(h, name, CCN_V_NOW, 0, 0); if (ccn_name_from_uri(name, "%00") < 0) goto Bail; sp.sp_flags |= CCN_SP_FINAL_BLOCK; sp.type = CCN_CONTENT_LINK; res |= ccnb_append_Link(content, targetname, "Repository Policy", NULL); if (res != 0) goto Bail; res |= ccn_sign_content(h, cob, name, &sp, content->buf, content->length); if (res != 0) goto Bail; answer = cob; cob = NULL; Bail: ccn_charbuf_destroy(&name); ccn_charbuf_destroy(&pubid); ccn_charbuf_destroy(&pubkey); ccn_charbuf_destroy(&keyid); ccn_charbuf_destroy(&content); ccn_charbuf_destroy(&cob); return (answer); }
// replace_name() // Helper function to replace names in content objects // Could build another version that works on already parsed content objects // But as seen below it would be better to use a modified encoding call that // didn't include the name at all. // int replace_name(struct ccn_charbuf* dest, unsigned char* src, size_t src_size, struct ccn_charbuf* name) { struct ccn_parsed_ContentObject* pco = (struct ccn_parsed_ContentObject*) calloc(sizeof(struct ccn_parsed_ContentObject), 1); int res = 0; res = ccn_parse_ContentObject(src,src_size, pco, NULL); if (res < 0) { free(pco); return (res); } ccn_charbuf_append_tt(dest, CCN_DTAG_ContentObject, CCN_DTAG); ccn_charbuf_append(dest, &src[pco->offset[CCN_PCO_B_Signature]], pco->offset[CCN_PCO_E_Signature] - pco->offset[CCN_PCO_B_Signature]); ccn_charbuf_append_charbuf(dest, name); // Already tagged ccn_charbuf_append(dest, &src[pco->offset[CCN_PCO_B_SignedInfo]], pco->offset[CCN_PCO_E_SignedInfo] - pco->offset[CCN_PCO_B_SignedInfo]); ccnb_append_tagged_blob(dest, CCN_DTAG_Content, NULL, 0); ccn_charbuf_append_closer(dest); free(pco); return (0); }
/** * Delete a ccns_slice object from a repository. * @param h is the ccn_handle on which to write. * @param name is a pointer to a charbuf naming the slice to be deleted. * @returns 0 on success, -1 otherwise. */ int ccns_delete_slice(struct ccn *h, struct ccn_charbuf *name) { struct ccn_charbuf *n = NULL; int res = 0; // calculate versioned and segmented name for the slice n = ccn_charbuf_create_n(32 + name->length); if (n == NULL) return(-1); res |= ccn_charbuf_append_charbuf(n, name); res |= ccn_create_version(h, n, CCN_V_NOW | CCN_V_REPLACE, 0, 0); res |= ccn_name_append_numeric(n, CCN_MARKER_SEQNUM, 0); if (res >= 0) res = write_slice(h, NULL, n); ccn_charbuf_destroy(&n); return (res); }
int sign_interest(struct ccn_charbuf* name_signed, struct ccn_charbuf* name, struct ccn_charbuf* signed_info, const char* digest_algorithm, struct ccn_pkey* key) { int res = 0; // Now assemble a signed Content object // Use ccn_encode_ContentObject so we can specify the key of our choice struct ccn_charbuf *tempContentObj = ccn_charbuf_create(); res = ccn_encode_ContentObject(tempContentObj, name, signed_info, NULL /* no data */, 0, digest_algorithm, key); if (res < 0) { fprintf(stderr, "Error building content object (res == %d)\n", res); return(res); } // Call replace_name to knock out the name; // it would be more efficient to assemble this with no name a modified ccn_encode_ContentObject() call // but that requires modification to the library function struct ccn_charbuf *empty_name = ccn_charbuf_create(); struct ccn_charbuf *sigContentObj = ccn_charbuf_create(); ccn_name_init(empty_name); // First prepend the namespace; (should this be done as a "name component"?) ccn_charbuf_append(sigContentObj, NS_SIGNATURE, NS_SIGNATURE_LEN); replace_name(sigContentObj, tempContentObj->buf, tempContentObj->length, empty_name); //fprintf(stderr, "replace_name == %d (%s)\n", res, (res==0)?"ok":"fail"); /* // Check that we didn't break things struct ccn_parsed_ContentObject pco = {0}; res = ccn_parse_ContentObject(&sigContentObj->buf[NS_SIGNATURE_LEN], sigContentObj->length - NS_SIGNATURE_LEN, &pco, NULL); if (res < 0) { fprintf(stderr, "Error parsing built content object (res == %d)\n", res); return(1); } */ ccn_charbuf_destroy(&empty_name); ccn_charbuf_destroy(&tempContentObj); // Build the final name for the interest <prefix>/<namespace><contentObj> ccn_charbuf_append_charbuf(name_signed, name); // Copy the name ccn_name_append(name_signed, sigContentObj->buf, sigContentObj->length); // Concatenate the new component // Dump the signature // print_hex(stderr,&(sigContentObj->buf)[NS_SIGNATURE_LEN],sigContentObj->length - NS_SIGNATURE_LEN,12); // fprintf(stderr,"\n"); // ccn_charbuf_destroy(&sigContentObj); return (res); }
/** * Request the current segment number from the ccnx data producer * * This is a request for meta data for the media stream the user has named with their URI. * We assume that they want to join the media broadcast from what is currently being published * and \em not want to start from the beginning...although there is good reason for that too. * * Getting this data is done by expressing interests in the meta data. The producer of the * media stream will catch this through one of its ccnx filters and produce this meta data * back through the network to us. * * \param h ccnx context handle * \param name the content name for which we desire the meta data * \param timeout how long to wait around * \return the segment number to ask for first, 0 on timeout */ static uintmax_t * get_segment (struct ccn *h, struct ccn_charbuf *name, int timeout) { struct ccn_charbuf *hn; uintmax_t *result = NULL; int res = 0; GST_INFO ("get_segment step 1"); hn = ccn_charbuf_create (); // ccn_name_append_components(hn, name->buf, 0, name->length ); ccn_charbuf_append_charbuf (hn, name); ccn_name_from_uri (hn, "_meta_/.segment"); // ccn_name_append_str(hn, "_meta_"); // ccn_name_append_str(hn, ".segment"); GST_INFO ("get_segment step 2"); // res = ccn_resolve_version(h, hn, CCN_V_HIGHEST, timeout); GST_INFO ("get_segment step 3, res: %d", res); if (res == 0) { struct ccn_charbuf *ho = ccn_charbuf_create (); struct ccn_parsed_ContentObject pcobuf = { 0 }; const unsigned char *hc; size_t hcs; // hDump(DUMP_ADDR(hn->buf), DUMP_SIZE(hn->length)); GST_INFO ("get_segment step 10"); res = ccn_get (h, hn, NULL, timeout, ho, &pcobuf, NULL, 0); GST_INFO ("get_segment step 11, res: %d", res); if (res >= 0) { hc = ho->buf; hcs = ho->length; // hDump( DUMP_ADDR(hc), DUMP_SIZE(hcs)); ccn_content_get_value (hc, hcs, &pcobuf, &hc, &hcs); // hDump( DUMP_ADDR(hc), DUMP_SIZE(hcs)); result = calloc (1, sizeof (uintmax_t)); memcpy (result, hc, sizeof (uintmax_t)); } ccn_charbuf_destroy (&ho); } GST_INFO ("get_segment step 9"); ccn_charbuf_destroy (&hn); return (result); }
/** * Read a slice (from a repository) given the name. * @param h is the ccn_handle on which to read. * @param name is the charbuf containing the name of the sync slice to be read. * @param slice is a pointer to a ccns_slice object which will be filled in * on successful return. * @returns 0 on success, -1 otherwise. */ int ccns_read_slice(struct ccn *h, struct ccn_charbuf *name, struct ccns_slice *slice) { struct ccn_parsed_ContentObject pco_space = { 0 }; struct ccn_parsed_ContentObject *pco = &pco_space; struct ccn_charbuf *nc = ccn_charbuf_create_n(name->length); struct ccn_charbuf *cob = ccn_charbuf_create(); const unsigned char *content; size_t content_length; int res = -1; if (nc == NULL || cob == NULL) goto Cleanup; ccn_charbuf_append_charbuf(nc, name); res = ccn_resolve_version(h, nc, CCN_V_HIGHEST, 100); // XXX: timeout if (res < 0) goto Cleanup; if (res == 0) { // TODO: check if the last component is a segment number, chop it off, try again. } res = ccn_get(h, nc, NULL, 100, cob, pco, NULL, 0); if (res < 0) goto Cleanup; if (pco->type != CCN_CONTENT_DATA) { res = -1; goto Cleanup; } res = ccn_content_get_value(cob->buf, cob->length, pco, &content, &content_length); if (res < 0) goto Cleanup; res = slice_parse(slice, content, content_length); Cleanup: ccn_charbuf_destroy(&nc); ccn_charbuf_destroy(&cob); return (res); }
static struct ccn_charbuf * ccnr_init_policy_cob(struct ccnr_handle *ccnr, struct ccn *h, struct ccn_charbuf *basename, int freshness, struct ccn_charbuf *content) { struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT; struct ccn_charbuf *name = ccn_charbuf_create(); struct ccn_charbuf *pubid = ccn_charbuf_create(); struct ccn_charbuf *pubkey = ccn_charbuf_create(); struct ccn_charbuf *keyid = ccn_charbuf_create(); struct ccn_charbuf *tcob = ccn_charbuf_create(); struct ccn_charbuf *cob = NULL; // result int res; res = ccn_get_public_key(h, NULL, pubid, pubkey); if (res < 0) goto Leave; res = ccn_charbuf_append_charbuf(name, basename); if (ccn_name_from_uri(name, "%00") < 0) goto Leave; sp.sp_flags |= CCN_SP_FINAL_BLOCK; sp.type = CCN_CONTENT_DATA; sp.freshness = freshness; res |= ccn_sign_content(h, tcob, name, &sp, content->buf, content->length); if (res == 0) { cob = tcob; tcob = NULL; } Leave: ccn_charbuf_destroy(&name); ccn_charbuf_destroy(&pubid); ccn_charbuf_destroy(&pubkey); ccn_charbuf_destroy(&keyid); ccn_charbuf_destroy(&tcob); return (cob); }
/** * Encode and sign a ContentObject. * @param buf is the output buffer where encoded object is written. * @param Name is the ccnb-encoded name from ccn_name_init and friends. * @param SignedInfo is the ccnb-encoded info from ccn_signed_info_create. * @param data pintes to the raw data to be encoded. * @param size is the size, in bytes, of the raw data to be encoded. * @param digest_algorithm may be NULL for default. * @param private_key is the private key to use for signing. * @returns 0 for success or -1 for error. */ int ccn_encode_ContentObject(struct ccn_charbuf *buf, const struct ccn_charbuf *Name, const struct ccn_charbuf *SignedInfo, const void *data, size_t size, const char *digest_algorithm, const struct ccn_pkey *private_key ) { int res = 0; struct ccn_sigc *sig_ctx; struct ccn_signature *signature; size_t signature_size; struct ccn_charbuf *content_header; size_t closer_start; content_header = ccn_charbuf_create(); res |= ccn_charbuf_append_tt(content_header, CCN_DTAG_Content, CCN_DTAG); if (size != 0) res |= ccn_charbuf_append_tt(content_header, size, CCN_BLOB); closer_start = content_header->length; res |= ccn_charbuf_append_closer(content_header); if (res < 0) return(-1); sig_ctx = ccn_sigc_create(); if (sig_ctx == NULL) return(-1); if (0 != ccn_sigc_init(sig_ctx, digest_algorithm, private_key)) return(-1); if (0 != ccn_sigc_update(sig_ctx, Name->buf, Name->length)) return(-1); if (0 != ccn_sigc_update(sig_ctx, SignedInfo->buf, SignedInfo->length)) return(-1); if (0 != ccn_sigc_update(sig_ctx, content_header->buf, closer_start)) return(-1); if (0 != ccn_sigc_update(sig_ctx, data, size)) return(-1); if (0 != ccn_sigc_update(sig_ctx, content_header->buf + closer_start, content_header->length - closer_start)) return(-1); signature = calloc(1, ccn_sigc_signature_max_size(sig_ctx, private_key)); if (signature == NULL) return(-1); res = ccn_sigc_final(sig_ctx, signature, &signature_size, private_key); if (0 != res) { free(signature); return(-1); } ccn_sigc_destroy(&sig_ctx); res |= ccn_charbuf_append_tt(buf, CCN_DTAG_ContentObject, CCN_DTAG); res |= ccn_encode_Signature(buf, digest_algorithm, NULL, 0, signature, signature_size); res |= ccn_charbuf_append_charbuf(buf, Name); res |= ccn_charbuf_append_charbuf(buf, SignedInfo); res |= ccnb_append_tagged_blob(buf, CCN_DTAG_Content, data, size); res |= ccn_charbuf_append_closer(buf); free(signature); ccn_charbuf_destroy(&content_header); return(res == 0 ? 0 : -1); }
int main(int argc, char** argv) { int res = 0; struct ccn* ccn_pub; struct ccn* ccn_rec; // Will hold the public/private key used for signing struct ccn_pkey* public_key = NULL; struct ccn_pkey* private_key = NULL; int complete=0; int outstanding_interests=0; // We need two ccn handles because the same handle cannot be used // to answer interests it issues. // ccn_pub = ccn_create(); if (ccn_connect(ccn_pub, NULL) == -1) { fprintf(stderr, "Could not connect to ccnd"); return(1); } ccn_rec = ccn_create(); if (ccn_connect(ccn_rec, NULL) == -1) { fprintf(stderr, "Could not connect to ccnd"); return(1); } // Closure to handle upcalls struct ccn_closure *cl = NULL; cl = (struct ccn_closure*) calloc(1, sizeof(struct ccn_closure)); cl->p = &packet_handler; handler_data h_data = { &complete, &outstanding_interests, &public_key, &ccn_pub, &ccn_rec}; cl->data = &h_data; // Setup our one test name without signature // The nonce here is just a random string, to avoid content store caching struct ccn_charbuf* name; name = ccn_charbuf_create(); ccn_name_from_uri(name, TEST_URI); ccn_name_append_nonce(name); fprintf(stderr, "Our name: %s/<nonce>\n", TEST_URI); // Set up a filter for interests in that name res = ccn_set_interest_filter(ccn_pub, name, cl); if (res < 0) { fprintf(stderr, "Failed to register interest (res == %d)\n", res); return(1); } // Get our default keys -- Why do we have to do all this work?? // Borrowed from ccn_client.c struct ccn_signing_params name_sp = CCN_SIGNING_PARAMS_INIT; struct ccn_signing_params p = CCN_SIGNING_PARAMS_INIT; struct ccn_keystore *keystore = NULL; struct ccn_charbuf *timestamp = NULL; struct ccn_charbuf *finalblockid = NULL; struct ccn_charbuf *keylocator = NULL; unsigned char* public_key_digest = NULL; size_t public_key_digest_length = 0; res = ccn_chk_signing_params(ccn_pub, &name_sp, &p, ×tamp, &finalblockid, &keylocator); if (res < 0) return(res); // For this test, use our default signing keys get_default_keys(ccn_pub, &p, &keystore, &public_key, &public_key_digest, &public_key_digest_length, &private_key); // We'll need a KeyLocator for our ContentObject // So continue borrowed code /* Construct a key locator containing the key itself */ build_keylocator_from_key(&keylocator, public_key); // And a SignedInfo too struct ccn_charbuf *signed_info = ccn_charbuf_create(); res = ccn_signed_info_create(signed_info, public_key_digest, public_key_digest_length, timestamp, p.type, p.freshness, 0, /* FinalBlockID is optional */ keylocator); // * Test using interests for a name that has one more component than our registered prefix // This is more representative of real apps... // 20-May-2011 ccn_name_append_str(name, "some stuff in a name component"); ccn_name_append_nonce(name); ccn_name_append_nonce(name); // Sign the interest struct ccn_charbuf *name_signed = ccn_charbuf_create(); sign_interest(name_signed, name, signed_info, NULL /* default digest alg */, private_key); // Express the signed interest from a different ccn handle so we get the packet res = ccn_express_interest(ccn_rec, name_signed, cl, NULL); // TODO: AnswerOriginKind could limit to signed interest? outstanding_interests++; // Express an interest with an incorrect namespace struct ccn_charbuf *name_signed_copy = ccn_charbuf_create(); ccn_charbuf_append_charbuf(name_signed_copy, name_signed); size_t k = name->length + 10; // Seek into the namespace part of the buffer name_signed_copy->buf[k] = name_signed_copy->buf[k] + 1; res = ccn_express_interest(ccn_rec, name_signed_copy, cl, NULL); // TODO: AnswerOriginKind could limit to signed interest? outstanding_interests++; // Express an interest with bogus signature name_signed_copy = ccn_charbuf_create(); ccn_charbuf_append_charbuf(name_signed_copy, name_signed); k = name->length + 30; // Seek into the signature part of the buffer name_signed_copy->buf[k] = name_signed_copy->buf[k] + 1; res = ccn_express_interest(ccn_rec, name_signed_copy, cl, NULL); // TODO: AnswerOriginKind could limit to signed interest? outstanding_interests++; if (res < 0) { fprintf(stderr, "Error expressing interest (res == %d)\n", res); } cl = NULL; // freed by ccn? while(!complete && outstanding_interests>0) { // Not sure how to handle two ccn_runs? ccn_run(ccn_rec, 100); /* stop if we run dry for .1 sec */ ccn_run(ccn_pub, 100); /* stop if we run dry for .1 sec */ fflush(stdout); } ccn_charbuf_destroy(×tamp); ccn_charbuf_destroy(&keylocator); ccn_charbuf_destroy(&finalblockid); ccn_charbuf_destroy(&signed_info); ccn_charbuf_destroy(&name); ccn_charbuf_destroy(&name_signed); ccn_charbuf_destroy(&name_signed_copy); ccn_destroy(&ccn_pub); ccn_destroy(&ccn_rec); fflush(stderr); return(0); }
/** * Load a link to the repo policy from the repoPolicy file and load the link * target to extract the actual policy. * If a policy file does not exist a new one is created, with a link to a policy * based either on the environment variable CCNR_GLOBAL_PREFIX or the system * default value of ccnx:/parc.com/csl/ccn/Repos, plus the system defaults for * other fields. * This routine must be called after the btree code is initialized and capable * of returning content objects. * Sets the parsed_policy field of the handle to be the new policy. */ static int load_policy(struct ccnr_handle *ccnr) { int fd; ssize_t res; struct content_entry *content = NULL; const unsigned char *content_msg = NULL; struct ccn_parsed_ContentObject pco = {0}; struct ccn_parsed_Link pl = {0}; struct ccn_indexbuf *nc = NULL; struct ccn_charbuf *basename = NULL; struct ccn_charbuf *policy = NULL; struct ccn_charbuf *policy_cob = NULL; struct ccn_charbuf *policyFileName; const char *global_prefix; const unsigned char *buf = NULL; size_t length = 0; int segment = 0; int final = 0; struct ccn_buf_decoder decoder; struct ccn_buf_decoder *d; policyFileName = ccn_charbuf_create(); ccn_charbuf_putf(policyFileName, "%s/repoPolicy", ccnr->directory); ccnr->parsed_policy = ccnr_parsed_policy_create(); fd = open(ccn_charbuf_as_string(policyFileName), O_RDONLY); if (fd >= 0) { ccnr->policy_link_cob = ccn_charbuf_create(); ccn_charbuf_reserve(ccnr->policy_link_cob, 4096); // limits the size of the policy link ccnr->policy_link_cob->length = 0; // clear the buffer res = read(fd, ccnr->policy_link_cob->buf, ccnr->policy_link_cob->limit - ccnr->policy_link_cob->length); close(fd); if (res == -1) { r_init_fail(ccnr, __LINE__, "Error reading repoPolicy file.", errno); ccn_charbuf_destroy(&ccnr->policy_link_cob); ccn_charbuf_destroy(&policyFileName); return(-1); } ccnr->policy_link_cob->length = res; nc = ccn_indexbuf_create(); res = ccn_parse_ContentObject(ccnr->policy_link_cob->buf, ccnr->policy_link_cob->length, &pco, nc); res = ccn_ref_tagged_BLOB(CCN_DTAG_Content, ccnr->policy_link_cob->buf, pco.offset[CCN_PCO_B_Content], pco.offset[CCN_PCO_E_Content], &buf, &length); d = ccn_buf_decoder_start(&decoder, buf, length); res = ccn_parse_Link(d, &pl, NULL); if (res <= 0) { ccnr_msg(ccnr, "Policy link is malformed."); goto CreateNewPolicy; } basename = ccn_charbuf_create(); ccn_charbuf_append(basename, buf + pl.offset[CCN_PL_B_Name], pl.offset[CCN_PL_E_Name] - pl.offset[CCN_PL_B_Name]); ccnr->policy_name = ccn_charbuf_create(); // to detect writes to this name ccn_charbuf_append_charbuf(ccnr->policy_name, basename); // has version ccn_name_chop(ccnr->policy_name, NULL, -1); // get rid of version policy = ccn_charbuf_create(); // if we fail to retrieve the link target, report and then create a new one do { ccn_name_append_numeric(basename, CCN_MARKER_SEQNUM, segment++); content = r_store_lookup_ccnb(ccnr, basename->buf, basename->length); if (content == NULL) { ccnr_debug_ccnb(ccnr, __LINE__, "policy lookup failed for", NULL, basename->buf, basename->length); break; } ccn_name_chop(basename, NULL, -1); content_msg = r_store_content_base(ccnr, content); if (content_msg == NULL) { ccnr_debug_ccnb(ccnr, __LINE__, "Unable to read policy object", NULL, basename->buf, basename->length); break; } res = ccn_parse_ContentObject(content_msg, r_store_content_size(ccnr, content), &pco, nc); res = ccn_ref_tagged_BLOB(CCN_DTAG_Content, content_msg, pco.offset[CCN_PCO_B_Content], pco.offset[CCN_PCO_E_Content], &buf, &length); ccn_charbuf_append(policy, buf, length); final = ccn_is_final_pco(content_msg, &pco, nc); } while (!final && segment < 100);
static int write_slice(struct ccn *h, struct ccns_slice *slice, struct ccn_charbuf *name) { struct ccn_charbuf *content = NULL; unsigned char *cbuf = NULL; size_t clength = 0; struct ccn_charbuf *sw = NULL; struct ccn_charbuf *templ = NULL; struct ccn_charbuf *cob = NULL; struct ccn_signing_params sparm = CCN_SIGNING_PARAMS_INIT; struct ccn_closure *wc = NULL; int res; sw = ccn_charbuf_create_n(32 + name->length); if (sw == NULL) { res = -1; goto Cleanup; } ccn_charbuf_append_charbuf(sw, name); ccn_name_chop(sw, NULL, -1); // remove segment number ccn_name_from_uri(sw, "%C1.R.sw"); ccn_name_append_nonce(sw); // create and sign the content object cob = ccn_charbuf_create(); if (cob == NULL) { res = -1; goto Cleanup; } if (slice != NULL) { content = ccn_charbuf_create(); if (content == NULL) { res = -1; goto Cleanup; } res = append_slice(content, slice); if (res < 0) goto Cleanup; cbuf = content->buf; clength = content->length; } else { sparm.type = CCN_CONTENT_GONE; } sparm.sp_flags = CCN_SP_FINAL_BLOCK; res = ccn_sign_content(h, cob, name, &sparm, cbuf, clength); if (res < 0) goto Cleanup; // establish handler for interest in the slice content object wc = calloc(1, sizeof(*wc)); if (wc == NULL) { res = -1; goto Cleanup; } wc->p = &write_interest_handler; wc->data = cob; res = ccn_set_interest_filter(h, name, wc); if (res < 0) goto Cleanup; templ = make_scope1_template(); if (templ == NULL) { res = -1; goto Cleanup; } res = ccn_get(h, sw, templ, 1000, NULL, NULL, NULL, 0); if (res < 0) goto Cleanup; ccn_run(h, 1000); // give the repository a chance to fetch the data if (wc->intdata != 1) { res = -1; goto Cleanup; } res = 0; Cleanup: ccn_set_interest_filter(h, name, NULL); if (wc != NULL) free(wc); ccn_charbuf_destroy(&cob); ccn_charbuf_destroy(&content); ccn_charbuf_destroy(&sw); ccn_charbuf_destroy(&templ); return (res); }
int sign_content_with_user_defined_keystore(struct ccn_charbuf *content_name, struct ccn_charbuf *resultbuf, const void *data, size_t data_size, char *keystore_path, char *keystore_passphrase, char *key_repo_name, char *site_name, char *router_name){ if ( nlsr->debugging ) printf("sign_content_with_user_defined_keystore called\n"); int res; struct ccn_charbuf * pubid_out=ccn_charbuf_create(); struct ccn_charbuf * keyname; struct ccn_keystore *keystore = NULL; keystore=ccn_keystore_create(); res=ccn_keystore_init(keystore, keystore_path,keystore_passphrase ); if ( res < 0 ){ if ( nlsr->debugging ) printf("Error in initiating keystore :(\n"); ccn_keystore_destroy(&keystore); return -1; } res=ccn_load_private_key (nlsr->ccn, keystore_path, keystore_passphrase, pubid_out); if(res < 0 ){ if ( nlsr->debugging ) printf("Error in loading keystore :( \n"); ccn_charbuf_destroy(&pubid_out); return -1; } char *baseuri=(char *)calloc(strlen(key_repo_name)+strlen(site_name)+ strlen(router_name)+strlen("/%C1.R.N.Start")+5,sizeof(char)); memcpy(baseuri,key_repo_name,strlen(key_repo_name)+1); if ( site_name[0] != '/') memcpy(baseuri+strlen(baseuri),"/",1); memcpy(baseuri+strlen(baseuri),site_name,strlen(site_name)+1); memcpy(baseuri+strlen(baseuri),"/%C1.R.N.Start",strlen("/%C1.R.N.Start")); memcpy(baseuri+strlen(baseuri),router_name,strlen(router_name)+1); baseuri[strlen(baseuri)]='\0'; keyname=ccn_charbuf_create(); if(keyname == NULL ){ ccn_charbuf_destroy(&pubid_out); free(baseuri); return -1; } ccn_name_from_uri(keyname,baseuri); if ( res < 0 ){ if ( nlsr->debugging ) printf("Bad URI format: %s\n",baseuri); ccn_charbuf_destroy(&pubid_out); ccn_charbuf_destroy(&keyname); free(baseuri); return -1; } ccn_name_append_str(keyname,"nlsr"); struct ccn_charbuf *keyid = ccn_charbuf_create(); ccn_charbuf_append_value(keyid, CCN_MARKER_CONTROL, 1); ccn_charbuf_append_string(keyid, ".M.K"); ccn_charbuf_append_value(keyid, 0, 1); ccn_charbuf_append_charbuf(keyid, pubid_out); ccn_name_append(keyname, keyid->buf, keyid->length); struct ccn_charbuf *uri = ccn_charbuf_create(); ccn_uri_append(uri, keyname->buf, keyname->length, 0); if ( nlsr->debugging ) printf("Key Name Included when processing content: %s\n", ccn_charbuf_as_string(uri)); ccn_charbuf_destroy(&uri); struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT; sp.type = CCN_CONTENT_DATA; sp.template_ccnb = ccn_charbuf_create(); ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_SignedInfo, CCN_DTAG); ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_KeyLocator, CCN_DTAG); ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_KeyName, CCN_DTAG); ccn_charbuf_append(sp.template_ccnb, keyname->buf, keyname->length); ccn_charbuf_append_closer(sp.template_ccnb); // KeyName closer ccn_charbuf_append_closer(sp.template_ccnb); // KeyLocator closer ccn_charbuf_append_closer(sp.template_ccnb); // SignedInfo closer sp.sp_flags |= CCN_SP_TEMPL_KEY_LOCATOR; sp.sp_flags |= CCN_SP_FINAL_BLOCK; sp.freshness = 60; if (pubid_out->length != sizeof(sp.pubid)){ if ( nlsr->debugging ) printf("Size of pubid and sp.pubid is not equal"); ccn_charbuf_destroy(&keyname); ccn_charbuf_destroy(&pubid_out); free(baseuri); return -1; } memcpy(sp.pubid, pubid_out->buf, pubid_out->length); res=ccn_sign_content(nlsr->ccn,resultbuf,content_name,&sp,data,data_size); if( res < 0 ){ if ( nlsr->debugging ) printf("Content signing error \n"); ccn_charbuf_destroy(&sp.template_ccnb); ccn_charbuf_destroy(&keyid); ccn_charbuf_destroy(&keyname); ccn_charbuf_destroy(&pubid_out); free(baseuri); return -1; } ccn_charbuf_destroy(&sp.template_ccnb); ccn_charbuf_destroy(&keyid); ccn_charbuf_destroy(&keyname); ccn_charbuf_destroy(&pubid_out); free(baseuri); return 0; }
static PyObject * Interest_obj_to_ccn(PyObject *py_obj_Interest) { struct ccn_charbuf *interest; PyObject *py_interest, *py_o; int r; py_interest = CCNObject_New_charbuf(INTEREST, &interest); if (!py_interest) return NULL; r = ccn_charbuf_append_tt(interest, CCN_DTAG_Interest, CCN_DTAG); JUMP_IF_NEG_MEM(r, error); /* Name */ { struct ccn_charbuf *name; PyObject *py_name; r = is_attr_set(py_obj_Interest, "name", &py_o); JUMP_IF_NEG(r, error); if (r) { py_name = Name_obj_to_ccn(py_o); Py_DECREF(py_o); JUMP_IF_NULL(py_name, error); name = CCNObject_Get(NAME, py_name); r = ccn_charbuf_append_charbuf(interest, name); Py_DECREF(py_name); JUMP_IF_NEG_MEM(r, error); } else { // Even though Name is mandatory we still use this code to generate // templates, so it is ok if name is not given, the code below // creates an empty tag r = ccn_charbuf_append_tt(interest, CCN_DTAG_Name, CCN_DTAG); JUMP_IF_NEG(r, error); r = ccn_charbuf_append_closer(interest); /* </Name> */ JUMP_IF_NEG(r, error); } } r = process_int_attribute(interest, CCN_DTAG_MinSuffixComponents, py_obj_Interest, "minSuffixComponents"); JUMP_IF_NEG(r, error); r = process_int_attribute(interest, CCN_DTAG_MaxSuffixComponents, py_obj_Interest, "maxSuffixComponents"); JUMP_IF_NEG(r, error); r = is_attr_set(py_obj_Interest, "publisherPublicKeyDigest", &py_o); JUMP_IF_NEG(r, error); if (r) { const char *blob; Py_ssize_t blobsize; blob = PyBytes_AsString(py_o); if (!blob) { Py_DECREF(py_o); goto error; } blobsize = PyBytes_GET_SIZE(py_o); r = ccnb_append_tagged_blob(interest, CCN_DTAG_PublisherPublicKeyDigest, blob, blobsize); Py_DECREF(py_o); JUMP_IF_NEG_MEM(r, error); } r = is_attr_set(py_obj_Interest, "exclude", &py_o); JUMP_IF_NEG(r, error); if (r) { PyObject *py_exclusions; struct ccn_charbuf *exclusion_filter; if (!PyObject_IsInstance(py_o, g_type_ExclusionFilter)) { Py_DECREF(py_o); PyErr_SetString(PyExc_TypeError, "Expected ExclusionFilter"); goto error; } r = is_attr_set(py_o, "ccn_data", &py_exclusions); Py_DECREF(py_o); JUMP_IF_NEG(r, error); exclusion_filter = CCNObject_Get(EXCLUSION_FILTER, py_exclusions); r = ccn_charbuf_append_charbuf(interest, exclusion_filter); Py_DECREF(py_exclusions); JUMP_IF_NEG(r, error); } r = process_int_attribute(interest, CCN_DTAG_ChildSelector, py_obj_Interest, "childSelector"); JUMP_IF_NEG(r, error); r = process_int_attribute(interest, CCN_DTAG_AnswerOriginKind, py_obj_Interest, "answerOriginKind"); JUMP_IF_NEG(r, error); r = process_int_attribute(interest, CCN_DTAG_Scope, py_obj_Interest, "scope"); JUMP_IF_NEG(r, error); r = is_attr_set(py_obj_Interest, "interestLifetime", &py_o); if (r) { unsigned char buf[3] = {0}; double lifetime; unsigned long i_lifetime; if (!PyFloat_Check(py_o)) { Py_DECREF(py_o); PyErr_SetString(PyExc_TypeError, "expected float type in interest" " lifetime"); goto error; } lifetime = PyFloat_AS_DOUBLE(py_o); Py_DECREF(py_o); i_lifetime = lifetime * 4096; /* XXX: probably won't work in bigendian */ for (int i = sizeof(buf) - 1; i >= 0; i--, i_lifetime >>= 8) buf[i] = i_lifetime & 0xff; r = ccnb_append_tagged_blob(interest, CCN_DTAG_InterestLifetime, buf, sizeof(buf)); JUMP_IF_NEG_MEM(r, error); } r = is_attr_set(py_obj_Interest, "nonce", &py_o); if (r) { char *s; Py_ssize_t len; r = PyBytes_AsStringAndSize(py_o, &s, &len); if (r < 0) { Py_DECREF(py_o); goto error; } r = ccnb_append_tagged_blob(interest, CCN_DTAG_Nonce, s, len); Py_DECREF(py_o); JUMP_IF_NEG_MEM(r, error); } r = ccn_charbuf_append_closer(interest); /* </Interest> */ JUMP_IF_NEG_MEM(r, error); return py_interest; error: Py_DECREF(py_interest); return NULL; }
/** * Create SignedInfo. * * * @param c is used to hold the result. * @param publisher_key_id points to the digest of the publisher key id. * @param publisher_key_id_size is the size in bytes(32) of the pub key digest * @param timestamp holds the timestamp, as a ccnb-encoded blob, or is NULL to use the current time. * @param type indicates the Type of the ContentObject. * @param freshness is the FreshnessSeconds value, or -1 to omit. * @param finalblockid holds the FinalBlockID, as a ccnb-encoded blob, or is NULL to omit. * @param key_locator is the ccnb-encoded KeyLocator element, or NULL to omit. * @returns 0 for success or -1 for error. */ int ccn_signed_info_create(struct ccn_charbuf *c, const void *publisher_key_id, /* input, sha256 hash */ size_t publisher_key_id_size, /* input, 32 for sha256 hashes */ const struct ccn_charbuf *timestamp,/* input ccnb blob, NULL for "now" */ enum ccn_content_type type, /* input */ int freshness, /* input, -1 means omit */ const struct ccn_charbuf *finalblockid, /* input, NULL means omit */ const struct ccn_charbuf *key_locator) /* input, optional, ccnb encoded */ { int res = 0; const char fakepubkeyid[32] = {0}; if (publisher_key_id != NULL && publisher_key_id_size != 32) return(-1); res |= ccn_charbuf_append_tt(c, CCN_DTAG_SignedInfo, CCN_DTAG); res |= ccn_charbuf_append_tt(c, CCN_DTAG_PublisherPublicKeyDigest, CCN_DTAG); if (publisher_key_id != NULL) { res |= ccn_charbuf_append_tt(c, publisher_key_id_size, CCN_BLOB); res |= ccn_charbuf_append(c, publisher_key_id, publisher_key_id_size); } else { /* XXX - obtain the default publisher key id and append it */ res |= ccn_charbuf_append_tt(c, sizeof(fakepubkeyid), CCN_BLOB); res |= ccn_charbuf_append(c, fakepubkeyid, sizeof(fakepubkeyid)); } res |= ccn_charbuf_append_closer(c); res |= ccn_charbuf_append_tt(c, CCN_DTAG_Timestamp, CCN_DTAG); if (timestamp != NULL) res |= ccn_charbuf_append_charbuf(c, timestamp); else res |= ccnb_append_now_blob(c, CCN_MARKER_NONE); res |= ccn_charbuf_append_closer(c); if (type != CCN_CONTENT_DATA) { res |= ccn_charbuf_append_tt(c, CCN_DTAG_Type, CCN_DTAG); res |= ccn_charbuf_append_tt(c, 3, CCN_BLOB); res |= ccn_charbuf_append_value(c, type, 3); res |= ccn_charbuf_append_closer(c); } if (freshness >= 0) res |= ccnb_tagged_putf(c, CCN_DTAG_FreshnessSeconds, "%d", freshness); if (finalblockid != NULL) { res |= ccn_charbuf_append_tt(c, CCN_DTAG_FinalBlockID, CCN_DTAG); res |= ccn_charbuf_append_charbuf(c, finalblockid); res |= ccn_charbuf_append_closer(c); } if (key_locator != NULL) { /* key_locator is a sub-type that should already be encoded */ res |= ccn_charbuf_append_charbuf(c, key_locator); } res |= ccn_charbuf_append_closer(c); return(res == 0 ? 0 : -1); }
/** * Creates a stream for a named interest. * The name should be a ccnb encoded interest. * If resolveVersion, then we assume that the version is unresolved, * and an attempt is made to determine the version number using the highest * version. * The number of buffers (nBufs) may be silently limited. * @returns NULL if the stream creation failed, * otherwise returns the new stream. */ extern struct ccn_fetch_stream * ccn_fetch_open(struct ccn_fetch *f, struct ccn_charbuf *name, const char *id, struct ccn_charbuf *interestTemplate, int maxBufs, int resolveVersion, int assumeFixed) { // returns a new ccn_fetch_stream object based on the arguments // returns NULL if not successful if (maxBufs <= 0) return NULL; if (maxBufs > 16) maxBufs = 16; int res = 0; FILE *debug = f->debug; ccn_fetch_flags flags = f->debugFlags; // first, resolve the version struct ccn_fetch_stream *fs = calloc(1, sizeof(*fs)); fs->segSize = (assumeFixed ? 0 : -1); fs->name = ccn_charbuf_create(); fs->id = newStringCopy(id); ccn_charbuf_append_charbuf(fs->name, name); if (resolveVersion) { int tmInc = 40; // TBD: need better strategy for version timeout int tm = 0; while (tm < CCN_VERSION_TIMEOUT) { res = ccn_resolve_version(f->h, fs->name, resolveVersion, tmInc); if (res >= 0) break; tm = tm + tmInc; } if (res < 0) { // could not resolve version for this name // get rid of allocations so far and bail out if (debug != NULL && (flags & ccn_fetch_flags_NoteOpenClose)) { fprintf(debug, "-- ccn_fetch open, %s, failed to resolve version\n", fs->id); fflush(debug); } ccn_charbuf_destroy(&fs->name); freeString(fs->id); free(fs); return NULL; } } fs->maxBufs = maxBufs; fs->segsAhead = 0; fs->fileSize = -1; fs->finalSeg = -1; fs->timeoutSeg = -1; fs->zeroLenSeg = -1; fs->parent = f; fs->timeoutUSecs = CCN_INTEREST_TIMEOUT_USECS; // TBD: how to get better timeout? // use the supplied template or the default if (interestTemplate != NULL) { struct ccn_charbuf *cb = ccn_charbuf_create(); ccn_charbuf_append_charbuf(cb, interestTemplate); fs->interest = cb; } else fs->interest = make_data_template(MaxSuffixDefault); // remember the stream in the parent int ns = f->nStreams; int max = f->maxStreams; if (ns >= max) { // extend the vector int nMax = max+max/2+4; f->streams = realloc(f->streams, sizeof(*(f->streams)) * nMax); f->maxStreams = nMax; } // guaranteed room to add at the end f->streams[ns] = fs; f->nStreams = ns+1; if (debug != NULL && (flags & ccn_fetch_flags_NoteOpenClose)) { fprintf(debug, "-- ccn_fetch open, %s\n", fs->id); fflush(debug); } // prep for the first segment NeedSegment(fs, 0); return fs; }