ccn_match.c

Go to the documentation of this file.
00001 /**
00002  * @file ccn_match.c
00003  * Support for the match predicate between interest and content.
00004  * 
00005  * Part of the CCNx C Library.
00006  */
00007 /*
00008  * Copyright (C) 2008, 2009, 2012 Palo Alto Research Center, Inc.
00009  *
00010  * This library is free software; you can redistribute it and/or modify it
00011  * under the terms of the GNU Lesser General Public License version 2.1
00012  * as published by the Free Software Foundation.
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * Lesser General Public License for more details. You should have received
00017  * a copy of the GNU Lesser General Public License along with this library;
00018  * if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
00019  * Fifth Floor, Boston, MA 02110-1301 USA.
00020  */
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include <ccn/bloom.h>
00024 #include <ccn/ccn.h>
00025 #include <ccn/charbuf.h>
00026 #include <ccn/coding.h>
00027 #include <ccn/digest.h>
00028 
00029 /**
00030  * Compute the digest of the entire ContentObject if necessary,
00031  * caching the result in pc->digest, pc->digest_bytes.
00032  */
00033 void
00034 ccn_digest_ContentObject(const unsigned char *content_object,
00035                          struct ccn_parsed_ContentObject *pc)
00036 {
00037     int res;
00038     struct ccn_digest *d = NULL;
00039 
00040     if (pc->magic < 20080000) abort();
00041     if (pc->digest_bytes == sizeof(pc->digest))
00042         return;
00043     if (pc->digest_bytes != 0) abort();
00044     d = ccn_digest_create(CCN_DIGEST_SHA256);
00045     ccn_digest_init(d);
00046     res = ccn_digest_update(d, content_object, pc->offset[CCN_PCO_E]);
00047     if (res < 0) abort();
00048     res = ccn_digest_final(d, pc->digest, sizeof(pc->digest));
00049     if (res < 0) abort();
00050     if (pc->digest_bytes != 0) abort();
00051     pc->digest_bytes = sizeof(pc->digest);
00052     ccn_digest_destroy(&d);
00053 }
00054 
00055 static int
00056 ccn_pubid_matches(const unsigned char *content_object,
00057                   struct ccn_parsed_ContentObject *pc,
00058                   const unsigned char *interest_msg,
00059                   const struct ccn_parsed_interest *pi)
00060 {
00061     struct ccn_buf_decoder decoder;
00062     struct ccn_buf_decoder *d;
00063     int pubidstart;
00064     int pubidbytes;
00065     int contentpubidstart = 0;
00066     int contentpubidbytes = 0;
00067     pubidstart = pi->offset[CCN_PI_B_PublisherIDKeyDigest];
00068     pubidbytes = pi->offset[CCN_PI_E_PublisherIDKeyDigest] - pubidstart;
00069     if (pubidbytes > 0) {
00070         d = ccn_buf_decoder_start(&decoder,
00071                                   content_object +
00072                                    pc->offset[CCN_PCO_B_PublisherPublicKeyDigest],
00073                                   (pc->offset[CCN_PCO_E_PublisherPublicKeyDigest] -
00074                                    pc->offset[CCN_PCO_B_PublisherPublicKeyDigest]));
00075         ccn_buf_advance(d);
00076         if (ccn_buf_match_some_blob(d)) {
00077             contentpubidstart = d->decoder.token_index;
00078             ccn_buf_advance(d);
00079             contentpubidbytes = d->decoder.token_index - contentpubidstart;
00080         }
00081         if (pubidbytes != contentpubidbytes)
00082             return(0); // This is fishy
00083         if (0 != memcmp(interest_msg + pubidstart,
00084                         d->buf + contentpubidstart,
00085                         pubidbytes))
00086             return(0);
00087     }
00088     return(1);
00089 }
00090 
00091 /**
00092  * Test for a match between a next component and an exclusion clause
00093  *
00094  * @param excl                  address of exclusion encoding
00095  * @param excl_size             bytes in exclusion encoding
00096  * @param nextcomp              addr of nextcomp bytes
00097  * @param nextcomp_size         number of nextcomp bytes
00098  * @result 1 if the ccnb-encoded nextcomp matches the 
00099  *           ccnb-encoded exclusion clause, otherwise 0.
00100  */
00101 int
00102 ccn_excluded(const unsigned char *excl,
00103              size_t excl_size,
00104              const unsigned char *nextcomp,
00105              size_t nextcomp_size)
00106 {
00107     unsigned char match_any[2] = "-";
00108     const unsigned char *bloom = NULL;
00109     size_t bloom_size = 0;
00110     struct ccn_buf_decoder decoder;
00111     struct ccn_buf_decoder *d = ccn_buf_decoder_start(&decoder, excl, excl_size);
00112     const unsigned char *comp = NULL;
00113     size_t comp_size = 0;
00114     const int excluded = 1;
00115     
00116     if (!ccn_buf_match_dtag(d, CCN_DTAG_Exclude))
00117         abort();
00118     ccn_buf_advance(d);
00119     if (ccn_buf_match_dtag(d, CCN_DTAG_Any)) {
00120         ccn_buf_advance(d);
00121         bloom = match_any;
00122         ccn_buf_check_close(d);
00123     }
00124     else if (ccn_buf_match_dtag(d, CCN_DTAG_Bloom)) {
00125         ccn_buf_advance(d);
00126         if (ccn_buf_match_blob(d, &bloom, &bloom_size))
00127             ccn_buf_advance(d);
00128         ccn_buf_check_close(d);
00129     }
00130     while (ccn_buf_match_dtag(d, CCN_DTAG_Component)) {
00131         ccn_buf_advance(d);
00132         comp_size = 0;
00133         if (ccn_buf_match_blob(d, &comp, &comp_size))
00134             ccn_buf_advance(d);
00135         ccn_buf_check_close(d);
00136         if (comp_size > nextcomp_size)
00137             break;
00138         if (comp_size == nextcomp_size) {
00139             int res = memcmp(comp, nextcomp, comp_size);
00140             if (res == 0)
00141                 return(excluded); /* One of the explicit excludes */
00142             if (res > 0)
00143                 break;
00144         }
00145         bloom = NULL;
00146         bloom_size = 0;
00147         if (ccn_buf_match_dtag(d, CCN_DTAG_Any)) {
00148             ccn_buf_advance(d);
00149             bloom = match_any;
00150             ccn_buf_check_close(d);
00151         }
00152         else if (ccn_buf_match_dtag(d, CCN_DTAG_Bloom)) {
00153             ccn_buf_advance(d);
00154             if (ccn_buf_match_blob(d, &bloom, &bloom_size))
00155                 ccn_buf_advance(d);
00156             ccn_buf_check_close(d);
00157         }
00158     }
00159     /*
00160      * Now we have isolated the applicable filter (Any or Bloom or none).
00161      */
00162     if (bloom == match_any)
00163         return(excluded);
00164     else if (bloom_size != 0) {
00165         const struct ccn_bloom_wire *f = ccn_bloom_validate_wire(bloom, bloom_size);
00166         /* If not a valid filter, treat like a false positive */
00167         if (f == NULL)
00168             return(excluded);
00169         if (ccn_bloom_match_wire(f, nextcomp, nextcomp_size))
00170             return(excluded);
00171     }
00172     return(!excluded);
00173 }
00174 
00175 /**
00176  * Test for a match between a ContentObject and an Interest
00177  *
00178  * @param content_object        ccnb-encoded ContentObject
00179  * @param content_object_size   its size in bytes
00180  * @param implicit_content_digest boolean indicating whether the
00181  *                              final name component is implicit (as in
00182  *                              the on-wire format) or explicit (as within
00183  *                              ccnd's content store).
00184  * @param pc                    Valid parse information may be provided to
00185  *                              speed things up. If NULL it will be
00186  *                              reconstructed internally.
00187  * @param interest_msg          ccnb-encoded Interest
00188  * @param interest_msg_size     its size in bytes
00189  * @param pi                    see _pc_
00190  *
00191  * @result 1 if the ccnb-encoded content_object matches the 
00192  *           ccnb-encoded interest_msg, otherwise 0.
00193  */
00194 int
00195 ccn_content_matches_interest(const unsigned char *content_object,
00196                              size_t content_object_size,
00197                              int implicit_content_digest,
00198                              struct ccn_parsed_ContentObject *pc,
00199                              const unsigned char *interest_msg,
00200                              size_t interest_msg_size,
00201                              const struct ccn_parsed_interest *pi)
00202 {
00203     struct ccn_parsed_ContentObject pc_store;
00204     struct ccn_parsed_interest pi_store;
00205     int res;
00206     int ncomps;
00207     int prefixstart;
00208     int prefixbytes;
00209     int namecompstart;
00210     int namecompbytes;
00211     int checkdigest = 0;
00212     struct ccn_buf_decoder decoder;
00213     struct ccn_buf_decoder *d;
00214     const unsigned char *nextcomp;
00215     size_t nextcomp_size = 0;
00216     const unsigned char *comp = NULL;
00217     size_t comp_size = 0;
00218     if (pc == NULL) {
00219         res = ccn_parse_ContentObject(content_object, content_object_size,
00220                                       &pc_store, NULL);
00221         if (res < 0) return(0);
00222         pc = &pc_store;
00223     }
00224     if (pi == NULL) {
00225         res = ccn_parse_interest(interest_msg, interest_msg_size,
00226                                  &pi_store, NULL);
00227         if (res < 0) return(0);
00228         pi = &pi_store;
00229     }
00230     if (!ccn_pubid_matches(content_object, pc, interest_msg, pi))
00231         return(0);
00232     ncomps = pc->name_ncomps + (implicit_content_digest ? 1 : 0);
00233     if (ncomps < pi->prefix_comps + pi->min_suffix_comps)
00234         return(0);
00235     if (ncomps > pi->prefix_comps + pi->max_suffix_comps)
00236         return(0);
00237     prefixstart = pi->offset[CCN_PI_B_Component0];
00238     prefixbytes = pi->offset[CCN_PI_E_LastPrefixComponent] - prefixstart;
00239     namecompstart = pc->offset[CCN_PCO_B_Component0];
00240     namecompbytes = pc->offset[CCN_PCO_E_ComponentLast] - namecompstart;
00241     if (prefixbytes > namecompbytes) {
00242         /*
00243          * The only way for this to be a match is if the implicit
00244          * content digest name component comes into play.
00245          */
00246         if (implicit_content_digest &&
00247             pi->offset[CCN_PI_B_LastPrefixComponent] - prefixstart == namecompbytes &&
00248             (pi->offset[CCN_PI_E_LastPrefixComponent] -
00249              pi->offset[CCN_PI_B_LastPrefixComponent]) == 1 + 2 + 32 + 1) {
00250             prefixbytes = namecompbytes;
00251             checkdigest = 1;
00252         }
00253         else
00254             return(0);
00255     }
00256     if (0 != memcmp(interest_msg + prefixstart,
00257                     content_object + namecompstart,
00258                     prefixbytes))
00259         return(0);
00260     if (checkdigest) {
00261         /*
00262          * The Exclude by next component is not relevant in this case,
00263          * since there is no next component present.
00264          */
00265         ccn_digest_ContentObject(content_object, pc);
00266         d = ccn_buf_decoder_start(&decoder,
00267                         interest_msg + pi->offset[CCN_PI_B_LastPrefixComponent],
00268                         (pi->offset[CCN_PI_E_LastPrefixComponent] -
00269                          pi->offset[CCN_PI_B_LastPrefixComponent]));
00270         comp_size = 0;
00271         if (ccn_buf_match_dtag(d, CCN_DTAG_Component)) {
00272                 ccn_buf_advance(d);
00273                 ccn_buf_match_blob(d, &comp, &comp_size);
00274             }
00275         if (comp_size != pc->digest_bytes) abort();
00276         if (0 != memcmp(comp, pc->digest, comp_size))
00277             return(0);
00278     }
00279     else if (pi->offset[CCN_PI_E_Exclude] > pi->offset[CCN_PI_B_Exclude]) {
00280         if (prefixbytes < namecompbytes) {
00281             /* pick out the next component in the content object name */
00282             d = ccn_buf_decoder_start(&decoder,
00283                                       content_object +
00284                                         (namecompstart + prefixbytes),
00285                                       pc->offset[CCN_PCO_E_ComponentLast] -
00286                                         (namecompstart + prefixbytes));
00287             if (ccn_buf_match_dtag(d, CCN_DTAG_Component)) {
00288                 ccn_buf_advance(d);
00289                 ccn_buf_match_blob(d, &nextcomp, &nextcomp_size);
00290             }
00291             else
00292                 return(0);
00293         }
00294         else if (!implicit_content_digest)
00295             goto exclude_checked;
00296         else if (prefixbytes == namecompbytes) {
00297             /* use the digest name as the next component */
00298             ccn_digest_ContentObject(content_object, pc);
00299             nextcomp_size = pc->digest_bytes;
00300             nextcomp = pc->digest;
00301         }
00302         else abort(); /* bug - should have returned already */
00303         if (ccn_excluded(interest_msg + pi->offset[CCN_PI_B_Exclude],
00304                          (pi->offset[CCN_PI_E_Exclude] -
00305                           pi->offset[CCN_PI_B_Exclude]),
00306                          nextcomp,
00307                          nextcomp_size))
00308             return(0);
00309     exclude_checked: {}
00310     }
00311     /*
00312      * At this point the prefix matches and exclude-by-next-component is done.
00313      */
00314     // test any other qualifiers here
00315     return(1);
00316 }
Generated on Tue Aug 21 14:54:18 2012 for Content-Centric Networking in C by  doxygen 1.6.3