Пример #1
0
void ccnl_do_retransmit(void *ptr, void *dummy)
{
    (void) dummy; /* unused */

    struct ccnl_relay_s *relay = (struct ccnl_relay_s *) ptr;

    for (struct ccnl_interest_s *i = relay->pit; i; i = i->next) {
        // CONFORM: "Entries in the PIT MUST timeout rather
        // than being held indefinitely."
        if(i->retries <= CCNL_MAX_INTEREST_RETRANSMIT) {
            // CONFORM: "A node MUST retransmit Interest Messages
            // periodically for pending PIT entries."
            DEBUGMSG(7, " retransmit %d <%s>\n", i->retries,
                     ccnl_prefix_to_path(i->prefix));

            if (i->forwarded_over
                && !(i->forwarded_over->flags & CCNL_FORWARD_FLAGS_STATIC)
                && (i->retries >= CCNL_MAX_INTEREST_OPTIMISTIC)) {
                DEBUGMSG(1, "  removed dynamic forward %p\n", (void *) i->forwarded_over);
                ccnl_forward_remove(relay, i->forwarded_over);
            }

            i->retries++;
            ccnl_interest_propagate(relay, i);
        }
    }
}
Пример #2
0
void
ccnl_do_ageing(void *ptr, void *dummy)
{
    (void) dummy;
    struct ccnl_relay_s *relay = (struct ccnl_relay_s*) ptr;
    struct ccnl_content_s *c = relay->contents;
    struct ccnl_interest_s *i = relay->pit;
    struct ccnl_face_s *f = relay->faces;
    time_t t = CCNL_NOW();
    DEBUGMSG_CORE(TRACE, "ageing t=%d\n", (int)t);

    while (c) {
        if ((c->last_used + CCNL_CONTENT_TIMEOUT) <= t &&
                                !(c->flags & CCNL_CONTENT_FLAGS_STATIC)){
          DEBUGMSG_CORE(TRACE, "AGING: CONTENT REMOVE %p\n", (void*) c);
            c = ccnl_content_remove(relay, c);
        }
        else
            c = c->next;
    }
    while (i) { // CONFORM: "Entries in the PIT MUST timeout rather
                // than being held indefinitely."
        if ((i->last_used + CCNL_INTEREST_TIMEOUT) <= t ||
                                i->retries > CCNL_MAX_INTEREST_RETRANSMIT) {
            DEBUGMSG_CORE(TRACE, "AGING: INTEREST REMOVE %p\n", (void*) i);
            DEBUGMSG_CORE(DEBUG, " timeout: remove interest 0x%p <%s>\n",
                          (void*)i,
                     ccnl_prefix_to_path(i->pkt->pfx));
            i = ccnl_nfn_interest_remove(relay, i);
        } else {
            // CONFORM: "A node MUST retransmit Interest Messages
            // periodically for pending PIT entries."
            DEBUGMSG_CORE(DEBUG, " retransmit %d <%s>\n", i->retries,
                     ccnl_prefix_to_path(i->pkt->pfx));
#ifdef USE_NFN
            if (i->flags & CCNL_PIT_COREPROPAGATES){
#endif
                DEBUGMSG_CORE(TRACE, "AGING: PROPAGATING INTEREST %p\n", (void*) i);
                ccnl_interest_propagate(relay, i);
#ifdef USE_NFN
            }
#endif

            i->retries++;
            i = i->next;
        }
    }
    while (f) {
        if (!(f->flags & CCNL_FACE_FLAGS_STATIC) &&
                (f->last_used + CCNL_FACE_TIMEOUT) <= t){
            DEBUGMSG_CORE(TRACE, "AGING: FACE REMOVE %p\n", (void*) f);
            f = ccnl_face_remove(relay, f);
    }
        else
            f = f->next;
    }
}
Пример #3
0
char*
op_builtin_find(struct ccnl_relay_s *ccnl, struct configuration_s *config,
                int *restart, int *halt, char *prog, char *pending,
                struct stack_s **stack)
{
    int local_search = 0;
    struct stack_s *h;
    char *cp = NULL;
    struct ccnl_prefix_s *prefix;
    struct ccnl_content_s *c = NULL;

