ccnr_proto.c

Go to the documentation of this file.
00001 /**
00002  * @file ccnr_proto.c
00003  * 
00004  * Part of ccnr -  CCNx Repository Daemon.
00005  *
00006  */
00007 
00008 /*
00009  * Copyright (C) 2011 Palo Alto Research Center, Inc.
00010  *
00011  * This work is free software; you can redistribute it and/or modify it under
00012  * the terms of the GNU General Public License version 2 as published by the
00013  * Free Software Foundation.
00014  * This work is distributed in the hope that it will be useful, but WITHOUT ANY
00015  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
00016  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
00017  * for more details. You should have received a copy of the GNU General Public
00018  * License along with this program; if not, write to the
00019  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020  * Boston, MA 02110-1301, USA.
00021  */
00022  
00023 #include <errno.h>
00024 #include <stdint.h>
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027 #include <fcntl.h>
00028 #include <string.h>
00029 #include <sys/errno.h>
00030 #include <sys/stat.h>
00031 #include <sys/types.h>
00032 #include <unistd.h>
00033 #include <ccn/ccn.h>
00034 #include <ccn/charbuf.h>
00035 #include <ccn/ccn_private.h>
00036 #include <ccn/schedule.h>
00037 #include <ccn/sockaddrutil.h>
00038 #include <ccn/uri.h>
00039 #include <ccn/coding.h>
00040 #include <sync/SyncBase.h>
00041 #include "ccnr_private.h"
00042 
00043 #include "ccnr_proto.h"
00044 
00045 #include "ccnr_dispatch.h"
00046 #include "ccnr_forwarding.h"
00047 #include "ccnr_init.h"
00048 #include "ccnr_io.h"
00049 #include "ccnr_msg.h"
00050 #include "ccnr_sendq.h"
00051 #include "ccnr_store.h"
00052 #include "ccnr_sync.h"
00053 #include "ccnr_util.h"
00054 
00055 #define CCNR_MAX_RETRY 5
00056 
00057 static enum ccn_upcall_res
00058 r_proto_start_write(struct ccn_closure *selfp,
00059                     enum ccn_upcall_kind kind,
00060                     struct ccn_upcall_info *info,
00061                     int marker_comp);
00062 
00063 static enum ccn_upcall_res
00064 r_proto_start_write_checked(struct ccn_closure *selfp,
00065                             enum ccn_upcall_kind kind,
00066                             struct ccn_upcall_info *info,
00067                             int marker_comp);
00068 
00069 static enum ccn_upcall_res
00070 r_proto_begin_enumeration(struct ccn_closure *selfp,
00071                           enum ccn_upcall_kind kind,
00072                           struct ccn_upcall_info *info,
00073                           int marker_comp);
00074 
00075 static enum ccn_upcall_res
00076 r_proto_continue_enumeration(struct ccn_closure *selfp,
00077                              enum ccn_upcall_kind kind,
00078                              struct ccn_upcall_info *info,
00079                              int marker_comp);
00080 
00081 static enum ccn_upcall_res
00082 r_proto_bulk_import(struct ccn_closure *selfp,
00083                              enum ccn_upcall_kind kind,
00084                              struct ccn_upcall_info *info,
00085                              int marker_comp);
00086 static int
00087 name_comp_equal_prefix(const unsigned char *data,
00088                     const struct ccn_indexbuf *indexbuf,
00089                     unsigned int i, const void *buf, size_t length);
00090 
00091 PUBLIC enum ccn_upcall_res
00092 r_proto_answer_req(struct ccn_closure *selfp,
00093                  enum ccn_upcall_kind kind,
00094                  struct ccn_upcall_info *info)
00095 {
00096     struct ccn_charbuf *msg = NULL;
00097     struct ccn_charbuf *name = NULL;
00098     struct ccn_charbuf *keylocator = NULL;
00099     struct ccn_charbuf *signed_info = NULL;
00100     struct ccn_charbuf *reply_body = NULL;
00101     struct ccnr_handle *ccnr = NULL;
00102     struct content_entry *content = NULL;
00103     int res = 0;
00104     int ncomps;
00105     int marker_comp;
00106     // struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
00107     
00108     switch (kind) {
00109         case CCN_UPCALL_FINAL:
00110             free(selfp);
00111             return(CCN_UPCALL_RESULT_OK);
00112         case CCN_UPCALL_INTEREST:
00113             break;
00114         case CCN_UPCALL_CONSUMED_INTEREST:
00115             return(CCN_UPCALL_RESULT_OK);
00116         default:
00117             return(CCN_UPCALL_RESULT_ERR);
00118     }
00119     ccnr = (struct ccnr_handle *)selfp->data;
00120     if (CCNSHOULDLOG(ccnr, LM_128, CCNL_FINE))
00121         ccnr_debug_ccnb(ccnr, __LINE__, "r_proto_answer_req", NULL,
00122                         info->interest_ccnb, info->pi->offset[CCN_PI_E]);
00123     
00124     content = r_store_lookup(ccnr, info->interest_ccnb, info->pi, info->interest_comps);
00125     if (content != NULL) {
00126         struct fdholder *fdholder = r_io_fdholder_from_fd(ccnr, ccn_get_connection_fd(info->h));
00127         if (fdholder != NULL)
00128             r_sendq_face_send_queue_insert(ccnr, r_io_fdholder_from_fd(ccnr, ccn_get_connection_fd(info->h)), content);
00129         res = CCN_UPCALL_RESULT_INTEREST_CONSUMED;
00130         goto Finish;
00131     }
00132     /* commands will potentially generate new content, test if new content is ok */
00133     if ((info->pi->answerfrom & CCN_AOK_NEW) == 0) {
00134         goto Bail;
00135     }
00136     
00137     /* check for command markers */
00138     ncomps = info->interest_comps->n;
00139     if (((marker_comp = ncomps - 2) >= 0) &&
00140         0 == r_util_name_comp_compare(info->interest_ccnb, info->interest_comps, marker_comp, NAME_BE, strlen(NAME_BE))) {
00141         if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINER))
00142             ccnr_debug_ccnb(ccnr, __LINE__, "name_enumeration", NULL,
00143                             info->interest_ccnb, info->pi->offset[CCN_PI_E]);
00144         res = r_proto_begin_enumeration(selfp, kind, info, marker_comp);
00145         goto Finish;
00146     } else if (((marker_comp = ncomps - 3) >= 0) &&
00147                0 == r_util_name_comp_compare(info->interest_ccnb, info->interest_comps, marker_comp, NAME_BE, strlen(NAME_BE)) &&
00148                0 == r_util_name_comp_compare(info->interest_ccnb, info->interest_comps, marker_comp + 1, ccnr->ccnr_keyid->buf, ccnr->ccnr_keyid->length)) {
00149         if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINER))
00150             ccnr_debug_ccnb(ccnr, __LINE__, "name_enumeration_repoid", NULL,
00151                             info->interest_ccnb, info->pi->offset[CCN_PI_E]);
00152         res = r_proto_begin_enumeration(selfp, kind, info, marker_comp);
00153         goto Finish;
00154     } else if (((marker_comp = ncomps - 5) >= 0) &&
00155                0 == r_util_name_comp_compare(info->interest_ccnb, info->interest_comps, marker_comp, NAME_BE, strlen(NAME_BE)) &&
00156                0 == r_util_name_comp_compare(info->interest_ccnb, info->interest_comps, marker_comp + 1, ccnr->ccnr_keyid->buf, ccnr->ccnr_keyid->length)) {
00157         if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINER))
00158             ccnr_debug_ccnb(ccnr, __LINE__, "name_enumeration_continuation",
00159                             NULL, info->interest_ccnb, info->pi->offset[CCN_PI_E]);
00160         res = r_proto_continue_enumeration(selfp, kind, info, marker_comp);
00161         goto Finish;
00162     } else if (((marker_comp = ncomps - 3) > 0) &&
00163                0 == r_util_name_comp_compare(info->interest_ccnb, info->interest_comps, marker_comp, REPO_SW, strlen(REPO_SW))) {
00164         if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINER))
00165             ccnr_debug_ccnb(ccnr, __LINE__, "repo_start_write", NULL,
00166                             info->interest_ccnb, info->pi->offset[CCN_PI_E]);
00167         res = r_proto_start_write(selfp, kind, info, marker_comp);
00168         goto Finish;
00169     } else if (((marker_comp = ncomps - 5) > 0) &&
00170                0 == r_util_name_comp_compare(info->interest_ccnb, info->interest_comps, marker_comp, REPO_SWC, strlen(REPO_SWC))) {
00171         if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINER))
00172             ccnr_debug_ccnb(ccnr, __LINE__, "repo_start_write_checked",
00173                             NULL, info->interest_ccnb, info->pi->offset[CCN_PI_E]);
00174         res = r_proto_start_write_checked(selfp, kind, info, marker_comp);
00175         goto Finish;
00176     } else if (((marker_comp = 0) == 0) &&
00177                name_comp_equal_prefix(info->interest_ccnb, info->interest_comps, marker_comp, REPO_AF, strlen(REPO_AF))) {
00178         if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINER))
00179             ccnr_debug_ccnb(ccnr, __LINE__, "repo_bulk_import",
00180                             NULL, info->interest_ccnb, info->pi->offset[CCN_PI_E]);
00181         res = r_proto_bulk_import(selfp, kind, info, marker_comp);
00182         goto Finish;
00183     }
00184     goto Bail;
00185 Bail:
00186     res = CCN_UPCALL_RESULT_ERR;
00187 Finish:
00188     ccn_charbuf_destroy(&msg);
00189     ccn_charbuf_destroy(&name);
00190     ccn_charbuf_destroy(&keylocator);
00191     ccn_charbuf_destroy(&reply_body);
00192     ccn_charbuf_destroy(&signed_info);
00193     return(res);
00194 }
00195 
00196 // XXX these should probably be rationalized and added to ccn_name_util.c
00197 /**
00198  * Compare a name component at index i to bytes in buf and return 1
00199  * if they are equal in the first length bytes.  The name component
00200  * must contain at least length bytes for this comparison to return
00201  * equality.
00202  * @returns 1 for equality, 0 for inequality.
00203  */
00204 static int
00205 name_comp_equal_prefix(const unsigned char *data,
00206                    const struct ccn_indexbuf *indexbuf,
00207                    unsigned int i, const void *buf, size_t length)
00208 {
00209     const unsigned char *comp_ptr;
00210     size_t comp_size;
00211     
00212     if (ccn_name_comp_get(data, indexbuf, i, &comp_ptr, &comp_size) != 0)
00213         return(0);
00214     if (comp_size < length || memcmp(comp_ptr, buf, length) != 0)
00215         return(0);
00216     return(1);
00217 }
00218 
00219 PUBLIC void
00220 r_proto_uri_listen(struct ccnr_handle *ccnr, struct ccn *ccn, const char *uri,
00221                    ccn_handler p, intptr_t intdata)
00222 {
00223     struct ccn_charbuf *name;
00224     struct ccn_closure *closure = NULL;
00225     
00226     name = ccn_charbuf_create();
00227     ccn_name_from_uri(name, uri);
00228     if (p != NULL) {
00229         closure = calloc(1, sizeof(*closure));
00230         closure->p = p;
00231         closure->data = ccnr;
00232         closure->intdata = intdata;
00233     }
00234     ccn_set_interest_filter(ccn, name, closure);
00235     ccn_charbuf_destroy(&name);
00236 }
00237 
00238 // XXX - need an r_proto_uninit to uninstall the policy
00239 PUBLIC void
00240 r_proto_init(struct ccnr_handle *ccnr) {
00241     // nothing to do
00242 }
00243 /**
00244  * Install the listener for the namespaces that the parsed policy says to serve
00245  * 
00246  * Normal usage is to deactivate the old policy and then activate the new one
00247  */
00248 PUBLIC void
00249 r_proto_activate_policy(struct ccnr_handle *ccnr, struct ccnr_parsed_policy *pp) {
00250     int i;
00251     
00252     for (i = 0; i < pp->namespaces->n; i++) {
00253         if (CCNSHOULDLOG(ccnr, sdfdf, CCNL_INFO))
00254             ccnr_msg(ccnr, "Adding listener for policy namespace %s",
00255                      (char *)pp->store->buf + pp->namespaces->buf[i]);
00256         r_proto_uri_listen(ccnr, ccnr->direct_client,
00257                            (char *)pp->store->buf + pp->namespaces->buf[i],
00258                            r_proto_answer_req, 0);
00259     }
00260     if (CCNSHOULDLOG(ccnr, sdfdf, CCNL_INFO))
00261         ccnr_msg(ccnr, "Adding listener for policy global prefix %s",
00262                  (char *)pp->store->buf + pp->global_prefix_offset);
00263     r_proto_uri_listen(ccnr, ccnr->direct_client,
00264                        (char *)pp->store->buf + pp->global_prefix_offset,
00265                        r_proto_answer_req, 0);    
00266 }
00267 /**
00268  * Uninstall the listener for the namespaces that the parsed policy says to serve
00269  */
00270 PUBLIC void
00271 r_proto_deactivate_policy(struct ccnr_handle *ccnr, struct ccnr_parsed_policy *pp) {
00272     int i;
00273 
00274     if (CCNSHOULDLOG(ccnr, sdfdf, CCNL_INFO))
00275         ccnr_msg(ccnr, "Removing listener for policy global prefix %s",
00276                  (char *)pp->store->buf + pp->global_prefix_offset);
00277     r_proto_uri_listen(ccnr, ccnr->direct_client,
00278                        (char *)pp->store->buf + pp->global_prefix_offset,
00279                        NULL, 0);    
00280     for (i = 0; i < pp->namespaces->n; i++) {
00281         if (CCNSHOULDLOG(ccnr, sdfdf, CCNL_INFO))
00282             ccnr_msg(ccnr, "Removing listener for policy namespace %s",
00283                      (char *)pp->store->buf + pp->namespaces->buf[i]);
00284         r_proto_uri_listen(ccnr, ccnr->direct_client,
00285                            (char *)pp->store->buf + pp->namespaces->buf[i],
00286                            NULL, 0);
00287     }
00288     
00289 }
00290 
00291 
00292 /**
00293  * Construct a charbuf with an encoding of a RepositoryInfo
00294  */ 
00295 PUBLIC int
00296 r_proto_append_repo_info(struct ccnr_handle *ccnr,
00297                          struct ccn_charbuf *rinfo,
00298                          struct ccn_charbuf *names,
00299                          const char *info) {
00300     int res;
00301     struct ccn_charbuf *name = ccn_charbuf_create();
00302     if (name == NULL) return (-1);
00303     res = ccnb_element_begin(rinfo, CCN_DTAG_RepositoryInfo);
00304     res |= ccnb_tagged_putf(rinfo, CCN_DTAG_Version, "%s", "1.1");
00305     res |= ccnb_tagged_putf(rinfo, CCN_DTAG_Type, "%s", (names != NULL) ? "DATA" : "INFO");
00306     res |= ccnb_tagged_putf(rinfo, CCN_DTAG_RepositoryVersion, "%s", "2.0");
00307     res |= ccnb_element_begin(rinfo, CCN_DTAG_GlobalPrefixName); // same structure as Name
00308     res |= ccnb_element_end(rinfo);
00309     ccn_name_init(name);
00310     res |= ccn_name_from_uri(name, (char *)ccnr->parsed_policy->store->buf + ccnr->parsed_policy->global_prefix_offset);
00311     res |= ccn_name_append_components(rinfo, name->buf, 1, name->length - 1);
00312     res |= ccnb_tagged_putf(rinfo, CCN_DTAG_LocalName, "%s", "Repository");
00313     if (names != NULL)
00314         res |= ccn_charbuf_append_charbuf(rinfo, names);
00315     if (info != NULL)
00316         res |= ccnb_tagged_putf(rinfo, CCN_DTAG_InfoString, "%s", info);
00317     // There is an optional CCN_DTAG_InfoString in the encoding here, like the LocalName
00318     res |= ccnb_element_end(rinfo); // CCN_DTAG_RepositoryInfo
00319     ccn_charbuf_destroy(&name);
00320     return (res);
00321 }
00322 
00323 static struct ccn_charbuf *
00324 r_proto_mktemplate(struct ccnr_expect_content *md, struct ccn_upcall_info *info)
00325 {
00326     struct ccn_charbuf *templ = ccn_charbuf_create();
00327     ccnb_element_begin(templ, CCN_DTAG_Interest); // same structure as Name
00328     ccnb_element_begin(templ, CCN_DTAG_Name);
00329     ccnb_element_end(templ); /* </Name> */
00330     // XXX - use pubid if possible
00331     // XXX - if start-write was scoped, use scope here?
00332     ccnb_tagged_putf(templ, CCN_DTAG_MinSuffixComponents, "%d", 1);
00333     ccnb_tagged_putf(templ, CCN_DTAG_MaxSuffixComponents, "%d", 1);
00334     ccnb_element_end(templ); /* </Interest> */
00335     return(templ);
00336 }
00337 
00338 PUBLIC enum ccn_upcall_res
00339 r_proto_expect_content(struct ccn_closure *selfp,
00340                  enum ccn_upcall_kind kind,
00341                  struct ccn_upcall_info *info)
00342 {
00343     struct ccn_charbuf *name = NULL;
00344     struct ccn_charbuf *templ = NULL;
00345     const unsigned char *ccnb = NULL;
00346     size_t ccnb_size = 0;
00347     const unsigned char *ib = NULL; /* info->interest_ccnb */
00348     struct ccn_indexbuf *ic = NULL;
00349     int res;
00350     struct ccnr_expect_content *md = selfp->data;
00351     struct ccnr_handle *ccnr = NULL;
00352     struct content_entry *content = NULL;
00353     int i;
00354     int empty_slots;
00355     intmax_t segment;
00356 
00357     if (kind == CCN_UPCALL_FINAL) {
00358         if (md != NULL) {
00359             selfp->data = NULL;
00360             free(md);
00361             md = NULL;
00362         }
00363         free(selfp);
00364         return(CCN_UPCALL_RESULT_OK);
00365     }
00366     if (md == NULL) {
00367         return(CCN_UPCALL_RESULT_ERR);
00368     }
00369     if (md->done)
00370         return(CCN_UPCALL_RESULT_ERR);
00371     ccnr = (struct ccnr_handle *)md->ccnr;
00372     if (kind == CCN_UPCALL_INTEREST_TIMED_OUT) {
00373         if (md->tries > CCNR_MAX_RETRY) {
00374             ccnr_debug_ccnb(ccnr, __LINE__, "fetch_failed", NULL,
00375                             info->interest_ccnb, info->pi->offset[CCN_PI_E]);
00376             return(CCN_UPCALL_RESULT_ERR);
00377         }
00378         md->tries++;
00379         return(CCN_UPCALL_RESULT_REEXPRESS);
00380     }
00381     if (kind == CCN_UPCALL_CONTENT_UNVERIFIED) {
00382         // XXX - Some forms of key locator can confuse libccn. Don't provoke it to fetch keys until that is hardened.
00383         if (CCNSHOULDLOG(ccnr, sdfdf, CCNL_FINE))
00384             ccnr_debug_ccnb(ccnr, __LINE__, "key_needed", NULL, info->content_ccnb, info->pco->offset[CCN_PCO_E]);
00385     }
00386     switch (kind) {
00387         case CCN_UPCALL_CONTENT:
00388         case CCN_UPCALL_CONTENT_UNVERIFIED:
00389 #if (CCN_API_VERSION >= 4004)
00390         case CCN_UPCALL_CONTENT_RAW:
00391         case CCN_UPCALL_CONTENT_KEYMISSING:
00392 #endif
00393             break;
00394         default:
00395             return(CCN_UPCALL_RESULT_ERR);
00396     }
00397     
00398     ccnb = info->content_ccnb;
00399     ccnb_size = info->pco->offset[CCN_PCO_E];
00400     ib = info->interest_ccnb;
00401     ic = info->interest_comps;
00402     
00403     content = process_incoming_content(ccnr, r_io_fdholder_from_fd(ccnr, ccn_get_connection_fd(info->h)),
00404                                        (void *)ccnb, ccnb_size);
00405     if (content == NULL) {
00406         ccnr_msg(ccnr, "r_proto_expect_content: failed to process incoming content");
00407         return(CCN_UPCALL_RESULT_ERR);
00408     }
00409     r_store_commit_content(ccnr, content);
00410     r_proto_initiate_key_fetch(ccnr, ccnb, info->pco, 0,
00411                                r_store_content_cookie(ccnr, content));
00412     
00413     md->tries = 0;
00414     segment = r_util_segment_from_component(ib, ic->buf[ic->n - 2], ic->buf[ic->n - 1]);
00415 
00416     if (ccn_is_final_block(info) == 1)
00417         md->final = segment;
00418     
00419     if (md->keyfetch != 0 && segment <= 0) {
00420         /* This should either be a key, or a link to get to it. */
00421         if (info->pco->type == CCN_CONTENT_LINK) {
00422             r_proto_initiate_key_fetch(ccnr, ccnb, info->pco, 1, md->keyfetch);
00423         }
00424         else if (info->pco->type == CCN_CONTENT_KEY) {
00425             if (CCNSHOULDLOG(ccnr, sdfdf, CCNL_FINE))
00426                 ccnr_msg(ccnr, "key_arrived %u", (unsigned)(md->keyfetch));
00427             // XXX - should check that we got the right key.
00428         }
00429         else {
00430             // not a key or a link.  Log it so we have a clue.
00431             ccnr_msg(ccnr, "ERROR - got something else when trying to fetch key for item %u", (unsigned)(md->keyfetch));
00432         }
00433     }
00434     
00435     // Unsegmented content should skip pipeline processing.
00436     if (segment < 0) {
00437         if (md->expect_complete != NULL) {
00438             (md->expect_complete)(selfp, kind, info);
00439         }
00440         return(CCN_UPCALL_RESULT_OK);
00441     }
00442     
00443     /* retire the current segment and any segments beyond the final one */
00444     empty_slots = 0;
00445     for (i = 0; i < CCNR_PIPELINE; i++) {
00446         if (md->outstanding[i] == segment || ((md->final > -1) && (md->outstanding[i] > md->final)))
00447             md->outstanding[i] = -1;
00448         if (md->outstanding[i] == -1)
00449             empty_slots++;
00450     
00451     }
00452     md->done = (md->final > -1) && (empty_slots == CCNR_PIPELINE);
00453     // if there is a completion handler set up, and we've got all the blocks
00454     // call it -- note that this may not be the last block if they arrive out of order.
00455     if (md->done && (md->expect_complete != NULL))
00456         (md->expect_complete)(selfp, kind, info);
00457                               
00458     if (md->final > -1) {
00459         return (CCN_UPCALL_RESULT_OK);
00460     }
00461 
00462     name = ccn_charbuf_create();
00463     if (ic->n < 2) abort();    
00464     templ = r_proto_mktemplate(md, info);
00465     /* fill the pipeline with new requests */
00466     for (i = 0; i < CCNR_PIPELINE; i++) {
00467         if (md->outstanding[i] == -1) {
00468             ccn_name_init(name);
00469             res = ccn_name_append_components(name, ib, ic->buf[0], ic->buf[ic->n - 2]);
00470             if (res < 0) abort();
00471             ccn_name_append_numeric(name, CCN_MARKER_SEQNUM, ++(selfp->intdata));
00472             res = ccn_express_interest(info->h, name, selfp, templ);
00473             if (res < 0) abort();
00474             md->outstanding[i] = selfp->intdata;
00475         }
00476     }
00477     ccn_charbuf_destroy(&templ);
00478     ccn_charbuf_destroy(&name);
00479     
00480     return(CCN_UPCALL_RESULT_OK);
00481 }
00482 
00483 static int
00484 r_proto_policy_update(struct ccn_schedule *sched,
00485                       void *clienth,
00486                       struct ccn_scheduled_event *ev,
00487                       int flags)
00488 {
00489     struct ccnr_handle *ccnr = clienth;
00490     struct ccn_charbuf *name = ev->evdata;
00491     struct content_entry *content = NULL;
00492     const unsigned char *content_msg = NULL;
00493     const unsigned char *vers = NULL;
00494     size_t vers_size = 0;
00495     struct ccn_parsed_ContentObject pco = {0};
00496     struct ccn_indexbuf *nc;
00497     struct ccn_charbuf *policy = NULL;
00498     struct ccn_charbuf *policy_link_cob = NULL;
00499     struct ccn_charbuf *policyFileName = NULL;
00500     const unsigned char *buf = NULL;
00501     size_t length = 0;
00502     struct ccnr_parsed_policy *pp;
00503     int segment = -1;
00504     int final = 0;
00505     int res;
00506     int ans = -1;
00507     int fd = -1;
00508     
00509     if ((flags & CCN_SCHEDULE_CANCEL) != 0) {
00510         ans = 0;
00511         goto Bail;
00512     }
00513     
00514     policy = ccn_charbuf_create();
00515     nc = ccn_indexbuf_create();
00516     do {
00517         ccn_name_append_numeric(name, CCN_MARKER_SEQNUM, ++segment);
00518         content = r_store_lookup_ccnb(ccnr, name->buf, name->length);
00519         if (content == NULL) {
00520             ccnr_debug_ccnb(ccnr, __LINE__, "policy lookup failed for", NULL,
00521                             name->buf, name->length);
00522             goto Bail;
00523         }
00524         ccn_name_chop(name, NULL, -1);
00525         content_msg = r_store_content_base(ccnr, content);
00526         res = ccn_parse_ContentObject(content_msg, r_store_content_size(ccnr, content), &pco, nc);
00527         res = ccn_ref_tagged_BLOB(CCN_DTAG_Content, content_msg,
00528                                   pco.offset[CCN_PCO_B_Content],
00529                                   pco.offset[CCN_PCO_E_Content],
00530                                   &buf, &length);
00531         ccn_charbuf_append(policy, buf, length);
00532         final = r_util_is_final_pco(content_msg, &pco, nc);
00533     } while (!final);
00534     
00535     pp = ccnr_parsed_policy_create();
00536     if (pp == NULL) {
00537         ccnr_msg(ccnr, "Parsed policy allocation error");
00538         goto Bail;
00539     }
00540     memmove(pp->version, vers, vers_size);
00541     if (r_proto_parse_policy(ccnr, policy->buf, policy->length, pp) < 0) {
00542         ccnr_msg(ccnr, "Malformed policy");
00543         goto Bail;
00544     }
00545     res = strcmp((char *)pp->store->buf + pp->global_prefix_offset,
00546                  (char *)ccnr->parsed_policy->store->buf + ccnr->parsed_policy->global_prefix_offset);
00547     if (0 != res) {
00548         ccnr_msg(ccnr, "Policy global prefix mismatch");
00549         goto Bail;
00550     }
00551     policy_link_cob = ccnr_init_policy_link_cob(ccnr, ccnr->direct_client, name);
00552     if (policy_link_cob != NULL)
00553         ccnr->policy_link_cob = policy_link_cob;
00554     policyFileName = ccn_charbuf_create();
00555     ccn_charbuf_putf(policyFileName, "%s/repoPolicy", ccnr->directory);
00556     fd = open(ccn_charbuf_as_string(policyFileName), O_WRONLY | O_CREAT, 0666);
00557     if (fd < 0) {
00558         ccnr_msg(ccnr, "open policy: %s (errno = %d)", strerror(errno), errno);
00559         goto Bail;
00560     }
00561     lseek(fd, 0, SEEK_SET);
00562     res = write(fd, ccnr->policy_link_cob->buf, ccnr->policy_link_cob->length);
00563     if (res == -1) {
00564         ccnr_msg(ccnr, "write policy: %s (errno = %d)", strerror(errno), errno);
00565         goto Bail;
00566     }
00567     res = ftruncate(fd, ccnr->policy_link_cob->length);
00568     if (res == -1) {
00569         ccnr_msg(ccnr, "Policy truncate %u :%s (errno = %d)",
00570                  fd, strerror(errno), errno);
00571         goto Bail;
00572     }
00573     close(fd);
00574     fd = -1;
00575     r_proto_deactivate_policy(ccnr, ccnr->parsed_policy);
00576     ccnr_parsed_policy_destroy(&ccnr->parsed_policy);
00577     ccnr->parsed_policy = pp;
00578     r_proto_activate_policy(ccnr, pp);
00579     
00580     ans = 0;
00581     
00582 Bail:
00583     ccn_charbuf_destroy(&name);
00584     ccn_indexbuf_destroy(&nc);
00585     ccn_charbuf_destroy(&policy);
00586     ccn_charbuf_destroy(&policyFileName);
00587     if (fd >= 0) close(fd);
00588     return (ans);
00589     
00590 }    
00591 
00592 static int
00593 r_proto_policy_complete(struct ccn_closure *selfp,
00594                         enum ccn_upcall_kind kind,
00595                         struct ccn_upcall_info *info)
00596 {
00597     struct ccnr_expect_content *md = selfp->data;
00598     struct ccnr_handle *ccnr = (struct ccnr_handle *)md->ccnr;
00599     const unsigned char *ccnb;
00600     size_t ccnb_size;
00601     const unsigned char *vers = NULL;
00602     size_t vers_size = 0;
00603     struct ccn_indexbuf *cc;
00604     struct ccn_charbuf *name;
00605     int res;
00606     
00607     // the version of the new policy must be greater than the exist one
00608     // or we will not activate it and update the link to point to it.
00609     
00610     ccnb = info->content_ccnb;
00611     ccnb_size = info->pco->offset[CCN_PCO_E];
00612     cc = info->content_comps;
00613     ccn_name_comp_get(ccnb, cc, cc->n - 3, &vers, &vers_size);
00614     if (vers_size != 7 || vers[0] != CCN_MARKER_VERSION)
00615         return(-1);
00616     if (memcmp(vers, ccnr->parsed_policy->version, sizeof(ccnr->parsed_policy->version)) <= 0) {
00617         if (CCNSHOULDLOG(ccnr, LM_128, CCNL_INFO))
00618             ccnr_debug_ccnb(ccnr, __LINE__, "r_proto_policy_complete older policy ignored", NULL,
00619                             ccnb, ccnb_size);        
00620         return (-1);
00621     }
00622     // all components not including segment
00623     name = ccn_charbuf_create();
00624     res = ccn_name_init(name);
00625     ccn_name_append_components(name, ccnb, cc->buf[0], cc->buf[cc->n - 2]);
00626     ccn_schedule_event(ccnr->sched, 500, r_proto_policy_update, name, 0);
00627     if (CCNSHOULDLOG(ccnr, LM_128, CCNL_FINEST))
00628         ccnr_msg(ccnr,"r_proto_policy_complete update scheduled");        
00629     
00630     return (0);
00631 }
00632 
00633 static enum ccn_upcall_res
00634 r_proto_start_write(struct ccn_closure *selfp,
00635                     enum ccn_upcall_kind kind,
00636                     struct ccn_upcall_info *info,
00637                     int marker_comp)
00638 {
00639     struct ccnr_handle *ccnr = NULL;
00640     struct ccn_charbuf *templ = NULL;
00641     struct ccn_closure *incoming = NULL;
00642     struct ccnr_expect_content *expect_content = NULL;
00643     struct ccn_charbuf *reply_body = NULL;
00644     struct ccn_charbuf *name = NULL;
00645     struct ccn_indexbuf *ic = NULL;
00646     enum ccn_upcall_res ans = CCN_UPCALL_RESULT_ERR;
00647     struct ccn_charbuf *msg = NULL;
00648     int res = 0;
00649     int start = 0;
00650     int end = 0;
00651     int is_policy = 0;
00652     int i;
00653     struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
00654     
00655     // XXX - Check for valid nonce
00656     // XXX - Check for pubid - if present and not ours, do not respond.
00657     // Check for answer origin kind.
00658     // If Exclude is there, there might be something fishy going on.
00659     
00660     ccnr = (struct ccnr_handle *)selfp->data;
00661     if (ccnr->start_write_scope_limit < 3) {
00662         start = info->pi->offset[CCN_PI_B_Scope];
00663         end = info->pi->offset[CCN_PI_E_Scope];
00664         if (start == end || info->pi->scope > ccnr->start_write_scope_limit) {
00665             if (CCNSHOULDLOG(ccnr, LM_128, CCNL_INFO))
00666                 ccnr_msg(ccnr, "r_proto_start_write: interest scope exceeds limit");
00667             return(CCN_UPCALL_RESULT_OK);
00668         }
00669     }
00670     // don't handle the policy file here
00671     start = info->pi->offset[CCN_PI_B_Name];
00672     end = info->interest_comps->buf[marker_comp - 1]; // not including version or marker
00673     name = ccn_charbuf_create();
00674     ccn_charbuf_append(name, info->interest_ccnb + start, end - start);
00675     ccn_charbuf_append_closer(name);
00676     if (0 ==ccn_compare_names(name->buf, name->length,
00677                               ccnr->policy_name->buf, ccnr->policy_name->length))
00678         is_policy = 1;
00679     
00680     /* Generate our reply */
00681     start = info->pi->offset[CCN_PI_B_Name];
00682     end = info->interest_comps->buf[info->pi->prefix_comps];
00683     name->length = 0;
00684     ccn_charbuf_append(name, info->interest_ccnb + start, end - start);
00685     ccn_charbuf_append_closer(name);
00686     msg = ccn_charbuf_create();
00687     reply_body = ccn_charbuf_create();
00688     r_proto_append_repo_info(ccnr, reply_body, NULL, NULL);
00689     sp.freshness = 12; /* seconds */
00690     res = ccn_sign_content(info->h, msg, name, &sp,
00691                            reply_body->buf, reply_body->length);
00692     if (res < 0)
00693         goto Bail;
00694     if (CCNSHOULDLOG(ccnr, LM_128, CCNL_FINE))
00695         ccnr_debug_ccnb(ccnr, __LINE__, "r_proto_start_write response", NULL,
00696                         msg->buf, msg->length);
00697     res = ccn_put(info->h, msg->buf, msg->length);
00698     if (res < 0) {
00699         ccnr_debug_ccnb(ccnr, __LINE__, "r_proto_start_write ccn_put FAILED", NULL,
00700                         msg->buf, msg->length);
00701         goto Bail;
00702     }
00703 
00704     /* Send an interest for segment 0 */
00705     expect_content = calloc(1, sizeof(*expect_content));
00706     if (expect_content == NULL)
00707         goto Bail;
00708     expect_content->ccnr = ccnr;
00709     expect_content->final = -1;
00710     for (i = 0; i < CCNR_PIPELINE; i++)
00711         expect_content->outstanding[i] = -1;
00712     if (is_policy) {
00713         expect_content->expect_complete = &r_proto_policy_complete;
00714         if (CCNSHOULDLOG(ccnr, LM_128, CCNL_FINE))
00715             ccnr_msg(ccnr, "r_proto_start_write: is policy file");
00716     }
00717     incoming = calloc(1, sizeof(*incoming));
00718     if (incoming == NULL)
00719         goto Bail;
00720     incoming->p = &r_proto_expect_content;
00721     incoming->data = expect_content;
00722     templ = r_proto_mktemplate(expect_content, NULL);
00723     ic = info->interest_comps;
00724     ccn_name_init(name);
00725     ccn_name_append_components(name, info->interest_ccnb, ic->buf[0], ic->buf[marker_comp]);
00726     ccn_name_append_numeric(name, CCN_MARKER_SEQNUM, 0);
00727     expect_content->outstanding[0] = 0;
00728     res = ccn_express_interest(info->h, name, incoming, templ);
00729     if (res >= 0) {
00730         /* upcall will free these when it is done. */
00731         incoming = NULL;
00732         expect_content = NULL;
00733         ans = CCN_UPCALL_RESULT_INTEREST_CONSUMED;
00734     }
00735     else {
00736         ccnr_debug_ccnb(ccnr, __LINE__, "r_proto_start_write ccn_express_interest FAILED", NULL,
00737                         name->buf, name->length);
00738         goto Bail;
00739     }
00740     
00741 Bail:
00742     if (incoming != NULL)
00743         free(incoming);
00744     if (expect_content != NULL)
00745         free(expect_content);
00746     ccn_charbuf_destroy(&templ);
00747     ccn_charbuf_destroy(&name);
00748     ccn_charbuf_destroy(&reply_body);
00749     ccn_charbuf_destroy(&msg);
00750     return(ans);
00751 }
00752 
00753 static enum ccn_upcall_res
00754 r_proto_start_write_checked(struct ccn_closure *selfp,
00755                             enum ccn_upcall_kind kind,
00756                             struct ccn_upcall_info *info,
00757                             int marker_comp)
00758 {
00759     struct ccnr_handle *ccnr = NULL;
00760     enum ccn_upcall_res ans = CCN_UPCALL_RESULT_OK;
00761     struct ccn_indexbuf *ic = NULL;
00762     struct content_entry *content = NULL;
00763     struct ccn_parsed_interest parsed_interest = {0};
00764     struct ccn_parsed_interest *pi = &parsed_interest;
00765     struct ccn_charbuf *name = NULL;
00766     struct ccn_charbuf *interest = NULL;
00767     struct ccn_indexbuf *comps = NULL;
00768     struct ccn_charbuf *msg = NULL;
00769     struct ccn_charbuf *reply_body = NULL;
00770     int start = 0;
00771     int end = 0;
00772     struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
00773     int res = 0;
00774     
00775     // XXX - do we need to disallow the policy file here too?
00776     ccnr = (struct ccnr_handle *)selfp->data;
00777     if (ccnr->start_write_scope_limit < 3) {
00778         start = info->pi->offset[CCN_PI_B_Scope];
00779         end = info->pi->offset[CCN_PI_E_Scope];
00780         if (start == end || info->pi->scope > ccnr->start_write_scope_limit) {
00781             if (CCNSHOULDLOG(ccnr, LM_128, CCNL_INFO))
00782                 ccnr_msg(ccnr, "r_proto_start_write_checked: interest scope exceeds limit");
00783             return(CCN_UPCALL_RESULT_OK);
00784         }
00785     }
00786     name = ccn_charbuf_create();
00787     ccn_name_init(name);
00788     ic = info->interest_comps;
00789     ccn_name_append_components(name, info->interest_ccnb, ic->buf[0], ic->buf[marker_comp]);
00790     ccn_name_append_components(name, info->interest_ccnb, ic->buf[marker_comp + 2], ic->buf[ic->n - 1]);
00791     // Make an interest for the exact item we're checking
00792     interest = ccn_charbuf_create();
00793     ccnb_element_begin(interest, CCN_DTAG_Interest);
00794     ccn_charbuf_append_charbuf(interest, name);
00795     ccnb_element_end(interest); /* </Interest> */
00796     // Parse it
00797     comps = ccn_indexbuf_create();
00798     res = ccn_parse_interest(interest->buf, interest->length, pi, comps);
00799     if (res < 0)
00800         abort();
00801     if (CCNSHOULDLOG(ccnr, LM_128, CCNL_FINE))
00802         ccnr_debug_ccnb(ccnr, __LINE__, "r_proto_start_write_checked looking for", NULL,
00803                         interest->buf, interest->length);
00804     content = r_store_lookup(ccnr, interest->buf, pi, comps);
00805     ccn_charbuf_destroy(&interest);
00806     ccn_indexbuf_destroy(&comps);
00807     if (content == NULL) {
00808         if (CCNSHOULDLOG(ccnr, LM_128, CCNL_FINE))
00809             ccnr_msg(ccnr, "r_proto_start_write_checked: NOT PRESENT");
00810         // XXX - dropping into the start_write case means we do not check the provided digest when fetching, so this is not completely right.
00811         return(r_proto_start_write(selfp, kind, info, marker_comp));
00812     }
00813     // what's the return value if the item is in the repository already?
00814     // if it does have it -- getRepoInfo(interest.name(), null, target_names)
00815     // response has local name as the full name of the thing we claim to have --
00816     // take the command marker and nonce out of the middle of the incoming interest,
00817     // which is what we have in the "name" of the interest we created to check the content.
00818     ///// begin copied code
00819     /* Generate our reply */
00820     msg = ccn_charbuf_create();
00821     reply_body = ccn_charbuf_create();
00822     r_proto_append_repo_info(ccnr, reply_body, name, NULL);
00823     start = info->pi->offset[CCN_PI_B_Name];
00824     end = info->interest_comps->buf[info->pi->prefix_comps];
00825     name->length = 0;
00826     ccn_charbuf_append(name, info->interest_ccnb + start, end - start);
00827     ccn_charbuf_append_closer(name);
00828     sp.freshness = 12; /* Seconds */
00829     res = ccn_sign_content(info->h, msg, name, &sp,
00830                            reply_body->buf, reply_body->length);
00831     if (res < 0)
00832         goto Bail;
00833     if (CCNSHOULDLOG(ccnr, LM_128, CCNL_FINE))
00834         ccnr_msg(ccnr, "r_proto_start_write_checked PRESENT");
00835     res = ccn_put(info->h, msg->buf, msg->length);
00836     if (res < 0) {
00837         // note the error somehow.
00838         ccnr_debug_ccnb(ccnr, __LINE__, "r_proto_start_write_checked ccn_put FAILED", NULL,
00839                         msg->buf, msg->length);
00840     }
00841     //// end of copied code
00842 Bail:
00843     ccn_charbuf_destroy(&name);
00844     ccn_charbuf_destroy(&reply_body);
00845     ccn_charbuf_destroy(&msg);
00846     return(ans);
00847 }
00848 
00849 /**
00850  * Returns 1 if the Exclude in the interest described by the info parameter
00851  * would exclude the full name in name.
00852  */
00853 static int
00854 r_proto_check_exclude(struct ccnr_handle *ccnr,
00855                       struct ccn_upcall_info *info,
00856                       struct ccn_charbuf *name)
00857 {
00858     struct ccn_buf_decoder decoder;
00859     struct ccn_buf_decoder *d = NULL;
00860     const unsigned char *comp = NULL;
00861     size_t comp_size;
00862     size_t name_comp_size;
00863     struct ccn_indexbuf *name_comps = NULL;
00864     const unsigned char *name_string = NULL;
00865     int nc;
00866     int ci;
00867     int res;
00868     int ans = 0;
00869     
00870     if (info->pi->offset[CCN_PI_B_Exclude] < info->pi->offset[CCN_PI_E_Exclude]) {
00871         d = ccn_buf_decoder_start(&decoder,
00872                                   info->interest_ccnb + info->pi->offset[CCN_PI_B_Exclude],
00873                                   info->pi->offset[CCN_PI_E_Exclude] -
00874                                   info->pi->offset[CCN_PI_B_Exclude]);
00875         
00876         // handle easy case of <Exclude><Component>...</Exclude>
00877         // XXX - this may need to be better, but not necessarily complete
00878         if (ccn_buf_match_dtag(d, CCN_DTAG_Exclude)) {
00879             ccn_buf_advance(d);
00880         } else 
00881             goto Bail;
00882         // there may be something to check, so get the components of the name
00883         name_comps = ccn_indexbuf_create();
00884         nc = ccn_name_split(name, name_comps);
00885         // the component in the name we are matching is last plus one of the interest
00886         // but ci includes an extra value for the end of the last component
00887         ci = info->interest_comps->n;
00888         res = ccn_name_comp_get(name->buf, name_comps, ci - 1, &name_string, &name_comp_size);
00889         if (res < 0)
00890             goto Bail;
00891         while (ccn_buf_match_dtag(d, CCN_DTAG_Component)) {
00892             ccn_buf_advance(d);
00893             comp_size = 0;
00894             if (ccn_buf_match_blob(d, &comp, &comp_size))
00895                 ccn_buf_advance(d);
00896             ccn_buf_check_close(d);
00897             if (comp_size == name_comp_size) {
00898                 res = memcmp(comp, name_string, comp_size);
00899                 if (res == 0) {
00900                     ans = 1;
00901                     goto Bail; /* One of the explicit excludes */
00902                 }
00903                 if (res > 0)
00904                     break;
00905             }
00906         }
00907     }
00908     
00909 Bail:
00910     ccn_indexbuf_destroy(&name_comps);
00911     if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINE))
00912         ccnr_msg(ccnr, "r_proto_check_exclude: do%s exclude", (ans == 1) ? "" : " not");
00913     return(ans);
00914 }
00915 
00916 #define ENUMERATION_STATE_TICK_MICROSEC 1000000
00917 /**
00918  * Remove expired enumeration table entries
00919  */
00920 static int
00921 reap_enumerations(struct ccn_schedule *sched,
00922                   void *clienth,
00923                   struct ccn_scheduled_event *ev,
00924                   int flags)
00925 {
00926     struct ccnr_handle *ccnr = clienth;
00927     struct hashtb_enumerator ee;
00928     struct hashtb_enumerator *e = &ee;
00929     struct enum_state *es = NULL;
00930     
00931     if ((flags & CCN_SCHEDULE_CANCEL) != 0) {
00932         ccnr->reap_enumerations = NULL;
00933         return(0);
00934     }
00935     hashtb_start(ccnr->enum_state_tab, e);
00936     for (es = e->data; es != NULL; es = e->data) {
00937         if (es->active != ES_ACTIVE &&
00938             r_util_timecmp(es->lastuse_sec + es->lifetime, es->lastuse_usec,
00939                             ccnr->sec, ccnr->usec) <= 0) {
00940             if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINER))
00941                 ccnr_debug_ccnb(ccnr, __LINE__, "reap enumeration state", NULL,
00942                                 es->name->buf, es->name->length);            
00943             // everything but the name has already been destroyed
00944             ccn_charbuf_destroy(&es->name);
00945             // remove the entry from the hash table
00946             hashtb_delete(e);
00947         }
00948         hashtb_next(e);
00949     }
00950     hashtb_end(e);
00951     if (hashtb_n(ccnr->enum_state_tab) == 0) {
00952         ccnr->reap_enumerations = NULL;
00953         return(0);
00954     }
00955     return(ENUMERATION_STATE_TICK_MICROSEC);
00956 }
00957 static void
00958 reap_enumerations_needed(struct ccnr_handle *ccnr)
00959 {
00960     if (ccnr->reap_enumerations == NULL)
00961         ccnr->reap_enumerations = ccn_schedule_event(ccnr->sched,
00962                                                      ENUMERATION_STATE_TICK_MICROSEC,
00963                                                      reap_enumerations,
00964                                                      NULL, 0);
00965 }
00966 
00967 static enum ccn_upcall_res
00968 r_proto_begin_enumeration(struct ccn_closure *selfp,
00969                           enum ccn_upcall_kind kind,
00970                           struct ccn_upcall_info *info,
00971                           int marker_comp)
00972 {
00973     struct ccnr_handle *ccnr = NULL;
00974     enum ccn_upcall_res ans = CCN_UPCALL_RESULT_ERR;
00975     struct ccn_parsed_interest parsed_interest = {0};
00976     struct ccn_parsed_interest *pi = &parsed_interest;
00977     struct hashtb_enumerator enumerator = {0};
00978     struct hashtb_enumerator *e = &enumerator;
00979     struct ccn_charbuf *name = NULL;
00980     struct ccn_charbuf *cob = NULL;
00981     struct ccn_charbuf *interest = NULL;
00982     struct ccn_indexbuf *comps = NULL;
00983     int res;
00984     struct content_entry *content = NULL;
00985     struct enum_state *es = NULL;
00986     
00987     ccnr = (struct ccnr_handle *)selfp->data;
00988     // Construct a name up to but not including the begin enumeration marker component
00989     name = ccn_charbuf_create();
00990     ccn_name_init(name);
00991     ccn_name_append_components(name, info->interest_ccnb,
00992                                info->interest_comps->buf[0],
00993                                info->interest_comps->buf[marker_comp]);
00994     // Make an interest for the part of the namespace we are after, from the name
00995     interest = ccn_charbuf_create();
00996     ccnb_element_begin(interest, CCN_DTAG_Interest);
00997     ccn_charbuf_append_charbuf(interest, name);
00998     ccnb_element_end(interest); /* </Interest> */
00999     
01000     // Parse it
01001     comps = ccn_indexbuf_create();
01002     res = ccn_parse_interest(interest->buf, interest->length, pi, comps);
01003     if (res < 0)
01004         abort();
01005     // Look for a previous enumeration under this prefix
01006     hashtb_start(ccnr->enum_state_tab, e);
01007     res = hashtb_seek(e, name->buf, name->length, 0);
01008     es = e->data;
01009     if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINE))
01010         ccnr_debug_ccnb(ccnr, __LINE__, "enumeration: begin hash key", NULL,
01011                         name->buf, name->length);
01012     // Do not restart an active enumeration, it is probably a duplicate interest
01013     // TODO: may need attention when es->active == ES_ACTIVE_PENDING_INACTIVE
01014     if (res == HT_OLD_ENTRY && es->active != ES_INACTIVE) {
01015         if (es->next_segment > 0)
01016             cob = es->cob[(es->next_segment - 1) % ENUM_N_COBS];
01017         if (cob && ccn_content_matches_interest(cob->buf, cob->length, 1, NULL,
01018                                          info->interest_ccnb, info->pi->offset[CCN_PI_E], info->pi)) {
01019             if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINER))
01020                 ccnr_msg(ccnr, "enumeration: duplicate request for last cob");
01021             ccn_put(info->h, cob->buf, cob->length);
01022             es->cob_deferred[(es->next_segment - 1) % ENUM_N_COBS] = 0;
01023             ans = CCN_UPCALL_RESULT_INTEREST_CONSUMED;
01024         } else {
01025             if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINEST)) {
01026                 ccnr_msg(ccnr, "enumeration: restart of active enumeration, or excluded");
01027                 ccnr_debug_ccnb(ccnr, __LINE__, "enum    interest: ", NULL, info->interest_ccnb, info->pi->offset[CCN_PI_E]);
01028                 if (cob != NULL)
01029                     ccnr_debug_ccnb(ccnr, __LINE__, "enum cob content: ", NULL, cob->buf, cob->length);
01030             }
01031             ans = CCN_UPCALL_RESULT_OK;
01032         }
01033         hashtb_end(e);
01034         goto Bail;
01035     }
01036     // Continue to construct the name under which we will respond: %C1.E.be
01037     ccn_name_append_components(name, info->interest_ccnb,
01038                                info->interest_comps->buf[marker_comp],
01039                                info->interest_comps->buf[marker_comp + 1]);
01040     // Append the repository key id %C1.K.%00<repoid>
01041     ccn_name_append(name, ccnr->ccnr_keyid->buf, ccnr->ccnr_keyid->length);
01042     
01043     if (res == HT_NEW_ENTRY || es->starting_cookie != ccnr->cookie) {
01044         // this is a new enumeration, the time is now.
01045         res = ccn_create_version(info->h, name, CCN_V_NOW, 0, 0);
01046         if (es->name != NULL)
01047             ccn_charbuf_destroy(&es->name);
01048         es->name = ccn_charbuf_create();
01049         ccn_charbuf_append_charbuf(es->name, name);
01050         es->starting_cookie = ccnr->cookie; // XXX - a conservative indicator of change
01051     }
01052     ccn_charbuf_destroy(&name);
01053     // check the exclude against the result name
01054     if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINE))
01055         ccnr_debug_ccnb(ccnr, __LINE__, "begin enum: result name", NULL,
01056                         es->name->buf, es->name->length);
01057     
01058     if (r_proto_check_exclude(ccnr, info, es->name) > 0) {
01059         hashtb_end(e);
01060         goto Bail;
01061     }
01062 
01063     // do we have anything that matches this enumeration request?
01064     content = r_store_find_first_match_candidate(ccnr, interest->buf, pi);
01065     if (content != NULL &&
01066         !r_store_content_matches_interest_prefix(ccnr, content, interest->buf, interest->length))
01067         content = NULL;
01068     es->cob[0] = ccn_charbuf_create();
01069     memset(es->cob_deferred, 0, sizeof(es->cob_deferred));
01070     es->reply_body = ccn_charbuf_create();
01071     ccnb_element_begin(es->reply_body, CCN_DTAG_Collection);
01072     es->content = content;
01073     es->interest = interest;
01074     es->interest_comps = comps;
01075     es->next_segment = 0;
01076     es->lastuse_sec = ccnr->sec;
01077     es->lastuse_usec = ccnr->usec;
01078     if (content) {
01079         es->lifetime = 3 * ccn_interest_lifetime_seconds(info->interest_ccnb, pi);
01080         es->active = ES_ACTIVE;
01081     } else {
01082         es->lifetime = ccn_interest_lifetime_seconds(info->interest_ccnb, pi);
01083         es->active = ES_PENDING;
01084     }
01085     hashtb_end(e);
01086     reap_enumerations_needed(ccnr);
01087     if (content)
01088         ans = r_proto_continue_enumeration(selfp, kind, info, marker_comp);
01089     else
01090         ans = CCN_UPCALL_RESULT_OK;
01091     return(ans);
01092     
01093 Bail:
01094     ccn_charbuf_destroy(&name);
01095     ccn_charbuf_destroy(&interest);
01096     ccn_indexbuf_destroy(&comps);
01097     return(ans);
01098 }
01099 
01100 static enum ccn_upcall_res
01101 r_proto_continue_enumeration(struct ccn_closure *selfp,
01102                              enum ccn_upcall_kind kind,
01103                              struct ccn_upcall_info *info,
01104                              int marker_comp) {
01105     // XXX - watch out for pipelined interests for the enumerations -- there
01106     // MUST be an active enumeration continuation before we do anything here.
01107     // Should chop 1 component off interest -- which will look like
01108     // ccnx:/.../%C1.E.be/%C1.M.K%00.../%FD.../%00%02
01109     struct ccn_charbuf *hashkey = NULL;
01110     struct ccn_charbuf *result_name = NULL;
01111     struct ccn_charbuf *cob = NULL;
01112     struct ccn_indexbuf *ic = NULL;
01113     intmax_t segment;
01114     struct enum_state *es = NULL;
01115     struct ccnr_handle *ccnr = NULL;
01116     struct hashtb_enumerator enumerator = {0};
01117     struct hashtb_enumerator *e = &enumerator;
01118     struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
01119     int cobs_deferred;
01120     int i;
01121     int res = 0;
01122     
01123     ccnr = (struct ccnr_handle *)selfp->data;
01124     ic = info->interest_comps;
01125     hashkey=ccn_charbuf_create();
01126     ccn_name_init(hashkey);
01127     ccn_name_append_components(hashkey, info->interest_ccnb,
01128                                info->interest_comps->buf[0],
01129                                info->interest_comps->buf[marker_comp]);
01130     hashtb_start(ccnr->enum_state_tab, e);
01131     res = hashtb_seek(e, hashkey->buf, hashkey->length, 0);
01132     ccn_charbuf_destroy(&hashkey);
01133     if (res != HT_OLD_ENTRY) {
01134         hashtb_end(e);
01135         return(CCN_UPCALL_RESULT_ERR);
01136     }
01137     es = e->data;
01138     if (es->active != ES_ACTIVE && es->active != ES_ACTIVE_PENDING_INACTIVE) {
01139         hashtb_end(e);
01140         return(CCN_UPCALL_RESULT_ERR);
01141     }
01142     // If there is a segment in the request, get the value.
01143     segment = r_util_segment_from_component(info->interest_ccnb,
01144                                             ic->buf[ic->n - 2],
01145                                             ic->buf[ic->n - 1]);
01146     if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINE))
01147         ccnr_msg(ccnr, "enumeration: requested %jd :: expected %jd", segment, es->next_segment);
01148     if (segment >= 0 && segment != es->next_segment) {
01149         // too far in the future for us to process
01150         if (segment > es->next_segment + (ENUM_N_COBS / 2)) {
01151             if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINER))
01152                 ccnr_msg(ccnr, "enumeration: ignoring future segment requested %jd :: expected %jd", segment, es->next_segment);
01153             hashtb_end(e);
01154             return (CCN_UPCALL_RESULT_OK);
01155         }
01156         // if theres a possibility we could have it
01157         if (segment >= es->next_segment - ENUM_N_COBS) {
01158             cob = es->cob[segment % ENUM_N_COBS];
01159             if (cob &&
01160                 ccn_content_matches_interest(cob->buf, cob->length, 1, NULL,
01161                                              info->interest_ccnb, info->pi->offset[CCN_PI_E], info->pi)) {
01162                     if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINER))
01163                         ccnr_msg(ccnr, "enumeration: putting cob for out-of-order segment %jd",
01164                                  segment);
01165                     ccn_put(info->h, cob->buf, cob->length);
01166                     es->cob_deferred[segment % ENUM_N_COBS] = 0;
01167                     if (es->active == ES_ACTIVE_PENDING_INACTIVE) {
01168                         for (i = 0, cobs_deferred = 0; i < ENUM_N_COBS; i++) {
01169                             cobs_deferred += es->cob_deferred[i];
01170                         }
01171                         if (cobs_deferred == 0)
01172                             goto EnumerationComplete;
01173                     }
01174                     hashtb_end(e);
01175                     return (CCN_UPCALL_RESULT_INTEREST_CONSUMED);
01176                 }
01177         }
01178     }
01179 NextSegment:
01180     if (CCNSHOULDLOG(ccnr, blah, CCNL_FINE))
01181         ccnr_msg(ccnr, "enumeration: generating segment %jd", es->next_segment);
01182     es->lastuse_sec = ccnr->sec;
01183     es->lastuse_usec = ccnr->usec;
01184     while (es->content != NULL &&
01185            r_store_content_matches_interest_prefix(ccnr, es->content,
01186                                                    es->interest->buf,
01187                                                    es->interest->length)) {
01188         int save = es->reply_body->length;
01189         ccnb_element_begin(es->reply_body, CCN_DTAG_Link);
01190         ccnb_element_begin(es->reply_body, CCN_DTAG_Name);
01191         ccnb_element_end(es->reply_body); /* </Name> */
01192         res = r_store_name_append_components(es->reply_body, ccnr, es->content, es->interest_comps->n - 1, 1);
01193         ccnb_element_end(es->reply_body); /* </Link> */
01194         if (res == 0) {
01195             /* The name matched exactly, need to skip. */
01196             es->reply_body->length = save;
01197             es->content = r_store_next_child_at_level(ccnr, es->content, es->interest_comps->n - 1);
01198             continue;
01199         }
01200         if (res != 1) {
01201             ccnr_debug_ccnb(ccnr, __LINE__, "oops", NULL, es->interest->buf, es->interest->length);
01202             ccnr_debug_content(ccnr, __LINE__, "oops", NULL, es->content);
01203             abort();
01204         }
01205         es->content = r_store_next_child_at_level(ccnr, es->content, es->interest_comps->n - 1);
01206         if (es->reply_body->length >= 4096) {
01207             result_name = ccn_charbuf_create();
01208             ccn_charbuf_append_charbuf(result_name, es->name);
01209             ccn_name_append_numeric(result_name, CCN_MARKER_SEQNUM, es->next_segment);
01210             sp.freshness = 60;
01211             cob = es->cob[es->next_segment % ENUM_N_COBS];
01212             if (cob == NULL) {
01213                 cob = ccn_charbuf_create();
01214                 es->cob[es->next_segment % ENUM_N_COBS] = cob;
01215             }
01216             cob->length = 0;
01217             res = ccn_sign_content(info->h, cob, result_name, &sp,
01218                                    es->reply_body->buf, 4096);
01219             ccn_charbuf_destroy(&result_name);
01220             if (segment == -1 || segment == es->next_segment) {
01221                 if (CCNSHOULDLOG(ccnr, blah, CCNL_FINER))
01222                     ccnr_msg(ccnr, "enumeration: putting cob for segment %jd", es->next_segment);
01223                 ccn_put(info->h, cob->buf, cob->length);
01224             } else {
01225                 es->cob_deferred[es->next_segment % ENUM_N_COBS] = 1;
01226             }
01227             es->next_segment++;
01228             memmove(es->reply_body->buf, es->reply_body->buf + 4096, es->reply_body->length - 4096);
01229             es->reply_body->length -= 4096;
01230             if (segment >= es->next_segment)
01231                  goto NextSegment;
01232             hashtb_end(e);
01233             return (CCN_UPCALL_RESULT_INTEREST_CONSUMED);
01234         }
01235     }
01236     // we will only get here if we are finishing an in-progress enumeration
01237     ccnb_element_end(es->reply_body); /* </Collection> */
01238     result_name = ccn_charbuf_create();
01239     ccn_charbuf_append_charbuf(result_name, es->name);
01240     ccn_name_append_numeric(result_name, CCN_MARKER_SEQNUM, es->next_segment);
01241     sp.freshness = 60;
01242     sp.sp_flags |= CCN_SP_FINAL_BLOCK;
01243     cob = es->cob[es->next_segment % ENUM_N_COBS];
01244     if (cob == NULL) {
01245         cob = ccn_charbuf_create();
01246         es->cob[es->next_segment % ENUM_N_COBS] = cob;
01247     }
01248     cob->length = 0;
01249     res = ccn_sign_content(info->h, cob, result_name, &sp, es->reply_body->buf,
01250                            es->reply_body->length);
01251     ccn_charbuf_destroy(&result_name);    
01252     if (CCNSHOULDLOG(ccnr, blah, CCNL_FINER))
01253         ccnr_msg(ccnr, "enumeration: putting final cob for segment %jd", es->next_segment);
01254     ccn_put(info->h, cob->buf, cob->length);
01255     es->cob_deferred[es->next_segment % ENUM_N_COBS] = 0;
01256     for (i = 0, cobs_deferred = 0; i < ENUM_N_COBS; i++) {
01257         cobs_deferred += es->cob_deferred[i];
01258     }
01259     if (cobs_deferred > 0) {
01260         if (CCNSHOULDLOG(ccnr, blah, CCNL_FINER))
01261             ccnr_msg(ccnr, "enumeration: %d pending cobs, inactive pending complete",
01262                      cobs_deferred);
01263         es->active = ES_ACTIVE_PENDING_INACTIVE;
01264         hashtb_end(e);
01265         return (CCN_UPCALL_RESULT_INTEREST_CONSUMED);
01266     }
01267 EnumerationComplete:
01268     if (CCNSHOULDLOG(ccnr, blah, CCNL_FINER))
01269         ccnr_msg(ccnr, "enumeration: inactive", es->next_segment);
01270     // The enumeration is complete, free charbufs but leave the name.
01271     es->active = ES_INACTIVE;
01272     ccn_charbuf_destroy(&es->interest);
01273     ccn_charbuf_destroy(&es->reply_body);
01274     for (i = 0; i < ENUM_N_COBS; i++)
01275         ccn_charbuf_destroy(&es->cob[i]);
01276     ccn_indexbuf_destroy(&es->interest_comps);
01277     hashtb_end(e);
01278     return(CCN_UPCALL_RESULT_INTEREST_CONSUMED);
01279 }
01280 
01281 void
01282 r_proto_dump_enums(struct ccnr_handle *ccnr)
01283 {
01284     struct enum_state *es = NULL;
01285     struct hashtb_enumerator enumerator = {0};
01286     struct hashtb_enumerator *e = &enumerator;
01287     
01288     for (hashtb_start(ccnr->enum_state_tab, e); e->data != NULL; hashtb_next(e)) {
01289         es = e->data;
01290         ccnr_msg(ccnr, "Enumeration active: %d, next segment %d, cookie %u",
01291                  es->active, es->next_segment, es->starting_cookie);
01292         ccnr_debug_ccnb(ccnr, __LINE__, "     enum name", NULL,
01293                         es->name->buf, es->name->length);
01294         
01295     }  
01296     hashtb_end(e);
01297 }
01298 
01299 static enum ccn_upcall_res
01300 r_proto_bulk_import(struct ccn_closure *selfp,
01301                           enum ccn_upcall_kind kind,
01302                           struct ccn_upcall_info *info,
01303                           int marker_comp)
01304 {
01305     enum ccn_upcall_res ans = CCN_UPCALL_RESULT_ERR;
01306     struct ccnr_handle *ccnr = NULL;
01307     struct ccn_charbuf *filename = NULL;
01308     struct ccn_charbuf *filename2 = NULL;
01309     const unsigned char *mstart = NULL;
01310     size_t mlength;
01311     struct ccn_indexbuf *ic = NULL;
01312     struct ccn_charbuf *msg = NULL;
01313     struct ccn_charbuf *name = NULL;
01314     struct ccn_charbuf *reply_body = NULL;
01315     struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
01316     const char *infostring = "OK";
01317     int res;
01318     
01319     ccnr = (struct ccnr_handle *)selfp->data;
01320     ccn_name_comp_get(info->interest_ccnb, info->interest_comps, marker_comp,
01321                       &mstart, &mlength);
01322     if (mlength <= strlen(REPO_AF) + 1 || mstart[strlen(REPO_AF)] != '~') {
01323         infostring = "missing or malformed bulk import name component";
01324         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01325         goto Reply;
01326     }
01327     mstart += strlen(REPO_AF) + 1;
01328     mlength -= (strlen(REPO_AF) + 1);
01329     if (memchr(mstart, '/', mlength) != NULL) {
01330         infostring = "bulk import filename must not include directory";
01331         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01332         goto Reply;
01333     }
01334     filename = ccn_charbuf_create();
01335     ccn_charbuf_append_string(filename, "import/");
01336     ccn_charbuf_append(filename, mstart, mlength);
01337     res = r_init_map_and_process_file(ccnr, filename, 0);
01338     if (res == 1) {
01339         infostring = "unable to open bulk import file";
01340         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01341         goto Reply;
01342     }
01343     if (res < 0) {
01344         infostring = "error parsing bulk import file";
01345         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01346         goto Reply;
01347     }
01348     /* we think we can process it */
01349     filename->length = 0;
01350     ccn_charbuf_putf(filename, "%s/import/", ccnr->directory);
01351     ccn_charbuf_append(filename, mstart, mlength);
01352     filename2 = ccn_charbuf_create();
01353     ccn_charbuf_putf(filename2, "%s/import/.", ccnr->directory);
01354     ccn_charbuf_append(filename2, mstart, mlength);
01355     res = rename(ccn_charbuf_as_string(filename),
01356                  ccn_charbuf_as_string(filename2));
01357     if (res < 0) {
01358         infostring = "error renaming bulk import file";
01359         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01360         goto Reply;        
01361     }
01362     filename->length = 0;
01363     ccn_charbuf_append_string(filename, "import/.");
01364     ccn_charbuf_append(filename, mstart, mlength);
01365     res = r_init_map_and_process_file(ccnr, filename, 1);
01366     if (res < 0) {
01367         infostring = "error merging bulk import file";
01368         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01369         // fall through and unlink anyway
01370     }
01371     if (CCNSHOULDLOG(ccnr, sdfdf, CCNL_FINE))
01372         ccnr_msg(ccnr, "unlinking bulk import file %s", ccn_charbuf_as_string(filename2));   
01373     unlink(ccn_charbuf_as_string(filename2));
01374 
01375 Reply:
01376     /* Generate our reply */
01377     name = ccn_charbuf_create();
01378     ccn_name_init(name);
01379     ic = info->interest_comps;
01380     ccn_name_append_components(name, info->interest_ccnb, ic->buf[0], ic->buf[ic->n - 1]);
01381 
01382     msg = ccn_charbuf_create();
01383     reply_body = ccn_charbuf_create();
01384     r_proto_append_repo_info(ccnr, reply_body, NULL, infostring);
01385     sp.freshness = 12; /* Seconds */
01386     res = ccn_sign_content(info->h, msg, name, &sp,
01387                            reply_body->buf, reply_body->length);
01388     if (res < 0)
01389         goto Bail;
01390     res = ccn_put(info->h, msg->buf, msg->length);
01391     if (res < 0) {
01392         ccnr_debug_ccnb(ccnr, __LINE__, "r_proto_bulk_import ccn_put FAILED", NULL,
01393                         msg->buf, msg->length);
01394         goto Bail;
01395     }
01396     ans = CCN_UPCALL_RESULT_INTEREST_CONSUMED;
01397 
01398 Bail:
01399     if (filename != NULL) ccn_charbuf_destroy(&filename);
01400     if (filename2 != NULL) ccn_charbuf_destroy(&filename2);
01401     if (name != NULL) ccn_charbuf_destroy(&name);
01402     if (msg != NULL) ccn_charbuf_destroy(&msg);
01403     if (reply_body != NULL) ccn_charbuf_destroy(&reply_body);
01404     return (ans);
01405 }
01406 
01407 /* Construct a charbuf with an encoding of a Policy object 
01408  *
01409  *  <xs:complexType name="PolicyType">
01410  *      <xs:sequence>
01411  *      <xs:element name="PolicyVersion" type="xs:string"/> 
01412  *      <xs:element name="LocalName" type="xs:string"/>
01413  *      <xs:element name="GlobalPrefix" type="xs:string"/>
01414  *  <!-- 0 or more names -->
01415  *      <xs:element name="Namespace" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
01416  *      </xs:sequence>
01417  *  </xs:complexType>
01418  */ 
01419 PUBLIC int
01420 r_proto_policy_append_basic(struct ccnr_handle *ccnr,
01421                             struct ccn_charbuf *policy,
01422                             const char *version, const char *local_name,
01423                             const char *global_prefix)
01424 {
01425     int res;
01426     res = ccnb_element_begin(policy, CCN_DTAG_Policy);
01427     res |= ccnb_tagged_putf(policy, CCN_DTAG_PolicyVersion, "%s", version);
01428     res |= ccnb_tagged_putf(policy, CCN_DTAG_LocalName, "%s", local_name);
01429     res |= ccnb_tagged_putf(policy, CCN_DTAG_GlobalPrefix, "%s", global_prefix);
01430     res |= ccnb_element_end(policy);
01431     return (res);
01432 }
01433 PUBLIC int
01434 r_proto_policy_append_namespace(struct ccnr_handle *ccnr,
01435                                 struct ccn_charbuf *policy,
01436                                 const char *namespace)
01437 {
01438     int res;
01439     if (policy->length < 2)
01440         return(-1);
01441     policy->length--;   /* remove the closer */
01442     res = ccnb_tagged_putf(policy, CCN_DTAG_Namespace, "%s", namespace);
01443     ccnb_element_end(policy);
01444     return(res);
01445 }
01446 
01447 /**
01448  * Parse a ccnb-encoded policy content object and fill in a ccn_parsed_policy
01449  * structure as the result.
01450  */
01451 PUBLIC int
01452 r_proto_parse_policy(struct ccnr_handle *ccnr, const unsigned char *buf, size_t length,
01453                      struct ccnr_parsed_policy *pp)
01454 {
01455     int res = 0;
01456     struct ccn_buf_decoder decoder;
01457     struct ccn_buf_decoder *d = ccn_buf_decoder_start(&decoder, buf,
01458                                                       length);
01459     if (ccn_buf_match_dtag(d, CCN_DTAG_Policy)) {
01460         ccn_buf_advance(d);
01461         pp->policy_version_offset = ccn_parse_tagged_string(d, CCN_DTAG_PolicyVersion, pp->store);
01462         pp->local_name_offset = ccn_parse_tagged_string(d, CCN_DTAG_LocalName, pp->store);
01463         pp->global_prefix_offset = ccn_parse_tagged_string(d, CCN_DTAG_GlobalPrefix, pp->store);
01464         pp->namespaces->n = 0;
01465         while (ccn_buf_match_dtag(d, CCN_DTAG_Namespace)) {
01466             ccn_indexbuf_append_element(pp->namespaces, ccn_parse_tagged_string(d, CCN_DTAG_Namespace, pp->store));
01467         }
01468         ccn_buf_check_close(d);
01469     } else {
01470         return(-1);
01471     }
01472     return (res);
01473 }
01474 
01475 /**
01476  * Initiate a key fetch if necessary.
01477  * @returns -1 if error or no name, 0 if fetch was issued, 1 if already stored.
01478  */
01479 int
01480 r_proto_initiate_key_fetch(struct ccnr_handle *ccnr,
01481                            const unsigned char *msg,
01482                            struct ccn_parsed_ContentObject *pco,
01483                            int use_link,
01484                            ccnr_cookie a)
01485 {
01486     /* 
01487      * Create a new interest in the key name, set up a callback that will
01488      * insert the key into repo.
01489      */
01490     int res;
01491     struct ccn_charbuf *key_name = NULL;
01492     struct ccn_closure *key_closure = NULL;
01493     struct ccn_charbuf *templ = NULL;
01494     struct ccnr_expect_content *expect_content = NULL;
01495     const unsigned char *namestart = NULL;
01496     int namelen = 0;
01497     int keynamelen;
01498     int i;
01499     
01500     keynamelen = (pco->offset[CCN_PCO_E_KeyName_Name] -
01501                   pco->offset[CCN_PCO_B_KeyName_Name]);
01502     if (use_link) {
01503         /* Try to follow a link instead of using keyname */
01504         if (pco->type == CCN_CONTENT_LINK) {
01505             /* For now we only pay attention to the Name in the Link. */
01506             const unsigned char *data = NULL;
01507             size_t data_size = 0;
01508             struct ccn_buf_decoder decoder;
01509             struct ccn_buf_decoder *d;
01510             res = ccn_content_get_value(msg, pco->offset[CCN_PCO_E], pco,
01511                                         &data, &data_size);
01512             if (res < 0)
01513                 return(-1);
01514             d = ccn_buf_decoder_start(&decoder, data, data_size);
01515             if (ccn_buf_match_dtag(d, CCN_DTAG_Link)) {
01516                 int start = 0;
01517                 int end = 0;
01518                 ccn_buf_advance(d);
01519                 start = d->decoder.token_index;
01520                 ccn_parse_Name(d, NULL);
01521                 end = d->decoder.token_index;
01522                 ccn_buf_check_close(d);
01523                 if (d->decoder.state < 0)
01524                     return(-1);
01525                 namestart = data + start;
01526                 namelen = end - start;
01527                 if (namelen == keynamelen &&
01528                     0 == memcmp(namestart, msg + pco->offset[CCN_PCO_B_KeyName_Name], namelen)) {
01529                     /*
01530                      * The link matches the key locator. There is no point
01531                      * in checking two times for the same thing.
01532                      */
01533                     if (CCNSHOULDLOG(ccnr, sdfdf, CCNL_FINE))
01534                         ccnr_debug_ccnb(ccnr, __LINE__, "keyfetch_link_opt",
01535                                         NULL, namestart, namelen);
01536                     return(-1);
01537                 }
01538             }
01539         }
01540     }
01541     else {
01542         /* Use the KeyName if present */
01543         namestart = msg + pco->offset[CCN_PCO_B_KeyName_Name];
01544         namelen = (pco->offset[CCN_PCO_E_KeyName_Name] -
01545                    pco->offset[CCN_PCO_B_KeyName_Name]);
01546     }
01547     /*
01548      * If there is no KeyName or link, provided, we can't ask, so do not bother.
01549      */
01550     if (namelen == 0 || a == 0)
01551         return(-1);
01552     key_name = ccn_charbuf_create();
01553     ccn_charbuf_append(key_name, namestart, namelen);
01554     /* Construct an interest complete with Name so we can do lookup */
01555     templ = ccn_charbuf_create();
01556     ccn_charbuf_append_tt(templ, CCN_DTAG_Interest, CCN_DTAG);
01557     ccn_charbuf_append(templ, key_name->buf, key_name->length);
01558     ccnb_tagged_putf(templ, CCN_DTAG_MinSuffixComponents, "%d", 1);
01559     ccnb_tagged_putf(templ, CCN_DTAG_MaxSuffixComponents, "%d", 3);
01560     if (pco->offset[CCN_PCO_B_KeyName_Pub] < pco->offset[CCN_PCO_E_KeyName_Pub]) {
01561         ccn_charbuf_append(templ,
01562                            msg + pco->offset[CCN_PCO_B_KeyName_Pub],
01563                            (pco->offset[CCN_PCO_E_KeyName_Pub] - 
01564                             pco->offset[CCN_PCO_B_KeyName_Pub]));
01565     }
01566     ccn_charbuf_append_closer(templ); /* </Interest> */
01567     /* See if we already have it - if so we declare we are done. */
01568     if (r_sync_lookup(ccnr, templ, NULL) == 0) {
01569         res = 1;
01570         // Note - it might be that the thing we found is not really the thing
01571         // we were after.  For now we don't check.
01572     }
01573     else {
01574         /* We do not have it; need to ask */
01575         res = -1;
01576         expect_content = calloc(1, sizeof(*expect_content));
01577         if (expect_content == NULL)
01578             goto Bail;
01579         expect_content->ccnr = ccnr;
01580         expect_content->final = -1;
01581         for (i = 0; i < CCNR_PIPELINE; i++)
01582             expect_content->outstanding[i] = -1;
01583         /* inform r_proto_expect_content we are looking for a key. */
01584         expect_content->keyfetch = a;
01585         key_closure = calloc(1, sizeof(*key_closure));
01586         if (key_closure == NULL)
01587             goto Bail;
01588         key_closure->p = &r_proto_expect_content;
01589         key_closure->data = expect_content;
01590         res = ccn_express_interest(ccnr->direct_client, key_name, key_closure, templ);
01591         if (res >= 0) {
01592             if (CCNSHOULDLOG(ccnr, sdfdf, CCNL_FINE))
01593                 ccnr_debug_ccnb(ccnr, __LINE__, "keyfetch_start",
01594                                 NULL, templ->buf, templ->length);
01595             key_closure = NULL;
01596             expect_content = NULL;
01597             res = 0;
01598         }
01599     }
01600 Bail:
01601     if (key_closure != NULL)
01602         free(key_closure);
01603     if (expect_content != NULL)
01604         free(expect_content);
01605     ccn_charbuf_destroy(&key_name);
01606     ccn_charbuf_destroy(&templ);
01607     return(res);
01608 }
01609 
Generated on Sun Apr 22 23:31:53 2012 for Content-Centric Networking in C by  doxygen 1.6.3