ccn_client.c

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