00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00052 struct interests_by_prefix;
00053 struct expressed_interest;
00054 struct interest_filter;
00055 struct ccn_reg_closure;
00056
00057
00058
00059
00060 struct ccn {
00061 int sock;
00062 size_t outbufindex;
00063 struct ccn_charbuf *connect_type;
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;
00073 struct hashtb *keystores;
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;
00080 int errline;
00081 int verbose_error;
00082 int tap;
00083 int running;
00084 int defer_verification;
00085 };
00086
00087 struct interests_by_prefix {
00088 struct expressed_interest *list;
00089 };
00090
00091 struct expressed_interest {
00092 int magic;
00093 struct timeval lasttime;
00094 struct ccn_closure *action;
00095 unsigned char *interest_msg;
00096 size_t size;
00097 int target;
00098 int outstanding;
00099 int lifetime_us;
00100 struct ccn_charbuf *wanted_pub;
00101 struct expressed_interest *next;
00102 };
00103
00104
00105
00106
00107 struct interest_filter {
00108 struct ccn_closure *action;
00109 struct ccn_reg_closure *ccn_reg_closure;
00110 struct timeval expiry;
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;
00118 };
00119
00120
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
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
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
00160
00161
00162
00163
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
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
00190
00191
00192
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
00208
00209
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
00242
00243
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
00265
00266
00267
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 *), ¶m);
00284 param.finalize = &finalize_keystore;
00285 h->keystores = hashtb_create(sizeof(struct ccn_keystore *), ¶m);
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
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
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
00347
00348
00349
00350
00351
00352
00353
00354
00355
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);
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 = ⅇ
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
00587
00588
00589
00590
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
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 = ⅇ
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
00692
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
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
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
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 = ⅇ
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), ¶m);
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
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
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
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
00838
00839
00840
00841
00842 struct multifilt_item {
00843 struct ccn_closure *action;
00844 int forw_flags;
00845 };
00846
00847
00848
00849
00850
00851
00852
00853 struct multifilt {
00854 struct ccn_closure me;
00855 int n;
00856 struct multifilt_item *a;
00857 };
00858
00859
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
00874
00875
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
00891 abort();
00892 }
00893 if (f->action->p == &handle_multifilt) {
00894
00895 md = f->action->data;
00896 if (md->me.data != md)
00897 abort();
00898 a = md->a;
00899 }
00900 else {
00901
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;
00918 ccn_replace_handler(h, &f->action, &md->me);
00919 }
00920
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
00932 if (forw_flags == 0) {
00933 action->refcount++;
00934 ccn_replace_handler(h, &action, NULL);
00935 goto Finish;
00936 }
00937
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
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
00954
00955
00956
00957
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;
00967 struct multifilt_item *c = NULL;
00968 int i, j, m;
00969
00970 a = *ap;
00971
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
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
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
01040
01041
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
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
01108 ccn_charbuf_append(h->outbuf, p, length);
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;
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
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 = ⅇ
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
01275
01276
01277
01278
01279
01280
01281
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
01312 if (pco->offset[CCN_PCO_B_KeyLocator] == pco->offset[CCN_PCO_E_KeyLocator])
01313 return (-1);
01314
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 = ⅇ
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;
01364 }
01365
01366 return (-1);
01367 }
01368
01369
01370
01371
01372
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
01399
01400
01401
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
01425 return(CCN_UPCALL_RESULT_OK);
01426 case CCN_UPCALL_CONTENT_UNVERIFIED:
01427
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
01436
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);
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);
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
01473
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
01487
01488
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
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
01517
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;
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);
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);
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
01552
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
01569
01570
01571
01572
01573
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 = π
01587 info.interest_comps = ccn_indexbuf_obtain(h);
01588 res = ccn_parse_interest(msg, size, &pi, info.interest_comps);
01589 if (res >= 0) {
01590
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
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
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)) {
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
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 }
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
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 = π
01777 firstcall = (interest->lasttime.tv_sec == 0);
01778 if (interest->lasttime.tv_sec + 30 < h->now.tv_sec) {
01779
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 = ⅇ
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 = ⅇ
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
01868
01869
01870
01871 struct ccn_schedule *
01872 ccn_get_schedule(struct ccn *h)
01873 {
01874 return(h->schedule);
01875 }
01876
01877
01878
01879
01880
01881
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
01893
01894
01895
01896
01897
01898 int
01899 ccn_process_scheduled_operations(struct ccn *h)
01900 {
01901 struct hashtb_enumerator ee;
01902 struct hashtb_enumerator *e = ⅇ
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
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
01952
01953
01954
01955
01956
01957
01958
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
01970
01971
01972
01973
01974
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
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
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
02101
02102
02103
02104
02105
02106
02107
02108
02109
02110
02111
02112
02113
02114
02115
02116
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) {
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;
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
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
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
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
02325 if (h->sock == -1)
02326 return;
02327
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;
02352 fe->name_prefix = ccn_charbuf_create();
02353 fe->flags = i->flags & 0xFF;
02354 fe->lifetime = -1;
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
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(®_request);
02372 ccn_charbuf_destroy(&signed_reg_request);
02373 ccn_charbuf_destroy(&empty);
02374 }
02375
02376
02377
02378
02379
02380
02381
02382
02383
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;
02393
02394 res = ccn_locate_key(h, msg, pco, &pubkey);
02395 if (res == 0) {
02396
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
02405
02406
02407
02408
02409
02410
02411
02412
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 = ⅇ
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
02470
02471
02472
02473
02474
02475
02476
02477
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
02510
02511
02512
02513
02514
02515
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 = ⅇ
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
02567
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
02719
02720
02721
02722
02723
02724
02725
02726
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 = ⅇ
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 ×tamp, &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
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);
02762 ccn_charbuf_append_closer(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(×tamp);
02807 ccn_charbuf_destroy(&keylocator);
02808 ccn_charbuf_destroy(&finalblockid);
02809 ccn_charbuf_destroy(&signed_info);
02810 return(res);
02811 }
02812
02813
02814
02815
02816
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 }