int ccnl_i_prefixof_c(struct ccnl_prefix_s *prefix, struct ccnl_buf_s *ppkd, int minsuffix, int maxsuffix, struct ccnl_content_s *c) { unsigned char *md; DEBUGMSG(99, "ccnl_i_prefixof_c prefix=%s min=%d max=%d\n", ccnl_prefix_to_path(prefix), minsuffix, maxsuffix); // CONFORM: we do prefix match, honour min. and maxsuffix, // and check the PublisherPublicKeyDigest if present // NON-CONFORM: "Note that to match a ContentObject must satisfy // all of the specifications given in the Interest Message." // >> CCNL does not honour the exclusion filtering if ((ppkd && !buf_equal(ppkd, c->ppkd)) || (prefix->compcnt + minsuffix) > (c->name->compcnt + 1) || (prefix->compcnt + maxsuffix) < (c->name->compcnt + 1)) { return 0; } md = NULL; if ((prefix->compcnt - c->name->compcnt) == 1) { md = compute_ccnx_digest(c->pkt); } return ccnl_prefix_cmp(c->name, md, prefix, CMP_MATCH) == prefix->compcnt; }
int ccnl_nonce_find_or_append(struct ccnl_relay_s *ccnl, struct ccnl_buf_s *nonce) { struct ccnl_nonce_s *n, *last; int i; DEBUGMSG(99, "ccnl_nonce_find_or_append: %u:%u:%u:%u\n", nonce->data[0], nonce->data[1], nonce->data[2], nonce->data[3]); /* test for noce in nonce cache */ for (n = ccnl->nonces, i = 0; n; n = n->next, i++) { DEBUGMSG(1, "known: %u:%u:%u:%u\n", n->buf->data[0], n->buf->data[1], n->buf->data[2], n->buf->data[3]); if (buf_equal(n->buf, nonce)) { /* nonce in cache -> known */ return -1; } if (n->next) { last = n->next; } } /* nonce not in local cache, add it */ n = ccnl_nonce_new(nonce); DBL_LINKED_LIST_ADD(ccnl->nonces, n); /* nonce chache full? */ if (i >= CCNL_MAX_NONCES) { /* cache is full, drop oldest nonce: its the last element in the list */ ccnl_nonce_remove(ccnl, last); } return 0; }
int ccnl_face_enqueue(struct ccnl_relay_s *ccnl, struct ccnl_face_s *to, struct ccnl_buf_s *buf) { struct ccnl_buf_s *msg; DEBUGMSG(20, "ccnl_face_enqueue face=%p (id=%d.%d) buf=%p len=%d\n", (void *) to, ccnl->id, to->faceid, (void *) buf, buf->datalen); for (msg = to->outq; msg; msg = msg->next) // already in the queue? if (buf_equal(msg, buf)) { DEBUGMSG(31, " not enqueued because already there\n"); ccnl_free(buf); return -1; } buf->next = NULL; if (to->outqend) { to->outqend->next = buf; } else { to->outq = buf; } to->outqend = buf; ccnl_face_CTS(ccnl, to); return 0; }
int ccnl_interest_isSame(struct ccnl_interest_s *i, struct ccnl_pkt_s *pkt) { if (i->pkt->pfx->suite != pkt->suite || ccnl_prefix_cmp(i->pkt->pfx, NULL, pkt->pfx, CMP_EXACT)) return 0; switch (i->pkt->pfx->suite) { #ifdef USE_SUITE_CCNB case CCNL_SUITE_CCNB: return i->pkt->s.ccnb.minsuffix == pkt->s.ccnb.minsuffix && i->pkt->s.ccnb.maxsuffix == pkt->s.ccnb.maxsuffix && ((!i->pkt->s.ccnb.ppkd && !pkt->s.ccnb.ppkd) || buf_equal(i->pkt->s.ccnb.ppkd, pkt->s.ccnb.ppkd)); #endif #ifdef USE_SUITE_NDNTLV case CCNL_SUITE_NDNTLV: return i->pkt->s.ndntlv.minsuffix == pkt->s.ndntlv.minsuffix && i->pkt->s.ndntlv.maxsuffix == pkt->s.ndntlv.maxsuffix && ((!i->pkt->s.ndntlv.ppkl && !pkt->s.ndntlv.ppkl) || buf_equal(i->pkt->s.ndntlv.ppkl, pkt->s.ndntlv.ppkl)); #endif #ifdef USE_SUITE_CCNTLV case CCNL_SUITE_CCNTLV: #endif #ifdef USE_SUITE_CISTLV case CCNL_SUITE_CISTLV: #endif #ifdef USE_SUITE_IOTTLV case CCNL_SUITE_IOTTLV: #endif default: break; } return 1; }
int ccnl_face_enqueue(struct ccnl_relay_s *ccnl, struct ccnl_face_s *to, struct ccnl_buf_s *buf) { struct ccnl_buf_s *msg; if (buf == NULL) { DEBUGMSG_CORE(ERROR, "enqueue face: buf most not be NULL\n"); return -1; } DEBUGMSG_CORE(TRACE, "enqueue face=%p (id=%d.%d) buf=%p len=%zd\n", (void*) to, ccnl->id, to->faceid, (void*) buf, buf ? buf->datalen : -1); for (msg = to->outq; msg; msg = msg->next) // already in the queue? if (buf_equal(msg, buf)) { DEBUGMSG_CORE(VERBOSE, " not enqueued because already there\n"); ccnl_free(buf); return -1; } buf->next = NULL; if (to->outqend) to->outqend->next = buf; else to->outq = buf; to->outqend = buf; #ifdef USE_SCHEDULER if (to->sched) { #ifdef USE_FRAG int len, cnt = ccnl_frag_getfragcount(to->frag, buf->datalen, &len); #else int len = buf->datalen, cnt = 1; #endif ccnl_sched_RTS(to->sched, cnt, len, ccnl, to); } else ccnl_face_CTS(ccnl, to); #else ccnl_face_CTS(ccnl, to); #endif return 0; }
int ccnl_nonce_find_or_append(struct ccnl_relay_s *ccnl, struct ccnl_buf_s *nonce) { struct ccnl_buf_s *n, *n2 = 0; int i; DEBUGMSG_CORE(TRACE, "ccnl_nonce_find_or_append\n"); for (n = ccnl->nonces, i = 0; n; n = n->next, i++) { if (buf_equal(n, nonce)) return -1; if (n->next) n2 = n; } n = ccnl_buf_new(nonce->data, nonce->datalen); if (n) { n->next = ccnl->nonces; ccnl->nonces = n; if (i >= CCNL_MAX_NONCES && n2) { ccnl_free(n2->next); n2->next = 0; } } return 0; }
int ccnl_ccnb_forwarder(struct ccnl_relay_s *relay, struct ccnl_face_s *from, unsigned char **data, int *datalen) { int rc= -1, scope=3, aok=3, minsfx=0, maxsfx=CCNL_MAX_NAME_COMP, contlen; struct ccnl_buf_s *buf = 0, *nonce=0, *ppkd=0; struct ccnl_interest_s *i = 0; struct ccnl_content_s *c = 0; struct ccnl_prefix_s *p = 0; unsigned char *content = 0; DEBUGMSG(99, "ccnl/ccnb forwarder (%d bytes left)\n", *datalen); buf = ccnl_ccnb_extract(data, datalen, &scope, &aok, &minsfx, &maxsfx, &p, &nonce, &ppkd, &content, &contlen); if (!buf) { DEBUGMSG(6, " parsing error or no prefix\n"); goto Done; } if (nonce && ccnl_nonce_find_or_append(relay, nonce)) { DEBUGMSG(6, " dropped because of duplicate nonce\n"); goto Skip; } if (buf->data[0] == 0x01 && buf->data[1] == 0xd2) { // interest DEBUGMSG(6, " interest=<%s>\n", ccnl_prefix_to_path(p)); ccnl_print_stats(relay, STAT_RCV_I); //log count recv_interest if (p->compcnt > 0 && p->comp[0][0] == (unsigned char) 0xc1) goto Skip; if (p->compcnt == 4 && !memcmp(p->comp[0], "ccnx", 4)) { rc = ccnl_mgmt(relay, buf, p, from); goto Done; } // CONFORM: Step 1: if ( aok & 0x01 ) { // honor "answer-from-existing-content-store" flag for (c = relay->contents; c; c = c->next) { if (c->suite != CCNL_SUITE_CCNB) continue; if (!ccnl_i_prefixof_c(p, minsfx, maxsfx, c)) continue; if (ppkd && !buf_equal(ppkd, c->details.ccnb.ppkd)) continue; // FIXME: should check stale bit in aok here DEBUGMSG(7, " matching content for interest, content %p\n", (void *) c); ccnl_print_stats(relay, STAT_SND_C); //log sent_c if (from->ifndx >= 0) ccnl_face_enqueue(relay, from, buf_dup(c->pkt)); else ccnl_app_RX(relay, c); goto Skip; } } // CONFORM: Step 2: check whether interest is already known for (i = relay->pit; i; i = i->next) { if (i->suite == CCNL_SUITE_CCNB && !ccnl_prefix_cmp(i->prefix, NULL, p, CMP_EXACT) && i->details.ccnb.minsuffix == minsfx && i->details.ccnb.maxsuffix == maxsfx && ((!ppkd && !i->details.ccnb.ppkd) || buf_equal(ppkd, i->details.ccnb.ppkd)) ) break; } if (!i) { // this is a new/unknown I request: create and propagate i = ccnl_interest_new(relay, from, CCNL_SUITE_CCNB, &buf, &p, minsfx, maxsfx); if (ppkd) i->details.ccnb.ppkd = ppkd, ppkd = NULL; if (i) { // CONFORM: Step 3 (and 4) DEBUGMSG(7, " created new interest entry %p\n", (void *) i); if (scope > 2) ccnl_interest_propagate(relay, i); } } else if (scope > 2 && (from->flags & CCNL_FACE_FLAGS_FWDALLI)) { DEBUGMSG(7, " old interest, nevertheless propagated %p\n", (void *) i); ccnl_interest_propagate(relay, i); } if (i) { // store the I request, for the incoming face (Step 3) DEBUGMSG(7, " appending interest entry %p\n", (void *) i); ccnl_interest_append_pending(i, from); } } else { // content DEBUGMSG(6, " content=<%s>\n", ccnl_prefix_to_path(p)); ccnl_print_stats(relay, STAT_RCV_C); //log count recv_content #ifdef USE_SIGNATURES if (p->compcnt == 2 && !memcmp(p->comp[0], "ccnx", 4) && !memcmp(p->comp[1], "crypto", 6) && from == relay->crypto_face) { rc = ccnl_crypto(relay, buf, p, from); goto Done; } #endif /*USE_SIGNATURES*/ // CONFORM: Step 1: for (c = relay->contents; c; c = c->next) if (buf_equal(c->pkt, buf)) goto Skip; // content is dup c = ccnl_content_new(relay, CCNL_SUITE_CCNB, &buf, &p, &ppkd, content, contlen); if (c) { // CONFORM: Step 2 (and 3) if (!ccnl_content_serve_pending(relay, c)) { // unsolicited content // CONFORM: "A node MUST NOT forward unsolicited data [...]" DEBUGMSG(7, " removed because no matching interest\n"); free_content(c); goto Skip; } if (relay->max_cache_entries != 0) { // it's set to -1 or a limit DEBUGMSG(7, " adding content to cache\n"); ccnl_content_add2cache(relay, c); } else { DEBUGMSG(7, " content not added to cache\n"); free_content(c); } } } Skip: rc = 0; Done: free_prefix(p); free_3ptr_list(buf, nonce, ppkd); return rc; }
int ccnl_core_RX_i_or_c(struct ccnl_relay_s *relay, struct ccnl_face_s *from, unsigned char **data, int *datalen) { int rc = -1, scope = 3, aok = 3, minsfx = 0, maxsfx = CCNL_MAX_NAME_COMP, contlen; struct ccnl_buf_s *buf = 0, *nonce = 0, *ppkd = 0; struct ccnl_interest_s *i = 0; struct ccnl_content_s *c = 0; struct ccnl_prefix_s *p = 0; unsigned char *content = 0; DEBUGMSG(1, "ccnl_core_RX_i_or_c: (%d bytes left)\n", *datalen); buf = ccnl_extract_prefix_nonce_ppkd(data, datalen, &scope, &aok, &minsfx, &maxsfx, &p, &nonce, &ppkd, &content, &contlen); if (!buf) { DEBUGMSG(6, " parsing error or no prefix\n"); goto Done; } if (nonce && ccnl_nonce_find_or_append(relay, nonce)) { DEBUGMSG(6, " dropped because of duplicate nonce\n"); goto Skip; } if (buf->data[0] == 0x01 && buf->data[1] == 0xd2) { // interest DEBUGMSG(1, "ccnl_core_RX_i_or_c: interest=<%s>\n", ccnl_prefix_to_path(p)); from->stat.received_interest++; if (p->compcnt > 0 && p->comp[0][0] == (unsigned char) 0xc1) { goto Skip; } if (p->compcnt == 4 && !memcmp(p->comp[0], "ccnx", 4)) { DEBUGMSG(1, "it's a mgnt msg!\n"); rc = ccnl_mgmt(relay, buf, p, from); DEBUGMSG(1, "mgnt processing done!\n"); goto Done; } // CONFORM: Step 1: if (aok & 0x01) { // honor "answer-from-existing-content-store" flag for (c = relay->contents; c; c = c->next) { if (!ccnl_i_prefixof_c(p, ppkd, minsfx, maxsfx, c)) { continue; } // FIXME: should check stale bit in aok here DEBUGMSG(7, " matching content for interest, content %p\n", (void *) c); from->stat.send_content[c->served_cnt % CCNL_MAX_CONTENT_SERVED_STAT]++; c->served_cnt++; if (from->ifndx >= 0) { ccnl_face_enqueue(relay, from, buf_dup(c->pkt)); } goto Skip; } } // CONFORM: Step 2: check whether interest is already known for (i = relay->pit; i; i = i->next) { if (!ccnl_prefix_cmp(i->prefix, NULL, p, CMP_EXACT) && i->minsuffix == minsfx && i->maxsuffix == maxsfx && ((!ppkd && !i->ppkd) || buf_equal(ppkd, i->ppkd))) { break; } } if (!i) { // this is a new/unknown I request: create and propagate i = ccnl_interest_new(relay, from, &buf, &p, minsfx, maxsfx, &ppkd); if (i) { // CONFORM: Step 3 (and 4) DEBUGMSG(7, " created new interest entry %p\n", (void *) i); if (scope > 2) { ccnl_interest_propagate(relay, i); } } } else if (scope > 2 && (from->flags & CCNL_FACE_FLAGS_FWDALLI)) { DEBUGMSG(7, " old interest, nevertheless propagated %p\n", (void *) i); ccnl_interest_propagate(relay, i); } if (i) { // store the I request, for the incoming face (Step 3) DEBUGMSG(7, " appending interest entry %p\n", (void *) i); ccnl_interest_append_pending(i, from); } } else { // content DEBUGMSG(6, " content=<%s>\n", ccnl_prefix_to_path(p)); from->stat.received_content++; // CONFORM: Step 1: for (c = relay->contents; c; c = c->next) { if (buf_equal(c->pkt, buf)) { DEBUGMSG(1, "content is dup: skip\n"); goto Skip; } } c = ccnl_content_new(relay, &buf, &p, &ppkd, content, contlen); if (c) { // CONFORM: Step 2 (and 3) if (!ccnl_content_serve_pending(relay, c, from)) { // unsolicited content // CONFORM: "A node MUST NOT forward unsolicited data [...]" DEBUGMSG(7, " removed because no matching interest\n"); free_content(c); goto Skip; } #if CCNL_DYNAMIC_FIB else { /* content has matched an interest, we consider this name as available on this face */ ccnl_content_learn_name_route(relay, c->name, from, relay->fib_threshold_prefix, 0); } #endif if (relay->max_cache_entries != 0) { // it's set to -1 or a limit DEBUGMSG(7, " adding content to cache\n"); ccnl_content_add2cache(relay, c); } else { DEBUGMSG(7, " content not added to cache\n"); free_content(c); } } } Skip: rc = 0; Done: free_prefix(p); free_3ptr_list(buf, nonce, ppkd); DEBUGMSG(1, "leaving\n"); return rc; }