ccn_btree_content.c

Go to the documentation of this file.
00001 /**
00002  * B-tree for indexing ccnx content objects
00003  */
00004 /* Part of the CCNx C Library.
00005  *
00006  * Copyright (C) 2011-2012 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 *nextcomp = NULL;
00150     int i;
00151     int n;
00152     int ncomps;
00153     int pubidend;
00154     int pubidstart;
00155     int res;
00156     int rnc;
00157     size_t blob_size = 0;
00158     size_t nextcomp_size = 0;
00159     size_t size;
00160     struct ccn_btree_content_payload *e = NULL;
00161     unsigned char *flatname = NULL;
00162     
00163     e = ccn_btree_node_getentry(sizeof(*e), node, ndx);
00164     if (e == NULL || e->magic[0] != CCN_BT_CONTENT_MAGIC)
00165         return(-1);
00166     
00167     ncomps = MYFETCH(e, ncomp);
00168     if (ncomps < pi->prefix_comps + pi->min_suffix_comps)
00169         return(0);
00170     if (ncomps > pi->prefix_comps + pi->max_suffix_comps)
00171         return(0);
00172     /* Check that the publisher id matches */
00173     pubidstart = pi->offset[CCN_PI_B_PublisherID];
00174     pubidend = pi->offset[CCN_PI_E_PublisherID];
00175     if (pubidstart < pubidend) {
00176         blob_size = 0;
00177         ccn_ref_tagged_BLOB(CCN_DTAG_PublisherPublicKeyDigest,
00178                             interest_msg,
00179                             pubidstart, pubidend,
00180                             &blob, &blob_size);
00181         if (blob_size != sizeof(e->ppkdg))
00182             return(0);
00183         if (0 != memcmp(blob, e->ppkdg, blob_size))
00184             return(0);
00185     }
00186     /* Do Exclude processing if necessary */
00187     if (pi->offset[CCN_PI_E_Exclude] > pi->offset[CCN_PI_B_Exclude]) {
00188         res = ccn_btree_key_fetch(scratch, node, ndx);
00189         if (res < 0)
00190             return(-1);
00191         flatname = scratch->buf;
00192         size = scratch->length;
00193         nextcomp = NULL;
00194         nextcomp_size = 0;
00195         for (i = 0, n = 0; i < size; i += CCNFLATSKIP(rnc), n++) {
00196             rnc = ccn_flatname_next_comp(flatname + i, size - i);
00197             if (rnc <= 0)
00198                 return(-1);
00199             if (n == pi->prefix_comps) {
00200                 nextcomp = flatname + i + CCNFLATDELIMSZ(rnc);
00201                 nextcomp_size = CCNFLATDATASZ(rnc);
00202                 break;
00203             }
00204         }
00205         if (nextcomp == NULL)
00206             return(0);
00207         if (ccn_excluded(interest_msg + pi->offset[CCN_PI_B_Exclude],
00208                          (pi->offset[CCN_PI_E_Exclude] -
00209                           pi->offset[CCN_PI_B_Exclude]),
00210                          nextcomp,
00211                          nextcomp_size))
00212             return(0);
00213     }
00214     /*
00215      * At this point the prefix matches and exclude-by-next-component is done.
00216      */
00217     // test any other qualifiers here
00218     return(1);
00219 }
00220 
00221 /**
00222  *  Get cobid from btree entry.
00223  *
00224  * @returns the cobid field of the indexed entry of node, or 0 if error.
00225  */
00226 uint_least64_t
00227 ccn_btree_content_cobid(struct ccn_btree_node *node, int ndx)
00228 {
00229     struct ccn_btree_content_payload *e = NULL;
00230     uint_least64_t ans = 0;
00231     
00232     e = ccn_btree_node_getentry(sizeof(*e), node, ndx);
00233     if (e != NULL)
00234         ans = MYFETCH64(e, cobid);
00235     return(ans);
00236 }
00237 
00238 /**
00239  *  Set cobid in a btree entry.
00240  *
00241  * @returns 0 for success, -1 for failure
00242  */
00243 int
00244 ccn_btree_content_set_cobid(struct ccn_btree_node *node, int ndx,
00245                             uint_least64_t cobid)
00246 {
00247     struct ccn_btree_content_payload *e = NULL;
00248     ptrdiff_t dirty;
00249     
00250     e = ccn_btree_node_getentry(sizeof(*e), node, ndx);
00251     if (e == NULL)
00252         return(-1);
00253     MYSTORE64(e, cobid, cobid);
00254     dirty = (((unsigned char *)e) - node->buf->buf);
00255     if (dirty >= 0 && dirty < node->clean)
00256         node->clean = dirty;
00257     return(0);
00258 }
00259 
00260 /**
00261  *  Get ContentObject size from btree entry.
00262  *
00263  * @returns the cobsz field of the indexed entry of node, or -1 if error.
00264  */
00265 int
00266 ccn_btree_content_cobsz(struct ccn_btree_node *node, int ndx)
00267 {
00268     struct ccn_btree_content_payload *e = NULL;
00269     
00270     e = ccn_btree_node_getentry(sizeof(*e), node, ndx);
00271     if (e != NULL)
00272         return(MYFETCH(e, cobsz));
00273     return(-1);
00274 }
00275 
00276 /**
00277  *  Compare flatnames a and b
00278  *
00279  * @returns negative, 0, or positive if a < b, a == b, a > b, respectively.
00280  * The special return value -9999 means a < b and a is also a prefix of b.
00281  * Similarly 9999 means b is a strict prefix of a.                              XXX should have defines for these values.
00282  */
00283 int
00284 ccn_flatname_charbuf_compare(struct ccn_charbuf *a, struct ccn_charbuf *b)
00285 {
00286     return(ccn_flatname_compare(a->buf, a->length, b->buf, b->length));
00287 }
00288 
00289 /**
00290  *  Compare flatnames a and b (raw version)
00291  */
00292 int
00293 ccn_flatname_compare(const unsigned char *a, size_t al, const unsigned char *b, size_t bl)
00294 {
00295     int res;
00296 
00297     res = memcmp(a, b, al < bl ? al : bl);
00298     if (res != 0)
00299         return(res);
00300     if (al < bl)
00301         return(-9999);
00302     else if (al == bl)
00303         return(0);
00304     else
00305         return(9999);
00306 }
00307 
00308 
00309 /**
00310  *  Append one component to a flatname
00311  *
00312  *  @returns 0, or -1 if there is an error.
00313  */
00314 int
00315 ccn_flatname_append_component(struct ccn_charbuf *dst,
00316                               const unsigned char *comp, size_t size)
00317 {
00318     int res;
00319     int s;
00320     size_t save;
00321     
00322     if (size >= (1 << 21))
00323         return(-1);
00324     save = dst->length;
00325     res = 0;
00326     for (s = 0; size >= (1 << (s + 7)); s += 7)
00327         continue;
00328     for (; s > 0; s -= 7)
00329         res |= ccn_charbuf_append_value(dst, (((size >> s) & 0x7F) | 0x80), 1);
00330     res |= ccn_charbuf_append_value(dst, (size & 0x7F), 1);
00331     res |= ccn_charbuf_append(dst, comp, size);
00332     if (res < 0)
00333         dst->length = save;
00334     return(res);
00335 }
00336 
00337 /**
00338  *  Append Components from a ccnb-encoded Name to a flatname
00339  *
00340  *  The ccnb encoded input may be a ContentObject, Interest, Prefix,
00341  *  or Component instead of simply a Name.
00342  *  @param dst is the destination, which should hold a ccnb-encoded Name
00343  *  @param ccnb points to first byte of Name
00344  *  @param size is the number of bytes in ccnb
00345  *  @param skip is the number of components at the front of flatname to skip
00346  *  @param count is the maximum number of componebts to append, or -1 for all
00347  *  @returns number of appended components, or -1 if there is an error.
00348  */
00349 int
00350 ccn_flatname_append_from_ccnb(struct ccn_charbuf *dst,
00351                               const unsigned char *ccnb, size_t size,
00352                               int skip, int count)
00353 {
00354     int ans = 0;
00355     int ncomp = 0;
00356     const unsigned char *comp = NULL;
00357     size_t compsize = 0;
00358     struct ccn_buf_decoder decoder;
00359     struct ccn_buf_decoder *d = ccn_buf_decoder_start(&decoder, ccnb, size);
00360     int checkclose = 0;
00361     int res;
00362     
00363     if (ccn_buf_match_dtag(d, CCN_DTAG_Interest)    ||
00364         ccn_buf_match_dtag(d, CCN_DTAG_ContentObject)) {
00365         ccn_buf_advance(d);
00366         if (ccn_buf_match_dtag(d, CCN_DTAG_Signature))
00367             ccn_buf_advance_past_element(d);
00368     }
00369     if ((ccn_buf_match_dtag(d, CCN_DTAG_Name) ||
00370          ccn_buf_match_dtag(d, CCN_DTAG_Prefix))) {
00371         checkclose = 1;
00372         ccn_buf_advance(d);
00373     }
00374     else if (count != 0)
00375         count = 1;
00376     while (ccn_buf_match_dtag(d, CCN_DTAG_Component)) {
00377         if (ans == count)
00378             return(ans);
00379         ccn_buf_advance(d);
00380         compsize = 0;
00381         if (ccn_buf_match_blob(d, &comp, &compsize))
00382             ccn_buf_advance(d);
00383         ccn_buf_check_close(d);
00384         if (d->decoder.state < 0)
00385             return(-1);
00386         ncomp += 1;
00387         if (ncomp > skip) {
00388             res = ccn_flatname_append_component(dst, comp, compsize);
00389             if (res < 0)
00390                 return(-1);
00391             ans++;
00392         }
00393     }
00394     if (checkclose)
00395         ccn_buf_check_close(d);
00396     if (d->decoder.state < 0)
00397         return (-1);
00398     return(ans);
00399 }
00400 
00401 /**
00402  *  Convert a ccnb-encoded Name to a flatname
00403  *  @returns number of components, or -1 if there is an error.
00404  */
00405 int
00406 ccn_flatname_from_ccnb(struct ccn_charbuf *dst,
00407                        const unsigned char *ccnb, size_t size)
00408 {
00409     dst->length = 0;
00410     return(ccn_flatname_append_from_ccnb(dst, ccnb, size, 0, -1));
00411 }
00412 
00413 /**
00414  * Parse the component delimiter from the start of a flatname
00415  *
00416  * The delimiter size is limited to 3 bytes.
00417  * @returns -1 for error, 0 nothing left, or compsize * 4 + delimsize
00418  */
00419 int
00420 ccn_flatname_next_comp(const unsigned char *flatname, size_t size)
00421 {
00422     unsigned i, l, m;
00423     
00424     if (size == 0)
00425         return(0);
00426     if (flatname[0] == 0x80)
00427         return(-1); /* Must use min number of bytes. */
00428     m = (size < 3) ? size : 3;
00429     for (i = 0, l = 0; i < m && (flatname[i] & 0x80) != 0; i++)
00430         l = (l | (flatname[i] & 0x7F)) << 7;
00431     if (i >= m)
00432         return(-1);
00433     l |= flatname[i++];
00434     if (i + l > size)
00435         return(-1);
00436     return(l * 4 + i);
00437 }
00438 
00439 /**
00440  *  Append Components from a flatname to a ccnb-encoded Name
00441  *  @param dst is the destination, which should hold a ccnb-encoded Name
00442  *  @param flatname points to first byte of flatname
00443  *  @param size is the number of bytes in flatname
00444  *  @param skip is the number of components at the front of flatname to skip
00445  *  @param count is the maximum number of components to append, or -1 for all
00446  *  @returns number of appended components, or -1 if there is an error.
00447  */
00448 int
00449 ccn_name_append_flatname(struct ccn_charbuf *dst,
00450                          const unsigned char *flatname, size_t size,
00451                          int skip, int count)
00452 {
00453     int ans;
00454     int compnum;
00455     int i;
00456     int rnc;
00457     int res;
00458     const unsigned char *cp;
00459     size_t cs;
00460    
00461     if (skip < 0)
00462         return(-1);
00463     ans = 0;
00464     compnum = 0;
00465     for (i = 0; i < size; i += CCNFLATSKIP(rnc)) {
00466         if (ans == count)
00467             return(ans);
00468         rnc = ccn_flatname_next_comp(flatname + i, size - i);
00469         if (rnc <= 0)
00470             return(-1);
00471         cp = flatname + i + CCNFLATDELIMSZ(rnc);
00472         cs = CCNFLATDATASZ(rnc);
00473         if (compnum >= skip) {
00474             res = ccn_name_append(dst, cp, cs);
00475             if (res < 0)
00476                 return(-1);
00477             ans++;
00478         }
00479         compnum++;
00480     }
00481     return(ans);
00482 }
00483 
00484 /**
00485  * Like ccn_uri_append(), but accepts a flatname instead of ccnb
00486  */
00487 int
00488 ccn_uri_append_flatname(struct ccn_charbuf *uri,
00489                              const unsigned char *flatname, size_t size,
00490                              int includescheme)
00491 {
00492     struct ccn_charbuf *ccnb = NULL;
00493     int res;
00494     
00495     ccnb = ccn_charbuf_create();
00496     if (ccnb == NULL)
00497         return(-1);
00498     res = ccn_name_init(ccnb);
00499     if (res < 0)
00500         goto Bail;
00501     res = ccn_name_append_flatname(ccnb, flatname, size, 0, -1);
00502     if (res < 0)
00503         goto Bail;
00504     res = ccn_uri_append(uri, ccnb->buf, ccnb->length, includescheme);
00505 Bail:
00506     ccn_charbuf_destroy(&ccnb);
00507     return(res);
00508 }
00509 
00510 /**
00511  * Get flatname component count
00512  * @returns the number of name components in the flatname, or -1 if the
00513  *          flatname is not well-formed
00514  */
00515 int
00516 ccn_flatname_ncomps(const unsigned char *flatname, size_t size)
00517 {
00518     int ans;
00519     int i;
00520     int rnc;
00521     
00522     ans = 0;
00523     for (i = 0; i < size; i += CCNFLATSKIP(rnc)) {
00524         rnc = ccn_flatname_next_comp(flatname + i, size - i);
00525         if (rnc <= 0)
00526             return(-1);
00527         ans++;
00528     }
00529     return(ans);
00530 }
Generated on Tue Aug 21 14:54:17 2012 for Content-Centric Networking in C by  doxygen 1.6.3