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, NULL);
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         if (content_msg == NULL) {
00527             ccnr_debug_ccnb(ccnr, __LINE__, "Policy read failed for", NULL,
00528                             name->buf, name->length);
00529             goto Bail;            
00530         }
00531         res = ccn_parse_ContentObject(content_msg, r_store_content_size(ccnr, content), &pco, nc);
00532         res = ccn_ref_tagged_BLOB(CCN_DTAG_Content, content_msg,
00533                                   pco.offset[CCN_PCO_B_Content],
00534                                   pco.offset[CCN_PCO_E_Content],
00535                                   &buf, &length);
00536         ccn_charbuf_append(policy, buf, length);
00537         final = r_util_is_final_pco(content_msg, &pco, nc);
00538     } while (!final);
00539     
00540     pp = ccnr_parsed_policy_create();
00541     if (pp == NULL) {
00542         ccnr_msg(ccnr, "Parsed policy allocation error");
00543         goto Bail;
00544     }
00545     memmove(pp->version, vers, vers_size);
00546     if (r_proto_parse_policy(ccnr, policy->buf, policy->length, pp) < 0) {
00547         ccnr_msg(ccnr, "Malformed policy");
00548         goto Bail;
00549     }
00550     res = strcmp((char *)pp->store->buf + pp->global_prefix_offset,
00551                  (char *)ccnr->parsed_policy->store->buf + ccnr->parsed_policy->global_prefix_offset);
00552     if (0 != res) {
00553         ccnr_msg(ccnr, "Policy global prefix mismatch");
00554         goto Bail;
00555     }
00556     policy_link_cob = ccnr_init_policy_link_cob(ccnr, ccnr->direct_client, name);
00557     if (policy_link_cob != NULL)
00558         ccnr->policy_link_cob = policy_link_cob;
00559     policyFileName = ccn_charbuf_create();
00560     ccn_charbuf_putf(policyFileName, "%s/repoPolicy", ccnr->directory);
00561     fd = open(ccn_charbuf_as_string(policyFileName), O_WRONLY | O_CREAT, 0666);
00562     if (fd < 0) {
00563         ccnr_msg(ccnr, "open policy: %s (errno = %d)", strerror(errno), errno);
00564         goto Bail;
00565     }
00566     lseek(fd, 0, SEEK_SET);
00567     res = write(fd, ccnr->policy_link_cob->buf, ccnr->policy_link_cob->length);
00568     if (res == -1) {
00569         ccnr_msg(ccnr, "write policy: %s (errno = %d)", strerror(errno), errno);
00570         goto Bail;
00571     }
00572     res = ftruncate(fd, ccnr->policy_link_cob->length);
00573     if (res == -1) {
00574         ccnr_msg(ccnr, "Policy truncate %u :%s (errno = %d)",
00575                  fd, strerror(errno), errno);
00576         goto Bail;
00577     }
00578     close(fd);
00579     fd = -1;
00580     r_proto_deactivate_policy(ccnr, ccnr->parsed_policy);
00581     ccnr_parsed_policy_destroy(&ccnr->parsed_policy);
00582     ccnr->parsed_policy = pp;
00583     r_proto_activate_policy(ccnr, pp);
00584     
00585     ans = 0;
00586     
00587 Bail:
00588     ccn_charbuf_destroy(&name);
00589     ccn_indexbuf_destroy(&nc);
00590     ccn_charbuf_destroy(&policy);
00591     ccn_charbuf_destroy(&policyFileName);
00592     if (fd >= 0) close(fd);
00593     return (ans);
00594     
00595 }    
00596 
00597 static int
00598 r_proto_policy_complete(struct ccn_closure *selfp,
00599                         enum ccn_upcall_kind kind,
00600                         struct ccn_upcall_info *info)
00601 {
00602     struct ccnr_expect_content *md = selfp->data;
00603     struct ccnr_handle *ccnr = (struct ccnr_handle *)md->ccnr;
00604     const unsigned char *ccnb;
00605     size_t ccnb_size;
00606     const unsigned char *vers = NULL;
00607     size_t vers_size = 0;
00608     struct ccn_indexbuf *cc;
00609     struct ccn_charbuf *name;
00610     int res;
00611     
00612     // the version of the new policy must be greater than the exist one
00613     // or we will not activate it and update the link to point to it.
00614     
00615     ccnb = info->content_ccnb;
00616     ccnb_size = info->pco->offset[CCN_PCO_E];
00617     cc = info->content_comps;
00618     ccn_name_comp_get(ccnb, cc, cc->n - 3, &vers, &vers_size);
00619     if (vers_size != 7 || vers[0] != CCN_MARKER_VERSION)
00620         return(-1);
00621     if (memcmp(vers, ccnr->parsed_policy->version, sizeof(ccnr->parsed_policy->version)) <= 0) {
00622         if (CCNSHOULDLOG(ccnr, LM_128, CCNL_INFO))
00623             ccnr_debug_ccnb(ccnr, __LINE__, "r_proto_policy_complete older policy ignored", NULL,
00624                             ccnb, ccnb_size);        
00625         return (-1);
00626     }
00627     // all components not including segment
00628     name = ccn_charbuf_create();
00629     res = ccn_name_init(name);
00630     ccn_name_append_components(name, ccnb, cc->buf[0], cc->buf[cc->n - 2]);
00631     ccn_schedule_event(ccnr->sched, 500, r_proto_policy_update, name, 0);
00632     if (CCNSHOULDLOG(ccnr, LM_128, CCNL_FINEST))
00633         ccnr_msg(ccnr,"r_proto_policy_complete update scheduled");        
00634     
00635     return (0);
00636 }
00637 
00638 static enum ccn_upcall_res
00639 r_proto_start_write(struct ccn_closure *selfp,
00640                     enum ccn_upcall_kind kind,
00641                     struct ccn_upcall_info *info,
00642                     int marker_comp)
00643 {
00644     struct ccnr_handle *ccnr = NULL;
00645     struct ccn_charbuf *templ = NULL;
00646     struct ccn_closure *incoming = NULL;
00647     struct ccnr_expect_content *expect_content = NULL;
00648     struct ccn_charbuf *reply_body = NULL;
00649     struct ccn_charbuf *name = NULL;
00650     struct ccn_indexbuf *ic = NULL;
00651     enum ccn_upcall_res ans = CCN_UPCALL_RESULT_ERR;
00652     struct ccn_charbuf *msg = NULL;
00653     int res = 0;
00654     int start = 0;
00655     int end = 0;
00656     int is_policy = 0;
00657     int i;
00658     struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
00659     
00660     // XXX - Check for valid nonce
00661     // XXX - Check for pubid - if present and not ours, do not respond.
00662     // Check for answer origin kind.
00663     // If Exclude is there, there might be something fishy going on.
00664     
00665     ccnr = (struct ccnr_handle *)selfp->data;
00666     if (ccnr->start_write_scope_limit < 3) {
00667         start = info->pi->offset[CCN_PI_B_Scope];
00668         end = info->pi->offset[CCN_PI_E_Scope];
00669         if (start == end || info->pi->scope > ccnr->start_write_scope_limit) {
00670             if (CCNSHOULDLOG(ccnr, LM_128, CCNL_INFO))
00671                 ccnr_msg(ccnr, "r_proto_start_write: interest scope exceeds limit");
00672             return(CCN_UPCALL_RESULT_OK);
00673         }
00674     }
00675     // don't handle the policy file here
00676     start = info->pi->offset[CCN_PI_B_Name];
00677     end = info->interest_comps->buf[marker_comp - 1]; // not including version or marker
00678     name = ccn_charbuf_create();
00679     ccn_charbuf_append(name, info->interest_ccnb + start, end - start);
00680     ccn_charbuf_append_closer(name);
00681     if (0 ==ccn_compare_names(name->buf, name->length,
00682                               ccnr->policy_name->buf, ccnr->policy_name->length))
00683         is_policy = 1;
00684     
00685     /* Generate our reply */
00686     start = info->pi->offset[CCN_PI_B_Name];
00687     end = info->interest_comps->buf[info->pi->prefix_comps];
00688     name->length = 0;
00689     ccn_charbuf_append(name, info->interest_ccnb + start, end - start);
00690     ccn_charbuf_append_closer(name);
00691     msg = ccn_charbuf_create();
00692     reply_body = ccn_charbuf_create();
00693     r_proto_append_repo_info(ccnr, reply_body, NULL, NULL);
00694     sp.freshness = 12; /* seconds */
00695     res = ccn_sign_content(info->h, msg, name, &sp,
00696                            reply_body->buf, reply_body->length);
00697     if (res < 0)
00698         goto Bail;
00699     if (CCNSHOULDLOG(ccnr, LM_128, CCNL_FINE))
00700         ccnr_debug_ccnb(ccnr, __LINE__, "r_proto_start_write response", NULL,
00701                         msg->buf, msg->length);
00702     res = ccn_put(info->h, msg->buf, msg->length);
00703     if (res < 0) {
00704         ccnr_debug_ccnb(ccnr, __LINE__, "r_proto_start_write ccn_put FAILED", NULL,
00705                         msg->buf, msg->length);
00706         goto Bail;
00707     }
00708 
00709     /* Send an interest for segment 0 */
00710     expect_content = calloc(1, sizeof(*expect_content));
00711     if (expect_content == NULL)
00712         goto Bail;
00713     expect_content->ccnr = ccnr;
00714     expect_content->final = -1;
00715     for (i = 0; i < CCNR_PIPELINE; i++)
00716         expect_content->outstanding[i] = -1;
00717     if (is_policy) {
00718         expect_content->expect_complete = &r_proto_policy_complete;
00719         if (CCNSHOULDLOG(ccnr, LM_128, CCNL_FINE))
00720             ccnr_msg(ccnr, "r_proto_start_write: is policy file");
00721     }
00722     incoming = calloc(1, sizeof(*incoming));
00723     if (incoming == NULL)
00724         goto Bail;
00725     incoming->p = &r_proto_expect_content;
00726     incoming->data = expect_content;
00727     templ = r_proto_mktemplate(expect_content, NULL);
00728     ic = info->interest_comps;
00729     ccn_name_init(name);
00730     ccn_name_append_components(name, info->interest_ccnb, ic->buf[0], ic->buf[marker_comp]);
00731     ccn_name_append_numeric(name, CCN_MARKER_SEQNUM, 0);
00732     expect_content->outstanding[0] = 0;
00733     res = ccn_express_interest(info->h, name, incoming, templ);
00734     if (res >= 0) {
00735         /* upcall will free these when it is done. */
00736         incoming = NULL;
00737         expect_content = NULL;
00738         ans = CCN_UPCALL_RESULT_INTEREST_CONSUMED;
00739     }
00740     else {
00741         ccnr_debug_ccnb(ccnr, __LINE__, "r_proto_start_write ccn_express_interest FAILED", NULL,
00742                         name->buf, name->length);
00743         goto Bail;
00744     }
00745     
00746 Bail:
00747     if (incoming != NULL)
00748         free(incoming);
00749     if (expect_content != NULL)
00750         free(expect_content);
00751     ccn_charbuf_destroy(&templ);
00752     ccn_charbuf_destroy(&name);
00753     ccn_charbuf_destroy(&reply_body);
00754     ccn_charbuf_destroy(&msg);
00755     return(ans);
00756 }
00757 
00758 static enum ccn_upcall_res
00759 r_proto_start_write_checked(struct ccn_closure *selfp,
00760                             enum ccn_upcall_kind kind,
00761                             struct ccn_upcall_info *info,
00762                             int marker_comp)
00763 {
00764     struct ccnr_handle *ccnr = NULL;
00765     enum ccn_upcall_res ans = CCN_UPCALL_RESULT_OK;
00766     struct ccn_indexbuf *ic = NULL;
00767     struct content_entry *content = NULL;
00768     struct ccn_parsed_interest parsed_interest = {0};
00769     struct ccn_parsed_interest *pi = &parsed_interest;
00770     struct ccn_charbuf *name = NULL;
00771     struct ccn_charbuf *interest = NULL;
00772     struct ccn_indexbuf *comps = NULL;
00773     struct ccn_charbuf *msg = NULL;
00774     struct ccn_charbuf *reply_body = NULL;
00775     int start = 0;
00776     int end = 0;
00777     struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
00778     int res = 0;
00779     
00780     // XXX - do we need to disallow the policy file here too?
00781     ccnr = (struct ccnr_handle *)selfp->data;
00782     if (ccnr->start_write_scope_limit < 3) {
00783         start = info->pi->offset[CCN_PI_B_Scope];
00784         end = info->pi->offset[CCN_PI_E_Scope];
00785         if (start == end || info->pi->scope > ccnr->start_write_scope_limit) {
00786             if (CCNSHOULDLOG(ccnr, LM_128, CCNL_INFO))
00787                 ccnr_msg(ccnr, "r_proto_start_write_checked: interest scope exceeds limit");
00788             return(CCN_UPCALL_RESULT_OK);
00789         }
00790     }
00791     name = ccn_charbuf_create();
00792     ccn_name_init(name);
00793     ic = info->interest_comps;
00794     ccn_name_append_components(name, info->interest_ccnb, ic->buf[0], ic->buf[marker_comp]);
00795     ccn_name_append_components(name, info->interest_ccnb, ic->buf[marker_comp + 2], ic->buf[ic->n - 1]);
00796     // Make an interest for the exact item we're checking
00797     interest = ccn_charbuf_create();
00798     ccnb_element_begin(interest, CCN_DTAG_Interest);
00799     ccn_charbuf_append_charbuf(interest, name);
00800     ccnb_element_end(interest); /* </Interest> */
00801     // Parse it
00802     comps = ccn_indexbuf_create();
00803     res = ccn_parse_interest(interest->buf, interest->length, pi, comps);
00804     if (res < 0)
00805         abort();
00806     if (CCNSHOULDLOG(ccnr, LM_128, CCNL_FINE))
00807         ccnr_debug_ccnb(ccnr, __LINE__, "r_proto_start_write_checked looking for", NULL,
00808                         interest->buf, interest->length);
00809     content = r_store_lookup(ccnr, interest->buf, pi, comps);
00810     ccn_charbuf_destroy(&interest);
00811     ccn_indexbuf_destroy(&comps);
00812     if (content == NULL) {
00813         if (CCNSHOULDLOG(ccnr, LM_128, CCNL_FINE))
00814             ccnr_msg(ccnr, "r_proto_start_write_checked: NOT PRESENT");
00815         // XXX - dropping into the start_write case means we do not check the provided digest when fetching, so this is not completely right.
00816         return(r_proto_start_write(selfp, kind, info, marker_comp));
00817     }
00818     // what's the return value if the item is in the repository already?
00819     // if it does have it -- getRepoInfo(interest.name(), null, target_names)
00820     // response has local name as the full name of the thing we claim to have --
00821     // take the command marker and nonce out of the middle of the incoming interest,
00822     // which is what we have in the "name" of the interest we created to check the content.
00823     ///// begin copied code
00824     /* Generate our reply */
00825     msg = ccn_charbuf_create();
00826     reply_body = ccn_charbuf_create();
00827     r_proto_append_repo_info(ccnr, reply_body, name, NULL);
00828     start = info->pi->offset[CCN_PI_B_Name];
00829     end = info->interest_comps->buf[info->pi->prefix_comps];
00830     name->length = 0;
00831     ccn_charbuf_append(name, info->interest_ccnb + start, end - start);
00832     ccn_charbuf_append_closer(name);
00833     sp.freshness = 12; /* Seconds */
00834     res = ccn_sign_content(info->h, msg, name, &sp,
00835                            reply_body->buf, reply_body->length);
00836     if (res < 0)
00837         goto Bail;
00838     if (CCNSHOULDLOG(ccnr, LM_128, CCNL_FINE))
00839         ccnr_msg(ccnr, "r_proto_start_write_checked PRESENT");
00840     res = ccn_put(info->h, msg->buf, msg->length);
00841     if (res < 0) {
00842         // note the error somehow.
00843         ccnr_debug_ccnb(ccnr, __LINE__, "r_proto_start_write_checked ccn_put FAILED", NULL,
00844                         msg->buf, msg->length);
00845     }
00846     //// end of copied code
00847 Bail:
00848     ccn_charbuf_destroy(&name);
00849     ccn_charbuf_destroy(&reply_body);
00850     ccn_charbuf_destroy(&msg);
00851     return(ans);
00852 }
00853 
00854 /**
00855  * Returns 1 if the Exclude in the interest described by the info parameter
00856  * would exclude the full name in name.
00857  */
00858 static int
00859 r_proto_check_exclude(struct ccnr_handle *ccnr,
00860                       struct ccn_upcall_info *info,
00861                       struct ccn_charbuf *name)
00862 {
00863     struct ccn_buf_decoder decoder;
00864     struct ccn_buf_decoder *d = NULL;
00865     const unsigned char *comp = NULL;
00866     size_t comp_size;
00867     size_t name_comp_size;
00868     struct ccn_indexbuf *name_comps = NULL;
00869     const unsigned char *name_string = NULL;
00870     int nc;
00871     int ci;
00872     int res;
00873     int ans = 0;
00874     
00875     if (info->pi->offset[CCN_PI_B_Exclude] < info->pi->offset[CCN_PI_E_Exclude]) {
00876         d = ccn_buf_decoder_start(&decoder,
00877                                   info->interest_ccnb + info->pi->offset[CCN_PI_B_Exclude],
00878                                   info->pi->offset[CCN_PI_E_Exclude] -
00879                                   info->pi->offset[CCN_PI_B_Exclude]);
00880         
00881         // handle easy case of <Exclude><Component>...</Exclude>
00882         // XXX - this may need to be better, but not necessarily complete
00883         if (ccn_buf_match_dtag(d, CCN_DTAG_Exclude)) {
00884             ccn_buf_advance(d);
00885         } else 
00886             goto Bail;
00887         // there may be something to check, so get the components of the name
00888         name_comps = ccn_indexbuf_create();
00889         nc = ccn_name_split(name, name_comps);
00890         // the component in the name we are matching is last plus one of the interest
00891         // but ci includes an extra value for the end of the last component
00892         ci = info->interest_comps->n;
00893         res = ccn_name_comp_get(name->buf, name_comps, ci - 1, &name_string, &name_comp_size);
00894         if (res < 0)
00895             goto Bail;
00896         while (ccn_buf_match_dtag(d, CCN_DTAG_Component)) {
00897             ccn_buf_advance(d);
00898             comp_size = 0;
00899             if (ccn_buf_match_blob(d, &comp, &comp_size))
00900                 ccn_buf_advance(d);
00901             ccn_buf_check_close(d);
00902             if (comp_size == name_comp_size) {
00903                 res = memcmp(comp, name_string, comp_size);
00904                 if (res == 0) {
00905                     ans = 1;
00906                     goto Bail; /* One of the explicit excludes */
00907                 }
00908                 if (res > 0)
00909                     break;
00910             }
00911         }
00912     }
00913     
00914 Bail:
00915     ccn_indexbuf_destroy(&name_comps);
00916     if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINE))
00917         ccnr_msg(ccnr, "r_proto_check_exclude: do%s exclude", (ans == 1) ? "" : " not");
00918     return(ans);
00919 }
00920 
00921 #define ENUMERATION_STATE_TICK_MICROSEC 1000000
00922 /**
00923  * Remove expired enumeration table entries
00924  */
00925 static int
00926 reap_enumerations(struct ccn_schedule *sched,
00927                   void *clienth,
00928                   struct ccn_scheduled_event *ev,
00929                   int flags)
00930 {
00931     struct ccnr_handle *ccnr = clienth;
00932     struct hashtb_enumerator ee;
00933     struct hashtb_enumerator *e = &ee;
00934     struct enum_state *es = NULL;
00935     int i;
00936     
00937     if ((flags & CCN_SCHEDULE_CANCEL) != 0) {
00938         ccnr->reap_enumerations = NULL;
00939         return(0);
00940     }
00941     hashtb_start(ccnr->enum_state_tab, e);
00942     for (es = e->data; es != NULL; es = e->data) {
00943         if (es->active != ES_ACTIVE &&
00944             r_util_timecmp(es->lastuse_sec + es->lifetime, es->lastuse_usec,
00945                            ccnr->sec, ccnr->usec) <= 0) {
00946                 if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINER))
00947                     ccnr_debug_ccnb(ccnr, __LINE__, "reap enumeration state", NULL,
00948                                     es->name->buf, es->name->length);            
00949                 ccn_charbuf_destroy(&es->name);
00950                 ccn_charbuf_destroy(&es->interest); // unnecessary?
00951                 ccn_charbuf_destroy(&es->reply_body);
00952                 ccn_indexbuf_destroy(&es->interest_comps);
00953                 for (i = 0; i < ENUM_N_COBS; i++)
00954                     ccn_charbuf_destroy(&(es->cob[i]));
00955                 // remove the entry from the hash table
00956                 hashtb_delete(e);
00957             }
00958         hashtb_next(e);
00959     }
00960     hashtb_end(e);
00961     if (hashtb_n(ccnr->enum_state_tab) == 0) {
00962         ccnr->reap_enumerations = NULL;
00963         return(0);
00964     }
00965     return(ENUMERATION_STATE_TICK_MICROSEC);
00966 }
00967 static void
00968 reap_enumerations_needed(struct ccnr_handle *ccnr)
00969 {
00970     if (ccnr->reap_enumerations == NULL)
00971         ccnr->reap_enumerations = ccn_schedule_event(ccnr->sched,
00972                                                      ENUMERATION_STATE_TICK_MICROSEC,
00973                                                      reap_enumerations,
00974                                                      NULL, 0);
00975 }
00976 
00977 static enum ccn_upcall_res
00978 r_proto_begin_enumeration(struct ccn_closure *selfp,
00979                           enum ccn_upcall_kind kind,
00980                           struct ccn_upcall_info *info,
00981                           int marker_comp)
00982 {
00983     struct ccnr_handle *ccnr = NULL;
00984     enum ccn_upcall_res ans = CCN_UPCALL_RESULT_ERR;
00985     struct ccn_parsed_interest parsed_interest = {0};
00986     struct ccn_parsed_interest *pi = &parsed_interest;
00987     struct hashtb_enumerator enumerator = {0};
00988     struct hashtb_enumerator *e = &enumerator;
00989     struct ccn_charbuf *name = NULL;
00990     struct ccn_charbuf *cob = NULL;
00991     struct ccn_charbuf *interest = NULL;
00992     struct ccn_indexbuf *comps = NULL;
00993     int res;
00994     struct content_entry *content = NULL;
00995     struct enum_state *es = NULL;
00996     
00997     ccnr = (struct ccnr_handle *)selfp->data;
00998     // Construct a name up to but not including the begin enumeration marker component
00999     name = ccn_charbuf_create();
01000     ccn_name_init(name);
01001     ccn_name_append_components(name, info->interest_ccnb,
01002                                info->interest_comps->buf[0],
01003                                info->interest_comps->buf[marker_comp]);
01004     // Make an interest for the part of the namespace we are after, from the name
01005     interest = ccn_charbuf_create();
01006     ccnb_element_begin(interest, CCN_DTAG_Interest);
01007     ccn_charbuf_append_charbuf(interest, name);
01008     ccnb_element_end(interest); /* </Interest> */
01009     
01010     // Parse it
01011     comps = ccn_indexbuf_create();
01012     res = ccn_parse_interest(interest->buf, interest->length, pi, comps);
01013     if (res < 0)
01014         abort();
01015     // Look for a previous enumeration under this prefix
01016     hashtb_start(ccnr->enum_state_tab, e);
01017     res = hashtb_seek(e, name->buf, name->length, 0);
01018     es = e->data;
01019     if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINE))
01020         ccnr_debug_ccnb(ccnr, __LINE__, "enumeration: begin hash key", NULL,
01021                         name->buf, name->length);
01022     // Do not restart an active enumeration, it is probably a duplicate interest
01023     // TODO: may need attention when es->active == ES_ACTIVE_PENDING_INACTIVE
01024     if (res == HT_OLD_ENTRY && es->active != ES_INACTIVE) {
01025         if (es->next_segment > 0)
01026             cob = es->cob[(es->next_segment - 1) % ENUM_N_COBS];
01027         if (cob && ccn_content_matches_interest(cob->buf, cob->length, 1, NULL,
01028                                          info->interest_ccnb, info->pi->offset[CCN_PI_E], info->pi)) {
01029             if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINER))
01030                 ccnr_msg(ccnr, "enumeration: duplicate request for last cob");
01031             ccn_put(info->h, cob->buf, cob->length);
01032             es->cob_deferred[(es->next_segment - 1) % ENUM_N_COBS] = 0;
01033             ans = CCN_UPCALL_RESULT_INTEREST_CONSUMED;
01034         } else {
01035             if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINEST)) {
01036                 ccnr_msg(ccnr, "enumeration: restart of active enumeration, or excluded");
01037                 ccnr_debug_ccnb(ccnr, __LINE__, "enum    interest: ", NULL, info->interest_ccnb, info->pi->offset[CCN_PI_E]);
01038                 if (cob != NULL)
01039                     ccnr_debug_ccnb(ccnr, __LINE__, "enum cob content: ", NULL, cob->buf, cob->length);
01040             }
01041             ans = CCN_UPCALL_RESULT_OK;
01042         }
01043         hashtb_end(e);
01044         goto Bail;
01045     }
01046     // Continue to construct the name under which we will respond: %C1.E.be
01047     ccn_name_append_components(name, info->interest_ccnb,
01048                                info->interest_comps->buf[marker_comp],
01049                                info->interest_comps->buf[marker_comp + 1]);
01050     // Append the repository key id %C1.K.%00<repoid>
01051     ccn_name_append(name, ccnr->ccnr_keyid->buf, ccnr->ccnr_keyid->length);
01052     
01053     if (res == HT_NEW_ENTRY || es->starting_cookie != ccnr->cookie) {
01054         // this is a new enumeration, the time is now.
01055         res = ccn_create_version(info->h, name, CCN_V_NOW, 0, 0);
01056         if (es->name != NULL)
01057             ccn_charbuf_destroy(&es->name);
01058         es->name = ccn_charbuf_create();
01059         ccn_charbuf_append_charbuf(es->name, name);
01060         es->starting_cookie = ccnr->cookie; // XXX - a conservative indicator of change
01061     }
01062     ccn_charbuf_destroy(&name);
01063     // check the exclude against the result name
01064     if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINE))
01065         ccnr_debug_ccnb(ccnr, __LINE__, "begin enum: result name", NULL,
01066                         es->name->buf, es->name->length);
01067     
01068     if (r_proto_check_exclude(ccnr, info, es->name) > 0) {
01069         hashtb_end(e);
01070         goto Bail;
01071     }
01072 
01073     // do we have anything that matches this enumeration request?
01074     content = r_store_find_first_match_candidate(ccnr, interest->buf, pi);
01075     if (content != NULL &&
01076         !r_store_content_matches_interest_prefix(ccnr, content, interest->buf, interest->length))
01077         content = NULL;
01078     ccn_charbuf_destroy(&es->cob[0]);
01079     es->cob[0] = ccn_charbuf_create();
01080     memset(es->cob_deferred, 0, sizeof(es->cob_deferred));
01081     ccn_charbuf_destroy(&es->reply_body);
01082     es->reply_body = ccn_charbuf_create();
01083     ccnb_element_begin(es->reply_body, CCN_DTAG_Collection);
01084     es->content = content;
01085     ccn_charbuf_destroy(&es->interest);
01086     es->interest = interest;
01087     interest = NULL;
01088     ccn_indexbuf_destroy(&es->interest_comps);
01089     es->interest_comps = comps;
01090     comps = NULL;
01091     es->next_segment = 0;
01092     es->lastuse_sec = ccnr->sec;
01093     es->lastuse_usec = ccnr->usec;
01094     if (content) {
01095         es->lifetime = 3 * ccn_interest_lifetime_seconds(info->interest_ccnb, pi);
01096         es->active = ES_ACTIVE;
01097     } else {
01098         es->lifetime = ccn_interest_lifetime_seconds(info->interest_ccnb, pi);
01099         es->active = ES_PENDING;
01100     }
01101     hashtb_end(e);
01102     reap_enumerations_needed(ccnr);
01103     if (content)
01104         ans = r_proto_continue_enumeration(selfp, kind, info, marker_comp);
01105     else
01106         ans = CCN_UPCALL_RESULT_OK;
01107 Bail:
01108     ccn_charbuf_destroy(&name);
01109     ccn_charbuf_destroy(&interest);
01110     ccn_indexbuf_destroy(&comps);
01111     return(ans);
01112 }
01113 
01114 static enum ccn_upcall_res
01115 r_proto_continue_enumeration(struct ccn_closure *selfp,
01116                              enum ccn_upcall_kind kind,
01117                              struct ccn_upcall_info *info,
01118                              int marker_comp) {
01119     // XXX - watch out for pipelined interests for the enumerations -- there
01120     // MUST be an active enumeration continuation before we do anything here.
01121     // Should chop 1 component off interest -- which will look like
01122     // ccnx:/.../%C1.E.be/%C1.M.K%00.../%FD.../%00%02
01123     struct ccn_charbuf *hashkey = NULL;
01124     struct ccn_charbuf *result_name = NULL;
01125     struct ccn_charbuf *cob = NULL;
01126     struct ccn_indexbuf *ic = NULL;
01127     intmax_t segment;
01128     struct enum_state *es = NULL;
01129     struct ccnr_handle *ccnr = NULL;
01130     struct hashtb_enumerator enumerator = {0};
01131     struct hashtb_enumerator *e = &enumerator;
01132     struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
01133     int cobs_deferred;
01134     int i;
01135     int res = 0;
01136     
01137     ccnr = (struct ccnr_handle *)selfp->data;
01138     ic = info->interest_comps;
01139     hashkey=ccn_charbuf_create();
01140     ccn_name_init(hashkey);
01141     ccn_name_append_components(hashkey, info->interest_ccnb,
01142                                info->interest_comps->buf[0],
01143                                info->interest_comps->buf[marker_comp]);
01144     hashtb_start(ccnr->enum_state_tab, e);
01145     res = hashtb_seek(e, hashkey->buf, hashkey->length, 0);
01146     ccn_charbuf_destroy(&hashkey);
01147     if (res != HT_OLD_ENTRY) {
01148         hashtb_end(e);
01149         return(CCN_UPCALL_RESULT_ERR);
01150     }
01151     es = e->data;
01152     if (es->active != ES_ACTIVE && es->active != ES_ACTIVE_PENDING_INACTIVE) {
01153         hashtb_end(e);
01154         return(CCN_UPCALL_RESULT_ERR);
01155     }
01156     // If there is a segment in the request, get the value.
01157     segment = r_util_segment_from_component(info->interest_ccnb,
01158                                             ic->buf[ic->n - 2],
01159                                             ic->buf[ic->n - 1]);
01160     if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINE))
01161         ccnr_msg(ccnr, "enumeration: requested %jd :: expected %jd", segment, es->next_segment);
01162     if (segment >= 0 && segment != es->next_segment) {
01163         // too far in the future for us to process
01164         if (segment > es->next_segment + (ENUM_N_COBS / 2)) {
01165             if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINER))
01166                 ccnr_msg(ccnr, "enumeration: ignoring future segment requested %jd :: expected %jd", segment, es->next_segment);
01167             hashtb_end(e);
01168             return (CCN_UPCALL_RESULT_OK);
01169         }
01170         // if theres a possibility we could have it
01171         if (segment >= es->next_segment - ENUM_N_COBS) {
01172             cob = es->cob[segment % ENUM_N_COBS];
01173             if (cob &&
01174                 ccn_content_matches_interest(cob->buf, cob->length, 1, NULL,
01175                                              info->interest_ccnb, info->pi->offset[CCN_PI_E], info->pi)) {
01176                     if (CCNSHOULDLOG(ccnr, LM_8, CCNL_FINER))
01177                         ccnr_msg(ccnr, "enumeration: putting cob for out-of-order segment %jd",
01178                                  segment);
01179                     ccn_put(info->h, cob->buf, cob->length);
01180                     es->cob_deferred[segment % ENUM_N_COBS] = 0;
01181                     if (es->active == ES_ACTIVE_PENDING_INACTIVE) {
01182                         for (i = 0, cobs_deferred = 0; i < ENUM_N_COBS; i++) {
01183                             cobs_deferred += es->cob_deferred[i];
01184                         }
01185                         if (cobs_deferred == 0)
01186                             goto EnumerationComplete;
01187                     }
01188                     hashtb_end(e);
01189                     return (CCN_UPCALL_RESULT_INTEREST_CONSUMED);
01190                 }
01191         }
01192     }
01193 NextSegment:
01194     if (CCNSHOULDLOG(ccnr, blah, CCNL_FINE))
01195         ccnr_msg(ccnr, "enumeration: generating segment %jd", es->next_segment);
01196     es->lastuse_sec = ccnr->sec;
01197     es->lastuse_usec = ccnr->usec;
01198     while (es->content != NULL &&
01199            r_store_content_matches_interest_prefix(ccnr, es->content,
01200                                                    es->interest->buf,
01201                                                    es->interest->length)) {
01202         int save = es->reply_body->length;
01203         ccnb_element_begin(es->reply_body, CCN_DTAG_Link);
01204         ccnb_element_begin(es->reply_body, CCN_DTAG_Name);
01205         ccnb_element_end(es->reply_body); /* </Name> */
01206         res = r_store_name_append_components(es->reply_body, ccnr, es->content, es->interest_comps->n - 1, 1);
01207         ccnb_element_end(es->reply_body); /* </Link> */
01208         if (res == 0) {
01209             /* The name matched exactly, need to skip. */
01210             es->reply_body->length = save;
01211             es->content = r_store_next_child_at_level(ccnr, es->content, es->interest_comps->n - 1);
01212             continue;
01213         }
01214         if (res != 1) {
01215             ccnr_debug_ccnb(ccnr, __LINE__, "oops", NULL, es->interest->buf, es->interest->length);
01216             ccnr_debug_content(ccnr, __LINE__, "oops", NULL, es->content);
01217             abort();
01218         }
01219         es->content = r_store_next_child_at_level(ccnr, es->content, es->interest_comps->n - 1);
01220         if (es->reply_body->length >= 4096) {
01221             result_name = ccn_charbuf_create();
01222             ccn_charbuf_append_charbuf(result_name, es->name);
01223             ccn_name_append_numeric(result_name, CCN_MARKER_SEQNUM, es->next_segment);
01224             sp.freshness = 60;
01225             cob = es->cob[es->next_segment % ENUM_N_COBS];
01226             if (cob == NULL) {
01227                 cob = ccn_charbuf_create();
01228                 es->cob[es->next_segment % ENUM_N_COBS] = cob;
01229             }
01230             cob->length = 0;
01231             res = ccn_sign_content(info->h, cob, result_name, &sp,
01232                                    es->reply_body->buf, 4096);
01233             ccn_charbuf_destroy(&result_name);
01234             if (segment == -1 || segment == es->next_segment) {
01235                 if (CCNSHOULDLOG(ccnr, blah, CCNL_FINER))
01236                     ccnr_msg(ccnr, "enumeration: putting cob for segment %jd", es->next_segment);
01237                 ccn_put(info->h, cob->buf, cob->length);
01238             } else {
01239                 es->cob_deferred[es->next_segment % ENUM_N_COBS] = 1;
01240             }
01241             es->next_segment++;
01242             memmove(es->reply_body->buf, es->reply_body->buf + 4096, es->reply_body->length - 4096);
01243             es->reply_body->length -= 4096;
01244             if (segment >= es->next_segment)
01245                  goto NextSegment;
01246             hashtb_end(e);
01247             return (CCN_UPCALL_RESULT_INTEREST_CONSUMED);
01248         }
01249     }
01250     // we will only get here if we are finishing an in-progress enumeration
01251     ccnb_element_end(es->reply_body); /* </Collection> */
01252     result_name = ccn_charbuf_create();
01253     ccn_charbuf_append_charbuf(result_name, es->name);
01254     ccn_name_append_numeric(result_name, CCN_MARKER_SEQNUM, es->next_segment);
01255     sp.freshness = 60;
01256     sp.sp_flags |= CCN_SP_FINAL_BLOCK;
01257     cob = es->cob[es->next_segment % ENUM_N_COBS];
01258     if (cob == NULL) {
01259         cob = ccn_charbuf_create();
01260         es->cob[es->next_segment % ENUM_N_COBS] = cob;
01261     }
01262     cob->length = 0;
01263     res = ccn_sign_content(info->h, cob, result_name, &sp, es->reply_body->buf,
01264                            es->reply_body->length);
01265     ccn_charbuf_destroy(&result_name);    
01266     if (CCNSHOULDLOG(ccnr, blah, CCNL_FINER))
01267         ccnr_msg(ccnr, "enumeration: putting final cob for segment %jd", es->next_segment);
01268     ccn_put(info->h, cob->buf, cob->length);
01269     es->cob_deferred[es->next_segment % ENUM_N_COBS] = 0;
01270     for (i = 0, cobs_deferred = 0; i < ENUM_N_COBS; i++) {
01271         cobs_deferred += es->cob_deferred[i];
01272     }
01273     if (cobs_deferred > 0) {
01274         if (CCNSHOULDLOG(ccnr, blah, CCNL_FINER))
01275             ccnr_msg(ccnr, "enumeration: %d pending cobs, inactive pending complete",
01276                      cobs_deferred);
01277         es->active = ES_ACTIVE_PENDING_INACTIVE;
01278         hashtb_end(e);
01279         return (CCN_UPCALL_RESULT_INTEREST_CONSUMED);
01280     }
01281 EnumerationComplete:
01282     if (CCNSHOULDLOG(ccnr, blah, CCNL_FINER))
01283         ccnr_msg(ccnr, "enumeration: inactive", es->next_segment);
01284     // The enumeration is complete, free charbufs but leave the name.
01285     es->active = ES_INACTIVE;
01286     ccn_charbuf_destroy(&es->interest);
01287     ccn_charbuf_destroy(&es->reply_body);
01288     for (i = 0; i < ENUM_N_COBS; i++)
01289         ccn_charbuf_destroy(&es->cob[i]);
01290     ccn_indexbuf_destroy(&es->interest_comps);
01291     hashtb_end(e);
01292     return(CCN_UPCALL_RESULT_INTEREST_CONSUMED);
01293 }
01294 
01295 void
01296 r_proto_dump_enums(struct ccnr_handle *ccnr)
01297 {
01298     struct enum_state *es = NULL;
01299     struct hashtb_enumerator enumerator = {0};
01300     struct hashtb_enumerator *e = &enumerator;
01301     
01302     for (hashtb_start(ccnr->enum_state_tab, e); e->data != NULL; hashtb_next(e)) {
01303         es = e->data;
01304         ccnr_msg(ccnr, "Enumeration active: %d, next segment %d, cookie %u",
01305                  es->active, es->next_segment, es->starting_cookie);
01306         ccnr_debug_ccnb(ccnr, __LINE__, "     enum name", NULL,
01307                         es->name->buf, es->name->length);
01308         
01309     }  
01310     hashtb_end(e);
01311 }
01312 
01313 static enum ccn_upcall_res
01314 r_proto_bulk_import(struct ccn_closure *selfp,
01315                           enum ccn_upcall_kind kind,
01316                           struct ccn_upcall_info *info,
01317                           int marker_comp)
01318 {
01319     enum ccn_upcall_res ans = CCN_UPCALL_RESULT_ERR;
01320     struct ccnr_handle *ccnr = NULL;
01321     struct ccn_charbuf *filename = NULL;
01322     struct ccn_charbuf *filename2 = NULL;
01323     const unsigned char *mstart = NULL;
01324     size_t mlength;
01325     struct ccn_indexbuf *ic = NULL;
01326     struct ccn_charbuf *msg = NULL;
01327     struct ccn_charbuf *name = NULL;
01328     struct ccn_charbuf *reply_body = NULL;
01329     struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
01330     const char *infostring = "OK";
01331     int res;
01332     
01333     ccnr = (struct ccnr_handle *)selfp->data;
01334     ccn_name_comp_get(info->interest_ccnb, info->interest_comps, marker_comp,
01335                       &mstart, &mlength);
01336     if (mlength <= strlen(REPO_AF) + 1 || mstart[strlen(REPO_AF)] != '~') {
01337         infostring = "missing or malformed bulk import name component";
01338         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01339         goto Reply;
01340     }
01341     mstart += strlen(REPO_AF) + 1;
01342     mlength -= (strlen(REPO_AF) + 1);
01343     if (memchr(mstart, '/', mlength) != NULL) {
01344         infostring = "bulk import filename must not include directory";
01345         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01346         goto Reply;
01347     }
01348     filename = ccn_charbuf_create();
01349     ccn_charbuf_append_string(filename, "import/");
01350     ccn_charbuf_append(filename, mstart, mlength);
01351     res = r_init_map_and_process_file(ccnr, filename, 0);
01352     if (res == 1) {
01353         infostring = "unable to open bulk import file";
01354         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01355         goto Reply;
01356     }
01357     if (res < 0) {
01358         infostring = "error parsing bulk import file";
01359         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01360         goto Reply;
01361     }
01362     /* we think we can process it */
01363     filename->length = 0;
01364     ccn_charbuf_putf(filename, "%s/import/", ccnr->directory);
01365     ccn_charbuf_append(filename, mstart, mlength);
01366     filename2 = ccn_charbuf_create();
01367     ccn_charbuf_putf(filename2, "%s/import/.", ccnr->directory);
01368     ccn_charbuf_append(filename2, mstart, mlength);
01369     res = rename(ccn_charbuf_as_string(filename),
01370                  ccn_charbuf_as_string(filename2));
01371     if (res < 0) {
01372         infostring = "error renaming bulk import file";
01373         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01374         goto Reply;        
01375     }
01376     filename->length = 0;
01377     ccn_charbuf_append_string(filename, "import/.");
01378     ccn_charbuf_append(filename, mstart, mlength);
01379     res = r_init_map_and_process_file(ccnr, filename, 1);
01380     if (res < 0) {
01381         infostring = "error merging bulk import file";
01382         ccnr_msg(ccnr, "r_proto_bulk_import: %s", infostring);
01383         // fall through and unlink anyway
01384     }
01385     if (CCNSHOULDLOG(ccnr, sdfdf, CCNL_FINE))
01386         ccnr_msg(ccnr, "unlinking bulk import file %s", ccn_charbuf_as_string(filename2));   
01387     unlink(ccn_charbuf_as_string(filename2));
01388 
01389 Reply:
01390     /* Generate our reply */
01391     name = ccn_charbuf_create();
01392     ccn_name_init(name);
01393     ic = info->interest_comps;
01394     ccn_name_append_components(name, info->interest_ccnb, ic->buf[0], ic->buf[ic->n - 1]);
01395 
01396     msg = ccn_charbuf_create();
01397     reply_body = ccn_charbuf_create();
01398     r_proto_append_repo_info(ccnr, reply_body, NULL, infostring);
01399     sp.freshness = 12; /* Seconds */
01400     res = ccn_sign_content(info->h, msg, name, &sp,
01401                            reply_body->buf, reply_body->length);
01402     if (res < 0)
01403         goto Bail;
01404     res = ccn_put(info->h, msg->buf, msg->length);
01405     if (res < 0) {
01406         ccnr_debug_ccnb(ccnr, __LINE__, "r_proto_bulk_import ccn_put FAILED", NULL,
01407                         msg->buf, msg->length);
01408         goto Bail;
01409     }
01410     ans = CCN_UPCALL_RESULT_INTEREST_CONSUMED;
01411 
01412 Bail:
01413     if (filename != NULL) ccn_charbuf_destroy(&filename);
01414     if (filename2 != NULL) ccn_charbuf_destroy(&filename2);
01415     if (name != NULL) ccn_charbuf_destroy(&name);
01416     if (msg != NULL) ccn_charbuf_destroy(&msg);
01417     if (reply_body != NULL) ccn_charbuf_destroy(&reply_body);
01418     return (ans);
01419 }
01420 
01421 /* Construct a charbuf with an encoding of a Policy object 
01422  *
01423  *  <xs:complexType name="PolicyType">
01424  *      <xs:sequence>
01425  *      <xs:element name="PolicyVersion" type="xs:string"/> 
01426  *      <xs:element name="LocalName" type="xs:string"/>
01427  *      <xs:element name="GlobalPrefix" type="xs:string"/>
01428  *  <!-- 0 or more names -->
01429  *      <xs:element name="Namespace" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
01430  *      </xs:sequence>
01431  *  </xs:complexType>
01432  */ 
01433 PUBLIC int
01434 r_proto_policy_append_basic(struct ccnr_handle *ccnr,
01435                             struct ccn_charbuf *policy,
01436                             const char *version, const char *local_name,
01437                             const char *global_prefix)
01438 {
01439     int res;
01440     res = ccnb_element_begin(policy, CCN_DTAG_Policy);
01441     res |= ccnb_tagged_putf(policy, CCN_DTAG_PolicyVersion, "%s", version);
01442     res |= ccnb_tagged_putf(policy, CCN_DTAG_LocalName, "%s", local_name);
01443     res |= ccnb_tagged_putf(policy, CCN_DTAG_GlobalPrefix, "%s", global_prefix);
01444     res |= ccnb_element_end(policy);
01445     return (res);
01446 }
01447 PUBLIC int
01448 r_proto_policy_append_namespace(struct ccnr_handle *ccnr,
01449                                 struct ccn_charbuf *policy,
01450                                 const char *namespace)
01451 {
01452     int res;
01453     if (policy->length < 2)
01454         return(-1);
01455     policy->length--;   /* remove the closer */
01456     res = ccnb_tagged_putf(policy, CCN_DTAG_Namespace, "%s", namespace);
01457     ccnb_element_end(policy);
01458     return(res);
01459 }
01460 
01461 /**
01462  * Parse a ccnb-encoded policy content object and fill in a ccn_parsed_policy
01463  * structure as the result.
01464  */
01465 PUBLIC int
01466 r_proto_parse_policy(struct ccnr_handle *ccnr, const unsigned char *buf, size_t length,
01467                      struct ccnr_parsed_policy *pp)
01468 {
01469     int res = 0;
01470     struct ccn_buf_decoder decoder;
01471     struct ccn_buf_decoder *d = ccn_buf_decoder_start(&decoder, buf,
01472                                                       length);
01473     if (ccn_buf_match_dtag(d, CCN_DTAG_Policy)) {
01474         ccn_buf_advance(d);
01475         pp->policy_version_offset = ccn_parse_tagged_string(d, CCN_DTAG_PolicyVersion, pp->store);
01476         pp->local_name_offset = ccn_parse_tagged_string(d, CCN_DTAG_LocalName, pp->store);
01477         pp->global_prefix_offset = ccn_parse_tagged_string(d, CCN_DTAG_GlobalPrefix, pp->store);
01478         pp->namespaces->n = 0;
01479         while (ccn_buf_match_dtag(d, CCN_DTAG_Namespace)) {
01480             ccn_indexbuf_append_element(pp->namespaces, ccn_parse_tagged_string(d, CCN_DTAG_Namespace, pp->store));
01481         }
01482         ccn_buf_check_close(d);
01483     } else {
01484         return(-1);
01485     }
01486     return (res);
01487 }
01488 
01489 /**
01490  * Initiate a key fetch if necessary.
01491  * @returns -1 if error or no name, 0 if fetch was issued, 1 if already stored.
01492  */
01493 int
01494 r_proto_initiate_key_fetch(struct ccnr_handle *ccnr,
01495                            const unsigned char *msg,
01496                            struct ccn_parsed_ContentObject *pco,
01497                            int use_link,
01498                            ccnr_cookie a)
01499 {
01500     /* 
01501      * Create a new interest in the key name, set up a callback that will
01502      * insert the key into repo.
01503      */
01504     int res;
01505     struct ccn_charbuf *key_name = NULL;
01506     struct ccn_closure *key_closure = NULL;
01507     struct ccn_charbuf *templ = NULL;
01508     struct ccnr_expect_content *expect_content = NULL;
01509     const unsigned char *namestart = NULL;
01510     int namelen = 0;
01511     int keynamelen;
01512     int i;
01513     
01514     keynamelen = (pco->offset[CCN_PCO_E_KeyName_Name] -
01515                   pco->offset[CCN_PCO_B_KeyName_Name]);
01516     if (use_link) {
01517         /* Try to follow a link instead of using keyname */
01518         if (pco->type == CCN_CONTENT_LINK) {
01519             /* For now we only pay attention to the Name in the Link. */
01520             const unsigned char *data = NULL;
01521             size_t data_size = 0;
01522             struct ccn_buf_decoder decoder;
01523             struct ccn_buf_decoder *d;
01524             res = ccn_content_get_value(msg, pco->offset[CCN_PCO_E], pco,
01525                                         &data, &data_size);
01526             if (res < 0)
01527                 return(-1);
01528             d = ccn_buf_decoder_start(&decoder, data, data_size);
01529             if (ccn_buf_match_dtag(d, CCN_DTAG_Link)) {
01530                 int start = 0;
01531                 int end = 0;
01532                 ccn_buf_advance(d);
01533                 start = d->decoder.token_index;
01534                 ccn_parse_Name(d, NULL);
01535                 end = d->decoder.token_index;
01536                 ccn_buf_check_close(d);
01537                 if (d->decoder.state < 0)
01538                     return(-1);
01539                 namestart = data + start;
01540                 namelen = end - start;
01541                 if (namelen == keynamelen &&
01542                     0 == memcmp(namestart, msg + pco->offset[CCN_PCO_B_KeyName_Name], namelen)) {
01543                     /*
01544                      * The link matches the key locator. There is no point
01545                      * in checking two times for the same thing.
01546                      */
01547                     if (CCNSHOULDLOG(ccnr, sdfdf, CCNL_FINE))
01548                         ccnr_debug_ccnb(ccnr, __LINE__, "keyfetch_link_opt",
01549                                         NULL, namestart, namelen);
01550                     return(-1);
01551                 }
01552             }
01553         }
01554     }
01555     else {
01556         /* Use the KeyName if present */
01557         namestart = msg + pco->offset[CCN_PCO_B_KeyName_Name];
01558         namelen = (pco->offset[CCN_PCO_E_KeyName_Name] -
01559                    pco->offset[CCN_PCO_B_KeyName_Name]);
01560     }
01561     /*
01562      * If there is no KeyName or link, provided, we can't ask, so do not bother.
01563      */
01564     if (namelen == 0 || a == 0)
01565         return(-1);
01566     key_name = ccn_charbuf_create();
01567     ccn_charbuf_append(key_name, namestart, namelen);
01568     /* Construct an interest complete with Name so we can do lookup */
01569     templ = ccn_charbuf_create();
01570     ccn_charbuf_append_tt(templ, CCN_DTAG_Interest, CCN_DTAG);
01571     ccn_charbuf_append(templ, key_name->buf, key_name->length);
01572     ccnb_tagged_putf(templ, CCN_DTAG_MinSuffixComponents, "%d", 1);
01573     ccnb_tagged_putf(templ, CCN_DTAG_MaxSuffixComponents, "%d", 3);
01574     if (pco->offset[CCN_PCO_B_KeyName_Pub] < pco->offset[CCN_PCO_E_KeyName_Pub]) {
01575         ccn_charbuf_append(templ,
01576                            msg + pco->offset[CCN_PCO_B_KeyName_Pub],
01577                            (pco->offset[CCN_PCO_E_KeyName_Pub] - 
01578                             pco->offset[CCN_PCO_B_KeyName_Pub]));
01579     }
01580     ccn_charbuf_append_closer(templ); /* </Interest> */
01581     /* See if we already have it - if so we declare we are done. */
01582     if (r_sync_lookup(ccnr, templ, NULL) == 0) {
01583         res = 1;
01584         // Note - it might be that the thing we found is not really the thing
01585         // we were after.  For now we don't check.
01586     }
01587     else {
01588         /* We do not have it; need to ask */
01589         res = -1;
01590         expect_content = calloc(1, sizeof(*expect_content));
01591         if (expect_content == NULL)
01592             goto Bail;
01593         expect_content->ccnr = ccnr;
01594         expect_content->final = -1;
01595         for (i = 0; i < CCNR_PIPELINE; i++)
01596             expect_content->outstanding[i] = -1;
01597         /* inform r_proto_expect_content we are looking for a key. */
01598         expect_content->keyfetch = a;
01599         key_closure = calloc(1, sizeof(*key_closure));
01600         if (key_closure == NULL)
01601             goto Bail;
01602         key_closure->p = &r_proto_expect_content;
01603         key_closure->data = expect_content;
01604         res = ccn_express_interest(ccnr->direct_client, key_name, key_closure, templ);
01605         if (res >= 0) {
01606             if (CCNSHOULDLOG(ccnr, sdfdf, CCNL_FINE))
01607                 ccnr_debug_ccnb(ccnr, __LINE__, "keyfetch_start",
01608                                 NULL, templ->buf, templ->length);
01609             key_closure = NULL;
01610             expect_content = NULL;
01611             res = 0;
01612         }
01613     }
01614 Bail:
01615     if (key_closure != NULL)
01616         free(key_closure);
01617     if (expect_content != NULL)
01618         free(expect_content);
01619     ccn_charbuf_destroy(&key_name);
01620     ccn_charbuf_destroy(&templ);
01621     return(res);
01622 }
01623 
Generated on Tue Aug 21 14:54:16 2012 for Content-Centric Networking in C by  doxygen 1.6.3