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