    if (*restart) {
        DEBUGMSG(DEBUG, "---to do: OP_FIND restart\n");
        *restart = 0;
        local_search = 1;
    } else {
        DEBUGMSG(DEBUG, "---to do: OP_FIND <%s> <%s>\n", prog+7, pending);
        h = pop_from_stack(&config->result_stack);
        //    if (h->type != STACK_TYPE_PREFIX)  ...
        config->fox_state->num_of_params = 1;
        config->fox_state->params = ccnl_malloc(sizeof(struct ccnl_stack_s *));
        config->fox_state->params[0] = h;
        config->fox_state->it_routable_param = 0;
    }
    prefix = config->fox_state->params[0]->content;

    //check if result is now available
    //loop by reentering (with local_search) after timeout of the interest...
    DEBUGMSG(DEBUG, "FIND: Checking if result was received\n");
    c = ccnl_nfn_local_content_search(ccnl, config, prefix);
    if (!c) {
        struct ccnl_prefix_s *copy;
        struct ccnl_interest_s *interest;
        if (local_search) {
            DEBUGMSG(INFO, "FIND: no content\n");
            return NULL;
        }
        //Result not in cache, search over the network
        //        struct ccnl_interest_s *interest = mkInterestObject(ccnl, config, prefix);
        copy = ccnl_prefix_dup(prefix);
        interest = ccnl_nfn_query2interest(ccnl, &copy, config);
        DEBUGMSG(DEBUG, "FIND: sending new interest from Face ID: %d\n",
                 interest->from->faceid);
        if (interest)
            ccnl_interest_propagate(ccnl, interest);
        //wait for content, return current program to continue later
        *halt = -1; //set halt to -1 for async computations
        return ccnl_strdup(prog);
    }

    DEBUGMSG(INFO, "FIND: result was found ---> handle it (%s), prog=%s, pending=%s\n", ccnl_prefix_to_path(prefix), prog, pending);
#ifdef USE_NACK
/*
    if (!strncmp((char*)c->content, ":NACK", 5)) {
        DEBUGMSG(DEBUG, "NACK RECEIVED, going to next parameter\n");
        ++config->fox_state->it_routable_param;
        
        return prog ? ccnl_strdup(prog) : NULL;
    }
*/
#endif
    prefix = ccnl_prefix_dup(prefix);
    push_to_stack(&config->result_stack, prefix, STACK_TYPE_PREFIX);

