Esempio n. 1
0
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;
}
Esempio n. 2
0
// 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;
}
Esempio n. 3
0
// 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;
}
Esempio n. 4
0
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;
}