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     if (res == HT_OLD_ENTRY && es->active != ES_INACTIVE) {
01014         if (es->next_segment > 0)
01015             cob = es->cob[(es->next_segment - 1) % ENUM_N_COBS];
01016         if (cob && ccn_content_matches_interest(cob->buf, cob->length, 1, NULL,
01017                                          info->interest_ccnb, info->pi->offset[CCN_PI_E], info->pi)) {
01018             if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINER))
01019                 ccnr_msg(ccnr, "enumeration: duplicate request for last cob");
01020             ccn_put(info->h, cob->buf, cob->length);
01021             ans = CCN_UPCALL_RESULT_INTEREST_CONSUMED;
01022         } else {
01023             if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINEST)) {
01024                 ccnr_msg(ccnr, "enumeration: restart of active enumeration, or excluded");
01025                 ccnr_debug_ccnb(ccnr, __LINE__, "enum    interest: ", NULL, info->interest_ccnb, info->pi->offset[CCN_PI_E]);
01026                 if (cob != NULL)
01027                     ccnr_debug_ccnb(ccnr, __LINE__, "enum cob content: ", NULL, cob->buf, cob->length);
01028             }
01029             ans = CCN_UPCALL_RESULT_OK;
01030         }
01031         hashtb_end(e);
01032         goto Bail;
01033     }
01034     // Continue to construct the name under which we will respond: %C1.E.be
01035     ccn_name_append_components(name, info->interest_ccnb,
01036                                info->interest_comps->buf[marker_comp],
01037                                info->interest_comps->buf[marker_comp + 1]);
01038     // Append the repository key id %C1.K.%00<repoid>
01039     ccn_name_append(name, ccnr->ccnr_keyid->buf, ccnr->ccnr_keyid->length);
01040     
01041     if (res == HT_NEW_ENTRY || es->starting_cookie != ccnr->cookie) {
01042         // this is a new enumeration, the time is now.
01043         res = ccn_create_version(info->h, name, CCN_V_NOW, 0, 0);
01044         if (es->name != NULL)
01045             ccn_charbuf_destroy(&es->name);
01046         es->name = ccn_charbuf_create();
01047         ccn_charbuf_append_charbuf(es->name, name);
01048         es->starting_cookie = ccnr->cookie; // XXX - a conservative indicator of change
01049     }
01050     ccn_charbuf_destroy(&name);
01051     // check the exclude against the result name
01052     if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINE))
01053         ccnr_debug_ccnb(ccnr, __LINE__, "begin enum: result name", NULL,
01054                         es->name->buf, es->name->length);
01055     
01056     if (r_proto_check_exclude(ccnr, info, es->name) > 0) {
01057         hashtb_end(e);
01058         goto Bail;
01059     }
01060 
01061     // do we have anything that matches this enumeration request?
01062     content = r_store_find_first_match_candidate(ccnr, interest->buf, pi);
01063     if (content != NULL &&
01064         !r_store_content_matches_interest_prefix(ccnr, content, interest->buf, interest->length))
01065         content = NULL;
01066     es->cob[0] = ccn_charbuf_create();
01067     es->reply_body = ccn_charbuf_create();
01068     ccnb_element_begin(es->reply_body, CCN_DTAG_Collection);
01069     es->content = content;
01070     es->interest = interest;
01071     es->interest_comps = comps;
01072     es->next_segment = 0;
01073     es->lastuse_sec = ccnr->sec;
01074     es->lastuse_usec = ccnr->usec;
01075     if (content) {
01076         es->lifetime = 3 * ccn_interest_lifetime_seconds(info->interest_ccnb, pi);
01077         es->active = ES_ACTIVE;
01078     } else {
01079         es->lifetime = ccn_interest_lifetime_seconds(info->interest_ccnb, pi);
01080         es->active = ES_PENDING;
01081     }
01082     hashtb_end(e);
01083     reap_enumerations_needed(ccnr);
01084     if (content)
01085         ans = r_proto_continue_enumeration(selfp, kind, info, marker_comp);
01086     else
01087         ans = CCN_UPCALL_RESULT_OK;
01088     return(ans);
01089     
01090 Bail:
01091     ccn_charbuf_destroy(&name);
01092     ccn_charbuf_destroy(&interest);
01093     ccn_indexbuf_destroy(&comps);
01094     return(ans);
01095 }
01096 
01097 static enum ccn_upcall_res
01098 r_proto_continue_enumeration(struct ccn_closure *selfp,
01099                              enum ccn_upcall_kind kind,
01100                              struct ccn_upcall_info *info,
01101                              int marker_comp) {
01102     // XXX - watch out for pipelined interests for the enumerations -- there
01103     // MUST be an active enumeration continuation before we do anything here.
01104     // Should chop 1 component off interest -- which will look like
01105     // ccnx:/.../%C1.E.be/%C1.M.K%00.../%FD.../%00%02
01106     struct ccn_charbuf *hashkey = NULL;
01107     struct ccn_charbuf *result_name = NULL;
01108     struct ccn_charbuf *cob = NULL;
01109     struct ccn_indexbuf *ic = NULL;
01110     intmax_t segment;
01111     struct enum_state *es = NULL;
01112     struct ccnr_handle *ccnr = NULL;
01113     struct hashtb_enumerator enumerator = {0};
01114     struct hashtb_enumerator *e = &enumerator;
01115     struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
01116     int i;
01117     int res = 0;
01118     int ans = CCN_UPCALL_RESULT_ERR;
01119     
01120     ccnr = (struct ccnr_handle *)selfp->data;
01121     ic = info->interest_comps;
01122     hashkey=ccn_charbuf_create();
01123     ccn_name_init(hashkey);
01124     ccn_name_append_components(hashkey, info->interest_ccnb,
01125                                info->interest_comps->buf[0],
01126                                info->interest_comps->buf[marker_comp]);
01127     hashtb_start(ccnr->enum_state_tab, e);
01128     res = hashtb_seek(e, hashkey->buf, hashkey->length, 0);
01129     ccn_charbuf_destroy(&hashkey);
01130     if (res != HT_OLD_ENTRY) {
01131         goto Bail;
01132     }
01133     es = e->data;
01134     if (es->active != ES_ACTIVE) {
01135         hashtb_end(e);
01136         return(ans);
01137     }
01138     // If there is a segment in the request, get the value.
01139     segment = r_util_segment_from_component(info->interest_ccnb,
01140                                             ic->buf[ic->n - 2],
01141                                             ic->buf[ic->n - 1]);
01142     if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINE))
01143         ccnr_msg(ccnr, "enumeration: requested %jd :: expected %jd", segment, es->next_segment);
01144     if (segment >= 0 && segment != es->next_segment) {
01145         // too far in the future for us to process
01146         if (segment > es->next_segment + (ENUM_N_COBS / 2)) {
01147             if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINER))
01148                 ccnr_msg(ccnr, "enumeration: ignoring future segment requested %jd :: expected %jd", segment, es->next_segment);
01149             hashtb_end(e);
01150             return (CCN_UPCALL_RESULT_OK);
01151         }
01152         // if theres a possibility we could have it
01153         if (segment >= es->next_segment - ENUM_N_COBS) {
01154             cob = es->cob[segment % ENUM_N_COBS];
01155             if (cob &&
01156                 ccn_content_matches_interest(cob->buf, cob->length, 1, NULL,
01157                                              info->interest_ccnb, info->pi->offset[CCN_PI_E], info->pi)) {
01158                     if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINER))
01159                         ccnr_msg(ccnr, "enumeration: processing dup request for segment %jd", segment);
01160                     ccn_put(info->h, cob->buf, cob->length);
01161                     hashtb_end(e);
01162                     return (CCN_UPCALL_RESULT_INTEREST_CONSUMED);
01163                 }
01164         }
01165     }
01166 NextSegment:
01167     if (CCNSHOULDLOG(ccnr, blah, CCNL_FINE))
01168         ccnr_msg(ccnr, "enumeration: generating segment %jd", es->next_segment);
01169     es->lastuse_sec = ccnr->sec;
01170     es->lastuse_usec = ccnr->usec;
01171     while (es->content != NULL &&
01172            r_store_content_matches_interest_prefix(ccnr, es->content,
01173                                                    es->interest->buf,
01174                                                    es->interest->length)) {
01175         int save = es->reply_body->length;
01176         ccnb_element_begin(es->reply_body, CCN_DTAG_Link);
01177         ccnb_element_begin(es->reply_body, CCN_DTAG_Name);
01178         ccnb_element_end(es->reply_body); /* </Name> */
01179         res = r_store_name_append_components(es->reply_body, ccnr, es->content, es->interest_comps->n - 1, 1);
01180         ccnb_element_end(es->reply_body); /* </Link> */
01181         if (res == 0) {
01182             /* The name matched exactly, need to skip. */
01183             es->reply_body->length = save;
01184             es->content = r_store_next_child_at_level(ccnr, es->content, es->interest_comps->n - 1);
01185             continue;
01186         }
01187         if (res != 1) {
01188             ccnr_debug_ccnb(ccnr, __LINE__, "oops", NULL, es->interest->buf, es->interest->length);
01189             ccnr_debug_content(ccnr, __LINE__, "oops", NULL, es->content);
01190             abort();
01191         }
01192         es->content = r_store_next_child_at_level(ccnr, es->content, es->interest_comps->n - 1);
01193         if (es->reply_body->length >= 4096) {
01194             result_name = ccn_charbuf_create();
01195             ccn_charbuf_append_charbuf(result_name, es->name);
01196             ccn_name_append_numeric(result_name, CCN_MARKER_SEQNUM, es->next_segment);
01197             sp.freshness = 60;
01198             cob = es->cob[es->next_segment % ENUM_N_COBS];
01199             if (cob == NULL) {
01200                 cob = ccn_charbuf_create();
01201                 es->cob[es->next_segment % ENUM_N_COBS] = cob;
01202             }
01203             cob->length = 0;
01204             res = ccn_sign_content(info->h, cob, result_name, &sp,
01205                                    es->reply_body->buf, 4096);
01206             ccn_charbuf_destroy(&result_name);
01207             if (CCNSHOULDLOG(ccnr, blah, CCNL_FINER))
01208                 ccnr_msg(ccnr, "enumeration: putting cob for segment %jd, req %jd", es->next_segment, segment);
01209             if (segment == -1 || segment == es->next_segment)
01210                 ccn_put(info->h, cob->buf, cob->length);
01211             es->next_segment++;
01212             memmove(es->reply_body->buf, es->reply_body->buf + 4096, es->reply_body->length - 4096);
01213             es->reply_body->length -= 4096;
01214             if (segment >= es->next_segment)
01215                  goto NextSegment;
01216             hashtb_end(e);
01217             return (CCN_UPCALL_RESULT_INTEREST_CONSUMED);
01218         }
01219     }
01220     // we will only get here if we are finishing an in-progress enumeration
01221     ccnb_element_end(es->reply_body); /* </Collection> */
01222     result_name = ccn_charbuf_create();
01223     ccn_charbuf_append_charbuf(result_name, es->name);
01224     ccn_name_append_numeric(result_name, CCN_MARKER_SEQNUM, es->next_segment);
01225     sp.freshness = 60;
01226     sp.sp_flags |= CCN_SP_FINAL_BLOCK;
01227     cob = es->cob[es->next_segment % ENUM_N_COBS];
01228     if (cob == NULL) {
01229         cob = ccn_charbuf_create();
01230         es->cob[es->next_segment % ENUM_N_COBS] = cob;
01231     }
01232     cob->length = 0;
01233     res = ccn_sign_content(info->h, cob, result_name, &sp, es->reply_body->buf,
01234                            es->reply_body->length);
01235     ccn_charbuf_destroy(&result_name);    
01236     if (CCNSHOULDLOG(ccnr, blah, CCNL_FINER))
01237         ccnr_msg(ccnr, "enumeration: putting final cob for segment %jd", es->next_segment);
01238     ccn_put(info->h, cob->buf, cob->length);
01239     es->active = ES_INACTIVE;
01240     ans = CCN_UPCALL_RESULT_INTEREST_CONSUMED;
01241     
01242 Bail:
01243     if (es != NULL) {
01244         // leave the name 
01245         ccn_charbuf_destroy(&es->interest);
01246         ccn_charbuf_destroy(&es->reply_body);
01247         for (i = 0; i < ENUM_N_COBS; i++)
01248             ccn_charbuf_destroy(&es->cob[i]);
01249         ccn_indexbuf_destroy(&es->interest_comps);
01250     }
01251     hashtb_end(e);
01252     return(ans);
01253 }
01254 
01255 void
01256 r_proto_dump_enums(struct ccnr_handle *ccnr)
01257 {
01258     struct enum_state *es = NULL;
01259     struct hashtb_enumerator enumerator = {0};
01260     struct hashtb_enumerator *e = &enumerator;
01261     
01262     for (hashtb_start(ccnr->enum_state_tab, e); e->data != NULL; hashtb_next(e)) {
01263         es = e->data;
01264         ccnr_msg(ccnr, "Enumeration active: %d, next segment %d, cookie %u",
01265                  es->active, es->next_segment, es->starting_cookie);
01266         ccnr_debug_ccnb(ccnr, __LINE__, "     enum name", NULL,
01267                         es->name->buf, es->name->length);
01268         
01269     }  
01270     hashtb_end(e);
01271 }
01272 
01273 static enum ccn_upcall_res
01274 r_proto_bulk_import(struct ccn_closure *selfp,
01275                           enum ccn_upcall_kind kind,
01276                           struct ccn_upcall_info *info,
01277                           int marker_comp)
01278 {
01279     enum ccn_upcall_res ans = CCN_UPCALL_RESULT_ERR;
01280     struct ccnr_handle *ccnr = NULL;
01281     struct ccn_charbuf *filename = NULL;
01282     struct ccn_charbuf *filename2 = NULL;
01283     const unsigned char *mstart = NULL;
01284     size_t mlength;
01285     struct ccn_indexbuf *ic = NULL;
01286     struct ccn_charbuf *msg = NULL;
01287     struct ccn_charbuf *name = NULL;
01288     struct ccn_charbuf *reply_body = NULL;
01289     struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
01290     const char *infostring = "OK";
01291     int res;
01292     
01293     ccnr = (struct ccnr_handle *)selfp->data;
01294     ccn_name_comp_get(info->interest_ccnb, info->interest_comps, marker_comp,
01295                       &mstart, &mlength);
01296     if (mlength <= strlen(REPO_AF) + 1 || mstart[strlen(REPO_AF)] != '~') {
01297         infostring = "missing or malformed bulk import name component";
01298         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01299         goto Reply;
01300     }
01301     mstart += strlen(REPO_AF) + 1;
01302     mlength -= (strlen(REPO_AF) + 1);
01303     if (memchr(mstart, '/', mlength) != NULL) {
01304         infostring = "bulk import filename must not include directory";
01305         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01306         goto Reply;
01307     }
01308     filename = ccn_charbuf_create();
01309     ccn_charbuf_append_string(filename, "import/");
01310     ccn_charbuf_append(filename, mstart, mlength);
01311     res = r_init_map_and_process_file(ccnr, filename, 0);
01312     if (res == 1) {
01313         infostring = "unable to open bulk import file";
01314         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01315         goto Reply;
01316     }
01317     if (res < 0) {
01318         infostring = "error parsing bulk import file";
01319         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01320         goto Reply;
01321     }
01322     /* we think we can process it */
01323     filename->length = 0;
01324     ccn_charbuf_putf(filename, "%s/import/", ccnr->directory);
01325     ccn_charbuf_append(filename, mstart, mlength);
01326     filename2 = ccn_charbuf_create();
01327     ccn_charbuf_putf(filename2, "%s/import/.", ccnr->directory);
01328     ccn_charbuf_append(filename2, mstart, mlength);
01329     res = rename(ccn_charbuf_as_string(filename),
01330                  ccn_charbuf_as_string(filename2));
01331     if (res < 0) {
01332         infostring = "error renaming bulk import file";
01333         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01334         goto Reply;        
01335     }
01336     filename->length = 0;
01337     ccn_charbuf_append_string(filename, "import/.");
01338     ccn_charbuf_append(filename, mstart, mlength);
01339     res = r_init_map_and_process_file(ccnr, filename, 1);
01340     if (res < 0) {
01341         infostring = "error merging bulk import file";
01342         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01343         // fall through and unlink anyway
01344     }
01345     if (CCNSHOULDLOG(ccnr, sdfdf, CCNL_FINE))
01346         ccnr_msg(ccnr, "unlinking bulk import file %s", ccn_charbuf_as_string(filename2));   
01347     unlink(ccn_charbuf_as_string(filename2));
01348 
01349 Reply:
01350     /* Generate our reply */
01351     name = ccn_charbuf_create();
01352     ccn_name_init(name);
01353     ic = info->interest_comps;
01354     ccn_name_append_components(name, info->interest_ccnb, ic->buf[0], ic->buf[ic->n - 1]);
01355 
01356     msg = ccn_charbuf_create();
01357     reply_body = ccn_charbuf_create();
01358     r_proto_append_repo_info(ccnr, reply_body, NULL, infostring);
01359     sp.freshness = 12; /* Seconds */
01360     res = ccn_sign_content(info->h, msg, name, &sp,
01361                            reply_body->buf, reply_body->length);
01362     if (res < 0)
01363         goto Bail;
01364     res = ccn_put(info->h, msg->buf, msg->length);
01365     if (res < 0) {
01366         ccnr_debug_ccnb(ccnr, __LINE__, "r_proto_bulk_import ccn_put FAILED", NULL,
01367                         msg->buf, msg->length);
01368         goto Bail;
01369     }
01370     ans = CCN_UPCALL_RESULT_INTEREST_CONSUMED;
01371 
01372 Bail:
01373     if (filename != NULL) ccn_charbuf_destroy(&filename);
01374     if (filename2 != NULL) ccn_charbuf_destroy(&filename2);
01375     if (name != NULL) ccn_charbuf_destroy(&name);
01376     if (msg != NULL) ccn_charbuf_destroy(&msg);
01377     if (reply_body != NULL) ccn_charbuf_destroy(&reply_body);
01378     return (ans);
01379 }
01380 
01381 /* Construct a charbuf with an encoding of a Policy object 
01382  *
01383  *  <xs:complexType name="PolicyType">
01384  *      <xs:sequence>
01385  *      <xs:element name="PolicyVersion" type="xs:string"/> 
01386  *      <xs:element name="LocalName" type="xs:string"/>
01387  *      <xs:element name="GlobalPrefix" type="xs:string"/>
01388  *  <!-- 0 or more names -->
01389  *      <xs:element name="Namespace" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
01390  *      </xs:sequence>
01391  *  </xs:complexType>
01392  */ 
01393 PUBLIC int
01394 r_proto_policy_append_basic(struct ccnr_handle *ccnr,
01395                             struct ccn_charbuf *policy,
01396                             const char *version, const char *local_name,
01397                             const char *global_prefix)
01398 {
01399     int res;
01400     res = ccnb_element_begin(policy, CCN_DTAG_Policy);
01401     res |= ccnb_tagged_putf(policy, CCN_DTAG_PolicyVersion, "%s", version);
01402     res |= ccnb_tagged_putf(policy, CCN_DTAG_LocalName, "%s", local_name);
01403     res |= ccnb_tagged_putf(policy, CCN_DTAG_GlobalPrefix, "%s", global_prefix);
01404     res |= ccnb_element_end(policy);
01405     return (res);
01406 }
01407 PUBLIC int
01408 r_proto_policy_append_namespace(struct ccnr_handle *ccnr,
01409                                 struct ccn_charbuf *policy,
01410                                 const char *namespace)
01411 {
01412     int res;
01413     if (policy->length < 2)
01414         return(-1);
01415     policy->length--;   /* remove the closer */
01416     res = ccnb_tagged_putf(policy, CCN_DTAG_Namespace, "%s", namespace);
01417     ccnb_element_end(policy);
01418     return(res);
01419 }
01420 
01421 /**
01422  * Parse a ccnb-encoded policy content object and fill in a ccn_parsed_policy
01423  * structure as the result.
01424  */
01425 PUBLIC int
01426 r_proto_parse_policy(struct ccnr_handle *ccnr, const unsigned char *buf, size_t length,
01427                      struct ccnr_parsed_policy *pp)
01428 {
01429     int res = 0;
01430     struct ccn_buf_decoder decoder;
01431     struct ccn_buf_decoder *d = ccn_buf_decoder_start(&decoder, buf,
01432                                                       length);
01433     if (ccn_buf_match_dtag(d, CCN_DTAG_Policy)) {
01434         ccn_buf_advance(d);
01435         pp->policy_version_offset = ccn_parse_tagged_string(d, CCN_DTAG_PolicyVersion, pp->store);
01436         pp->local_name_offset = ccn_parse_tagged_string(d, CCN_DTAG_LocalName, pp->store);
01437         pp->global_prefix_offset = ccn_parse_tagged_string(d, CCN_DTAG_GlobalPrefix, pp->store);
01438         pp->namespaces->n = 0;
01439         while (ccn_buf_match_dtag(d, CCN_DTAG_Namespace)) {
01440             ccn_indexbuf_append_element(pp->namespaces, ccn_parse_tagged_string(d, CCN_DTAG_Namespace, pp->store));
01441         }
01442         ccn_buf_check_close(d);
01443     } else {
01444         return(-1);
01445     }
01446     return (res);
01447 }
01448 
01449 /**
01450  * Initiate a key fetch if necessary.
01451  * @returns -1 if error or no name, 0 if fetch was issued, 1 if already stored.
01452  */
01453 int
01454 r_proto_initiate_key_fetch(struct ccnr_handle *ccnr,
01455                            const unsigned char *msg,
01456                            struct ccn_parsed_ContentObject *pco,
01457                            int use_link,
01458                            ccnr_cookie a)
01459 {
01460     /* 
01461      * Create a new interest in the key name, set up a callback that will
01462      * insert the key into repo.
01463      */
01464     int res;
01465     struct ccn_charbuf *key_name = NULL;
01466     struct ccn_closure *key_closure = NULL;
01467     struct ccn_charbuf *templ = NULL;
01468     struct ccnr_expect_content *expect_content = NULL;
01469     const unsigned char *namestart = NULL;
01470     int namelen = 0;
01471     int keynamelen;
01472     int i;
01473     
01474     keynamelen = (pco->offset[CCN_PCO_E_KeyName_Name] -
01475                   pco->offset[CCN_PCO_B_KeyName_Name]);
01476     if (use_link) {
01477         /* Try to follow a link instead of using keyname */
01478         if (pco->type == CCN_CONTENT_LINK) {
01479             /* For now we only pay attention to the Name in the Link. */
01480             const unsigned char *data = NULL;
01481             size_t data_size = 0;
01482             struct ccn_buf_decoder decoder;
01483             struct ccn_buf_decoder *d;
01484             res = ccn_content_get_value(msg, pco->offset[CCN_PCO_E], pco,
01485                                         &data, &data_size);
01486             if (res < 0)
01487                 return(-1);
01488             d = ccn_buf_decoder_start(&decoder, data, data_size);
01489             if (ccn_buf_match_dtag(d, CCN_DTAG_Link)) {
01490                 int start = 0;
01491                 int end = 0;
01492                 ccn_buf_advance(d);
01493                 start = d->decoder.token_index;
01494                 ccn_parse_Name(d, NULL);
01495                 end = d->decoder.token_index;
01496                 ccn_buf_check_close(d);
01497                 if (d->decoder.state < 0)
01498                     return(-1);
01499                 namestart = data + start;
01500                 namelen = end - start;
01501                 if (namelen == keynamelen &&
01502                     0 == memcmp(namestart, msg + pco->offset[CCN_PCO_B_KeyName_Name], namelen)) {
01503                     /*
01504                      * The link matches the key locator. There is no point
01505                      * in checking two times for the same thing.
01506                      */
01507                     if (CCNSHOULDLOG(ccnr, sdfdf, CCNL_FINE))
01508                         ccnr_debug_ccnb(ccnr, __LINE__, "keyfetch_link_opt",
01509                                         NULL, namestart, namelen);
01510                     return(-1);
01511                 }
01512             }
01513         }
01514     }
01515     else {
01516         /* Use the KeyName if present */
01517         namestart = msg + pco->offset[CCN_PCO_B_KeyName_Name];
01518         namelen = (pco->offset[CCN_PCO_E_KeyName_Name] -
01519                    pco->offset[CCN_PCO_B_KeyName_Name]);
01520     }
01521     /*
01522      * If there is no KeyName or link, provided, we can't ask, so do not bother.
01523      */
01524     if (namelen == 0 || a == 0)
01525         return(-1);
01526     key_name = ccn_charbuf_create();
01527     ccn_charbuf_append(key_name, namestart, namelen);
01528     /* Construct an interest complete with Name so we can do lookup */
01529     templ = ccn_charbuf_create();
01530     ccn_charbuf_append_tt(templ, CCN_DTAG_Interest, CCN_DTAG);
01531     ccn_charbuf_append(templ, key_name->buf, key_name->length);
01532     ccnb_tagged_putf(templ, CCN_DTAG_MinSuffixComponents, "%d", 1);
01533     ccnb_tagged_putf(templ, CCN_DTAG_MaxSuffixComponents, "%d", 3);
01534     if (pco->offset[CCN_PCO_B_KeyName_Pub] < pco->offset[CCN_PCO_E_KeyName_Pub]) {
01535         ccn_charbuf_append(templ,
01536                            msg + pco->offset[CCN_PCO_B_KeyName_Pub],
01537                            (pco->offset[CCN_PCO_E_KeyName_Pub] - 
01538                             pco->offset[CCN_PCO_B_KeyName_Pub]));
01539     }
01540     ccn_charbuf_append_closer(templ); /* </Interest> */
01541     /* See if we already have it - if so we declare we are done. */
01542     if (r_sync_lookup(ccnr, templ, NULL) == 0) {
01543         res = 1;
01544         // Note - it might be that the thing we found is not really the thing
01545         // we were after.  For now we don't check.
01546     }
01547     else {
01548         /* We do not have it; need to ask */
01549         res = -1;
01550         expect_content = calloc(1, sizeof(*expect_content));
01551         if (expect_content == NULL)
01552             goto Bail;
01553         expect_content->ccnr = ccnr;
01554         expect_content->final = -1;
01555         for (i = 0; i < CCNR_PIPELINE; i++)
01556             expect_content->outstanding[i] = -1;
01557         /* inform r_proto_expect_content we are looking for a key. */
01558         expect_content->keyfetch = a;
01559         key_closure = calloc(1, sizeof(*key_closure));
01560         if (key_closure == NULL)
01561             goto Bail;
01562         key_closure->p = &r_proto_expect_content;
01563         key_closure->data = expect_content;
01564         res = ccn_express_interest(ccnr->direct_client, key_name, key_closure, templ);
01565         if (res >= 0) {
01566             if (CCNSHOULDLOG(ccnr, sdfdf, CCNL_FINE))
01567                 ccnr_debug_ccnb(ccnr, __LINE__, "keyfetch_start",
01568                                 NULL, templ->buf, templ->length);
01569             key_closure = NULL;
01570             expect_content = NULL;
01571             res = 0;
01572         }
01573     }
01574 Bail:
01575     if (key_closure != NULL)
01576         free(key_closure);
01577     if (expect_content != NULL)
01578         free(expect_content);
01579     ccn_charbuf_destroy(&key_name);
01580     ccn_charbuf_destroy(&templ);
01581     return(res);
01582 }
01583 

Generated on Thu Feb 16 00:43:58 2012 for Content-Centric Networking in C by  doxygen 1.5.6