ccn_client.c

Go to the documentation of this file.
00001 /**
00002  * @file ccn_client.c
00003  * @brief Support for ccn clients.
00004  * 
00005  * Part of the CCNx C Library.
00006  *
00007  * Copyright (C) 2008-2011 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 <arpa/inet.h>
00021 #include <errno.h>
00022 #include <fcntl.h>
00023 #include <poll.h>
00024 #include <signal.h>
00025 #include <stdint.h>
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <sys/socket.h>
00030 #include <sys/stat.h>
00031 #include <sys/time.h>
00032 #include <sys/types.h>
00033 #include <sys/un.h>
00034 #include <unistd.h>
00035 
00036 #include <ccn/ccn.h>
00037 #include <ccn/ccn_private.h>
00038 #include <ccn/ccnd.h>
00039 #include <ccn/charbuf.h>
00040 #include <ccn/coding.h>
00041 #include <ccn/digest.h>
00042 #include <ccn/hashtb.h>
00043 #include <ccn/reg_mgmt.h>
00044 #include <ccn/signing.h>
00045 #include <ccn/keystore.h>
00046 #include <ccn/uri.h>
00047 
00048 struct ccn {
00049     int sock;
00050     size_t outbufindex;
00051     struct ccn_charbuf *interestbuf;
00052     struct ccn_charbuf *inbuf;
00053     struct ccn_charbuf *outbuf;
00054     struct ccn_charbuf *ccndid;
00055     struct hashtb *interests_by_prefix;
00056     struct hashtb *interest_filters;
00057     struct ccn_skeleton_decoder decoder;
00058     struct ccn_indexbuf *scratch_indexbuf;
00059     struct hashtb *keys;    /* public keys, by pubid */
00060     struct hashtb *keystores;   /* unlocked private keys */
00061     struct ccn_charbuf *default_pubid;
00062     struct timeval now;
00063     int timeout;
00064     int refresh_us;
00065     int err;                    /* pos => errno value, neg => other */
00066     int errline;
00067     int verbose_error;
00068     int tap;
00069     int running;
00070     int defer_verification;
00071 };
00072 
00073 struct expressed_interest;
00074 struct ccn_reg_closure;
00075 
00076 struct interests_by_prefix { /* keyed by components of name prefix */
00077     struct expressed_interest *list;
00078 };
00079 
00080 struct expressed_interest {
00081     int magic;                   /* for sanity checking */
00082     struct timeval lasttime;     /* time most recently expressed */
00083     struct ccn_closure *action;  /* handler for incoming content */
00084     unsigned char *interest_msg; /* the interest message as sent */
00085     size_t size;                 /* its size in bytes */
00086     int target;                  /* how many we want outstanding (0 or 1) */
00087     int outstanding;             /* number currently outstanding (0 or 1) */
00088     int lifetime_us;             /* interest lifetime in microseconds */
00089     struct ccn_charbuf *wanted_pub; /* waiting for this pub to arrive */
00090     struct expressed_interest *next; /* link to next in list */
00091 };
00092 
00093 struct interest_filter { /* keyed by components of name */
00094     struct ccn_closure *action;
00095     struct ccn_reg_closure *ccn_reg_closure;
00096     struct timeval expiry;       /* Expiration time */
00097     int flags;
00098 };
00099 #define CCN_FORW_WAITING_CCNDID (1<<30)
00100 
00101 struct ccn_reg_closure {
00102     struct ccn_closure action;
00103     struct interest_filter *interest_filter;
00104 };
00105 
00106 #define NOTE_ERR(h, e) (h->err = (e), h->errline = __LINE__, ccn_note_err(h))
00107 #define NOTE_ERRNO(h) NOTE_ERR(h, errno)
00108 
00109 #define THIS_CANNOT_HAPPEN(h) \
00110     do { NOTE_ERR(h, -73); ccn_perror(h, "Can't happen");} while (0)
00111 
00112 #define XXX \
00113     do { NOTE_ERR(h, -76); ccn_perror(h, "Please write some more code here"); } while (0)
00114 
00115 static void ccn_refresh_interest(struct ccn *, struct expressed_interest *);
00116 static void ccn_initiate_prefix_reg(struct ccn *,
00117                                     const void *, size_t,
00118                                     struct interest_filter *);
00119 static void finalize_pkey(struct hashtb_enumerator *e);
00120 static void finalize_keystore(struct hashtb_enumerator *e);
00121 static int ccn_pushout(struct ccn *h);
00122 
00123 static int
00124 tv_earlier(const struct timeval *a, const struct timeval *b)
00125 {
00126     if (a->tv_sec > b->tv_sec)
00127         return(0);
00128     if (a->tv_sec < b->tv_sec)
00129         return(1);
00130     return(a->tv_usec < b->tv_usec);
00131 }
00132 
00133 /**
00134  * Produce message on standard error output describing the last
00135  * error encountered during a call using the given handle.
00136  * @param h is the ccn handle - may not be NULL.
00137  * @param s is a client-supplied message; if NULL a message will be supplied
00138  *        where available.
00139  */
00140 void
00141 ccn_perror(struct ccn *h, const char *s)
00142 {
00143     const char *dlm = ": ";
00144     if (s == NULL) {
00145         if (h->err > 0)
00146             s = strerror(h->err);
00147         else
00148             dlm = s = "";
00149     }
00150     // XXX - time stamp
00151     fprintf(stderr, "ccn_client.c:%d[%d] - error %d%s%s\n",
00152                         h->errline, (int)getpid(), h->err, dlm, s);
00153 }
00154 
00155 static int
00156 ccn_note_err(struct ccn *h)
00157 {
00158     if (h->verbose_error)
00159         ccn_perror(h, NULL);
00160     return(-1);
00161 }
00162 
00163 /**
00164  * Set the error code in a ccn handle.
00165  * @param h is the ccn handle - may be NULL.
00166  * @param error_code is the code to set.
00167  * @returns -1 in all cases.
00168  */
00169 int
00170 ccn_seterror(struct ccn *h, int error_code)
00171 {
00172     if (h == NULL)
00173         return(-1);
00174     h->err = error_code;
00175     h->errline = 0;
00176     if (error_code != 0)
00177         ccn_note_err(h);
00178     return(-1);
00179 }
00180 
00181 /**
00182  * Recover last error code.
00183  * @param h is the ccn handle - may be NULL.
00184  * @returns the most recently set error code, or 0 if h is NULL.
00185  */
00186 int
00187 ccn_geterror(struct ccn *h)
00188 {
00189     if (h == NULL)
00190         return(0);
00191     return(h->err);
00192 }
00193 
00194 static struct ccn_indexbuf *
00195 ccn_indexbuf_obtain(struct ccn *h)
00196 {
00197     struct ccn_indexbuf *c = h->scratch_indexbuf;
00198     if (c == NULL)
00199         return(ccn_indexbuf_create());
00200     h->scratch_indexbuf = NULL;
00201     c->n = 0;
00202     return(c);
00203 }
00204 
00205 static void
00206 ccn_indexbuf_release(struct ccn *h, struct ccn_indexbuf *c)
00207 {
00208     c->n = 0;
00209     if (h->scratch_indexbuf == NULL)
00210         h->scratch_indexbuf = c;
00211     else
00212         ccn_indexbuf_destroy(&c);
00213 }
00214 
00215 static void
00216 ccn_replace_handler(struct ccn *h,
00217                     struct ccn_closure **dstp,
00218                     struct ccn_closure *src)
00219 {
00220     struct ccn_closure *old = *dstp;
00221     if (src == old)
00222         return;
00223     if (src != NULL)
00224         src->refcount++;
00225     *dstp = src;
00226     if (old != NULL && (--(old->refcount)) == 0) {
00227         struct ccn_upcall_info info = { 0 };
00228         info.h = h;
00229         (old->p)(old, CCN_UPCALL_FINAL, &info);
00230     }
00231 }
00232 
00233 /**
00234  * Create a client handle.
00235  * The new handle is not yet connected.
00236  * On error, returns NULL and sets errno.
00237  * Errors: ENOMEM
00238  */ 
00239 struct ccn *
00240 ccn_create(void)
00241 {
00242     struct ccn *h;
00243     const char *s;
00244     struct hashtb_param param = {0};
00245 
00246     h = calloc(1, sizeof(*h));
00247     if (h == NULL)
00248         return(h);
00249     param.finalize_data = h;
00250     h->sock = -1;
00251     h->interestbuf = ccn_charbuf_create();
00252     param.finalize = &finalize_pkey;
00253     h->keys = hashtb_create(sizeof(struct ccn_pkey *), &param);
00254     param.finalize = &finalize_keystore;
00255     h->keystores = hashtb_create(sizeof(struct ccn_keystore *), &param);
00256     s = getenv("CCN_DEBUG");
00257     h->verbose_error = (s != NULL && s[0] != 0);
00258     s = getenv("CCN_TAP");
00259     if (s != NULL && s[0] != 0) {
00260     char tap_name[255];
00261     struct timeval tv;
00262     gettimeofday(&tv, NULL);
00263         if (snprintf(tap_name, 255, "%s-%d-%d-%d", s, (int)getpid(),
00264                      (int)tv.tv_sec, (int)tv.tv_usec) >= 255) {
00265             fprintf(stderr, "CCN_TAP path is too long: %s\n", s);
00266         } else {
00267             h->tap = open(tap_name, O_WRONLY|O_APPEND|O_CREAT, S_IRWXU);
00268             if (h->tap == -1) {
00269                 NOTE_ERRNO(h);
00270                 ccn_perror(h, "Unable to open CCN_TAP file");
00271             }
00272             else
00273                 fprintf(stderr, "CCN_TAP writing to %s\n", tap_name);
00274         }
00275     } else
00276         h->tap = -1;
00277     h->defer_verification = 0;
00278     return(h);
00279 }
00280 
00281 /**
00282  * Tell the library to defer verification.
00283  *
00284  * For some specialized applications (performance testing being an example),
00285  * the normal verification done within the library may be undesirable.
00286  * Setting the "defer validation" flag will cause the library to pass content
00287  * to the application without attempting to verify it. In this case,
00288  * the CCN_UPCALL_CONTENT_RAW upcall kind will be passed instead of
00289  * CCN_UPCALL_CONTENT, and CCN_UPCALL_CONTENT_KEYMISSING instead of
00290  * CCN_UPCALL_CONTENT_UNVERIFIED.  If the application wants do still do
00291  * key fetches, it may use the CCN_UPCALL_RESULT_FETCHKEY response instead
00292  * of CCN_UPCALL_RESULT_VERIFY.
00293  *
00294  * Calling this while there are interests outstanding is not recommended.
00295  * 
00296  * This call is available beginning with CCN_API_VERSION 4004.
00297  *
00298  * @param defer is 0 to verify, 1 to defer, -1 to leave unchanged.
00299  * @returns previous value, or -1 in case of error.
00300  */
00301 int
00302 ccn_defer_verification(struct ccn *h, int defer)
00303 {
00304     int old;
00305 
00306     if (h == NULL || defer > 1 || defer < -1)
00307         return(-1);
00308     old = h->defer_verification;
00309     if (defer >= 0)
00310         h->defer_verification = defer;
00311     return(old);
00312 }
00313 
00314 /**
00315  * Connect to local ccnd.
00316  * @param h is a ccn library handle
00317  * @param name is the name of the unix-domain socket to connect to;
00318  *             use NULL to get the default.
00319  * @returns the fd for the connection, or -1 for error.
00320  */ 
00321 int
00322 ccn_connect(struct ccn *h, const char *name)
00323 {
00324     struct sockaddr_un addr = {0};
00325     int res;
00326     if (h == NULL)
00327         return(-1);
00328     h->err = 0;
00329     if (h->sock != -1)
00330         return(NOTE_ERR(h, EINVAL));
00331     addr.sun_family = AF_UNIX;
00332     if (name == NULL || name[0] == 0)
00333         ccn_setup_sockaddr_un(NULL, &addr);
00334     else {
00335         addr.sun_family = AF_UNIX;
00336         strncpy(addr.sun_path, name, sizeof(addr.sun_path));
00337     }
00338     h->sock = socket(AF_UNIX, SOCK_STREAM, 0);
00339     if (h->sock == -1)
00340         return(NOTE_ERRNO(h));
00341     res = connect(h->sock, (struct sockaddr *)&addr, sizeof(addr));
00342     if (res == -1)
00343         return(NOTE_ERRNO(h));
00344     res = fcntl(h->sock, F_SETFL, O_NONBLOCK);
00345     if (res == -1)
00346         return(NOTE_ERRNO(h));
00347     return(h->sock);
00348 }
00349 
00350 int
00351 ccn_get_connection_fd(struct ccn *h)
00352 {
00353     return(h->sock);
00354 }
00355 
00356 int
00357 ccn_disconnect(struct ccn *h)
00358 {
00359     int res;
00360     res = ccn_pushout(h);
00361     if (res == 1) {
00362         res = fcntl(h->sock, F_SETFL, 0); /* clear O_NONBLOCK */
00363         if (res == 0)
00364             ccn_pushout(h);
00365     }
00366     ccn_charbuf_destroy(&h->inbuf);
00367     ccn_charbuf_destroy(&h->outbuf);
00368     res = close(h->sock);
00369     h->sock = -1;
00370     if (res == -1)
00371         return(NOTE_ERRNO(h));
00372     return(0);
00373 }
00374 
00375 static void
00376 ccn_gripe(struct expressed_interest *i)
00377 {
00378     fprintf(stderr, "BOTCH - (struct expressed_interest *)%p has bad magic value\n", (void *)i);
00379 }
00380 
00381 static void
00382 replace_interest_msg(struct expressed_interest *interest,
00383                      struct ccn_charbuf *cb)
00384 {
00385     if (interest->magic != 0x7059e5f4) {
00386         ccn_gripe(interest);
00387         return;
00388     }
00389     if (interest->interest_msg != NULL)
00390         free(interest->interest_msg);
00391     interest->interest_msg = NULL;
00392     interest->size = 0;
00393     if (cb != NULL && cb->length > 0) {
00394         interest->interest_msg = calloc(1, cb->length);
00395         if (interest->interest_msg != NULL) {
00396             memcpy(interest->interest_msg, cb->buf, cb->length);
00397             interest->size = cb->length;
00398         }
00399     }
00400 }
00401 
00402 static struct expressed_interest *
00403 ccn_destroy_interest(struct ccn *h, struct expressed_interest *i)
00404 {
00405     struct expressed_interest *ans = i->next;
00406     if (i->magic != 0x7059e5f4) {
00407         ccn_gripe(i);
00408         return(NULL);
00409     }
00410     ccn_replace_handler(h, &(i->action), NULL);
00411     replace_interest_msg(i, NULL);
00412     ccn_charbuf_destroy(&i->wanted_pub);
00413     i->magic = -1;
00414     free(i);
00415     return(ans);
00416 }
00417 
00418 void
00419 ccn_check_interests(struct expressed_interest *list)
00420 {
00421     struct expressed_interest *ie;
00422     for (ie = list; ie != NULL; ie = ie->next) {
00423         if (ie->magic != 0x7059e5f4) {
00424             ccn_gripe(ie);
00425             abort();
00426         }
00427     }
00428 }
00429 
00430 void
00431 ccn_clean_interests_by_prefix(struct ccn *h, struct interests_by_prefix *entry)
00432 {
00433     struct expressed_interest *ie;
00434     struct expressed_interest *next;
00435     struct expressed_interest **ip;
00436     ccn_check_interests(entry->list);
00437     ip = &(entry->list);
00438     for (ie = entry->list; ie != NULL; ie = next) {
00439         next = ie->next;
00440         if (ie->action == NULL)
00441             ccn_destroy_interest(h, ie);
00442         else {
00443             (*ip) = ie;
00444             ip = &(ie->next);
00445         }
00446     }
00447     (*ip) = NULL;
00448     ccn_check_interests(entry->list);
00449 }
00450 
00451 void
00452 ccn_destroy(struct ccn **hp)
00453 {
00454     struct hashtb_enumerator ee;
00455     struct hashtb_enumerator *e = &ee;
00456     struct ccn *h = *hp;
00457     if (h == NULL)
00458         return;
00459     ccn_disconnect(h);
00460     if (h->interests_by_prefix != NULL) {
00461         for (hashtb_start(h->interests_by_prefix, e); e->data != NULL; hashtb_next(e)) {
00462             struct interests_by_prefix *entry = e->data;
00463             while (entry->list != NULL)
00464                 entry->list = ccn_destroy_interest(h, entry->list);
00465         }
00466         hashtb_end(e);
00467         hashtb_destroy(&(h->interests_by_prefix));
00468     }
00469     if (h->interest_filters != NULL) {
00470         for (hashtb_start(h->interest_filters, e); e->data != NULL; hashtb_next(e)) {
00471             struct interest_filter *i = e->data;
00472             ccn_replace_handler(h, &(i->action), NULL);
00473         }
00474         hashtb_end(e);
00475         hashtb_destroy(&(h->interest_filters));
00476     }
00477     hashtb_destroy(&(h->keys));
00478     hashtb_destroy(&(h->keystores));
00479     ccn_charbuf_destroy(&h->interestbuf);
00480     ccn_indexbuf_destroy(&h->scratch_indexbuf);
00481     ccn_charbuf_destroy(&h->default_pubid);
00482     if (h->tap != -1)
00483         close(h->tap);
00484     free(h);
00485     *hp = NULL;
00486 }
00487 
00488 /*
00489  * ccn_check_namebuf: check that name is valid
00490  * Returns the byte offset of the end of prefix portion,
00491  * as given by prefix_comps, or -1 for error.
00492  * prefix_comps = -1 means the whole name is the prefix.
00493  * If omit_possible_digest, chops off a potential digest name at the end
00494  */
00495 static int
00496 ccn_check_namebuf(struct ccn *h, struct ccn_charbuf *namebuf, int prefix_comps,
00497                   int omit_possible_digest)
00498 {
00499     struct ccn_buf_decoder decoder;
00500     struct ccn_buf_decoder *d;
00501     int i = 0;
00502     int ans = 0;
00503     int prev_ans = 0;
00504     if (namebuf == NULL || namebuf->length < 2)
00505         return(-1);
00506     d = ccn_buf_decoder_start(&decoder, namebuf->buf, namebuf->length);
00507     if (ccn_buf_match_dtag(d, CCN_DTAG_Name)) {
00508         ccn_buf_advance(d);
00509         prev_ans = ans = d->decoder.token_index;
00510         while (ccn_buf_match_dtag(d, CCN_DTAG_Component)) {
00511             ccn_buf_advance(d);
00512             if (ccn_buf_match_blob(d, NULL, NULL)) {
00513                 ccn_buf_advance(d);
00514             }
00515             ccn_buf_check_close(d);
00516             i += 1;
00517             if (prefix_comps < 0 || i <= prefix_comps) {
00518                 prev_ans = ans;
00519                 ans = d->decoder.token_index;
00520             }
00521         }
00522         ccn_buf_check_close(d);
00523     }
00524     if (d->decoder.state < 0 || ans < prefix_comps)
00525         return(-1);
00526     if (omit_possible_digest && ans == prev_ans + 36 && ans == namebuf->length - 1)
00527         return(prev_ans);
00528     return(ans);
00529 }
00530 
00531 static void
00532 ccn_construct_interest(struct ccn *h,
00533                        struct ccn_charbuf *name_prefix,
00534                        struct ccn_charbuf *interest_template,
00535                        struct expressed_interest *dest)
00536 {
00537     struct ccn_charbuf *c = h->interestbuf;
00538     size_t start;
00539     size_t size;
00540     int res;
00541     
00542     dest->lifetime_us = CCN_INTEREST_LIFETIME_MICROSEC;
00543     c->length = 0;
00544     ccn_charbuf_append_tt(c, CCN_DTAG_Interest, CCN_DTAG);
00545     ccn_charbuf_append(c, name_prefix->buf, name_prefix->length);
00546     res = 0;
00547     if (interest_template != NULL) {
00548         struct ccn_parsed_interest pi = { 0 };
00549         res = ccn_parse_interest(interest_template->buf,
00550                                  interest_template->length, &pi, NULL);
00551         if (res >= 0) {
00552             intmax_t lifetime = ccn_interest_lifetime(interest_template->buf, &pi);
00553             // XXX - for now, don't try to handle lifetimes over 30 seconds.
00554             if (lifetime < 1 || lifetime > (30 << 12))
00555                 NOTE_ERR(h, EINVAL);
00556             else
00557                 dest->lifetime_us = (lifetime * 1000000) >> 12;
00558             start = pi.offset[CCN_PI_E_Name];
00559             size = pi.offset[CCN_PI_B_Nonce] - start;
00560             ccn_charbuf_append(c, interest_template->buf + start, size);
00561             start = pi.offset[CCN_PI_B_OTHER];
00562             size = pi.offset[CCN_PI_E_OTHER] - start;
00563             if (size != 0)
00564                 ccn_charbuf_append(c, interest_template->buf + start, size);
00565         }
00566         else
00567             NOTE_ERR(h, EINVAL);
00568     }
00569     ccn_charbuf_append_closer(c);
00570     replace_interest_msg(dest, (res >= 0 ? c : NULL));
00571 }
00572 
00573 int
00574 ccn_express_interest(struct ccn *h,
00575                      struct ccn_charbuf *namebuf,
00576                      struct ccn_closure *action,
00577                      struct ccn_charbuf *interest_template)
00578 {
00579     struct hashtb_enumerator ee;
00580     struct hashtb_enumerator *e = &ee;
00581     int res;
00582     int prefixend;
00583     struct expressed_interest *interest = NULL;
00584     struct interests_by_prefix *entry = NULL;
00585     if (h->interests_by_prefix == NULL) {
00586         h->interests_by_prefix = hashtb_create(sizeof(struct interests_by_prefix), NULL);
00587         if (h->interests_by_prefix == NULL)
00588             return(NOTE_ERRNO(h));
00589     }
00590     prefixend = ccn_check_namebuf(h, namebuf, -1, 1);
00591     if (prefixend < 0)
00592         return(prefixend);
00593     /*
00594      * To make it easy to lookup prefixes of names, we keep only
00595      * the prefix name components as the key in the hash table.
00596      */
00597     hashtb_start(h->interests_by_prefix, e);
00598     res = hashtb_seek(e, namebuf->buf + 1, prefixend - 1, 0);
00599     entry = e->data;
00600     if (entry == NULL) {
00601         NOTE_ERRNO(h);
00602         hashtb_end(e);
00603         return(res);
00604     }
00605     if (res == HT_NEW_ENTRY)
00606         entry->list = NULL;
00607     interest = calloc(1, sizeof(*interest));
00608     if (interest == NULL) {
00609         NOTE_ERRNO(h);
00610         hashtb_end(e);
00611         return(-1);
00612     }
00613     interest->magic = 0x7059e5f4;
00614     ccn_construct_interest(h, namebuf, interest_template, interest);
00615     if (interest->interest_msg == NULL) {
00616         free(interest);
00617         hashtb_end(e);
00618         return(-1);
00619     }
00620     ccn_replace_handler(h, &(interest->action), action);
00621     interest->target = 1;
00622     interest->next = entry->list;
00623     entry->list = interest;
00624     hashtb_end(e);
00625     /* Actually send the interest out right away */
00626     ccn_refresh_interest(h, interest);
00627     return(0);
00628 }
00629 
00630 static void
00631 finalize_interest_filter(struct hashtb_enumerator *e)
00632 {
00633     struct interest_filter *i = e->data;
00634     if (i->ccn_reg_closure != NULL) {
00635         i->ccn_reg_closure->interest_filter = NULL;
00636         i->ccn_reg_closure = NULL;
00637     }
00638 }
00639 
00640 int
00641 ccn_set_interest_filter_with_flags(struct ccn *h, struct ccn_charbuf *namebuf,
00642                         struct ccn_closure *action, int forw_flags)
00643 {
00644     struct hashtb_enumerator ee;
00645     struct hashtb_enumerator *e = &ee;
00646     int res;
00647     struct interest_filter *entry;
00648     if (h->interest_filters == NULL) {
00649         struct hashtb_param param = {0};
00650         param.finalize = &finalize_interest_filter;
00651         h->interest_filters = hashtb_create(sizeof(struct interest_filter), &param);
00652         if (h->interest_filters == NULL)
00653             return(NOTE_ERRNO(h));
00654     }
00655     res = ccn_check_namebuf(h, namebuf, -1, 0);
00656     if (res < 0)
00657         return(res);
00658     hashtb_start(h->interest_filters, e);
00659     res = hashtb_seek(e, namebuf->buf + 1, namebuf->length - 2, 0);
00660     if (res >= 0) {
00661         entry = e->data;
00662         entry->flags = forw_flags;
00663         ccn_replace_handler(h, &(entry->action), action);
00664         if (action == NULL)
00665             hashtb_delete(e);
00666     }
00667     hashtb_end(e);
00668     return(res);
00669 }
00670 
00671 int
00672 ccn_set_interest_filter(struct ccn *h, struct ccn_charbuf *namebuf,
00673                         struct ccn_closure *action)
00674 {
00675     int forw_flags = CCN_FORW_ACTIVE | CCN_FORW_CHILD_INHERIT;
00676     return(ccn_set_interest_filter_with_flags(h, namebuf, action, forw_flags));
00677 }
00678 
00679 static int
00680 ccn_pushout(struct ccn *h)
00681 {
00682     ssize_t res;
00683     size_t size;
00684     if (h->outbuf != NULL && h->outbufindex < h->outbuf->length) {
00685         if (h->sock < 0)
00686             return(1);
00687         size = h->outbuf->length - h->outbufindex;
00688         res = write(h->sock, h->outbuf->buf + h->outbufindex, size);
00689         if (res == size) {
00690             h->outbuf->length = h->outbufindex = 0;
00691             return(0);
00692         }
00693         if (res == -1)
00694             return ((errno == EAGAIN) ? 1 : NOTE_ERRNO(h));
00695         h->outbufindex += res;
00696         return(1);
00697     }
00698     return(0);
00699 }
00700 
00701 int
00702 ccn_put(struct ccn *h, const void *p, size_t length)
00703 {
00704     struct ccn_skeleton_decoder dd = {0};
00705     ssize_t res;
00706     if (h == NULL)
00707         return(-1);
00708     if (p == NULL || length == 0)
00709         return(NOTE_ERR(h, EINVAL));
00710     res = ccn_skeleton_decode(&dd, p, length);
00711     if (!(res == length && dd.state == 0))
00712         return(NOTE_ERR(h, EINVAL));
00713     if (h->tap != -1) {
00714         res = write(h->tap, p, length);
00715         if (res == -1) {
00716             NOTE_ERRNO(h);
00717             (void)close(h->tap);
00718             h->tap = -1;
00719         }
00720     }
00721     if (h->outbuf != NULL && h->outbufindex < h->outbuf->length) {
00722         // XXX - should limit unbounded growth of h->outbuf
00723         ccn_charbuf_append(h->outbuf, p, length); // XXX - check res
00724         return (ccn_pushout(h));
00725     }
00726     if (h->sock == -1)
00727         res = 0;
00728     else
00729         res = write(h->sock, p, length);
00730     if (res == length)
00731         return(0);
00732     if (res == -1) {
00733         if (errno != EAGAIN)
00734             return(NOTE_ERRNO(h));
00735         res = 0;
00736     }
00737     if (h->outbuf == NULL) {
00738         h->outbuf = ccn_charbuf_create();
00739         h->outbufindex = 0;
00740     }
00741     ccn_charbuf_append(h->outbuf, ((const unsigned char *)p)+res, length-res);
00742     return(1);
00743 }
00744 
00745 int
00746 ccn_output_is_pending(struct ccn *h)
00747 {
00748     return(h != NULL && h->outbuf != NULL && h->outbufindex < h->outbuf->length);
00749 }
00750 
00751 struct ccn_charbuf *
00752 ccn_grab_buffered_output(struct ccn *h)
00753 {
00754     if (ccn_output_is_pending(h) && h->outbufindex == 0) {
00755         struct ccn_charbuf *ans = h->outbuf;
00756         h->outbuf = NULL;
00757         return(ans);
00758     }
00759     return(NULL);
00760 }
00761 
00762 static void
00763 ccn_refresh_interest(struct ccn *h, struct expressed_interest *interest)
00764 {
00765     int res;
00766     if (interest->magic != 0x7059e5f4) {
00767         ccn_gripe(interest);
00768         return;
00769     }
00770     if (interest->outstanding < interest->target) {
00771         res = ccn_put(h, interest->interest_msg, interest->size);
00772         if (res >= 0) {
00773             interest->outstanding += 1;
00774             if (h->now.tv_sec == 0)
00775                 gettimeofday(&h->now, NULL);
00776             interest->lasttime = h->now;
00777         }
00778     }
00779 }
00780 
00781 static int
00782 ccn_get_content_type(const unsigned char *ccnb,
00783                      const struct ccn_parsed_ContentObject *pco)
00784 {
00785     enum ccn_content_type type = pco->type;
00786     (void)ccnb; // XXX - don't need now
00787     switch (type) {
00788         case CCN_CONTENT_DATA:
00789         case CCN_CONTENT_ENCR:
00790         case CCN_CONTENT_GONE:
00791         case CCN_CONTENT_KEY:
00792         case CCN_CONTENT_LINK:
00793         case CCN_CONTENT_NACK:
00794             return (type);
00795         default:
00796             return (-1);
00797     }
00798 }
00799 
00800 /**
00801  * Compute the digest of just the Content portion of content_object.
00802  */
00803 static void
00804 ccn_digest_Content(const unsigned char *content_object,
00805                    struct ccn_parsed_ContentObject *pc,
00806                    unsigned char *digest,
00807                    size_t digest_bytes)
00808 {
00809     int res;
00810     struct ccn_digest *d = NULL;
00811     const unsigned char *content = NULL;
00812     size_t content_bytes = 0;
00813     
00814     if (pc->magic < 20080000) abort();
00815     if (digest_bytes == sizeof(digest))
00816         return;
00817     d = ccn_digest_create(CCN_DIGEST_SHA256);
00818     ccn_digest_init(d);
00819     res = ccn_ref_tagged_BLOB(CCN_DTAG_Content, content_object,
00820                               pc->offset[CCN_PCO_B_Content],
00821                               pc->offset[CCN_PCO_E_Content],
00822                               &content, &content_bytes);
00823     if (res < 0) abort();
00824     res = ccn_digest_update(d, content, content_bytes);
00825     if (res < 0) abort();
00826     res = ccn_digest_final(d, digest, digest_bytes);
00827     if (res < 0) abort();
00828     ccn_digest_destroy(&d);
00829 }
00830 
00831 static int
00832 ccn_cache_key(struct ccn *h,
00833               const unsigned char *ccnb, size_t size,
00834               struct ccn_parsed_ContentObject *pco)
00835 {
00836     int type;
00837     struct ccn_pkey **entry;
00838     struct hashtb_enumerator ee;
00839     struct hashtb_enumerator *e = &ee;
00840     int res;
00841     unsigned char digest[32];
00842 
00843     type = ccn_get_content_type(ccnb, pco);
00844     if (type != CCN_CONTENT_KEY) {
00845         return (0);
00846     }
00847 
00848     ccn_digest_Content(ccnb, pco, digest, sizeof(digest));
00849 
00850     hashtb_start(h->keys, e);
00851     res = hashtb_seek(e, (void *)digest, sizeof(digest), 0);
00852     if (res < 0) {
00853         hashtb_end(e);
00854         return(NOTE_ERRNO(h));
00855     }
00856     entry = e->data;
00857     if (res == HT_NEW_ENTRY) {
00858         struct ccn_pkey *pkey;
00859         const unsigned char *data = NULL;
00860         size_t data_size = 0;
00861 
00862         res = ccn_content_get_value(ccnb, size, pco, &data, &data_size);
00863         if (res < 0) {
00864             hashtb_delete(e);
00865             hashtb_end(e);
00866             return(NOTE_ERRNO(h));
00867         }
00868         pkey = ccn_d2i_pubkey(data, data_size);
00869         if (pkey == NULL) {
00870             hashtb_delete(e);
00871             hashtb_end(e);
00872             return(NOTE_ERRNO(h));
00873         }
00874         *entry = pkey;
00875     }
00876     hashtb_end(e);
00877     return (0);
00878 }
00879 
00880 static void
00881 finalize_pkey(struct hashtb_enumerator *e)
00882 {
00883     struct ccn_pkey **entry = e->data;
00884     if (*entry != NULL)
00885         ccn_pubkey_free(*entry);
00886 }
00887 
00888 /**
00889  * Examine a ContentObject and try to find the public key needed to
00890  * verify it.  It might be present in our cache of keys, or in the
00891  * object itself; in either of these cases, we can satisfy the request
00892  * right away. Or there may be an indirection (a KeyName), in which case
00893  * return without the key. The final possibility is that there is no key
00894  * locator we can make sense of.
00895  * @returns negative for error, 0 when pubkey is filled in,
00896  *         or 1 if the key needs to be requested.
00897  */
00898 static int
00899 ccn_locate_key(struct ccn *h,
00900                const unsigned char *msg,
00901                struct ccn_parsed_ContentObject *pco,
00902                struct ccn_pkey **pubkey)
00903 {
00904     int res;
00905     const unsigned char *pkeyid;
00906     size_t pkeyid_size;
00907     struct ccn_pkey **entry;
00908     struct ccn_buf_decoder decoder;
00909     struct ccn_buf_decoder *d;
00910 
00911     if (h->keys == NULL) {
00912         return (NOTE_ERR(h, EINVAL));
00913     }
00914 
00915     res = ccn_ref_tagged_BLOB(CCN_DTAG_PublisherPublicKeyDigest, msg,
00916                               pco->offset[CCN_PCO_B_PublisherPublicKeyDigest],
00917                               pco->offset[CCN_PCO_E_PublisherPublicKeyDigest],
00918                               &pkeyid, &pkeyid_size);
00919     if (res < 0)
00920         return (NOTE_ERR(h, res));
00921     entry = hashtb_lookup(h->keys, pkeyid, pkeyid_size);
00922     if (entry != NULL) {
00923         *pubkey = *entry;
00924         return (0);
00925     }
00926     /* Is a key locator present? */
00927     if (pco->offset[CCN_PCO_B_KeyLocator] == pco->offset[CCN_PCO_E_KeyLocator])
00928         return (-1);
00929     /* Use the key locator */
00930     d = ccn_buf_decoder_start(&decoder, msg + pco->offset[CCN_PCO_B_Key_Certificate_KeyName],
00931                               pco->offset[CCN_PCO_E_Key_Certificate_KeyName] -
00932                               pco->offset[CCN_PCO_B_Key_Certificate_KeyName]);
00933     if (ccn_buf_match_dtag(d, CCN_DTAG_KeyName)) {
00934         return(1);
00935     }
00936     else if (ccn_buf_match_dtag(d, CCN_DTAG_Key)) {
00937         const unsigned char *dkey;
00938         size_t dkey_size;
00939         struct ccn_digest *digest = NULL;
00940         unsigned char *key_digest = NULL;
00941         size_t key_digest_size;
00942         struct hashtb_enumerator ee;
00943         struct hashtb_enumerator *e = &ee;
00944 
00945         res = ccn_ref_tagged_BLOB(CCN_DTAG_Key, msg,
00946                                   pco->offset[CCN_PCO_B_Key_Certificate_KeyName],
00947                                   pco->offset[CCN_PCO_E_Key_Certificate_KeyName],
00948                                   &dkey, &dkey_size);
00949         *pubkey = ccn_d2i_pubkey(dkey, dkey_size);
00950         digest = ccn_digest_create(CCN_DIGEST_SHA256);
00951         ccn_digest_init(digest);
00952         key_digest_size = ccn_digest_size(digest);
00953         key_digest = calloc(1, key_digest_size);
00954         if (key_digest == NULL) abort();
00955         res = ccn_digest_update(digest, dkey, dkey_size);
00956         if (res < 0) abort();
00957         res = ccn_digest_final(digest, key_digest, key_digest_size);
00958         if (res < 0) abort();
00959         ccn_digest_destroy(&digest);
00960         hashtb_start(h->keys, e);
00961         res = hashtb_seek(e, (void *)key_digest, key_digest_size, 0);
00962         free(key_digest);
00963         key_digest = NULL;
00964         if (res < 0) {
00965             hashtb_end(e);
00966             return(NOTE_ERRNO(h));
00967         }
00968         entry = e->data;
00969         if (res == HT_NEW_ENTRY) {
00970             *entry = *pubkey;
00971         }
00972         else
00973             THIS_CANNOT_HAPPEN(h);
00974         hashtb_end(e);
00975         return (0);
00976     }
00977     else if (ccn_buf_match_dtag(d, CCN_DTAG_Certificate)) {
00978         XXX; // what should we really do in this case?
00979     }
00980 
00981     return (-1);
00982 }
00983 
00984 /**
00985  * Get the name out of a Link.
00986  *
00987  * XXX - this needs a better home.
00988  */
00989 static int
00990 ccn_append_link_name(struct ccn_charbuf *name, const unsigned char *data, size_t data_size)
00991 {
00992     struct ccn_buf_decoder decoder;
00993     struct ccn_buf_decoder *d;
00994     size_t start = 0;
00995     size_t end = 0;
00996     
00997     d = ccn_buf_decoder_start(&decoder, data, data_size);
00998     if (ccn_buf_match_dtag(d, CCN_DTAG_Link)) {
00999         ccn_buf_advance(d);
01000         start = d->decoder.token_index;
01001         ccn_parse_Name(d, NULL);
01002         end = d->decoder.token_index;
01003         ccn_buf_check_close(d);
01004         if (d->decoder.state < 0)
01005             return (d->decoder.state);
01006         ccn_charbuf_append(name, data + start, end - start);
01007         return(0);
01008         }
01009     return(-1);
01010 }
01011 
01012 /**
01013  * Called when we get an answer to a KeyLocator fetch issued by
01014  * ccn_initiate_key_fetch.  This does not really have to do much,
01015  * since the main content handling logic picks up the keys as they
01016  * go by.
01017  */
01018 static enum ccn_upcall_res
01019 handle_key(struct ccn_closure *selfp,
01020            enum ccn_upcall_kind kind,
01021            struct ccn_upcall_info *info)
01022 {
01023     struct ccn *h = info->h;
01024     (void)h;
01025     int type = 0;
01026     const unsigned char *msg = NULL;
01027     const unsigned char *data = NULL;
01028     size_t size;
01029     size_t data_size;
01030     int res;
01031     struct ccn_charbuf *name = NULL;
01032     struct ccn_charbuf *templ = NULL;
01033     
01034     switch(kind) {
01035         case CCN_UPCALL_FINAL:
01036             free(selfp);
01037             return(CCN_UPCALL_RESULT_OK);
01038         case CCN_UPCALL_INTEREST_TIMED_OUT:
01039             /* Don't keep trying */
01040             return(CCN_UPCALL_RESULT_OK);
01041         case CCN_UPCALL_CONTENT_UNVERIFIED:
01042             /* This is not exactly right, but trying to follow the KeyLocator could be worse trouble. */
01043         case CCN_UPCALL_CONTENT_KEYMISSING:
01044         case CCN_UPCALL_CONTENT_RAW:
01045         case CCN_UPCALL_CONTENT:
01046             type = ccn_get_content_type(msg, info->pco);
01047             if (type == CCN_CONTENT_KEY)
01048                 return(CCN_UPCALL_RESULT_OK);
01049             if (type == CCN_CONTENT_LINK) {
01050                 /* resolve the link */
01051                 /* Limit how much we work at this. */
01052                 if (selfp->intdata <= 0)
01053                     return(NOTE_ERR(h, ELOOP));
01054                 selfp->intdata -= 1;
01055                 msg = info->content_ccnb;
01056                 size = info->pco->offset[CCN_PCO_E];
01057                 res = ccn_content_get_value(info->content_ccnb, size, info->pco,
01058                                             &data, &data_size);
01059                 if (res < 0)
01060                     return (CCN_UPCALL_RESULT_ERR);
01061                 templ = ccn_charbuf_create();
01062                 ccn_charbuf_append_tt(templ, CCN_DTAG_Interest, CCN_DTAG);
01063                 ccn_charbuf_append_tt(templ, CCN_DTAG_Name, CCN_DTAG);
01064                 ccn_charbuf_append_closer(templ); /* </Name> */
01065                 ccnb_tagged_putf(templ, CCN_DTAG_MinSuffixComponents, "%d", 1);
01066                 ccnb_tagged_putf(templ, CCN_DTAG_MaxSuffixComponents, "%d", 3);
01067                 ccn_charbuf_append_closer(templ); /* </Interest> */
01068                 name = ccn_charbuf_create();
01069                 res = ccn_append_link_name(name, data, data_size);
01070                 if (res < 0) {
01071                     NOTE_ERR(h, EINVAL);
01072                     res = CCN_UPCALL_RESULT_ERR;
01073                 }
01074                 else
01075                     res = ccn_express_interest(h, name, selfp, templ);
01076                 ccn_charbuf_destroy(&name);
01077                 ccn_charbuf_destroy(&templ);
01078                 return(res);
01079             }
01080             return (CCN_UPCALL_RESULT_ERR);
01081         default:
01082             return (CCN_UPCALL_RESULT_ERR);
01083     }
01084 }
01085 
01086 /**
01087  * This is the maximum number of links in we are willing to traverse
01088  * when resolving a key locator.
01089  */
01090 #ifndef CCN_MAX_KEY_LINK_CHAIN
01091 #define CCN_MAX_KEY_LINK_CHAIN 7
01092 #endif
01093 
01094 static int
01095 ccn_initiate_key_fetch(struct ccn *h,
01096                        unsigned char *msg,
01097                        struct ccn_parsed_ContentObject *pco,
01098                        struct expressed_interest *trigger_interest)
01099 {
01100     /* 
01101      * Create a new interest in the key name, set up a callback that will
01102      * insert the key into the h->keys hashtb for the calling handle and
01103      * cause the trigger_interest to be re-expressed.
01104      */
01105     int res;
01106     int namelen;
01107     struct ccn_charbuf *key_name = NULL;
01108     struct ccn_closure *key_closure = NULL;
01109     const unsigned char *pkeyid = NULL;
01110     size_t pkeyid_size = 0;
01111     struct ccn_charbuf *templ = NULL;
01112     
01113     if (trigger_interest != NULL) {
01114         /* Arrange a wakeup when the key arrives */
01115         if (trigger_interest->wanted_pub == NULL)
01116             trigger_interest->wanted_pub = ccn_charbuf_create();
01117         res = ccn_ref_tagged_BLOB(CCN_DTAG_PublisherPublicKeyDigest, msg,
01118                                   pco->offset[CCN_PCO_B_PublisherPublicKeyDigest],
01119                                   pco->offset[CCN_PCO_E_PublisherPublicKeyDigest],
01120                                   &pkeyid, &pkeyid_size);
01121         if (trigger_interest->wanted_pub != NULL && res >= 0) {
01122             trigger_interest->wanted_pub->length = 0;
01123             ccn_charbuf_append(trigger_interest->wanted_pub, pkeyid, pkeyid_size);
01124         }
01125         trigger_interest->target = 0;
01126     }
01127 
01128     namelen = (pco->offset[CCN_PCO_E_KeyName_Name] -
01129                pco->offset[CCN_PCO_B_KeyName_Name]);
01130     /*
01131      * If there is no KeyName provided, we can't ask, but we might win if the
01132      * key arrives along with some other content.
01133      */
01134     if (namelen == 0)
01135         return(-1);
01136     key_closure = calloc(1, sizeof(*key_closure));
01137     if (key_closure == NULL)
01138         return (NOTE_ERRNO(h));
01139     key_closure->p = &handle_key;
01140     key_closure->intdata = CCN_MAX_KEY_LINK_CHAIN; /* to limit how many links we will resolve */
01141     
01142     key_name = ccn_charbuf_create();
01143     res = ccn_charbuf_append(key_name,
01144                              msg + pco->offset[CCN_PCO_B_KeyName_Name],
01145                              namelen);
01146     templ = ccn_charbuf_create();
01147     ccn_charbuf_append_tt(templ, CCN_DTAG_Interest, CCN_DTAG);
01148     ccn_charbuf_append_tt(templ, CCN_DTAG_Name, CCN_DTAG);
01149     ccn_charbuf_append_closer(templ); /* </Name> */
01150     ccnb_tagged_putf(templ, CCN_DTAG_MinSuffixComponents, "%d", 1);
01151     ccnb_tagged_putf(templ, CCN_DTAG_MaxSuffixComponents, "%d", 3);
01152     if (pco->offset[CCN_PCO_B_KeyName_Pub] < pco->offset[CCN_PCO_E_KeyName_Pub]) {
01153         ccn_charbuf_append(templ,
01154                            msg + pco->offset[CCN_PCO_B_KeyName_Pub],
01155                            (pco->offset[CCN_PCO_E_KeyName_Pub] - 
01156                             pco->offset[CCN_PCO_B_KeyName_Pub]));
01157     }
01158     ccn_charbuf_append_closer(templ); /* </Interest> */
01159     res = ccn_express_interest(h, key_name, key_closure, templ);
01160     ccn_charbuf_destroy(&key_name);
01161     ccn_charbuf_destroy(&templ);
01162     return(res);
01163 }
01164 
01165 /**
01166  * If we were waiting for a key and it has arrived,
01167  * refresh the interest.
01168  */
01169 static void
01170 ccn_check_pub_arrival(struct ccn *h, struct expressed_interest *interest)
01171 {
01172     struct ccn_charbuf *want = interest->wanted_pub;
01173     if (want == NULL)
01174         return;
01175     if (hashtb_lookup(h->keys, want->buf, want->length) != NULL) {
01176         ccn_charbuf_destroy(&interest->wanted_pub);
01177         interest->target = 1;
01178         ccn_refresh_interest(h, interest);
01179     }
01180 }
01181 
01182 /**
01183  * Dispatch a message through the registered upcalls.
01184  * This is not used by normal ccn clients, but is made available for use when
01185  * ccnd needs to communicate with its internal client.
01186  * @param h is the ccn handle.
01187  * @param msg is the ccnb-encoded Interest or ContentObject.
01188  * @param size is its size in bytes.
01189  */
01190 void
01191 ccn_dispatch_message(struct ccn *h, unsigned char *msg, size_t size)
01192 {
01193     struct ccn_parsed_interest pi = {0};
01194     struct ccn_upcall_info info = {0};
01195     int i;
01196     int res;
01197     enum ccn_upcall_res ures;
01198     
01199     h->running++;
01200     info.h = h;
01201     info.pi = &pi;
01202     info.interest_comps = ccn_indexbuf_obtain(h);
01203     res = ccn_parse_interest(msg, size, &pi, info.interest_comps);
01204     if (res >= 0) {
01205         /* This message is an Interest */
01206         enum ccn_upcall_kind upcall_kind = CCN_UPCALL_INTEREST;
01207         info.interest_ccnb = msg;
01208         if (h->interest_filters != NULL && info.interest_comps->n > 0) {
01209             struct ccn_indexbuf *comps = info.interest_comps;
01210             size_t keystart = comps->buf[0];
01211             unsigned char *key = msg + keystart;
01212             struct interest_filter *entry;
01213             for (i = comps->n - 1; i >= 0; i--) {
01214                 entry = hashtb_lookup(h->interest_filters, key, comps->buf[i] - keystart);
01215                 if (entry != NULL) {
01216                     info.matched_comps = i;
01217                     ures = (entry->action->p)(entry->action, upcall_kind, &info);
01218                     if (ures == CCN_UPCALL_RESULT_INTEREST_CONSUMED)
01219                         upcall_kind = CCN_UPCALL_CONSUMED_INTEREST;
01220                 }
01221             }
01222         }
01223     }
01224     else {
01225         /* This message should be a ContentObject. */
01226         struct ccn_parsed_ContentObject obj = {0};
01227         info.pco = &obj;
01228         info.content_comps = ccn_indexbuf_create();
01229         res = ccn_parse_ContentObject(msg, size, &obj, info.content_comps);
01230         if (res >= 0) {
01231             info.content_ccnb = msg;
01232             if (h->interests_by_prefix != NULL) {
01233                 struct ccn_indexbuf *comps = info.content_comps;
01234                 size_t keystart = comps->buf[0];
01235                 unsigned char *key = msg + keystart;
01236                 struct expressed_interest *interest = NULL;
01237                 struct interests_by_prefix *entry = NULL;
01238                 for (i = comps->n - 1; i >= 0; i--) {
01239                     entry = hashtb_lookup(h->interests_by_prefix, key, comps->buf[i] - keystart);
01240                     if (entry != NULL) {
01241                         for (interest = entry->list; interest != NULL; interest = interest->next) {
01242                             if (interest->magic != 0x7059e5f4) {
01243                                 ccn_gripe(interest);
01244                             }
01245                             if (interest->target > 0 && interest->outstanding > 0) {
01246                                 res = ccn_parse_interest(interest->interest_msg,
01247                                                          interest->size,
01248                                                          info.pi,
01249                                                          info.interest_comps);
01250                                 if (res >= 0 &&
01251                                     ccn_content_matches_interest(msg, size,
01252                                                                  1, info.pco,
01253                                                                  interest->interest_msg,
01254                                                                  interest->size,
01255                                                                  info.pi)) {
01256                                     enum ccn_upcall_kind upcall_kind = CCN_UPCALL_CONTENT;
01257                                     struct ccn_pkey *pubkey = NULL;
01258                                     int type = ccn_get_content_type(msg, info.pco);
01259                                     if (type == CCN_CONTENT_KEY)
01260                                         res = ccn_cache_key(h, msg, size, info.pco);
01261                                     res = ccn_locate_key(h, msg, info.pco, &pubkey);
01262                                     if (h->defer_verification) {
01263                                         if (res == 0)
01264                                             upcall_kind = CCN_UPCALL_CONTENT_RAW;
01265                                         else
01266                                             upcall_kind = CCN_UPCALL_CONTENT_KEYMISSING;
01267                                     }
01268                                     else if (res == 0) {
01269                                         /* we have the pubkey, use it to verify the msg */
01270                                         res = ccn_verify_signature(msg, size, info.pco, pubkey);
01271                                         upcall_kind = (res == 1) ? CCN_UPCALL_CONTENT : CCN_UPCALL_CONTENT_BAD;
01272                                     } else
01273                                         upcall_kind = CCN_UPCALL_CONTENT_UNVERIFIED;
01274                                     interest->outstanding -= 1;
01275                                     info.interest_ccnb = interest->interest_msg;
01276                                     info.matched_comps = i;
01277                                     ures = (interest->action->p)(interest->action,
01278                                                                  upcall_kind,
01279                                                                  &info);
01280                                     if (interest->magic != 0x7059e5f4)
01281                                         ccn_gripe(interest);
01282                                     if (ures == CCN_UPCALL_RESULT_REEXPRESS)
01283                                         ccn_refresh_interest(h, interest);
01284                                     else if ((ures == CCN_UPCALL_RESULT_VERIFY ||
01285                                               ures == CCN_UPCALL_RESULT_FETCHKEY) &&
01286                                              (upcall_kind == CCN_UPCALL_CONTENT_UNVERIFIED ||
01287                                               upcall_kind == CCN_UPCALL_CONTENT_KEYMISSING)) { /* KEYS */
01288                                         ccn_initiate_key_fetch(h, msg, info.pco, interest);
01289                                     }
01290                                     else if (ures == CCN_UPCALL_RESULT_VERIFY &&
01291                                              upcall_kind == CCN_UPCALL_CONTENT_RAW) {
01292                                         /* For now, call this a client bug. */
01293                                         abort();
01294                                     }
01295                                     else {
01296                                         interest->target = 0;
01297                                         replace_interest_msg(interest, NULL);
01298                                         ccn_replace_handler(h, &(interest->action), NULL);
01299                                     }
01300                                 }
01301                             }
01302                         }
01303                     }
01304                 }
01305             }
01306         }
01307     } // XXX whew, what a lot of right braces!
01308     ccn_indexbuf_release(h, info.interest_comps);
01309     ccn_indexbuf_destroy(&info.content_comps);
01310     h->running--;
01311 }
01312 
01313 static int
01314 ccn_process_input(struct ccn *h)
01315 {
01316     ssize_t res;
01317     ssize_t msgstart;
01318     unsigned char *buf;
01319     struct ccn_skeleton_decoder *d = &h->decoder;
01320     struct ccn_charbuf *inbuf = h->inbuf;
01321     if (inbuf == NULL)
01322         h->inbuf = inbuf = ccn_charbuf_create();
01323     if (inbuf->length == 0)
01324         memset(d, 0, sizeof(*d));
01325     buf = ccn_charbuf_reserve(inbuf, 8800);
01326     res = read(h->sock, buf, inbuf->limit - inbuf->length);
01327     if (res == 0) {
01328         ccn_disconnect(h);
01329         return(-1);
01330     }
01331     if (res == -1) {
01332         if (errno == EAGAIN)
01333             res = 0;
01334         else
01335             return(NOTE_ERRNO(h));
01336     }
01337     inbuf->length += res;
01338     msgstart = 0;
01339     ccn_skeleton_decode(d, buf, res);
01340     while (d->state == 0) {
01341         ccn_dispatch_message(h, inbuf->buf + msgstart, 
01342                               d->index - msgstart);
01343         msgstart = d->index;
01344         if (msgstart == inbuf->length) {
01345             inbuf->length = 0;
01346             return(0);
01347         }
01348         ccn_skeleton_decode(d, inbuf->buf + d->index,
01349                             inbuf->length - d->index);
01350     }
01351     if (msgstart < inbuf->length && msgstart > 0) {
01352         /* move partial message to start of buffer */
01353         memmove(inbuf->buf, inbuf->buf + msgstart,
01354                 inbuf->length - msgstart);
01355         inbuf->length -= msgstart;
01356         d->index -= msgstart;
01357     }
01358     return(0);
01359 }
01360 
01361 static void
01362 ccn_update_refresh_us(struct ccn *h, struct timeval *tv)
01363 {
01364     int delta;
01365     if (tv->tv_sec < h->now.tv_sec)
01366         return;
01367     if (tv->tv_sec > h->now.tv_sec + CCN_INTEREST_LIFETIME_SEC)
01368         return;
01369     delta = (tv->tv_sec  - h->now.tv_sec)*1000000 +
01370             (tv->tv_usec - h->now.tv_usec);
01371     if (delta < 0)
01372         delta = 0;
01373     if (delta < h->refresh_us)
01374         h->refresh_us = delta;
01375 }
01376 
01377 static void
01378 ccn_age_interest(struct ccn *h,
01379                  struct expressed_interest *interest,
01380                  const unsigned char *key, size_t keysize)
01381 {
01382     struct ccn_parsed_interest pi = {0};
01383     struct ccn_upcall_info info = {0};
01384     int delta;
01385     int res;
01386     enum ccn_upcall_res ures;
01387     int firstcall;
01388     if (interest->magic != 0x7059e5f4)
01389         ccn_gripe(interest);
01390     info.h = h;
01391     info.pi = &pi;
01392     firstcall = (interest->lasttime.tv_sec == 0);
01393     if (interest->lasttime.tv_sec + 30 < h->now.tv_sec) {
01394         /* fixup so that delta does not overflow */
01395         interest->outstanding = 0;
01396         interest->lasttime = h->now;
01397         interest->lasttime.tv_sec -= 30;
01398     }
01399     delta = (h->now.tv_sec  - interest->lasttime.tv_sec)*1000000 +
01400             (h->now.tv_usec - interest->lasttime.tv_usec);
01401     if (delta >= interest->lifetime_us) {
01402         interest->outstanding = 0;
01403         delta = 0;
01404     }
01405     else if (delta < 0)
01406         delta = 0;
01407     if (interest->lifetime_us - delta < h->refresh_us)
01408         h->refresh_us = interest->lifetime_us - delta;
01409     interest->lasttime = h->now;
01410     while (delta > interest->lasttime.tv_usec) {
01411         delta -= 1000000;
01412         interest->lasttime.tv_sec -= 1;
01413     }
01414     interest->lasttime.tv_usec -= delta;
01415     if (interest->target > 0 && interest->outstanding == 0) {
01416         ures = CCN_UPCALL_RESULT_REEXPRESS;
01417         if (!firstcall) {
01418             info.interest_ccnb = interest->interest_msg;
01419             info.interest_comps = ccn_indexbuf_obtain(h);
01420             res = ccn_parse_interest(interest->interest_msg,
01421                                      interest->size,
01422                                      info.pi,
01423                                      info.interest_comps);
01424             if (res >= 0) {
01425                 ures = (interest->action->p)(interest->action,
01426                                              CCN_UPCALL_INTEREST_TIMED_OUT,
01427                                              &info);
01428                 if (interest->magic != 0x7059e5f4)
01429                     ccn_gripe(interest);
01430             }
01431             else {
01432                 int i;
01433                 fprintf(stderr, "URP!! interest has been corrupted ccn_client.c:%d\n", __LINE__);
01434                 for (i = 0; i < 120; i++)
01435                     sleep(1);
01436                 ures = CCN_UPCALL_RESULT_ERR;
01437             }
01438             ccn_indexbuf_release(h, info.interest_comps);
01439         }
01440         if (ures == CCN_UPCALL_RESULT_REEXPRESS)
01441             ccn_refresh_interest(h, interest);
01442         else
01443             interest->target = 0;
01444     }
01445 }
01446 
01447 static void
01448 ccn_clean_all_interests(struct ccn *h)
01449 {
01450     struct hashtb_enumerator ee;
01451     struct hashtb_enumerator *e = &ee;
01452     struct interests_by_prefix *entry;
01453     for (hashtb_start(h->interests_by_prefix, e); e->data != NULL;) {
01454         entry = e->data;
01455         ccn_clean_interests_by_prefix(h, entry);
01456         if (entry->list == NULL)
01457             hashtb_delete(e);
01458         else
01459             hashtb_next(e);
01460     }
01461     hashtb_end(e);
01462 }
01463 
01464 static void
01465 ccn_notify_ccndid_changed(struct ccn *h)
01466 {
01467     struct hashtb_enumerator ee;
01468     struct hashtb_enumerator *e = &ee;
01469     if (h->interest_filters != NULL) {
01470         for (hashtb_start(h->interest_filters, e); e->data != NULL; hashtb_next(e)) {
01471             struct interest_filter *i = e->data;
01472             if ((i->flags & CCN_FORW_WAITING_CCNDID) != 0) {
01473                 i->expiry = h->now;
01474                 i->flags &= ~CCN_FORW_WAITING_CCNDID;
01475             }
01476         }
01477         hashtb_end(e);
01478     }
01479 }
01480 
01481 /**
01482  * Process any scheduled operations that are due.
01483  * This is not used by normal ccn clients, but is made available for use
01484  * by ccnd to run its internal client.
01485  * @param h is the ccn handle.
01486  * @returns the number of microseconds until the next thing needs to happen.
01487  */
01488 int
01489 ccn_process_scheduled_operations(struct ccn *h)
01490 {
01491     struct hashtb_enumerator ee;
01492     struct hashtb_enumerator *e = &ee;
01493     struct interests_by_prefix *entry;
01494     struct expressed_interest *ie;
01495     int need_clean = 0;
01496     h->refresh_us = 5 * CCN_INTEREST_LIFETIME_MICROSEC;
01497     gettimeofday(&h->now, NULL);
01498     if (ccn_output_is_pending(h))
01499         return(h->refresh_us);
01500     h->running++;
01501     if (h->interest_filters != NULL) {
01502         for (hashtb_start(h->interest_filters, e); e->data != NULL; hashtb_next(e)) {
01503             struct interest_filter *i = e->data;
01504             if (tv_earlier(&i->expiry, &h->now)) {
01505                 /* registration is expiring, refresh it */
01506                 ccn_initiate_prefix_reg(h, e->key, e->keysize, i);
01507             }
01508             else
01509                 ccn_update_refresh_us(h, &i->expiry);
01510         }
01511         hashtb_end(e);
01512     }
01513     if (h->interests_by_prefix != NULL) {
01514         for (hashtb_start(h->interests_by_prefix, e); e->data != NULL; hashtb_next(e)) {
01515             entry = e->data;
01516             ccn_check_interests(entry->list);
01517             if (entry->list == NULL)
01518                 need_clean = 1;
01519             else {
01520                 for (ie = entry->list; ie != NULL; ie = ie->next) {
01521                     ccn_check_pub_arrival(h, ie);
01522                     if (ie->target != 0)
01523                         ccn_age_interest(h, ie, e->key, e->keysize);
01524                     if (ie->target == 0 && ie->wanted_pub == NULL) {
01525                         ccn_replace_handler(h, &(ie->action), NULL);
01526                         replace_interest_msg(ie, NULL);
01527                         need_clean = 1;
01528                     }
01529                 }
01530             }
01531         }
01532         hashtb_end(e);
01533         if (need_clean)
01534             ccn_clean_all_interests(h);
01535     }
01536     h->running--;
01537     return(h->refresh_us);
01538 }
01539 
01540 /**
01541  * Modify ccn_run timeout.
01542  * This may be called from an upcall to change the timeout value.
01543  * Most often this will be used to set the timeout to zero so that
01544  * ccn_run will return control to the client.
01545  * @param h is the ccn handle.
01546  * @param timeout is in milliseconds.
01547  * @returns old timeout value.
01548  */
01549 int
01550 ccn_set_run_timeout(struct ccn *h, int timeout)
01551 {
01552     int ans = h->timeout;
01553     h->timeout = timeout;
01554     return(ans);
01555 }
01556 
01557 /**
01558  * Run the ccn client event loop.
01559  * This may serve as the main event loop for simple apps by passing 
01560  * a timeout value of -1.
01561  * @param h is the ccn handle.
01562  * @param timeout is in milliseconds.
01563  * @returns a negative value for error, zero for success.
01564  */
01565 int
01566 ccn_run(struct ccn *h, int timeout)
01567 {
01568     struct timeval start;
01569     struct pollfd fds[1];
01570     int microsec;
01571     int millisec;
01572     int res = -1;
01573     if (h->running != 0)
01574         return(NOTE_ERR(h, EBUSY));
01575     memset(fds, 0, sizeof(fds));
01576     memset(&start, 0, sizeof(start));
01577     h->timeout = timeout;
01578     for (;;) {
01579         if (h->sock == -1) {
01580             res = -1;
01581             break;
01582         }
01583         microsec = ccn_process_scheduled_operations(h);
01584         timeout = h->timeout;
01585         if (start.tv_sec == 0)
01586             start = h->now;
01587         else if (timeout >= 0) {
01588             millisec = (h->now.tv_sec  - start.tv_sec) *1000 +
01589             (h->now.tv_usec - start.tv_usec)/1000;
01590             if (millisec >= timeout) {
01591                 res = 0;
01592                 break;
01593             }
01594         }
01595         fds[0].fd = h->sock;
01596         fds[0].events = POLLIN;
01597         if (ccn_output_is_pending(h))
01598             fds[0].events |= POLLOUT;
01599         millisec = microsec / 1000;
01600         if (timeout >= 0 && timeout < millisec)
01601             millisec = timeout;
01602         res = poll(fds, 1, millisec);
01603         if (res < 0 && errno != EINTR) {
01604             res = NOTE_ERRNO(h);
01605             break;
01606         }
01607         if (res > 0) {
01608             if ((fds[0].revents | POLLOUT) != 0)
01609                 ccn_pushout(h);
01610             if ((fds[0].revents | POLLIN) != 0)
01611                 ccn_process_input(h);
01612         }
01613         if (h->err == ENOTCONN)
01614             ccn_disconnect(h);
01615         if (h->timeout == 0)
01616             break;
01617     }
01618     if (h->running != 0)
01619         abort();
01620     return((res < 0) ? res : 0);
01621 }
01622 
01623 /* This is the upcall for implementing ccn_get() */
01624 struct simple_get_data {
01625     struct ccn_closure closure;
01626     struct ccn_charbuf *resultbuf;
01627     struct ccn_parsed_ContentObject *pcobuf;
01628     struct ccn_indexbuf *compsbuf;
01629     int flags;
01630     int res;
01631 };
01632 
01633 static enum ccn_upcall_res
01634 handle_simple_incoming_content(
01635     struct ccn_closure *selfp,
01636     enum ccn_upcall_kind kind,
01637     struct ccn_upcall_info *info)
01638 {
01639     struct simple_get_data *md = selfp->data;
01640     struct ccn *h = info->h;
01641     
01642     if (kind == CCN_UPCALL_FINAL) {
01643         if (selfp != &md->closure)
01644             abort();
01645         free(md);
01646         return(CCN_UPCALL_RESULT_OK);
01647     }
01648     if (kind == CCN_UPCALL_INTEREST_TIMED_OUT)
01649         return(selfp->intdata ? CCN_UPCALL_RESULT_REEXPRESS : CCN_UPCALL_RESULT_OK);
01650     if (kind == CCN_UPCALL_CONTENT_UNVERIFIED) {
01651         if ((md->flags & CCN_GET_NOKEYWAIT) == 0)
01652             return(CCN_UPCALL_RESULT_VERIFY);
01653     }
01654     if (kind == CCN_UPCALL_CONTENT_KEYMISSING) {
01655         if ((md->flags & CCN_GET_NOKEYWAIT) == 0)
01656             return(CCN_UPCALL_RESULT_FETCHKEY);
01657     }
01658     else if (kind != CCN_UPCALL_CONTENT && kind != CCN_UPCALL_CONTENT_RAW)
01659         return(CCN_UPCALL_RESULT_ERR);
01660     if (md->resultbuf != NULL) {
01661         md->resultbuf->length = 0;
01662         ccn_charbuf_append(md->resultbuf,
01663                            info->content_ccnb, info->pco->offset[CCN_PCO_E]);
01664     }
01665     if (md->pcobuf != NULL)
01666         memcpy(md->pcobuf, info->pco, sizeof(*md->pcobuf));
01667     if (md->compsbuf != NULL) {
01668         md->compsbuf->n = 0;
01669         ccn_indexbuf_append(md->compsbuf,
01670                             info->content_comps->buf, info->content_comps->n);
01671     }
01672     md->res = 0;
01673     ccn_set_run_timeout(h, 0);
01674     return(CCN_UPCALL_RESULT_OK);
01675 }
01676 
01677 /**
01678  * Get a single matching ContentObject
01679  * This is a convenience for getting a single matching ContentObject.
01680  * Blocks until a matching ContentObject arrives or there is a timeout.
01681  * @param h is the ccn handle. If NULL or ccn_get is called from inside
01682  *        an upcall, a new connection will be used and upcalls from other
01683  *        requests will not be processed while ccn_get is active.
01684  * @param name holds a ccnb-encoded Name
01685  * @param interest_template conveys other fields to be used in the interest
01686  *        (may be NULL).
01687  * @param timeout_ms limits the time spent waiting for an answer (milliseconds).
01688  * @param resultbuf is updated to contain the ccnb-encoded ContentObject.
01689  * @param pcobuf may be supplied to save the client the work of re-parsing the
01690  *        ContentObject; may be NULL if this information is not actually needed.
01691  * @param compsbuf works similarly.
01692  * @param flags - CCN_GET_NOKEYWAIT means that it is permitted to return
01693  *        unverified data.
01694  * @returns 0 for success, -1 for an error.
01695  */
01696 int
01697 ccn_get(struct ccn *h,
01698         struct ccn_charbuf *name,
01699         struct ccn_charbuf *interest_template,
01700         int timeout_ms,
01701         struct ccn_charbuf *resultbuf,
01702         struct ccn_parsed_ContentObject *pcobuf,
01703         struct ccn_indexbuf *compsbuf,
01704         int flags)
01705 {
01706     struct ccn *orig_h = h;
01707     struct hashtb *saved_keys = NULL;
01708     int res;
01709     struct simple_get_data *md;
01710     
01711     if ((flags & ~((int)CCN_GET_NOKEYWAIT)) != 0)
01712         return(-1);
01713     if (h == NULL || h->running) {
01714         h = ccn_create();
01715         if (h == NULL)
01716             return(-1);
01717         if (orig_h != NULL) { /* Dad, can I borrow the keys? */
01718             saved_keys = h->keys;
01719             h->keys = orig_h->keys;
01720         }
01721         res = ccn_connect(h, NULL);
01722         if (res < 0) {
01723             ccn_destroy(&h);
01724             return(-1);
01725         }
01726     }
01727     md = calloc(1, sizeof(*md));
01728     md->resultbuf = resultbuf;
01729     md->pcobuf = pcobuf;
01730     md->compsbuf = compsbuf;
01731     md->flags = flags;
01732     md->res = -1;
01733     md->closure.p = &handle_simple_incoming_content;
01734     md->closure.data = md;
01735     md->closure.intdata = 1; /* tell upcall to re-express if needed */
01736     md->closure.refcount = 1;
01737     res = ccn_express_interest(h, name, &md->closure, interest_template);
01738     if (res >= 0)
01739         res = ccn_run(h, timeout_ms);
01740     if (res >= 0)
01741         res = md->res;
01742     md->resultbuf = NULL;
01743     md->pcobuf = NULL;
01744     md->compsbuf = NULL;
01745     md->closure.intdata = 0;
01746     md->closure.refcount--;
01747     if (md->closure.refcount == 0)
01748         free(md);
01749     if (h != orig_h) {
01750         if (saved_keys != NULL)
01751             h->keys = saved_keys;
01752         ccn_destroy(&h);
01753     }
01754     return(res);
01755 }
01756 
01757 static enum ccn_upcall_res
01758 handle_ccndid_response(struct ccn_closure *selfp,
01759                      enum ccn_upcall_kind kind,
01760                      struct ccn_upcall_info *info)
01761 {
01762     int res;
01763     const unsigned char *ccndid = NULL;
01764     size_t size = 0;
01765     struct ccn *h = info->h;
01766     
01767     if (kind == CCN_UPCALL_FINAL) {
01768         free(selfp);
01769         return(CCN_UPCALL_RESULT_OK);
01770     }
01771     if (kind == CCN_UPCALL_CONTENT_UNVERIFIED)
01772         return(CCN_UPCALL_RESULT_VERIFY);
01773     if (kind == CCN_UPCALL_CONTENT_KEYMISSING)
01774         return(CCN_UPCALL_RESULT_FETCHKEY);
01775     if (kind == CCN_UPCALL_CONTENT_RAW) {
01776         if (ccn_verify_content(h, info->content_ccnb, info->pco) == 0)
01777             kind = CCN_UPCALL_CONTENT;
01778     }
01779     if (kind != CCN_UPCALL_CONTENT) {
01780         NOTE_ERR(h, -1000 - kind);
01781         return(CCN_UPCALL_RESULT_ERR);
01782     }
01783     res = ccn_ref_tagged_BLOB(CCN_DTAG_PublisherPublicKeyDigest,
01784                               info->content_ccnb,
01785                               info->pco->offset[CCN_PCO_B_PublisherPublicKeyDigest],
01786                               info->pco->offset[CCN_PCO_E_PublisherPublicKeyDigest],
01787                               &ccndid,
01788                               &size);
01789     if (res < 0) {
01790         NOTE_ERR(h, -1);
01791         return(CCN_UPCALL_RESULT_ERR);
01792     }
01793     if (h->ccndid == NULL) {
01794         h->ccndid = ccn_charbuf_create();
01795         if (h->ccndid == NULL)
01796             return(NOTE_ERRNO(h));
01797     }
01798     h->ccndid->length = 0;
01799     ccn_charbuf_append(h->ccndid, ccndid, size);
01800     ccn_notify_ccndid_changed(h);
01801     return(CCN_UPCALL_RESULT_OK);
01802 }
01803 
01804 static void
01805 ccn_initiate_ccndid_fetch(struct ccn *h)
01806 {
01807     struct ccn_charbuf *name = NULL;
01808     struct ccn_closure *action = NULL;
01809     
01810     name = ccn_charbuf_create();
01811     ccn_name_from_uri(name, "ccnx:/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY");
01812     action = calloc(1, sizeof(*action));
01813     action->p = &handle_ccndid_response;
01814     ccn_express_interest(h, name, action, NULL);
01815     ccn_charbuf_destroy(&name);
01816 }
01817 
01818 static enum ccn_upcall_res
01819 handle_prefix_reg_reply(
01820     struct ccn_closure *selfp,
01821     enum ccn_upcall_kind kind,
01822     struct ccn_upcall_info *info)
01823 {
01824     struct ccn_reg_closure *md = selfp->data;
01825     struct ccn *h = info->h;
01826     int lifetime = 10;
01827     struct ccn_forwarding_entry *fe = NULL;
01828     int res;
01829     const unsigned char *fe_ccnb = NULL;
01830     size_t fe_ccnb_size = 0;
01831 
01832     if (kind == CCN_UPCALL_FINAL) {
01833         // fprintf(stderr, "GOT TO handle_prefix_reg_reply FINAL\n");
01834         if (selfp != &md->action)
01835             abort();
01836         if (md->interest_filter != NULL)
01837             md->interest_filter->ccn_reg_closure = NULL;
01838         selfp->data = NULL;
01839         free(md);
01840         return(CCN_UPCALL_RESULT_OK);
01841     }
01842     if (kind == CCN_UPCALL_INTEREST_TIMED_OUT)
01843         return(CCN_UPCALL_RESULT_REEXPRESS);
01844     if (kind == CCN_UPCALL_CONTENT_UNVERIFIED)
01845         return(CCN_UPCALL_RESULT_VERIFY);
01846     if (kind == CCN_UPCALL_CONTENT_KEYMISSING)
01847         return(CCN_UPCALL_RESULT_FETCHKEY);
01848     if (kind == CCN_UPCALL_CONTENT_RAW) {
01849         if (ccn_verify_content(h, info->content_ccnb, info->pco) == 0)
01850             kind = CCN_UPCALL_CONTENT;
01851     }
01852     if (kind != CCN_UPCALL_CONTENT) {
01853         NOTE_ERR(h, -1000 - kind);
01854         return(CCN_UPCALL_RESULT_ERR);
01855     }
01856     res = ccn_content_get_value(info->content_ccnb,
01857                                 info->pco->offset[CCN_PCO_E],
01858                                 info->pco,
01859                                 &fe_ccnb, &fe_ccnb_size);
01860     if (res == 0)
01861         fe = ccn_forwarding_entry_parse(fe_ccnb, fe_ccnb_size);
01862     if (fe == NULL) {
01863         XXX;
01864         lifetime = 30;
01865     }
01866     else
01867         lifetime = fe->lifetime;
01868     if (lifetime < 0)
01869         lifetime = 0;
01870     else if (lifetime > 3600)
01871         lifetime = 3600;
01872     if (md->interest_filter != NULL) {
01873         md->interest_filter->expiry = h->now;
01874         md->interest_filter->expiry.tv_sec += lifetime;
01875     }
01876     ccn_forwarding_entry_destroy(&fe);
01877     return(CCN_UPCALL_RESULT_OK);
01878 }
01879 
01880 static void
01881 ccn_initiate_prefix_reg(struct ccn *h,
01882                         const void *prefix, size_t prefix_size,
01883                         struct interest_filter *i)
01884 {
01885     struct ccn_reg_closure *p = NULL;
01886     struct ccn_charbuf *reqname = NULL;
01887     struct ccn_charbuf *templ = NULL;
01888     struct ccn_forwarding_entry fe_store = { 0 };
01889     struct ccn_forwarding_entry *fe = &fe_store;
01890     struct ccn_charbuf *reg_request = NULL;
01891     struct ccn_charbuf *signed_reg_request = NULL;
01892     struct ccn_charbuf *empty = NULL;
01893 
01894     i->expiry = h->now;
01895     i->expiry.tv_sec += 60;
01896     /* This test is mainly for the benefit of the ccnd internal client */
01897     if (h->sock == -1)
01898         return;
01899     // fprintf(stderr, "GOT TO STUB ccn_initiate_prefix_reg()\n");
01900     if (h->ccndid == NULL) {
01901         ccn_initiate_ccndid_fetch(h);
01902         i->flags |= CCN_FORW_WAITING_CCNDID;
01903         return;
01904     }
01905     if (i->ccn_reg_closure != NULL)
01906         return;
01907     p = calloc(1, sizeof(*p));
01908     if (p == NULL) {
01909         NOTE_ERRNO(h);
01910         return;
01911     }
01912     p->action.data = p;
01913     p->action.p = &handle_prefix_reg_reply;
01914     p->interest_filter = i;
01915     i->ccn_reg_closure = p;
01916     reqname = ccn_charbuf_create();
01917     ccn_name_from_uri(reqname, "ccnx:/ccnx");
01918     ccn_name_append(reqname, h->ccndid->buf, h->ccndid->length);
01919     ccn_name_append_str(reqname, "selfreg");
01920     fe->action = "selfreg";
01921     fe->ccnd_id = h->ccndid->buf;
01922     fe->ccnd_id_size = h->ccndid->length;
01923     fe->faceid = ~0; // XXX - someday explicit faceid may be required
01924     fe->name_prefix = ccn_charbuf_create();
01925     fe->flags = i->flags & 0xFF;
01926     fe->lifetime = -1; /* Let ccnd decide */
01927     ccn_name_init(fe->name_prefix);
01928     ccn_name_append_components(fe->name_prefix, prefix, 0, prefix_size);
01929     reg_request = ccn_charbuf_create();
01930     ccnb_append_forwarding_entry(reg_request, fe);
01931     empty = ccn_charbuf_create();
01932     ccn_name_init(empty);
01933     signed_reg_request = ccn_charbuf_create();
01934     ccn_sign_content(h, signed_reg_request, empty, NULL,
01935                      reg_request->buf, reg_request->length);
01936     ccn_name_append(reqname,
01937                     signed_reg_request->buf, signed_reg_request->length);
01938     // XXX - should set up templ for scope 1
01939     ccn_express_interest(h, reqname, &p->action, templ);
01940     ccn_charbuf_destroy(&fe->name_prefix);
01941     ccn_charbuf_destroy(&reqname);
01942     ccn_charbuf_destroy(&templ);
01943     ccn_charbuf_destroy(&reg_request);
01944     ccn_charbuf_destroy(&signed_reg_request);
01945     ccn_charbuf_destroy(&empty);
01946 }
01947 
01948 /**
01949  * Verify a ContentObject using the public key from either the object
01950  * itself or our cache of keys.
01951  *
01952  * This routine does not attempt to fetch the public key if it is not
01953  * at hand.
01954  * @returns negative for error, 0 verification success,
01955  *         or 1 if the key needs to be requested.
01956  */
01957 int
01958 ccn_verify_content(struct ccn *h,
01959                    const unsigned char *msg,
01960                    struct ccn_parsed_ContentObject *pco)
01961 {
01962     struct ccn_pkey *pubkey = NULL;
01963     int res;
01964     unsigned char *buf = (unsigned char *)msg; /* XXX - discard const */
01965     
01966     res = ccn_locate_key(h, msg, pco, &pubkey);
01967     if (res == 0) {
01968         /* we have the pubkey, use it to verify the msg */
01969         res = ccn_verify_signature(buf, pco->offset[CCN_PCO_E], pco, pubkey);
01970         res = (res == 1) ? 0 : -1;
01971     }
01972     return(res);
01973 }
01974 
01975 /**
01976  * Load a private key from a keystore file.
01977  *
01978  * This call is only required for applications that use something other
01979  * than the user's default signing key.
01980  * @param h is the ccn handle
01981  * @param keystore_path is the pathname of the keystore file
01982  * @param keystore_passphrase is the passphase needed to unlock the keystore
01983  * @param pubid_out, if not NULL, is loaded with the digest of the public key
01984  * @result is 0 for success, negative for error.
01985  */
01986 int
01987 ccn_load_private_key(struct ccn *h,
01988                      const char *keystore_path,
01989                      const char *keystore_passphrase,
01990                      struct ccn_charbuf *pubid_out)
01991 {
01992     struct ccn_keystore *keystore = NULL;
01993     int res = 0;
01994     struct ccn_charbuf *pubid = pubid_out;
01995     struct ccn_charbuf *pubid_store = NULL;
01996     struct hashtb_enumerator ee;
01997     struct hashtb_enumerator *e = &ee;
01998     
01999     if (pubid == NULL)
02000         pubid = pubid_store = ccn_charbuf_create();
02001     if (pubid == NULL) {
02002         res = NOTE_ERRNO(h);
02003         goto Cleanup;
02004     }
02005     keystore = ccn_keystore_create();
02006     if (keystore == NULL) {
02007         res = NOTE_ERRNO(h);
02008         goto Cleanup;
02009     }
02010     res = ccn_keystore_init(keystore,
02011                            (char *)keystore_path,
02012                            (char *)keystore_passphrase);
02013     if (res != 0) {
02014         res = NOTE_ERRNO(h);
02015         goto Cleanup;
02016     }
02017     pubid->length = 0;
02018     ccn_charbuf_append(pubid,
02019                        ccn_keystore_public_key_digest(keystore),
02020                        ccn_keystore_public_key_digest_length(keystore));
02021     hashtb_start(h->keystores, e);
02022     res = hashtb_seek(e, pubid->buf, pubid->length, 0);
02023     if (res == HT_NEW_ENTRY) {
02024         struct ccn_keystore **p = e->data;
02025         *p = keystore;
02026         keystore = NULL;
02027         res = 0;
02028     }
02029     else if (res == HT_OLD_ENTRY)
02030         res = 0;
02031     else
02032         res = NOTE_ERRNO(h);
02033     hashtb_end(e);
02034 Cleanup:
02035     ccn_charbuf_destroy(&pubid_store);
02036     ccn_keystore_destroy(&keystore);
02037     return(res);
02038 }
02039 
02040 /**
02041  * Load the handle's default signing key from a keystore.
02042  *
02043  * This call is only required for applications that use something other
02044  * than the user's default signing key as the handle's default.  It should
02045  * be called early and at most once.
02046  * @param h is the ccn handle
02047  * @param keystore_path is the pathname of the keystore file
02048  * @param keystore_passphrase is the passphase needed to unlock the keystore
02049  * @result is 0 for success, negative for error.
02050  */
02051 int
02052 ccn_load_default_key(struct ccn *h,
02053                      const char *keystore_path,
02054                      const char *keystore_passphrase)
02055 {
02056     struct ccn_charbuf *default_pubid = NULL;
02057     int res;
02058     
02059     if (h->default_pubid != NULL)
02060         return(NOTE_ERR(h, EINVAL));
02061     default_pubid = ccn_charbuf_create();
02062     res = ccn_load_private_key(h,
02063                                keystore_path,
02064                                keystore_passphrase,
02065                                default_pubid);
02066     if (res == 0)
02067         h->default_pubid = default_pubid;
02068     else
02069         ccn_charbuf_destroy(&default_pubid);
02070     return(res);
02071 }
02072 
02073 static void
02074 finalize_keystore(struct hashtb_enumerator *e)
02075 {
02076     struct ccn_keystore **p = e->data;
02077     ccn_keystore_destroy(p);
02078 }
02079 
02080 /**
02081  * Place the public key associated with the params into result
02082  * buffer, and its digest into digest_result.
02083  *
02084  * This is for one of our signing keys, not just any key.
02085  * Result buffers may be NULL if the corresponding result is not wanted.
02086  *
02087  * @returns 0 for success, negative for error
02088  */
02089 int
02090 ccn_get_public_key(struct ccn *h,
02091                    const struct ccn_signing_params *params,
02092                    struct ccn_charbuf *digest_result,
02093                    struct ccn_charbuf *result)
02094 {
02095     struct hashtb_enumerator ee;
02096     struct hashtb_enumerator *e = &ee;
02097     struct ccn_keystore *keystore = NULL;
02098     struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
02099     int res;
02100     res = ccn_chk_signing_params(h, params, &sp, NULL, NULL, NULL);
02101     if (res < 0)
02102         return(res);
02103     hashtb_start(h->keystores, e);
02104     if (hashtb_seek(e, sp.pubid, sizeof(sp.pubid), 0) == HT_OLD_ENTRY) {
02105         struct ccn_keystore **pk = e->data;
02106         keystore = *pk;
02107         if (digest_result != NULL) {
02108             digest_result->length = 0;
02109             ccn_charbuf_append(digest_result,
02110                                ccn_keystore_public_key_digest(keystore),
02111                                ccn_keystore_public_key_digest_length(keystore));
02112         }
02113         if (result != NULL) {
02114             struct ccn_buf_decoder decoder;
02115             struct ccn_buf_decoder *d;
02116             const unsigned char *p;
02117             size_t size;
02118             result->length = 0;
02119             ccn_append_pubkey_blob(result, ccn_keystore_public_key(keystore));
02120             d = ccn_buf_decoder_start(&decoder, result->buf, result->length);
02121             res = ccn_buf_match_blob(d, &p, &size);
02122             if (res >= 0) {
02123                 memmove(result->buf, p, size);
02124                 result->length = size;
02125                 res = 0;
02126             }
02127         }
02128     }
02129     else {
02130         res = NOTE_ERR(h, -1);
02131         hashtb_delete(e);
02132     }
02133     hashtb_end(e);
02134     return(res);
02135 }
02136 
02137 /**
02138  * This is mostly for use within the library,
02139  * but may be useful for some clients.
02140  */
02141 int
02142 ccn_chk_signing_params(struct ccn *h,
02143                        const struct ccn_signing_params *params,
02144                        struct ccn_signing_params *result,
02145                        struct ccn_charbuf **ptimestamp,
02146                        struct ccn_charbuf **pfinalblockid,
02147                        struct ccn_charbuf **pkeylocator)
02148 {
02149     struct ccn_charbuf *default_pubid = NULL;
02150     struct ccn_charbuf *temp = NULL;
02151     const char *home = NULL;
02152     const char *ccnx_dir = NULL;
02153     int res = 0;
02154     int i;
02155     int conflicting;
02156     int needed;
02157     
02158     if (params != NULL)
02159         *result = *params;
02160     if ((result->sp_flags & ~(CCN_SP_TEMPL_TIMESTAMP      |
02161                               CCN_SP_TEMPL_FINAL_BLOCK_ID |
02162                               CCN_SP_TEMPL_FRESHNESS      |
02163                               CCN_SP_TEMPL_KEY_LOCATOR    |
02164                               CCN_SP_FINAL_BLOCK          |
02165                               CCN_SP_OMIT_KEY_LOCATOR
02166                               )) != 0)
02167         return(NOTE_ERR(h, EINVAL));
02168     conflicting = CCN_SP_TEMPL_FINAL_BLOCK_ID | CCN_SP_FINAL_BLOCK;
02169     if ((result->sp_flags & conflicting) == conflicting)
02170         return(NOTE_ERR(h, EINVAL));
02171     conflicting = CCN_SP_TEMPL_KEY_LOCATOR | CCN_SP_OMIT_KEY_LOCATOR;
02172         if ((result->sp_flags & conflicting) == conflicting)
02173         return(NOTE_ERR(h, EINVAL));
02174     for (i = 0; i < sizeof(result->pubid) && result->pubid[i] == 0; i++)
02175         continue;
02176     if (i == sizeof(result->pubid)) {
02177         if (h->default_pubid == NULL) {
02178             default_pubid = ccn_charbuf_create();
02179             temp = ccn_charbuf_create();
02180             if (default_pubid == NULL || temp == NULL)
02181                 return(NOTE_ERRNO(h));
02182             ccnx_dir = getenv("CCNX_DIR");
02183             if (ccnx_dir == NULL || ccnx_dir[0] == 0) {
02184                 home = getenv("HOME");
02185                 if (home == NULL)
02186                     home = "";
02187                 ccn_charbuf_putf(temp, "%s/.ccnx/.ccnx_keystore", home);
02188             }
02189             else
02190                 ccn_charbuf_putf(temp, "%s/.ccnx_keystore", ccnx_dir);
02191             res = ccn_load_private_key(h,
02192                                        ccn_charbuf_as_string(temp),
02193                                        "Th1s1sn0t8g00dp8ssw0rd.",
02194                                        default_pubid);
02195             if (res == 0 && default_pubid->length == sizeof(result->pubid)) {
02196                 h->default_pubid = default_pubid;
02197                 default_pubid = NULL;
02198             }
02199         }
02200         if (h->default_pubid == NULL)
02201             res = NOTE_ERRNO(h);
02202         else
02203             memcpy(result->pubid, h->default_pubid->buf, sizeof(result->pubid));
02204     }
02205     ccn_charbuf_destroy(&default_pubid);
02206     ccn_charbuf_destroy(&temp);
02207     needed = result->sp_flags & (CCN_SP_TEMPL_TIMESTAMP      |
02208                                  CCN_SP_TEMPL_FINAL_BLOCK_ID |
02209                                  CCN_SP_TEMPL_FRESHNESS      |
02210                                  CCN_SP_TEMPL_KEY_LOCATOR    );
02211     if (result->template_ccnb != NULL) {
02212         struct ccn_buf_decoder decoder;
02213         struct ccn_buf_decoder *d;
02214         size_t start;
02215         size_t stop;
02216         size_t size;
02217         const unsigned char *ptr = NULL;
02218         d = ccn_buf_decoder_start(&decoder,
02219                                   result->template_ccnb->buf,
02220                                   result->template_ccnb->length);
02221         if (ccn_buf_match_dtag(d, CCN_DTAG_SignedInfo)) {
02222             ccn_buf_advance(d);
02223             if (ccn_buf_match_dtag(d, CCN_DTAG_PublisherPublicKeyDigest))
02224                 ccn_parse_required_tagged_BLOB(d,
02225                     CCN_DTAG_PublisherPublicKeyDigest, 16, 64);
02226             start = d->decoder.token_index;
02227             ccn_parse_optional_tagged_BLOB(d, CCN_DTAG_Timestamp, 1, -1);
02228             stop = d->decoder.token_index;
02229             if ((needed & CCN_SP_TEMPL_TIMESTAMP) != 0) {
02230                 i = ccn_ref_tagged_BLOB(CCN_DTAG_Timestamp,
02231                                         d->buf,
02232                                         start, stop,
02233                                         &ptr, &size);
02234                 if (i == 0) {
02235                     if (ptimestamp != NULL) {
02236                         *ptimestamp = ccn_charbuf_create();
02237                         ccn_charbuf_append(*ptimestamp, ptr, size);
02238                     }
02239                     needed &= ~CCN_SP_TEMPL_TIMESTAMP;
02240                 }
02241             }
02242             ccn_parse_optional_tagged_BLOB(d, CCN_DTAG_Type, 1, -1);
02243             i = ccn_parse_optional_tagged_nonNegativeInteger(d,
02244                     CCN_DTAG_FreshnessSeconds);
02245             if ((needed & CCN_SP_TEMPL_FRESHNESS) != 0 && i >= 0) {
02246                 result->freshness = i;
02247                 needed &= ~CCN_SP_TEMPL_FRESHNESS;
02248             }
02249             if (ccn_buf_match_dtag(d, CCN_DTAG_FinalBlockID)) {
02250                 ccn_buf_advance(d);
02251                 start = d->decoder.token_index;
02252                 if (ccn_buf_match_some_blob(d))
02253                     ccn_buf_advance(d);
02254                 stop = d->decoder.token_index;
02255                 ccn_buf_check_close(d);
02256                 if ((needed & CCN_SP_TEMPL_FINAL_BLOCK_ID) != 0 && 
02257                     d->decoder.state >= 0 && stop > start) {
02258                     if (pfinalblockid != NULL) {
02259                         *pfinalblockid = ccn_charbuf_create();
02260                         ccn_charbuf_append(*pfinalblockid,
02261                                            d->buf + start, stop - start);
02262                     }
02263                     needed &= ~CCN_SP_TEMPL_FINAL_BLOCK_ID;
02264                 }
02265             }
02266             start = d->decoder.token_index;
02267             if (ccn_buf_match_dtag(d, CCN_DTAG_KeyLocator))
02268                 ccn_buf_advance_past_element(d);
02269             stop = d->decoder.token_index;
02270             if ((needed & CCN_SP_TEMPL_KEY_LOCATOR) != 0 && 
02271                 d->decoder.state >= 0 && stop > start) {
02272                 if (pkeylocator != NULL) {
02273                     *pkeylocator = ccn_charbuf_create();
02274                     ccn_charbuf_append(*pkeylocator,
02275                                        d->buf + start, stop - start);
02276                 }
02277                 needed &= ~CCN_SP_TEMPL_KEY_LOCATOR;
02278             }
02279             ccn_buf_check_close(d);
02280         }
02281         if (d->decoder.state < 0)
02282             res = NOTE_ERR(h, EINVAL);
02283     }
02284     if (needed != 0)
02285         res = NOTE_ERR(h, EINVAL);
02286     return(res);
02287 }
02288 
02289 /**
02290  * Create a signed ContentObject.
02291  *
02292  * @param h is the ccn handle
02293  * @param resultbuf - result buffer to which the ContentObject will be appended
02294  * @param name_prefix contains the ccnb-encoded name
02295  * @param params describe the ancillary information needed
02296  * @param data points to the raw content
02297  * @param size is the size of the raw content, in bytes
02298  * @returns 0 for success, -1 for error
02299  */
02300 int
02301 ccn_sign_content(struct ccn *h,
02302                  struct ccn_charbuf *resultbuf,
02303                  const struct ccn_charbuf *name_prefix,
02304                  const struct ccn_signing_params *params,
02305                  const void *data, size_t size)
02306 {
02307     struct hashtb_enumerator ee;
02308     struct hashtb_enumerator *e = &ee;
02309     struct ccn_signing_params p = CCN_SIGNING_PARAMS_INIT;
02310     struct ccn_charbuf *signed_info = NULL;
02311     struct ccn_keystore *keystore = NULL;
02312     struct ccn_charbuf *timestamp = NULL;
02313     struct ccn_charbuf *finalblockid = NULL;
02314     struct ccn_charbuf *keylocator = NULL;
02315     int res;
02316     
02317     res = ccn_chk_signing_params(h, params, &p,
02318                                  &timestamp, &finalblockid, &keylocator);
02319     if (res < 0)
02320         return(res);
02321     hashtb_start(h->keystores, e);
02322     if (hashtb_seek(e, p.pubid, sizeof(p.pubid), 0) == HT_OLD_ENTRY) {
02323         struct ccn_keystore **pk = e->data;
02324         keystore = *pk;
02325         signed_info = ccn_charbuf_create();
02326         if (keylocator == NULL && (p.sp_flags & CCN_SP_OMIT_KEY_LOCATOR) == 0) {
02327             /* Construct a key locator containing the key itself */
02328             keylocator = ccn_charbuf_create();
02329             ccn_charbuf_append_tt(keylocator, CCN_DTAG_KeyLocator, CCN_DTAG);
02330             ccn_charbuf_append_tt(keylocator, CCN_DTAG_Key, CCN_DTAG);
02331             res = ccn_append_pubkey_blob(keylocator,
02332                                          ccn_keystore_public_key(keystore));
02333             ccn_charbuf_append_closer(keylocator); /* </Key> */
02334             ccn_charbuf_append_closer(keylocator); /* </KeyLocator> */
02335         }
02336         if (res >= 0 && (p.sp_flags & CCN_SP_FINAL_BLOCK) != 0) {
02337             int ncomp;
02338             struct ccn_indexbuf *ndx;
02339             const unsigned char *comp = NULL;
02340             size_t size = 0;
02341             
02342             ndx = ccn_indexbuf_create();
02343             ncomp = ccn_name_split(name_prefix, ndx);
02344             if (ncomp < 0)
02345                 res = NOTE_ERR(h, EINVAL);
02346             else {
02347                 finalblockid = ccn_charbuf_create();
02348                 ccn_name_comp_get(name_prefix->buf,
02349                                   ndx, ncomp - 1, &comp, &size);
02350                 ccn_charbuf_append_tt(finalblockid, size, CCN_BLOB);
02351                 ccn_charbuf_append(finalblockid, comp, size);
02352             }
02353             ccn_indexbuf_destroy(&ndx);
02354         }
02355         if (res >= 0)
02356             res = ccn_signed_info_create(signed_info,
02357                                          ccn_keystore_public_key_digest(keystore),
02358                                          ccn_keystore_public_key_digest_length(keystore),
02359                                          timestamp,
02360                                          p.type,
02361                                          p.freshness,
02362                                          finalblockid,
02363                                          keylocator);
02364         if (res >= 0)
02365             res = ccn_encode_ContentObject(resultbuf,
02366                                            name_prefix,
02367                                            signed_info,
02368                                            data,
02369                                            size,
02370                                            NULL, // XXX
02371                                            ccn_keystore_private_key(keystore));
02372     }
02373     else {
02374         res = NOTE_ERR(h, -1);
02375         hashtb_delete(e);
02376     }
02377     hashtb_end(e);
02378     ccn_charbuf_destroy(&timestamp);
02379     ccn_charbuf_destroy(&keylocator);
02380     ccn_charbuf_destroy(&finalblockid);
02381     ccn_charbuf_destroy(&signed_info);
02382     return(res);
02383 }
02384 /**
02385  * Check whether content described by info is final block.
02386  *
02387  * @param info - the ccn_upcall_info describing the ContentObject
02388  * @returns 1 for final block, 0 for not final, -1 if an error occurs
02389  */
02390 int
02391 ccn_is_final_block(struct ccn_upcall_info *info)
02392 {
02393     const unsigned char *ccnb;
02394     size_t ccnb_size;
02395     int res;
02396     ccnb = info->content_ccnb;
02397     if (ccnb == NULL || info->pco == NULL)
02398         return(0);
02399     ccnb_size = info->pco->offset[CCN_PCO_E];
02400     if (info->pco->offset[CCN_PCO_B_FinalBlockID] !=
02401         info->pco->offset[CCN_PCO_E_FinalBlockID]) {
02402         const unsigned char *finalid = NULL;
02403         size_t finalid_size = 0;
02404         const unsigned char *nameid = NULL;
02405         size_t nameid_size = 0;
02406         struct ccn_indexbuf *cc = info->content_comps;
02407         if (cc->n < 2) return(-1);
02408         res = ccn_ref_tagged_BLOB(CCN_DTAG_FinalBlockID, ccnb,
02409                             info->pco->offset[CCN_PCO_B_FinalBlockID],
02410                             info->pco->offset[CCN_PCO_E_FinalBlockID],
02411                             &finalid,
02412                             &finalid_size);
02413         if (res < 0) return(-1);
02414         res = ccn_ref_tagged_BLOB(CCN_DTAG_Component, ccnb,
02415                             cc->buf[cc->n - 2],
02416                             cc->buf[cc->n - 1],
02417                             &nameid,
02418                             &nameid_size);
02419         if (res < 0) return(-1);
02420         if (finalid_size == nameid_size &&
02421             0 == memcmp(finalid, nameid, nameid_size))
02422             return(1);
02423     }
02424     return(0);
02425 }

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