int main(int argc, char **argv) { int opt; int max_cache_entries = CCNL_DEFAULT_MAX_CACHE_ENTRIES; // srand(time(NULL)); srandom(time(NULL)); while ((opt = getopt(argc, argv, "hc:g:i:s:v:")) != -1) { switch (opt) { case 'c': max_cache_entries = atoi(optarg); break; case 'g': inter_packet_interval = atoi(optarg); break; case 'i': inter_ccn_interval = atoi(optarg); break; case 'v': if (isdigit(optarg[0])) debug_level = atoi(optarg); else debug_level = ccnl_debug_str2level(optarg); break; case 's': theSuite = ccnl_str2suite(optarg); if (theSuite >= 0 && theSuite < CCNL_SUITE_LAST) break; case 'h': default: fprintf(stderr, "Xusage: %s [-h] [-c MAX_CONTENT_ENTRIES] " "[-g MIN_INTER_PACKET_INTERVAL] " "[-i MIN_INTER_CCNMSG_INTERVAL] " "[-s SUITE (ccnb, ccnx2014, iot2014, ndn2013)] " "[-v DEBUG_LEVEL]\n", argv[0]); exit(EXIT_FAILURE); } } time(&relays[0].startup_time); ccnl_core_init(); DEBUGMSG(INFO, "This is ccn-lite-simu, starting at %s", ctime(&relays[0].startup_time) + 4); DEBUGMSG(INFO, " ccnl-core: %s\n", CCNL_VERSION); DEBUGMSG(INFO, " compile time: %s %s\n", __DATE__, __TIME__); DEBUGMSG(INFO, " compile options: %s\n", compile_string()); DEBUGMSG(INFO, "using suite %s\n", ccnl_suite2str(theSuite)); ccnl_simu_init(max_cache_entries); DEBUGMSG(INFO, "simulation starts\n"); simu_eventloop(); DEBUGMSG(INFO, "simulation ends\n"); return -1; }
// turn an URI into an internal prefix (watch out: this modifies the uri string) struct ccnl_prefix_s * ccnl_URItoPrefix(char* uri, int suite, char *nfnexpr, unsigned int *chunknum) { struct ccnl_prefix_s *p; char *compvect[CCNL_MAX_NAME_COMP]; unsigned int complens[CCNL_MAX_NAME_COMP]; int cnt, i, len, tlen; DEBUGMSG_CPFX(TRACE, "ccnl_URItoPrefix(suite=%s, uri=%s, nfn=%s)\n", ccnl_suite2str(suite), uri, nfnexpr); if (strlen(uri)) cnt = ccnl_URItoComponents(compvect, complens, uri); else cnt = 0; if (nfnexpr && *nfnexpr) cnt += 1; p = ccnl_prefix_new(suite, cnt); if (!p) return NULL; for (i = 0, len = 0; i < cnt; i++) { if (i == (cnt-1) && nfnexpr && *nfnexpr) len += strlen(nfnexpr); else len += complens[i];//strlen(compvect[i]); } #ifdef USE_SUITE_CCNTLV if (suite == CCNL_SUITE_CCNTLV) len += cnt * 4; // add TL size #endif #ifdef USE_SUITE_CISTLV if (suite == CCNL_SUITE_CISTLV) len += cnt * 4; // add TL size #endif p->bytes = (unsigned char*) ccnl_malloc(len); if (!p->bytes) { free_prefix(p); return NULL; } for (i = 0, len = 0, tlen = 0; i < cnt; i++) { int isnfnfcomp = i == (cnt-1) && nfnexpr && *nfnexpr; char *cp = isnfnfcomp ? nfnexpr : (char*) compvect[i]; if (isnfnfcomp) tlen = strlen(nfnexpr); else tlen = complens[i]; p->comp[i] = p->bytes + len; tlen = ccnl_pkt_mkComponent(suite, p->comp[i], cp, tlen); p->complen[i] = tlen; len += tlen; } p->compcnt = cnt; #ifdef USE_NFN if (nfnexpr && *nfnexpr) p->nfnflags |= CCNL_PREFIX_NFN; #endif if(chunknum) { p->chunknum = ccnl_malloc(sizeof(int)); *p->chunknum = *chunknum; } return p; }
// deliver new content c to all clients with (loosely) matching interest, // but only one copy per face // returns: number of forwards int ccnl_content_serve_pending(struct ccnl_relay_s *ccnl, struct ccnl_content_s *c) { struct ccnl_interest_s *i; struct ccnl_face_s *f; int cnt = 0; DEBUGMSG_CORE(TRACE, "ccnl_content_serve_pending\n"); for (f = ccnl->faces; f; f = f->next){ f->flags &= ~CCNL_FACE_FLAGS_SERVED; // reply on a face only once } for (i = ccnl->pit; i;) { struct ccnl_pendint_s *pi; if (!i->pkt->pfx) continue; switch (i->pkt->pfx->suite) { #ifdef USE_SUITE_CCNB case CCNL_SUITE_CCNB: if (!ccnl_i_prefixof_c(i->pkt->pfx, i->pkt->s.ccnb.minsuffix, i->pkt->s.ccnb.maxsuffix, c)) { // XX must also check i->ppkd i = i->next; continue; } break; #endif #ifdef USE_SUITE_CCNTLV case CCNL_SUITE_CCNTLV: if (ccnl_prefix_cmp(c->pkt->pfx, NULL, i->pkt->pfx, CMP_EXACT)) { // XX must also check keyid i = i->next; continue; } break; #endif #ifdef USE_SUITE_CISTLV case CCNL_SUITE_CISTLV: if (ccnl_prefix_cmp(c->pkt->pfx, NULL, i->pkt->pfx, CMP_EXACT)) { // XX must also check keyid i = i->next; continue; } break; #endif #ifdef USE_SUITE_IOTTLV case CCNL_SUITE_IOTTLV: if (ccnl_prefix_cmp(c->pkt->pfx, NULL, i->pkt->pfx, CMP_EXACT)) { // XX must also check keyid i = i->next; continue; } break; #endif #ifdef USE_SUITE_NDNTLV case CCNL_SUITE_NDNTLV: if (!ccnl_i_prefixof_c(i->pkt->pfx, i->pkt->s.ndntlv.minsuffix, i->pkt->s.ndntlv.maxsuffix, c)) { // XX must also check i->ppkl, i = i->next; continue; } break; #endif default: i = i->next; continue; } //Hook for add content to cache by callback: if(i && ! i->pending){ DEBUGMSG_CORE(WARNING, "releasing interest 0x%p OK?\n", (void*)i); c->flags |= CCNL_CONTENT_FLAGS_STATIC; i = ccnl_interest_remove(ccnl, i); return 1; } // CONFORM: "Data MUST only be transmitted in response to // an Interest that matches the Data." for (pi = i->pending; pi; pi = pi->next) { if (pi->face->flags & CCNL_FACE_FLAGS_SERVED) continue; pi->face->flags |= CCNL_FACE_FLAGS_SERVED; if (pi->face->ifndx >= 0) { DEBUGMSG_CFWD(INFO, " outgoing data=<%s>%s to=%s\n", ccnl_prefix_to_path(i->pkt->pfx), ccnl_suite2str(i->pkt->pfx->suite), ccnl_addr2ascii(&pi->face->peer)); DEBUGMSG_CORE(VERBOSE, " Serve to face: %d (pkt=%p)\n", pi->face->faceid, (void*) c->pkt); ccnl_nfn_monitor(ccnl, pi->face, c->pkt->pfx, c->pkt->content, c->pkt->contlen); ccnl_face_enqueue(ccnl, pi->face, buf_dup(c->pkt->buf)); } else {// upcall to deliver content to local client ccnl_app_RX(ccnl, c); } c->served_cnt++; cnt++; } i = ccnl_interest_remove(ccnl, i); } return cnt; }
void ccnl_dump(int lev, int typ, void *p) { struct ccnl_buf_s *buf = (struct ccnl_buf_s *) p; struct ccnl_prefix_s *pre = (struct ccnl_prefix_s *) p; struct ccnl_relay_s *top = (struct ccnl_relay_s *) p; struct ccnl_face_s *fac = (struct ccnl_face_s *) p; #ifdef USE_FRAG struct ccnl_frag_s *frg = (struct ccnl_frag_s *) p; #endif struct ccnl_forward_s *fwd = (struct ccnl_forward_s *) p; struct ccnl_interest_s *itr = (struct ccnl_interest_s *) p; struct ccnl_pendint_s *pir = (struct ccnl_pendint_s *) p; struct ccnl_pkt_s *pkt = (struct ccnl_pkt_s *) p; struct ccnl_content_s *con = (struct ccnl_content_s *) p; int i, k; #define INDENT(lev) for (i = 0; i < lev; i++) CONSOLE(" ") switch(typ) { case CCNL_BUF: while (buf) { INDENT(lev); CONSOLE("%p BUF len=%zd next=%p\n", (void *) buf, buf->datalen, (void *) buf->next); buf = buf->next; } break; case CCNL_PREFIX: INDENT(lev); CONSOLE("%p PREFIX len=%d val=%s\n", (void *) pre, pre->compcnt, ccnl_prefix_to_path(pre)); break; case CCNL_RELAY: INDENT(lev); CONSOLE("%p RELAY\n", (void *) top); lev++; INDENT(lev); CONSOLE("interfaces:\n"); for (k = 0; k < top->ifcount; k++) { INDENT(lev+1); CONSOLE("ifndx=%d addr=%s", k, ccnl_addr2ascii(&top->ifs[k].addr)); #ifdef CCNL_LINUXKERNEL if (top->ifs[k].addr.sa.sa_family == AF_PACKET) CONSOLE(" netdev=%p", top->ifs[k].netdev); else CONSOLE(" sockstruct=%p", top->ifs[k].sock); #elif !defined(CCNL_RIOT) CONSOLE(" sock=%d", top->ifs[k].sock); #endif if (top->ifs[k].reflect) CONSOLE(" reflect=%d", top->ifs[k].reflect); CONSOLE("\n"); } if (top->faces) { INDENT(lev); CONSOLE("faces:\n"); ccnl_dump(lev+1, CCNL_FACE, top->faces); } if (top->fib) { INDENT(lev); CONSOLE("fib:\n"); ccnl_dump(lev+1, CCNL_FWD, top->fib); } if (top->pit) { INDENT(lev); CONSOLE("pit:\n"); ccnl_dump(lev+1, CCNL_INTEREST, top->pit); } if (top->contents) { INDENT(lev); CONSOLE("contents:\n"); ccnl_dump(lev+1, CCNL_CONTENT, top->contents); } break; case CCNL_FACE: while (fac) { INDENT(lev); CONSOLE("%p FACE id=%d next=%p prev=%p ifndx=%d flags=%02x", (void*) fac, fac->faceid, (void *) fac->next, (void *) fac->prev, fac->ifndx, fac->flags); if (0) {} #ifdef USE_IPV4 else if (fac->peer.sa.sa_family == AF_INET) CONSOLE(" ip=%s", ccnl_addr2ascii(&fac->peer)); #endif #ifdef USE_IPV6 else if (fac->peer.sa.sa_family == AF_INET6) CONSOLE(" ip=%s", ccnl_addr2ascii(&fac->peer)); #endif #ifdef USE_LINKLAYER else if (fac->peer.sa.sa_family == AF_PACKET) CONSOLE(" eth=%s", ccnl_addr2ascii(&fac->peer)); #endif #ifdef USE_WPAN else if (fac->peer.sa.sa_family == AF_IEEE802154) CONSOLE(" wpan=%s", ccnl_addr2ascii(&fac->peer)); #endif #ifdef USE_UNIXSOCKET else if (fac->peer.sa.sa_family == AF_UNIX) CONSOLE(" ux=%s", ccnl_addr2ascii(&fac->peer)); #endif else CONSOLE(" peer=?"); if (fac->frag) ccnl_dump(lev+2, CCNL_FRAG, fac->frag); CONSOLE("\n"); if (fac->outq) { INDENT(lev+1); CONSOLE("outq:\n"); ccnl_dump(lev+2, CCNL_BUF, fac->outq); } fac = fac->next; } break; #ifdef USE_FRAG case CCNL_FRAG: CONSOLE(" fragproto=%s mtu=%d", frag_protocol(frg->protocol), frg->mtu); break; #endif case CCNL_FWD: while (fwd) { INDENT(lev); CONSOLE("%p FWD next=%p face=%p (id=%d suite=%s)\n", (void *) fwd, (void *) fwd->next, (void *) fwd->face, fwd->face->faceid, ccnl_suite2str(fwd->suite)); ccnl_dump(lev+1, CCNL_PREFIX, fwd->prefix); fwd = fwd->next; } break; case CCNL_INTEREST: while (itr) { INDENT(lev); CONSOLE("%p INTEREST next=%p prev=%p last=%d retries=%d\n", (void *) itr, (void *) itr->next, (void *) itr->prev, itr->last_used, itr->retries); ccnl_dump(lev+1, CCNL_PACKET, itr->pkt); if (itr->pending) { INDENT(lev+1); CONSOLE("pending:\n"); ccnl_dump(lev+2, CCNL_PENDINT, itr->pending); } itr = itr->next; } break; case CCNL_PENDINT: while (pir) { INDENT(lev); CONSOLE("%p PENDINT next=%p face=%p last=%d\n", (void *) pir, (void *) pir->next, (void *) pir->face, pir->last_used); pir = pir->next; } break; case CCNL_PACKET: INDENT(lev); CONSOLE("%p PACKET %s typ=%d cont=%p contlen=%d finalBI=%d flags=0x%04x\n", (void *) pkt, ccnl_suite2str(pkt->suite), pkt->type, (void*) pkt->content, pkt->contlen, pkt->val.final_block_id, pkt->flags); ccnl_dump(lev+1, CCNL_PREFIX, pkt->pfx); switch(pkt->suite) { #ifdef USE_SUITE_CCNB case CCNL_SUITE_CCNB: INDENT(lev+1); CONSOLE("minsfx=%d maxsfx=%d aok=%d scope=%d", pkt->s.ccnb.minsuffix, pkt->s.ccnb.maxsuffix, pkt->s.ccnb.aok, pkt->s.ccnb.scope); if (pkt->s.ccnb.nonce) { CONSOLE(" nonce="); blob(pkt->s.ccnb.nonce); } CONSOLE("\n"); if (pkt->s.ccnb.ppkd) { INDENT(lev+1); CONSOLE("ppkd="); blob(pkt->s.ccnb.ppkd); CONSOLE("\n"); } break; #endif #ifdef USE_SUITE_CCNTLV case CCNL_SUITE_CCNTLV: if (pkt->s.ccntlv.keyid) { INDENT(lev+1); CONSOLE("keyid="); blob(pkt->s.ccntlv.keyid); CONSOLE("\n"); } break; #endif #ifdef USE_SUITE_IOTTLV case CCNL_SUITE_IOTTLV: INDENT(lev+1); CONSOLE("ttl=%d\n", pkt->s.iottlv.ttl); break; #endif #ifdef USE_SUITE_NDNTLV case CCNL_SUITE_NDNTLV: INDENT(lev+1); CONSOLE("minsfx=%d maxsfx=%d mbf=%d scope=%d", pkt->s.ndntlv.minsuffix, pkt->s.ndntlv.maxsuffix, pkt->s.ndntlv.mbf, pkt->s.ndntlv.scope); if (pkt->s.ndntlv.nonce) { CONSOLE(" nonce="); blob(pkt->s.ndntlv.nonce); } CONSOLE("\n"); if (pkt->s.ndntlv.ppkl) { INDENT(lev+1); CONSOLE("ppkl="); blob(pkt->s.ndntlv.ppkl); CONSOLE("\n"); } break; #endif default: INDENT(lev+1); CONSOLE("... suite-specific packet details here ...\n"); } ccnl_dump(lev+1, CCNL_BUF, pkt->buf); break; case CCNL_CONTENT: while (con) { INDENT(lev); CONSOLE("%p CONTENT next=%p prev=%p last_used=%d served_cnt=%d\n", (void *) con, (void *) con->next, (void *) con->prev, con->last_used, con->served_cnt); // ccnl_dump(lev+1, CCNL_PREFIX, con->pkt->pfx); ccnl_dump(lev+1, CCNL_PACKET, con->pkt); con = con->next; } break; default: INDENT(lev); CONSOLE("unknown data type %d at %p\n", typ, p); } }
int ccnl_extractDataAndChunkInfo(unsigned char **data, int *datalen, int suite, struct ccnl_prefix_s **prefix, unsigned int *lastchunknum, unsigned char **content, int *contentlen) { struct ccnl_pkt_s *pkt = NULL; switch (suite) { #ifdef USE_SUITE_CCNTLV case CCNL_SUITE_CCNTLV: { int hdrlen; unsigned char *start = *data; if (ccntlv_isData(*data, *datalen) < 0) { DEBUGMSG(WARNING, "Received non-content-object\n"); return -1; } hdrlen = ccnl_ccntlv_getHdrLen(*data, *datalen); if (hdrlen < 0) return -1; *data += hdrlen; *datalen -= hdrlen; pkt = ccnl_ccntlv_bytes2pkt(start, data, datalen); break; } #endif #ifdef USE_SUITE_CISTLV case CCNL_SUITE_CISTLV: { int hdrlen; unsigned char *start = *data; if (cistlv_isData(*data, *datalen) < 0) { DEBUGMSG(WARNING, "Received non-content-object\n"); return -1; } hdrlen = ccnl_cistlv_getHdrLen(*data, *datalen); if (hdrlen < 0) return -1; *data += hdrlen; *datalen -= hdrlen; pkt = ccnl_cistlv_bytes2pkt(start, data, datalen); break; } #endif #ifdef USE_SUITE_NDNTLV case CCNL_SUITE_NDNTLV: { unsigned int typ, len; unsigned char *start = *data; if (ccnl_ndntlv_dehead(data, datalen, &typ, &len)) { DEBUGMSG(WARNING, "could not dehead\n"); return -1; } if (typ != NDN_TLV_Data) { DEBUGMSG(WARNING, "received non-content-object packet with type %d\n", typ); return -1; } pkt = ccnl_ndntlv_bytes2pkt(typ, start, data, datalen); break; } #endif default: DEBUGMSG(WARNING, "extractDataAndChunkInfo: suite %d not implemented\n", suite); return -1; } if (!pkt) { DEBUGMSG(WARNING, "extract(%s): parsing error or no prefix\n", ccnl_suite2str(suite)); return -1; } *prefix = ccnl_prefix_dup(pkt->pfx); *lastchunknum = pkt->val.final_block_id; *content = pkt->content; *contentlen = pkt->contlen; free_packet(pkt); return 0; }
int main(int argc, char *argv[]) { unsigned char out[64*1024]; int len, opt, port, sock = 0, suite = CCNL_SUITE_DEFAULT; char *addr = NULL, *udp = NULL, *ux = NULL; struct sockaddr sa; float wait = 3.0; while ((opt = getopt(argc, argv, "hs:u:v:w:x:")) != -1) { switch (opt) { case 's': suite = ccnl_str2suite(optarg); if (!ccnl_isSuite(suite)) { DEBUGMSG(ERROR, "Unsupported suite %s\n", optarg); goto usage; } break; case 'u': udp = optarg; break; case 'w': wait = atof(optarg); break; case 'v': #ifdef USE_LOGGING if (isdigit(optarg[0])) debug_level = atoi(optarg); else debug_level = ccnl_debug_str2level(optarg); #endif break; case 'x': ux = optarg; break; case 'h': default: usage: fprintf(stderr, "usage: %s [options] URI [NFNexpr]\n" " -s SUITE (ccnb, ccnx2015, cisco2015, iot2014, ndn2013)\n" " -u a.b.c.d/port UDP destination (default is 127.0.0.1/6363)\n" #ifdef USE_LOGGING " -v DEBUG_LEVEL (fatal, error, warning, info, debug, verbose, trace)\n" #endif " -w timeout in sec (float)\n" " -x ux_path_name UNIX IPC: use this instead of UDP\n" "Examples:\n" "%% peek /ndn/edu/wustl/ping (classic lookup)\n" "%% peek /th/ere \"lambda expr\" (lambda expr, in-net)\n" "%% peek \"\" \"add 1 1\" (lambda expr, local)\n" "%% peek /rpc/site \"call 1 /test/data\" (lambda RPC, directed)\n", argv[0]); exit(1); } } if (!argv[optind]) goto usage; srandom(time(NULL)); if (ccnl_parseUdp(udp, suite, &addr, &port) != 0) { exit(-1); } DEBUGMSG(TRACE, "using suite %d:%s\n", suite, ccnl_suite2str(suite)); DEBUGMSG(TRACE, "using udp address %s/%d\n", addr, port); if (ux) { // use UNIX socket struct sockaddr_un *su = (struct sockaddr_un*) &sa; su->sun_family = AF_UNIX; strcpy(su->sun_path, ux); sock = ux_open(); } else { // UDP struct sockaddr_in *si = (struct sockaddr_in*) &sa; si->sin_family = PF_INET; si->sin_addr.s_addr = inet_addr(addr); si->sin_port = htons(port); sock = udp_open(); } char *url = argv[optind]; char *nfnexpr = 0; if (argv[optind+1]) { nfnexpr = argv[optind+1]; } unsigned char *content = 0; int contlen; unsigned int *curchunknum = NULL; // For CCNTLV always start with the first chunk because of exact content match // This means it can only fetch chunked data and not single content-object data if (suite == CCNL_SUITE_CCNTLV || suite == CCNL_SUITE_CISTLV) { curchunknum = ccnl_malloc(sizeof(unsigned int)); *curchunknum = 0; } struct ccnl_prefix_s *prefix = ccnl_URItoPrefix(url, suite, nfnexpr, curchunknum); const int maxretry = 3; int retry = 0; while (retry < maxretry) { if (curchunknum) { if (!prefix->chunknum) { prefix->chunknum = ccnl_malloc(sizeof(unsigned int)); } *(prefix->chunknum) = *curchunknum; DEBUGMSG(INFO, "fetching chunk %d for prefix '%s'\n", *curchunknum, ccnl_prefix_to_path(prefix)); } else { DEBUGMSG(DEBUG, "fetching first chunk...\n"); DEBUGMSG(INFO, "fetching first chunk for prefix '%s'\n", ccnl_prefix_to_path(prefix)); } // Fetch chunk if (ccnl_fetchContentForChunkName(prefix, nfnexpr, curchunknum, suite, out, sizeof(out), &len, wait, sock, sa) < 0) { retry++; DEBUGMSG(WARNING, "timeout\n");//, retry number %d of %d\n", retry, maxretry); } else { unsigned int lastchunknum; unsigned char *t = &out[0]; struct ccnl_prefix_s *nextprefix = 0; // Parse response if (ccnl_extractDataAndChunkInfo(&t, &len, suite, &nextprefix, &lastchunknum, &content, &contlen) < 0) { retry++; DEBUGMSG(WARNING, "Could not extract response or it was an interest\n"); } else { prefix = nextprefix; // Check if the fetched content is a chunk if (!(prefix->chunknum)) { // Response is not chunked, print content and exit write(1, content, contlen); goto Done; } else { int chunknum = *(prefix->chunknum); // allocate curchunknum because it is the first fetched chunk if(!curchunknum) { curchunknum = ccnl_malloc(sizeof(unsigned int)); *curchunknum = 0; } // Remove chunk component from name if (ccnl_prefix_removeChunkNumComponent(suite, prefix) < 0) { retry++; DEBUGMSG(WARNING, "Could not remove chunknum\n"); } // Check if the chunk is the first chunk or the next valid chunk // otherwise discard content and try again (except if it is the first fetched chunk) if (chunknum == 0 || (curchunknum && *curchunknum == chunknum)) { DEBUGMSG(DEBUG, "Found chunk %d with contlen=%d, lastchunk=%d\n", *curchunknum, contlen, lastchunknum); write(1, content, contlen); if (lastchunknum != -1 && lastchunknum == chunknum) { goto Done; } else { *curchunknum += 1; retry = 0; } } else { // retry if the fetched chunk retry++; DEBUGMSG(WARNING, "Could not find chunk %d, extracted chunknum is %d (lastchunk=%d)\n", *curchunknum, chunknum, lastchunknum); } } } } if(retry > 0) { DEBUGMSG(INFO, "Retry %d of %d\n", retry, maxretry); } } close(sock); return 1; Done: DEBUGMSG(DEBUG, "Sucessfully fetched content\n"); close(sock); return 0; }