ccn_btree_content.c

Go to the documentation of this file.
00001 /**
00002  * B-tree for indexing ccnx content objects
00003  */
00004 /* (Will be) Part of the CCNx C Library.
00005  *
00006  * Copyright (C) 2011 Palo Alto Research Center, Inc.
00007  *
00008  * This library is free software; you can redistribute it and/or modify it
00009  * under the terms of the GNU Lesser General Public License version 2.1
00010  * as published by the Free Software Foundation.
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00014  * Lesser General Public License for more details. You should have received
00015  * a copy of the GNU Lesser General Public License along with this library;
00016  * if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
00017  * Fifth Floor, Boston, MA 02110-1301 USA.
00018  */
00019  
00020 #include <stdint.h>
00021 #include <string.h>
00022 #include <ccn/btree.h>
00023 #include <ccn/btree_content.h>
00024 #include <ccn/bloom.h>
00025 #include <ccn/ccn.h>
00026 #include <ccn/uri.h>
00027 
00028 #ifndef MYFETCH
00029 #define MYFETCH(p, f) ccn_btree_fetchval(&((p)->f[0]), sizeof((p)->f))
00030 #endif
00031 
00032 #ifndef MYSTORE
00033 #define MYSTORE(p, f, v) ccn_btree_storeval(&((p)->f[0]), sizeof((p)->f), (v))
00034 #endif
00035 
00036 #ifndef MYFETCH64
00037 #define MYFETCH64(p, f) ccn_btree_fetchval64(&((p)->f[0]), sizeof((p)->f))
00038 #endif
00039 static uint_least64_t
00040 ccn_btree_fetchval64(const unsigned char *p, int size)
00041 {
00042     int i;
00043     uint_least64_t v;
00044     
00045     for (v = 0, i = 0; i < size; i++)
00046         v = (v << 8) + p[i];
00047     return(v);
00048 }
00049 
00050 #ifndef MYSTORE64
00051 #define MYSTORE64(p, f, v) ccn_btree_storeval64(&((p)->f[0]), sizeof((p)->f), (v))
00052 #endif
00053 static void
00054 ccn_btree_storeval64(unsigned char *p, int size, uint_least64_t v)
00055 {
00056     int i;
00057     
00058     for (i = size; i > 0; i--, v >>= 8)
00059         p[i-1] = v;
00060 }
00061 
00062 /**
00063  * Insert a ContentObject into a btree node
00064  *
00065  * The caller has presumably already done a lookup and found that the
00066  * object is not there.
00067  *
00068  * The caller is responsible for provinding a valid content parse (pc).
00069  *
00070  * The flatname buffer should hold the correct full name, including the
00071  * digest.
00072  *
00073  * @returns the new entry count or, -1 for error.
00074  */
00075 int
00076 ccn_btree_insert_content(struct ccn_btree_node *node, int ndx,
00077                          uint_least64_t cobid,
00078                          const unsigned char *content_object,
00079                          struct ccn_parsed_ContentObject *pc,
00080                          struct ccn_charbuf *flatname)
00081 {
00082     struct ccn_btree_content_payload payload;
00083     struct ccn_btree_content_payload *e = &payload;
00084     int ncomp;
00085     int res;
00086     unsigned size;
00087     unsigned flags = 0;
00088     const unsigned char *blob = NULL;
00089     size_t blob_size = 0;
00090     
00091     size = pc->offset[CCN_PCO_E];
00092     ncomp = ccn_flatname_ncomps(flatname->buf, flatname->length);
00093     if (ncomp != pc->name_ncomps + 1)
00094         return(-1);
00095     memset(e, 'U', sizeof(*e));
00096     MYSTORE(e, magic, CCN_BT_CONTENT_MAGIC);
00097     MYSTORE(e, ctype, pc->type);
00098     MYSTORE(e, cobsz, size);
00099     MYSTORE(e, ncomp, ncomp);
00100     MYSTORE(e, flags, flags); // XXX - need to set CCN_RCFLAG_LASTBLOCK
00101     MYSTORE(e, ttpad, 0);
00102     MYSTORE(e, timex, 0);
00103     res = ccn_ref_tagged_BLOB(CCN_DTAG_Timestamp, content_object,
00104                               pc->offset[CCN_PCO_B_Timestamp],
00105                               pc->offset[CCN_PCO_E_Timestamp],
00106                               &blob, &blob_size);
00107     if (res < 0 || blob_size > sizeof(e->timex))
00108         return(-1);
00109     memcpy(e->timex + sizeof(e->timex) - blob_size, blob, blob_size);
00110     // XXX - need to set accession time. Should we pass it in?
00111     MYSTORE64(e, cobid, cobid);
00112     res = ccn_ref_tagged_BLOB(CCN_DTAG_PublisherPublicKeyDigest, content_object,
00113                               pc->offset[CCN_PCO_B_PublisherPublicKeyDigest],
00114                               pc->offset[CCN_PCO_E_PublisherPublicKeyDigest],
00115                               &blob, &blob_size);
00116     if (res < 0 || blob_size != sizeof(e->ppkdg))
00117         return(-1);
00118     memcpy(e->ppkdg, blob, sizeof(e->ppkdg));
00119     /* Now actually do the insert */
00120     res = ccn_btree_insert_entry(node, ndx,
00121                                  flatname->buf, flatname->length,
00122                                  e, sizeof(*e));
00123     return(res);
00124 }
00125 
00126 /**
00127  * Test for a match between the ContentObject described by a btree 
00128  * index entry and an Interest, assuming that it is already known that
00129  * there is a prefix match.
00130  *
00131  * This does not need access to the actual ContentObject, since the index
00132  * entry contains everything that we know to know to do the match.
00133  *
00134  * @param node                  leaf node
00135  * @param ndx                   index of entry within leaf node
00136  * @param interest_msg          ccnb-encoded Interest
00137  * @param pi                    corresponding parsed interest
00138  * @param scratch               for scratch use
00139  *
00140  * @result 1 for match, 0 for no match, -1 for error.
00141  */
00142 int
00143 ccn_btree_match_interest(struct ccn_btree_node *node, int ndx,
00144                          const unsigned char *interest_msg,
00145                          const struct ccn_parsed_interest *pi,
00146                          struct ccn_charbuf *scratch)
00147 {
00148     const unsigned char *blob = NULL;
00149     const unsigned char *bloom = NULL;
00150     const unsigned char *comp = NULL;
00151     const unsigned char *nextcomp = NULL;
00152     int i;
00153     int n;
00154     int ncomps;
00155     int pubidend;
00156     int pubidstart;
00157     int res;
00158     int rnc;
00159     size_t blob_size = 0;
00160     size_t bloom_size = 0;
00161     size_t comp_size = 0;
00162     size_t nextcomp_size = 0;
00163     size_t size;
00164     struct ccn_btree_content_payload *e = NULL;
00165     struct ccn_buf_decoder *d = NULL;
00166     struct ccn_buf_decoder decoder;
00167     unsigned char *flatname = NULL;
00168     unsigned char match_any[2] = "-";
00169     
00170     e = ccn_btree_node_getentry(sizeof(*e), node, ndx);
00171     if (e == NULL || e->magic[0] != CCN_BT_CONTENT_MAGIC)
00172         return(-1);
00173     
00174     ncomps = MYFETCH(e, ncomp);
00175     if (ncomps < pi->prefix_comps + pi->min_suffix_comps)
00176         return(0);
00177     if (ncomps > pi->prefix_comps + pi->max_suffix_comps)
00178         return(0);
00179     /* Check that the publisher id matches */
00180     pubidstart = pi->offset[CCN_PI_B_PublisherID];
00181     pubidend = pi->offset[CCN_PI_E_PublisherID];
00182     if (pubidstart < pubidend) {
00183         blob_size = 0;
00184         ccn_ref_tagged_BLOB(CCN_DTAG_PublisherPublicKeyDigest,
00185                             interest_msg,
00186                             pubidstart, pubidend,
00187                             &blob, &blob_size);
00188         if (blob_size != sizeof(e->ppkdg))
00189             return(0);
00190         if (0 != memcmp(blob, e->ppkdg, blob_size))
00191             return(0);
00192     }
00193     /* Do Exclude processing if necessary */
00194     if (pi->offset[CCN_PI_E_Exclude] > pi->offset[CCN_PI_B_Exclude]) {
00195         res = ccn_btree_key_fetch(scratch, node, ndx);
00196         if (res < 0)
00197             return(-1);
00198         flatname = scratch->buf;
00199         size = scratch->length;
00200         nextcomp = NULL;
00201         nextcomp_size = 0;
00202         for (i = 0, n = 0; i < size; i += CCNFLATSKIP(rnc), n++) {
00203             rnc = ccn_flatname_next_comp(flatname + i, size - i);
00204             if (rnc <= 0)
00205                 return(-1);
00206             if (n == pi->prefix_comps) {
00207                 nextcomp = flatname + i + CCNFLATDELIMSZ(rnc);
00208                 nextcomp_size = CCNFLATDATASZ(rnc);
00209                 break;
00210             }
00211         }
00212         if (nextcomp == NULL)
00213             return(0);
00214         /* XXX - Lots of code here that came from ccn_match.c - should refactor */
00215         d = ccn_buf_decoder_start(&decoder,
00216                                   interest_msg + pi->offset[CCN_PI_B_Exclude],
00217                                   pi->offset[CCN_PI_E_Exclude] -
00218                                   pi->offset[CCN_PI_B_Exclude]);
00219         if (!ccn_buf_match_dtag(d, CCN_DTAG_Exclude))
00220             return(-1);
00221         ccn_buf_advance(d);
00222         bloom = NULL;
00223         bloom_size = 0;
00224         if (ccn_buf_match_dtag(d, CCN_DTAG_Any)) {
00225             ccn_buf_advance(d);
00226             bloom = match_any;
00227             ccn_buf_check_close(d);
00228         }
00229         else if (ccn_buf_match_dtag(d, CCN_DTAG_Bloom)) {
00230             ccn_buf_advance(d);
00231             if (ccn_buf_match_blob(d, &bloom, &bloom_size))
00232                 ccn_buf_advance(d);
00233             ccn_buf_check_close(d);
00234         }
00235         while (ccn_buf_match_dtag(d, CCN_DTAG_Component)) {
00236             ccn_buf_advance(d);
00237             comp_size = 0;
00238             if (ccn_buf_match_blob(d, &comp, &comp_size))
00239                 ccn_buf_advance(d);
00240             ccn_buf_check_close(d);
00241             if (comp_size > nextcomp_size)
00242                 break;
00243             if (comp_size == nextcomp_size) {
00244                 res = memcmp(comp, nextcomp, comp_size);
00245                 if (res == 0)
00246                     return(0); /* One of the explicit excludes */
00247                 if (res > 0)
00248                     break;
00249             }
00250             bloom = NULL;
00251             bloom_size = 0;
00252             if (ccn_buf_match_dtag(d, CCN_DTAG_Any)) {
00253                 ccn_buf_advance(d);
00254                 bloom = match_any;
00255                 ccn_buf_check_close(d);
00256             }
00257             else if (ccn_buf_match_dtag(d, CCN_DTAG_Bloom)) {
00258                 ccn_buf_advance(d);
00259                 if (ccn_buf_match_blob(d, &bloom, &bloom_size))
00260                     ccn_buf_advance(d);
00261                 ccn_buf_check_close(d);
00262             }
00263         }
00264         /*
00265          * Now we have isolated the applicable filter (Any or Bloom or none).
00266          */
00267         if (bloom == match_any)
00268             return(0);
00269         else if (bloom_size != 0) {
00270             const struct ccn_bloom_wire *f = ccn_bloom_validate_wire(bloom, bloom_size);
00271             /* If not a valid filter, treat like a false positive */
00272             if (f == NULL)
00273                 return(0);
00274             if (ccn_bloom_match_wire(f, nextcomp, nextcomp_size))
00275                 return(0);
00276         }
00277     }
00278     /*
00279      * At this point the prefix matches and exclude-by-next-component is done.
00280      */
00281     // test any other qualifiers here
00282     return(1);
00283 }
00284 
00285 /**
00286  *  Get cobid from btree entry.
00287  *
00288  * @returns the cobid field of the indexed entry of node, or 0 if error.
00289  */
00290 uint_least64_t
00291 ccn_btree_content_cobid(struct ccn_btree_node *node, int ndx)
00292 {
00293     struct ccn_btree_content_payload *e = NULL;
00294     uint_least64_t ans = 0;
00295     
00296     e = ccn_btree_node_getentry(sizeof(*e), node, ndx);
00297     if (e != NULL)
00298         ans = MYFETCH64(e, cobid);
00299     return(ans);
00300 }
00301 
00302 /**
00303  *  Set cobid in a btree entry.
00304  *
00305  * @returns 0 for success, -1 for failure
00306  */
00307 int
00308 ccn_btree_content_set_cobid(struct ccn_btree_node *node, int ndx,
00309                             uint_least64_t cobid)
00310 {
00311     struct ccn_btree_content_payload *e = NULL;
00312     ptrdiff_t dirty;
00313     
00314     e = ccn_btree_node_getentry(sizeof(*e), node, ndx);
00315     if (e == NULL)
00316         return(-1);
00317     MYSTORE64(e, cobid, cobid);
00318     dirty = (((unsigned char *)e) - node->buf->buf);
00319     if (dirty >= 0 && dirty < node->clean)
00320         node->clean = dirty;
00321     return(0);
00322 }
00323 
00324 /**
00325  *  Get ContentObject size from btree entry.
00326  *
00327  * @returns the cobsz field of the indexed entry of node, or -1 if error.
00328  */
00329 int
00330 ccn_btree_content_cobsz(struct ccn_btree_node *node, int ndx)
00331 {
00332     struct ccn_btree_content_payload *e = NULL;
00333     
00334     e = ccn_btree_node_getentry(sizeof(*e), node, ndx);
00335     if (e != NULL)
00336         return(MYFETCH(e, cobsz));
00337     return(-1);
00338 }
00339 
00340 /**
00341  *  Compare flatnames a and b
00342  *
00343  * @returns negative, 0, or positive if a < b, a == b, a > b, respectively.
00344  * The special return value -9999 means a < b and a is also a prefix of b.
00345  * Similarly 9999 means b is a strict prefix of a.                              XXX should have defines for these values.
00346  */
00347 int
00348 ccn_flatname_charbuf_compare(struct ccn_charbuf *a, struct ccn_charbuf *b)
00349 {
00350     return(ccn_flatname_compare(a->buf, a->length, b->buf, b->length));
00351 }
00352 
00353 /**
00354  *  Compare flatnames a and b (raw version)
00355  */
00356 int
00357 ccn_flatname_compare(const unsigned char *a, size_t al, const unsigned char *b, size_t bl)
00358 {
00359     int res;
00360 
00361     res = memcmp(a, b, al < bl ? al : bl);
00362     if (res != 0)
00363         return(res);
00364     if (al < bl)
00365         return(-9999);
00366     else if (al == bl)
00367         return(0);
00368     else
00369         return(9999);
00370 }
00371 
00372 
00373 /**
00374  *  Append one component to a flatname
00375  *
00376  *  @returns 0, or -1 if there is an error.
00377  */
00378 int
00379 ccn_flatname_append_component(struct ccn_charbuf *dst,
00380                               const unsigned char *comp, size_t size)
00381 {
00382     int res;
00383     int s;
00384     size_t save;
00385     
00386     if (size >= (1 << 21))
00387         return(-1);
00388     save = dst->length;
00389     res = 0;
00390     for (s = 0; size >= (1 << (s + 7)); s += 7)
00391         continue;
00392     for (; s > 0; s -= 7)
00393         res |= ccn_charbuf_append_value(dst, (((size >> s) & 0x7F) | 0x80), 1);
00394     res |= ccn_charbuf_append_value(dst, (size & 0x7F), 1);
00395     res |= ccn_charbuf_append(dst, comp, size);
00396     if (res < 0)
00397         dst->length = save;
00398     return(res);
00399 }
00400 
00401 /**
00402  *  Append Components from a ccnb-encoded Name to a flatname
00403  *
00404  *  The ccnb encoded input may be a ContentObject, Interest, Prefix,
00405  *  or Component instead of simply a Name.
00406  *  @param dst is the destination, which should hold a ccnb-encoded Name
00407  *  @param ccnb points to first byte of Name
00408  *  @param size is the number of bytes in ccnb
00409  *  @param skip is the number of components at the front of flatname to skip
00410  *  @param count is the maximum number of componebts to append, or -1 for all
00411  *  @returns number of appended components, or -1 if there is an error.
00412  */
00413 int
00414 ccn_flatname_append_from_ccnb(struct ccn_charbuf *dst,
00415                               const unsigned char *ccnb, size_t size,
00416                               int skip, int count)
00417 {
00418     int ans = 0;
00419     int ncomp = 0;
00420     const unsigned char *comp = NULL;
00421     size_t compsize = 0;
00422     struct ccn_buf_decoder decoder;
00423     struct ccn_buf_decoder *d = ccn_buf_decoder_start(&decoder, ccnb, size);
00424     int checkclose = 0;
00425     int res;
00426     
00427     if (ccn_buf_match_dtag(d, CCN_DTAG_Interest)    ||
00428         ccn_buf_match_dtag(d, CCN_DTAG_ContentObject)) {
00429         ccn_buf_advance(d);
00430         if (ccn_buf_match_dtag(d, CCN_DTAG_Signature))
00431             ccn_buf_advance_past_element(d);
00432     }
00433     if ((ccn_buf_match_dtag(d, CCN_DTAG_Name) ||
00434          ccn_buf_match_dtag(d, CCN_DTAG_Prefix))) {
00435         checkclose = 1;
00436         ccn_buf_advance(d);
00437     }
00438     else if (count != 0)
00439         count = 1;
00440     while (ccn_buf_match_dtag(d, CCN_DTAG_Component)) {
00441         if (ans == count)
00442             return(ans);
00443         ccn_buf_advance(d);
00444         compsize = 0;
00445         if (ccn_buf_match_blob(d, &comp, &compsize))
00446             ccn_buf_advance(d);
00447         ccn_buf_check_close(d);
00448         if (d->decoder.state < 0)
00449             return(-1);
00450         ncomp += 1;
00451         if (ncomp > skip) {
00452             res = ccn_flatname_append_component(dst, comp, compsize);
00453             if (res < 0)
00454                 return(-1);
00455             ans++;
00456         }
00457     }
00458     if (checkclose)
00459         ccn_buf_check_close(d);
00460     if (d->decoder.state < 0)
00461         return (-1);
00462     return(ans);
00463 }
00464 
00465 /**
00466  *  Convert a ccnb-encoded Name to a flatname
00467  *  @returns number of components, or -1 if there is an error.
00468  */
00469 int
00470 ccn_flatname_from_ccnb(struct ccn_charbuf *dst,
00471                        const unsigned char *ccnb, size_t size)
00472 {
00473     dst->length = 0;
00474     return(ccn_flatname_append_from_ccnb(dst, ccnb, size, 0, -1));
00475 }
00476 
00477 /**
00478  * Parse the component delimiter from the start of a flatname
00479  *
00480  * The delimiter size is limited to 3 bytes.
00481  * @returns -1 for error, 0 nothing left, or compsize * 4 + delimsize
00482  */
00483 int
00484 ccn_flatname_next_comp(const unsigned char *flatname, size_t size)
00485 {
00486     unsigned i, l, m;
00487     
00488     if (size == 0)
00489         return(0);
00490     if (flatname[0] == 0x80)
00491         return(-1); /* Must use min number of bytes. */
00492     m = (size < 3) ? size : 3;
00493     for (i = 0, l = 0; i < m && (flatname[i] & 0x80) != 0; i++)
00494         l = (l | (flatname[i] & 0x7F)) << 7;
00495     if (i >= m)
00496         return(-1);
00497     l |= flatname[i++];
00498     if (i + l > size)
00499         return(-1);
00500     return(l * 4 + i);
00501 }
00502 
00503 /**
00504  *  Append Components from a flatname to a ccnb-encoded Name
00505  *  @param dst is the destination, which should hold a ccnb-encoded Name
00506  *  @param flatname points to first byte of flatname
00507  *  @param size is the number of bytes in flatname
00508  *  @param skip is the number of components at the front of flatname to skip
00509  *  @param count is the maximum number of components to append, or -1 for all
00510  *  @returns number of appended components, or -1 if there is an error.
00511  */
00512 int
00513 ccn_name_append_flatname(struct ccn_charbuf *dst,
00514                          const unsigned char *flatname, size_t size,
00515                          int skip, int count)
00516 {
00517     int ans;
00518     int compnum;
00519     int i;
00520     int rnc;
00521     int res;
00522     const unsigned char *cp;
00523     size_t cs;
00524    
00525     if (skip < 0)
00526         return(-1);
00527     ans = 0;
00528     compnum = 0;
00529     for (i = 0; i < size; i += CCNFLATSKIP(rnc)) {
00530         if (ans == count)
00531             return(ans);
00532         rnc = ccn_flatname_next_comp(flatname + i, size - i);
00533         if (rnc <= 0)
00534             return(-1);
00535         cp = flatname + i + CCNFLATDELIMSZ(rnc);
00536         cs = CCNFLATDATASZ(rnc);
00537         if (compnum >= skip) {
00538             res = ccn_name_append(dst, cp, cs);
00539             if (res < 0)
00540                 return(-1);
00541             ans++;
00542         }
00543         compnum++;
00544     }
00545     return(ans);
00546 }
00547 
00548 /**
00549  * Like ccn_uri_append(), but accepts a flatname instead of ccnb
00550  */
00551 int
00552 ccn_uri_append_flatname(struct ccn_charbuf *uri,
00553                              const unsigned char *flatname, size_t size,
00554                              int includescheme)
00555 {
00556     struct ccn_charbuf *ccnb = NULL;
00557     int res;
00558     
00559     ccnb = ccn_charbuf_create();
00560     if (ccnb == NULL)
00561         return(-1);
00562     res = ccn_name_init(ccnb);
00563     if (res < 0)
00564         goto Bail;
00565     res = ccn_name_append_flatname(ccnb, flatname, size, 0, -1);
00566     if (res < 0)
00567         goto Bail;
00568     res = ccn_uri_append(uri, ccnb->buf, ccnb->length, includescheme);
00569 Bail:
00570     ccn_charbuf_destroy(&ccnb);
00571     return(res);
00572 }
00573 
00574 /**
00575  * Get flatname component count
00576  * @returns the number of name components in the flatname, or -1 if the
00577  *          flatname is not well-formed
00578  */
00579 int
00580 ccn_flatname_ncomps(const unsigned char *flatname, size_t size)
00581 {
00582     int ans;
00583     int i;
00584     int rnc;
00585     
00586     ans = 0;
00587     for (i = 0; i < size; i += CCNFLATSKIP(rnc)) {
00588         rnc = ccn_flatname_next_comp(flatname + i, size - i);
00589         if (rnc <= 0)
00590             return(-1);
00591         ans++;
00592     }
00593     return(ans);
00594 }

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