    if (pending) {
        DEBUGMSG(DEBUG, "Pending: %s\n", pending);

        cp = ccnl_strdup(pending);
    }
    return cp;
}
Пример #4
0
int 
ccnl_nfn(struct ccnl_relay_s *ccnl, // struct ccnl_buf_s *orig,
         struct ccnl_prefix_s *prefix, struct ccnl_face_s *from, 
         struct configuration_s *config, struct ccnl_interest_s *interest,
         int suite, int start_locally)
{
    int num_of_required_thunks = 0;
    int thunk_request = 0;
    struct ccnl_buf_s *res = NULL;
    char str[CCNL_MAX_PACKET_SIZE];
    int i, len = 0;

    DEBUGMSG(TRACE, "ccnl_nfn(%p, %s, %p, config=%p)\n",
             (void*)ccnl, ccnl_prefix_to_path(prefix),
             (void*)from, (void*)config);

    //    prefix = ccnl_prefix_dup(prefix);
    DEBUGMSG(DEBUG, "Namecomps: %s \n", ccnl_prefix_to_path(prefix));

    if (config){
        suite = config->suite;
        thunk_request = config->fox_state->thunk_request;
        goto restart; //do not do parsing thunks again
    }

    from->flags = CCNL_FACE_FLAGS_STATIC;

    if (ccnl_nfn_thunk_already_computing(ccnl, prefix)) {
        DEBUGMSG(DEBUG, "Computation for this interest is already running\n");
        return -1;
    }
    if (ccnl_nfnprefix_isTHUNK(prefix))
        thunk_request = 1;


    // Checks first if the interest has a routing hint and then searches for it locally.
    // If it exisits, the computation is started locally,  otherwise it is directly forwarded without entering the AM.
    // Without this mechanism, there will be situations where several nodes "overtake" a computation
    // applying the same strategy and, potentially, all executing it locally (after trying all arguments).
    // TODO: this is not an elegant solution and should be improved on, because the clients cannot send a
    // computation with a routing hint on which the network applies a strategy if the routable name
    // does not exist (because each node will just forward it without ever taking it into an abstract machine).
    // encoding the routing hint more explicitely as well as additonal information (e.g. already tried names) 
    // could solve the problem. More generally speaking, additional state describing the exact situation will be required.
    
    if (interest && interest->prefix->compcnt > 1) { // forward interests with outsourced components
        struct ccnl_prefix_s *copy = ccnl_prefix_dup(prefix);
        copy->compcnt -= (1 + thunk_request);
        DEBUGMSG(DEBUG, "   checking local available of %s\n", ccnl_prefix_to_path(copy));
        ccnl_nfnprefix_clear(copy, CCNL_PREFIX_NFN | CCNL_PREFIX_THUNK); 
        if (!ccnl_nfn_local_content_search(ccnl, NULL, copy)) {
            free_prefix(copy);
            ccnl_interest_propagate(ccnl, interest);
            return 0;
        }
        free_prefix(copy);
        start_locally = 1;
    }
   
    //put packet together
#ifdef USE_SUITE_CCNTLV
    if (prefix->suite == CCNL_SUITE_CCNTLV) {
        len = prefix->complen[prefix->compcnt-1] - 4;
        memcpy(str, prefix->comp[prefix->compcnt-1] + 4, len);
        str[len] = '\0';
    } else
#endif
    {
        len = prefix->complen[prefix->compcnt-1];
        memcpy(str, prefix->comp[prefix->compcnt-1], len);
        str[len] = '\0';
    }
    if (prefix->compcnt > 1)
        len += sprintf(str + len, " ");
    for (i = 0; i < prefix->compcnt-1; i++) {
#ifdef USE_SUITE_CCNTLV
        if (prefix->suite == CCNL_SUITE_CCNTLV)
            len += sprintf(str+len,"/%.*s",prefix->complen[i]-4,prefix->comp[i]+4);
        else
#endif
            len += sprintf(str+len,"/%.*s",prefix->complen[i],prefix->comp[i]);
    }

    DEBUGMSG(DEBUG, "expr is <%s>\n", str);
    //search for result here... if found return...
    if (thunk_request)
        num_of_required_thunks = ccnl_nfn_count_required_thunks(str);
    
    ++ccnl->km->numOfRunningComputations;
restart:
    res = Krivine_reduction(ccnl, str, thunk_request, start_locally,
                            num_of_required_thunks, &config, prefix, suite);

    //stores result if computed      
    if (res) {
        struct ccnl_prefix_s *copy;
        struct ccnl_content_s *c;

        DEBUGMSG(INFO,"Computation finished: res: %.*s size: %d bytes. Running computations: %d\n",
                 res->datalen, res->data, res->datalen, ccnl->km->numOfRunningComputations);
        if (config && config->fox_state->thunk_request) {
            // ccnl_nfn_remove_thunk_from_prefix(config->prefix);
            ccnl_nfnprefix_clear(config->prefix, CCNL_PREFIX_THUNK);
        }
        copy = ccnl_prefix_dup(config->prefix);
        c = ccnl_nfn_result2content(ccnl, &copy, res->data, res->datalen);
        c->flags = CCNL_CONTENT_FLAGS_STATIC;

        set_propagate_of_interests_to_1(ccnl, c->name);
        ccnl_content_serve_pending(ccnl,c);
        ccnl_content_add2cache(ccnl, c);
        --ccnl->km->numOfRunningComputations;

        DBL_LINKED_LIST_REMOVE(ccnl->km->configuration_list, config);
        ccnl_nfn_freeConfiguration(config);
        ccnl_free(res);
    }
#ifdef USE_NACK
    else if(config->local_done){
        struct ccnl_content_s *nack;
        nack = ccnl_nfn_result2content(ccnl, &config->prefix,
                                       (unsigned char*)":NACK", 5);
        ccnl_content_serve_pending(ccnl, nack);

    }
#endif

    return 0;
}
Пример #5
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;
}
Пример #6
0
void
ccnl_do_ageing(void *ptr, void *dummy)
{
    struct ccnl_relay_s *relay = (struct ccnl_relay_s*) ptr;
    struct ccnl_content_s *c = relay->contents;
    struct ccnl_interest_s *i = relay->pit;
    struct ccnl_face_s *f = relay->faces;
    time_t t = CCNL_NOW();
    char *bufp = NULL;
    DEBUGMSG_CORE(INFO, " ICNIoT: ageing t=%d\n", (int)t);

    while (c) {
        if ((c->last_used + CCNL_CONTENT_TIMEOUT) <= t &&
                                !(c->flags & CCNL_CONTENT_FLAGS_STATIC)){
          DEBUGMSG_CORE(INFO, " ICNIoT: AGING: CONTENT REMOVE %p\n", (void*) c);
            c = ccnl_content_remove(relay, c);
        }
        else{
//akhila 29-10-2015
        // check if it is the n th time instant. If yes then save the content store 
             if ((((int)t)%CS_SAVE_PERIOD == 0) && !(c->flags & CCNL_CONTENT_FLAGS_STATIC)){
                 bufp = ccnl_prefix_to_path((c->pkt)->pfx);
                 DEBUGMSG_CORE(INFO, " ICNIoT: ContentStoreItem :%s\n",bufp);
                 ccnl_free(bufp);
             }
            c = c->next;
        }
    }
    if (((int)t)%CS_SAVE_PERIOD == 0){
    	DEBUGMSG_CORE(INFO, " ICNIoT: ContentStoreItem contentCount:%d\n",relay->contentcnt);
      }
    while (i) { // CONFORM: "Entries in the PIT MUST timeout rather
                // than being held indefinitely."
        if ((i->last_used + CCNL_INTEREST_TIMEOUT) <= t){ // if it has timed out either resend it or remove it based on MAX_RETRIES
                if(i->retries >= CCNL_MAX_INTEREST_RETRANSMIT){
            		DEBUGMSG_CORE(INFO, " ICNIoT: AGING: INTEREST REMOVE %p\n", (void*) i);
//            		DEBUGMSG_CORE(DEBUG, " timeout: remove interest 0x%p <%s>\n",(void*)i,ccnl_prefix_to_path(i->pkt->pfx));
            		i = ccnl_nfn_interest_remove(relay, i);
        	  }
        	else {
            		// CONFORM: "A node MUST retransmit Interest Messages
            		// periodically for pending PIT entries."
            		DEBUGMSG_CORE(INFO, " ICNIoT: retransmit %d \n", i->retries);
//                      ccnl_prefix_to_path(i->pkt->pfx));
#ifdef USE_NFN
            		if (i->flags & CCNL_PIT_COREPROPAGATES){
#endif
     		           DEBUGMSG_CORE(INFO, " ICNIoT: AGING: PROPAGATING INTEREST %p\n", (void*) i);
                	   ccnl_interest_propagate(relay, i);
#ifdef USE_NFN
                        }
#endif
            		i->retries++;
            		i = i->next;
        	}
         }
        else{ // The interest has not timed out yet, so leave it alone !
//		DEBUGMSG_CORE(INFO, " ICNIoT: AGING: DO NOTHING %p\n", (void*) i);
		i = i->next;
            } 
    }
//    DEBUGMSG_CORE(INFO, " ICNIoT: PITcount %d\n",relay->pitcnt);
    while (f) {
        if (!(f->flags & CCNL_FACE_FLAGS_STATIC) &&
                (f->last_used + CCNL_FACE_TIMEOUT) <= t){
            DEBUGMSG_CORE(TRACE, "AGING: FACE REMOVE %p\n", (void*) f);
            f = ccnl_face_remove(relay, f);
    }
        else
            f = f->next;
    }
}
Пример #7
0
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;
}
char*
ZAM_fox(struct ccnl_relay_s *ccnl, struct configuration_s *config,
        int *restart, int *halt, char *prog, char *arg, char *contd)
{
    int local_search = 0, i;
    int parameter_number = 0;
    struct ccnl_content_s *c = NULL;
    struct ccnl_prefix_s *pref;
    struct ccnl_interest_s *interest;

    DEBUGMSG(DEBUG, "---to do: FOX <%s>\n", arg);
    ccnl_free(arg);
    if (*restart) {
        *restart = 0;
        local_search = 1;
        goto recontinue;
    }

    {
        struct stack_s *h;
        h = pop_or_resolve_from_result_stack(ccnl, config);
        assert(h);
        //TODO CHECK IF INT
        config->fox_state->num_of_params = *(int*)h->content;
        h->next = NULL;
        ccnl_nfn_freeStack(h);
    }
    DEBUGMSG(DEBUG, "NUM OF PARAMS: %d\n", config->fox_state->num_of_params);

    config->fox_state->params = ccnl_malloc(sizeof(struct ccnl_stack_s *) *
                                            config->fox_state->num_of_params);

    for (i = 0; i < config->fox_state->num_of_params; ++i) {
        //pop parameter from stack
        config->fox_state->params[i] = pop_from_stack(&config->result_stack);
        switch (config->fox_state->params[i]->type) {
        case STACK_TYPE_INT:
            DEBUGMSG(DEBUG, "  info: Parameter %d %d\n", i,
                     *(int *)config->fox_state->params[i]->content);
            break;
        case STACK_TYPE_PREFIX:
            DEBUGMSG(DEBUG, "  info: Parameter %d %s\n", i,
                     ccnl_prefix_to_path((struct ccnl_prefix_s*)
                                      config->fox_state->params[i]->content));
            break;
        default:
            break;
        }
    }
    //as long as there is a routable parameter: try to find a result
    config->fox_state->it_routable_param = 0;

    //check if last result is now available
recontinue: //loop by reentering after timeout of the interest...
    if (local_search) {
        DEBUGMSG(DEBUG, "Checking if result was received\n");
        parameter_number = choose_parameter(config);
        pref = create_namecomps(ccnl, config, parameter_number,
                        config->fox_state->params[parameter_number]->content);
        // search for a result
        c = ccnl_nfn_local_content_search(ccnl, config, pref);
        set_propagate_of_interests_to_1(ccnl, pref);
        free_prefix(pref);
        //TODO Check? //TODO remove interest here?
        if (c) {
	    DEBUGMSG(DEBUG, "Result was found\n");
            DEBUGMSG_CFWD(INFO, "data after result was found %.*s\n", c->pkt->contlen, c->pkt->content);
            goto handlecontent;
	}
    }

    //result was not delivered --> choose next parameter
    ++config->fox_state->it_routable_param;
    parameter_number = choose_parameter(config);
    if (parameter_number < 0)
        //no more parameter --> no result found, can try a local computation
        goto local_compute;
    // create new prefix with name components!!!!
    pref = create_namecomps(ccnl, config, parameter_number,
                        config->fox_state->params[parameter_number]->content);
    c = ccnl_nfn_local_content_search(ccnl, config, pref);
    if (c) {
        free_prefix(pref);
        goto handlecontent;
    }

    // Result not in cache, search over the network
//    pref2 = ccnl_prefix_dup(pref);
    interest = ccnl_nfn_query2interest(ccnl, &pref, config);
    if (pref)
        free_prefix(pref);
    if (interest) {
        ccnl_interest_propagate(ccnl, interest);
        DEBUGMSG(DEBUG, "  new interest's face is %d\n", interest->from->faceid);
    }
    // wait for content, return current program to continue later
    *halt = -1; //set halt to -1 for async computations
    return ccnl_strdup(prog);

local_compute:
    if (config->local_done)
        return NULL;

    config->local_done = 1;
    pref = ccnl_nfnprefix_mkComputePrefix(config, config->suite);
    DEBUGMSG(DEBUG, "Prefix local computation: %s\n",
             ccnl_prefix_to_path(pref));
    interest = ccnl_nfn_query2interest(ccnl, &pref, config);
    if (pref)
        free_prefix(pref);
    if (interest)
        ccnl_interest_propagate(ccnl, interest);

handlecontent: //if result was found ---> handle it
    if (c) {
#ifdef USE_NACK
        if (!strncmp((char*)c->pkt->content, ":NACK", 5)) {
            DEBUGMSG(DEBUG, "NACK RECEIVED, going to next parameter\n");
            ++config->fox_state->it_routable_param;
            return prog ? ccnl_strdup(prog) : NULL;
        }
#endif
        int isANumber = 1, i = 0;
	    for(i = 0; i < c->pkt->contlen; ++i){
	    	if(!isdigit(c->pkt->content[i])){
                isANumber = 0;
                break;
            }
	    }
	    
        if (isANumber){
            int *integer = ccnl_malloc(sizeof(int));
            *integer = strtol((char*)c->pkt->content, 0, 0);
            push_to_stack(&config->result_stack, integer, STACK_TYPE_INT);
        } else {
            struct prefix_mapping_s *mapping;
            struct ccnl_prefix_s *name =
                create_prefix_for_content_on_result_stack(ccnl, config);
            push_to_stack(&config->result_stack, name, STACK_TYPE_PREFIX);
            mapping = ccnl_malloc(sizeof(struct prefix_mapping_s));
            mapping->key = ccnl_prefix_dup(name); //TODO COPY
            mapping->value = ccnl_prefix_dup(c->pkt->pfx);
            DBL_LINKED_LIST_ADD(config->fox_state->prefix_mapping, mapping);
            DEBUGMSG(DEBUG, "Created a mapping %s - %s\n",
                        ccnl_prefix_to_path(mapping->key),
                        ccnl_prefix_to_path(mapping->value));
        }
    }
    
    DEBUGMSG(DEBUG, " FOX continuation: %s\n", contd);
    return ccnl_strdup(contd);
}