ccn_match.c

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