00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <errno.h>
00025 #include <fcntl.h>
00026 #include <limits.h>
00027 #include <netdb.h>
00028 #include <poll.h>
00029 #include <signal.h>
00030 #include <stddef.h>
00031 #include <stdint.h>
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <time.h>
00036 #include <unistd.h>
00037 #include <arpa/inet.h>
00038 #include <sys/time.h>
00039 #include <sys/socket.h>
00040 #include <sys/stat.h>
00041 #include <sys/types.h>
00042 #include <sys/un.h>
00043 #include <netinet/in.h>
00044
00045 #if defined(NEED_GETADDRINFO_COMPAT)
00046 #include "getaddrinfo.h"
00047 #include "dummyin6.h"
00048 #endif
00049
00050 #include <ccn/bloom.h>
00051 #include <ccn/ccn.h>
00052 #include <ccn/ccn_private.h>
00053 #include <ccn/ccnd.h>
00054 #include <ccn/charbuf.h>
00055 #include <ccn/face_mgmt.h>
00056 #include <ccn/hashtb.h>
00057 #include <ccn/indexbuf.h>
00058 #include <ccn/schedule.h>
00059 #include <ccn/reg_mgmt.h>
00060 #include <ccn/uri.h>
00061
00062 #include "ccnd_private.h"
00063
00064
00065 enum ccn_strategy_op {
00066 CCNST_NOP,
00067 CCNST_FIRST,
00068 CCNST_TIMER,
00069 CCNST_SATISFIED,
00070 CCNST_TIMEOUT,
00071 };
00072
00073 static void cleanup_at_exit(void);
00074 static void unlink_at_exit(const char *path);
00075 static int create_local_listener(struct ccnd_handle *h, const char *sockname, int backlog);
00076 static struct face *record_connection(struct ccnd_handle *h,
00077 int fd,
00078 struct sockaddr *who,
00079 socklen_t wholen,
00080 int setflags);
00081 static void process_input_message(struct ccnd_handle *h, struct face *face,
00082 unsigned char *msg, size_t size, int pdu_ok);
00083 static void process_input(struct ccnd_handle *h, int fd);
00084 static int ccn_stuff_interest(struct ccnd_handle *h,
00085 struct face *face, struct ccn_charbuf *c);
00086 static void do_deferred_write(struct ccnd_handle *h, int fd);
00087 static void clean_needed(struct ccnd_handle *h);
00088 static struct face *get_dgram_source(struct ccnd_handle *h, struct face *face,
00089 struct sockaddr *addr, socklen_t addrlen,
00090 int why);
00091 static void content_skiplist_insert(struct ccnd_handle *h,
00092 struct content_entry *content);
00093 static void content_skiplist_remove(struct ccnd_handle *h,
00094 struct content_entry *content);
00095 static void mark_stale(struct ccnd_handle *h,
00096 struct content_entry *content);
00097 static ccn_accession_t content_skiplist_next(struct ccnd_handle *h,
00098 struct content_entry *content);
00099 static void reap_needed(struct ccnd_handle *h, int init_delay_usec);
00100 static void check_comm_file(struct ccnd_handle *h);
00101 static int nameprefix_seek(struct ccnd_handle *h,
00102 struct hashtb_enumerator *e,
00103 const unsigned char *msg,
00104 struct ccn_indexbuf *comps,
00105 int ncomps);
00106 static void register_new_face(struct ccnd_handle *h, struct face *face);
00107 static void update_forward_to(struct ccnd_handle *h,
00108 struct nameprefix_entry *npe);
00109 static void stuff_and_send(struct ccnd_handle *h, struct face *face,
00110 const unsigned char *data1, size_t size1,
00111 const unsigned char *data2, size_t size2,
00112 const char *tag, int lineno);
00113 static void ccn_link_state_init(struct ccnd_handle *h, struct face *face);
00114 static void ccn_append_link_stuff(struct ccnd_handle *h,
00115 struct face *face,
00116 struct ccn_charbuf *c);
00117 static int process_incoming_link_message(struct ccnd_handle *h,
00118 struct face *face, enum ccn_dtag dtag,
00119 unsigned char *msg, size_t size);
00120 static void
00121 pfi_destroy(struct ccnd_handle *h, struct interest_entry *ie,
00122 struct pit_face_item *p);
00123 static struct pit_face_item *
00124 pfi_set_nonce(struct ccnd_handle *h, struct interest_entry *ie,
00125 struct pit_face_item *p,
00126 const unsigned char *nonce, size_t noncesize);
00127 static int
00128 pfi_nonce_matches(struct pit_face_item *p,
00129 const unsigned char *nonce, size_t size);
00130 static struct pit_face_item *
00131 pfi_copy_nonce(struct ccnd_handle *h, struct interest_entry *ie,
00132 struct pit_face_item *p, const struct pit_face_item *src);
00133 static int
00134 pfi_unique_nonce(struct ccnd_handle *h, struct interest_entry *ie,
00135 struct pit_face_item *p);
00136 static int wt_compare(ccn_wrappedtime, ccn_wrappedtime);
00137 static void
00138 update_npe_children(struct ccnd_handle *h, struct nameprefix_entry *npe, unsigned faceid);
00139 static void
00140 pfi_set_expiry_from_lifetime(struct ccnd_handle *h, struct interest_entry *ie,
00141 struct pit_face_item *p, intmax_t lifetime);
00142 static void
00143 pfi_set_expiry_from_micros(struct ccnd_handle *h, struct interest_entry *ie,
00144 struct pit_face_item *p, unsigned micros);
00145 static struct pit_face_item *
00146 pfi_seek(struct ccnd_handle *h, struct interest_entry *ie,
00147 unsigned faceid, unsigned pfi_flag);
00148 static void strategy_callout(struct ccnd_handle *h,
00149 struct interest_entry *ie,
00150 enum ccn_strategy_op op);
00151
00152
00153
00154
00155
00156
00157
00158
00159 #define WTHZ 500U
00160
00161
00162
00163
00164
00165
00166
00167 static const char *unlink_this_at_exit = NULL;
00168
00169 static void
00170 cleanup_at_exit(void)
00171 {
00172 if (unlink_this_at_exit != NULL) {
00173 unlink(unlink_this_at_exit);
00174 unlink_this_at_exit = NULL;
00175 }
00176 }
00177
00178 static void
00179 handle_fatal_signal(int sig)
00180 {
00181 cleanup_at_exit();
00182 _exit(sig);
00183 }
00184
00185
00186
00187
00188
00189
00190 static void
00191 unlink_at_exit(const char *path)
00192 {
00193 if (unlink_this_at_exit == NULL) {
00194 static char namstor[sizeof(struct sockaddr_un)];
00195 strncpy(namstor, path, sizeof(namstor));
00196 unlink_this_at_exit = namstor;
00197 signal(SIGTERM, &handle_fatal_signal);
00198 signal(SIGINT, &handle_fatal_signal);
00199 signal(SIGHUP, &handle_fatal_signal);
00200 atexit(&cleanup_at_exit);
00201 }
00202 }
00203
00204
00205
00206
00207
00208
00209 static int
00210 comm_file_ok(void)
00211 {
00212 struct stat statbuf;
00213 int res;
00214 if (unlink_this_at_exit == NULL)
00215 return(1);
00216 res = stat(unlink_this_at_exit, &statbuf);
00217 if (res == -1)
00218 return(0);
00219 return(1);
00220 }
00221
00222
00223
00224
00225 static struct ccn_charbuf *
00226 charbuf_obtain(struct ccnd_handle *h)
00227 {
00228 struct ccn_charbuf *c = h->scratch_charbuf;
00229 if (c == NULL)
00230 return(ccn_charbuf_create());
00231 h->scratch_charbuf = NULL;
00232 c->length = 0;
00233 return(c);
00234 }
00235
00236
00237
00238
00239 static void
00240 charbuf_release(struct ccnd_handle *h, struct ccn_charbuf *c)
00241 {
00242 c->length = 0;
00243 if (h->scratch_charbuf == NULL)
00244 h->scratch_charbuf = c;
00245 else
00246 ccn_charbuf_destroy(&c);
00247 }
00248
00249
00250
00251
00252 static struct ccn_indexbuf *
00253 indexbuf_obtain(struct ccnd_handle *h)
00254 {
00255 struct ccn_indexbuf *c = h->scratch_indexbuf;
00256 if (c == NULL)
00257 return(ccn_indexbuf_create());
00258 h->scratch_indexbuf = NULL;
00259 c->n = 0;
00260 return(c);
00261 }
00262
00263
00264
00265
00266 static void
00267 indexbuf_release(struct ccnd_handle *h, struct ccn_indexbuf *c)
00268 {
00269 c->n = 0;
00270 if (h->scratch_indexbuf == NULL)
00271 h->scratch_indexbuf = c;
00272 else
00273 ccn_indexbuf_destroy(&c);
00274 }
00275
00276
00277
00278
00279 static struct face *
00280 face_from_faceid(struct ccnd_handle *h, unsigned faceid)
00281 {
00282 unsigned slot = faceid & MAXFACES;
00283 struct face *face = NULL;
00284 if (slot < h->face_limit) {
00285 face = h->faces_by_faceid[slot];
00286 if (face != NULL && face->faceid != faceid)
00287 face = NULL;
00288 }
00289 return(face);
00290 }
00291
00292
00293
00294
00295 struct face *
00296 ccnd_face_from_faceid(struct ccnd_handle *h, unsigned faceid)
00297 {
00298 return(face_from_faceid(h, faceid));
00299 }
00300
00301
00302
00303
00304
00305 static int
00306 enroll_face(struct ccnd_handle *h, struct face *face)
00307 {
00308 unsigned i;
00309 unsigned n = h->face_limit;
00310 struct face **a = h->faces_by_faceid;
00311 for (i = h->face_rover; i < n; i++)
00312 if (a[i] == NULL) goto use_i;
00313 for (i = 0; i < n; i++)
00314 if (a[i] == NULL) {
00315
00316 h->face_gen += MAXFACES + 1;
00317 goto use_i;
00318 }
00319 i = (n + 1) * 3 / 2;
00320 if (i > MAXFACES) i = MAXFACES;
00321 if (i <= n)
00322 return(-1);
00323 a = realloc(a, i * sizeof(struct face *));
00324 if (a == NULL)
00325 return(-1);
00326 h->face_limit = i;
00327 while (--i > n)
00328 a[i] = NULL;
00329 h->faces_by_faceid = a;
00330 use_i:
00331 a[i] = face;
00332 h->face_rover = i + 1;
00333 face->faceid = i | h->face_gen;
00334 face->meter[FM_BYTI] = ccnd_meter_create(h, "bytein");
00335 face->meter[FM_BYTO] = ccnd_meter_create(h, "byteout");
00336 face->meter[FM_INTI] = ccnd_meter_create(h, "intrin");
00337 face->meter[FM_INTO] = ccnd_meter_create(h, "introut");
00338 face->meter[FM_DATI] = ccnd_meter_create(h, "datain");
00339 face->meter[FM_DATO] = ccnd_meter_create(h, "dataout");
00340 register_new_face(h, face);
00341 return (face->faceid);
00342 }
00343
00344
00345
00346
00347
00348
00349 static int
00350 choose_face_delay(struct ccnd_handle *h, struct face *face, enum cq_delay_class c)
00351 {
00352 int shift = (c == CCN_CQ_SLOW) ? 2 : 0;
00353 if (c == CCN_CQ_ASAP)
00354 return(1);
00355 if ((face->flags & CCN_FACE_LINK) != 0)
00356 return((h->data_pause_microsec) << shift);
00357 if ((face->flags & CCN_FACE_LOCAL) != 0)
00358 return(5);
00359 if ((face->flags & CCN_FACE_MCAST) != 0)
00360 return((h->data_pause_microsec) << shift);
00361 if ((face->flags & CCN_FACE_GG) != 0)
00362 return(100 << shift);
00363 if ((face->flags & CCN_FACE_DGRAM) != 0)
00364 return(500 << shift);
00365 return(100);
00366 }
00367
00368
00369
00370
00371 static struct content_queue *
00372 content_queue_create(struct ccnd_handle *h, struct face *face, enum cq_delay_class c)
00373 {
00374 struct content_queue *q;
00375 unsigned usec;
00376 q = calloc(1, sizeof(*q));
00377 if (q != NULL) {
00378 usec = choose_face_delay(h, face, c);
00379 q->burst_nsec = (usec <= 500 ? 500 : 150000);
00380 q->min_usec = usec;
00381 q->rand_usec = 2 * usec;
00382 q->nrun = 0;
00383 q->send_queue = ccn_indexbuf_create();
00384 if (q->send_queue == NULL) {
00385 free(q);
00386 return(NULL);
00387 }
00388 q->sender = NULL;
00389 }
00390 return(q);
00391 }
00392
00393
00394
00395
00396 static void
00397 content_queue_destroy(struct ccnd_handle *h, struct content_queue **pq)
00398 {
00399 struct content_queue *q;
00400 if (*pq != NULL) {
00401 q = *pq;
00402 ccn_indexbuf_destroy(&q->send_queue);
00403 if (q->sender != NULL) {
00404 ccn_schedule_cancel(h->sched, q->sender);
00405 q->sender = NULL;
00406 }
00407 free(q);
00408 *pq = NULL;
00409 }
00410 }
00411
00412
00413
00414
00415 static void
00416 close_fd(int *pfd)
00417 {
00418 if (*pfd != -1) {
00419 close(*pfd);
00420 *pfd = -1;
00421 }
00422 }
00423
00424
00425
00426
00427 static void
00428 ccnd_close_fd(struct ccnd_handle *h, unsigned faceid, int *pfd)
00429 {
00430 int res;
00431
00432 if (*pfd != -1) {
00433 int linger = 0;
00434 setsockopt(*pfd, SOL_SOCKET, SO_LINGER,
00435 &linger, sizeof(linger));
00436 res = close(*pfd);
00437 if (res == -1)
00438 ccnd_msg(h, "close failed for face %u fd=%d: %s (errno=%d)",
00439 faceid, *pfd, strerror(errno), errno);
00440 else
00441 ccnd_msg(h, "closing fd %d while finalizing face %u", *pfd, faceid);
00442 *pfd = -1;
00443 }
00444 }
00445
00446
00447
00448
00449
00450
00451
00452 static void
00453 finalize_face(struct hashtb_enumerator *e)
00454 {
00455 struct ccnd_handle *h = hashtb_get_param(e->ht, NULL);
00456 struct face *face = e->data;
00457 unsigned i = face->faceid & MAXFACES;
00458 enum cq_delay_class c;
00459 int recycle = 0;
00460 int m;
00461
00462 if (i < h->face_limit && h->faces_by_faceid[i] == face) {
00463 if ((face->flags & CCN_FACE_UNDECIDED) == 0)
00464 ccnd_face_status_change(h, face->faceid);
00465 if (e->ht == h->faces_by_fd)
00466 ccnd_close_fd(h, face->faceid, &face->recv_fd);
00467 h->faces_by_faceid[i] = NULL;
00468 if ((face->flags & CCN_FACE_UNDECIDED) != 0 &&
00469 face->faceid == ((h->face_rover - 1) | h->face_gen)) {
00470
00471 recycle = 1;
00472 h->face_rover--;
00473 }
00474 for (c = 0; c < CCN_CQ_N; c++)
00475 content_queue_destroy(h, &(face->q[c]));
00476 ccnd_msg(h, "%s face id %u (slot %u)",
00477 recycle ? "recycling" : "releasing",
00478 face->faceid, face->faceid & MAXFACES);
00479
00480 }
00481 else if (face->faceid != CCN_NOFACEID)
00482 ccnd_msg(h, "orphaned face %u", face->faceid);
00483 for (m = 0; m < CCND_FACE_METER_N; m++)
00484 ccnd_meter_destroy(&face->meter[m]);
00485 }
00486
00487
00488
00489
00490
00491
00492 static struct content_entry *
00493 content_from_accession(struct ccnd_handle *h, ccn_accession_t accession)
00494 {
00495 struct content_entry *ans = NULL;
00496 if (accession < h->accession_base) {
00497 struct sparse_straggler_entry *entry;
00498 entry = hashtb_lookup(h->sparse_straggler_tab,
00499 &accession, sizeof(accession));
00500 if (entry != NULL)
00501 ans = entry->content;
00502 }
00503 else if (accession < h->accession_base + h->content_by_accession_window) {
00504 ans = h->content_by_accession[accession - h->accession_base];
00505 if (ans != NULL && ans->accession != accession)
00506 ans = NULL;
00507 }
00508 return(ans);
00509 }
00510
00511
00512
00513
00514 static void
00515 cleanout_stragglers(struct ccnd_handle *h)
00516 {
00517 ccn_accession_t accession;
00518 struct hashtb_enumerator ee;
00519 struct hashtb_enumerator *e = ⅇ
00520 struct sparse_straggler_entry *entry = NULL;
00521 struct content_entry **a = h->content_by_accession;
00522 unsigned n_direct;
00523 unsigned n_occupied;
00524 unsigned window;
00525 unsigned i;
00526 if (h->accession <= h->accession_base || a[0] == NULL)
00527 return;
00528 n_direct = h->accession - h->accession_base;
00529 if (n_direct < 1000)
00530 return;
00531 n_occupied = hashtb_n(h->content_tab) - hashtb_n(h->sparse_straggler_tab);
00532 if (n_occupied >= (n_direct / 8))
00533 return;
00534
00535 hashtb_start(h->sparse_straggler_tab, e);
00536 window = h->content_by_accession_window;
00537 for (i = 0; i < window; i++) {
00538 if (a[i] != NULL) {
00539 if (n_occupied >= ((window - i) / 8))
00540 break;
00541 accession = h->accession_base + i;
00542 hashtb_seek(e, &accession, sizeof(accession), 0);
00543 entry = e->data;
00544 if (entry != NULL && entry->content == NULL) {
00545 entry->content = a[i];
00546 a[i] = NULL;
00547 n_occupied -= 1;
00548 }
00549 }
00550 }
00551 hashtb_end(e);
00552 }
00553
00554
00555
00556
00557 static int
00558 cleanout_empties(struct ccnd_handle *h)
00559 {
00560 unsigned i = 0;
00561 unsigned j = 0;
00562 struct content_entry **a = h->content_by_accession;
00563 unsigned window = h->content_by_accession_window;
00564 if (a == NULL)
00565 return(-1);
00566 cleanout_stragglers(h);
00567 while (i < window && a[i] == NULL)
00568 i++;
00569 if (i == 0)
00570 return(-1);
00571 h->accession_base += i;
00572 while (i < window)
00573 a[j++] = a[i++];
00574 while (j < window)
00575 a[j++] = NULL;
00576 return(0);
00577 }
00578
00579
00580
00581
00582 static void
00583 enroll_content(struct ccnd_handle *h, struct content_entry *content)
00584 {
00585 unsigned new_window;
00586 struct content_entry **new_array;
00587 struct content_entry **old_array;
00588 unsigned i = 0;
00589 unsigned j = 0;
00590 unsigned window = h->content_by_accession_window;
00591 if ((content->accession - h->accession_base) >= window &&
00592 cleanout_empties(h) < 0) {
00593 if (content->accession < h->accession_base)
00594 return;
00595 window = h->content_by_accession_window;
00596 old_array = h->content_by_accession;
00597 new_window = ((window + 20) * 3 / 2);
00598 if (new_window < window)
00599 return;
00600 new_array = calloc(new_window, sizeof(new_array[0]));
00601 if (new_array == NULL)
00602 return;
00603 while (i < h->content_by_accession_window && old_array[i] == NULL)
00604 i++;
00605 h->accession_base += i;
00606 h->content_by_accession = new_array;
00607 while (i < h->content_by_accession_window)
00608 new_array[j++] = old_array[i++];
00609 h->content_by_accession_window = new_window;
00610 free(old_array);
00611 }
00612 h->content_by_accession[content->accession - h->accession_base] = content;
00613 }
00614
00615
00616 static void
00617 finalize_content(struct hashtb_enumerator *content_enumerator)
00618 {
00619 struct ccnd_handle *h = hashtb_get_param(content_enumerator->ht, NULL);
00620 struct content_entry *entry = content_enumerator->data;
00621 unsigned i = entry->accession - h->accession_base;
00622 if (i < h->content_by_accession_window &&
00623 h->content_by_accession[i] == entry) {
00624 content_skiplist_remove(h, entry);
00625 h->content_by_accession[i] = NULL;
00626 }
00627 else {
00628 struct hashtb_enumerator ee;
00629 struct hashtb_enumerator *e = ⅇ
00630 hashtb_start(h->sparse_straggler_tab, e);
00631 if (hashtb_seek(e, &entry->accession, sizeof(entry->accession), 0) ==
00632 HT_NEW_ENTRY) {
00633 ccnd_msg(h, "orphaned content %llu",
00634 (unsigned long long)(entry->accession));
00635 hashtb_delete(e);
00636 hashtb_end(e);
00637 return;
00638 }
00639 content_skiplist_remove(h, entry);
00640 hashtb_delete(e);
00641 hashtb_end(e);
00642 }
00643 if (entry->comps != NULL) {
00644 free(entry->comps);
00645 entry->comps = NULL;
00646 }
00647 }
00648
00649
00650
00651
00652
00653
00654 static int
00655 content_skiplist_findbefore(struct ccnd_handle *h,
00656 const unsigned char *key,
00657 size_t keysize,
00658 struct content_entry *wanted_old,
00659 struct ccn_indexbuf **ans)
00660 {
00661 int i;
00662 int n = h->skiplinks->n;
00663 struct ccn_indexbuf *c;
00664 struct content_entry *content;
00665 int order;
00666 size_t start;
00667 size_t end;
00668
00669 c = h->skiplinks;
00670 for (i = n - 1; i >= 0; i--) {
00671 for (;;) {
00672 if (c->buf[i] == 0)
00673 break;
00674 content = content_from_accession(h, c->buf[i]);
00675 if (content == NULL)
00676 abort();
00677 start = content->comps[0];
00678 end = content->comps[content->ncomps - 1];
00679 order = ccn_compare_names(content->key + start - 1, end - start + 2,
00680 key, keysize);
00681 if (order > 0)
00682 break;
00683 if (order == 0 && (wanted_old == content || wanted_old == NULL))
00684 break;
00685 if (content->skiplinks == NULL || i >= content->skiplinks->n)
00686 abort();
00687 c = content->skiplinks;
00688 }
00689 ans[i] = c;
00690 }
00691 return(n);
00692 }
00693
00694
00695
00696
00697 #define CCN_SKIPLIST_MAX_DEPTH 30
00698
00699
00700
00701
00702 static void
00703 content_skiplist_insert(struct ccnd_handle *h, struct content_entry *content)
00704 {
00705 int d;
00706 int i;
00707 size_t start;
00708 size_t end;
00709 struct ccn_indexbuf *pred[CCN_SKIPLIST_MAX_DEPTH] = {NULL};
00710 if (content->skiplinks != NULL) abort();
00711 for (d = 1; d < CCN_SKIPLIST_MAX_DEPTH - 1; d++)
00712 if ((nrand48(h->seed) & 3) != 0) break;
00713 while (h->skiplinks->n < d)
00714 ccn_indexbuf_append_element(h->skiplinks, 0);
00715 start = content->comps[0];
00716 end = content->comps[content->ncomps - 1];
00717 i = content_skiplist_findbefore(h,
00718 content->key + start - 1,
00719 end - start + 2, NULL, pred);
00720 if (i < d)
00721 d = i;
00722 content->skiplinks = ccn_indexbuf_create();
00723 for (i = 0; i < d; i++) {
00724 ccn_indexbuf_append_element(content->skiplinks, pred[i]->buf[i]);
00725 pred[i]->buf[i] = content->accession;
00726 }
00727 }
00728
00729
00730
00731
00732 static void
00733 content_skiplist_remove(struct ccnd_handle *h, struct content_entry *content)
00734 {
00735 int i;
00736 int d;
00737 size_t start;
00738 size_t end;
00739 struct ccn_indexbuf *pred[CCN_SKIPLIST_MAX_DEPTH] = {NULL};
00740 if (content->skiplinks == NULL) abort();
00741 start = content->comps[0];
00742 end = content->comps[content->ncomps - 1];
00743 d = content_skiplist_findbefore(h,
00744 content->key + start - 1,
00745 end - start + 2, content, pred);
00746 if (d > content->skiplinks->n)
00747 d = content->skiplinks->n;
00748 for (i = 0; i < d; i++) {
00749 pred[i]->buf[i] = content->skiplinks->buf[i];
00750 }
00751 ccn_indexbuf_destroy(&content->skiplinks);
00752 }
00753
00754
00755
00756
00757 static struct content_entry *
00758 find_first_match_candidate(struct ccnd_handle *h,
00759 const unsigned char *interest_msg,
00760 const struct ccn_parsed_interest *pi)
00761 {
00762 int res;
00763 struct ccn_indexbuf *pred[CCN_SKIPLIST_MAX_DEPTH] = {NULL};
00764 size_t start = pi->offset[CCN_PI_B_Name];
00765 size_t end = pi->offset[CCN_PI_E_Name];
00766 struct ccn_charbuf *namebuf = NULL;
00767 if (pi->offset[CCN_PI_B_Exclude] < pi->offset[CCN_PI_E_Exclude]) {
00768
00769 struct ccn_buf_decoder decoder;
00770 struct ccn_buf_decoder *d;
00771 size_t ex1start;
00772 size_t ex1end;
00773 d = ccn_buf_decoder_start(&decoder,
00774 interest_msg + pi->offset[CCN_PI_B_Exclude],
00775 pi->offset[CCN_PI_E_Exclude] -
00776 pi->offset[CCN_PI_B_Exclude]);
00777 ccn_buf_advance(d);
00778 if (ccn_buf_match_dtag(d, CCN_DTAG_Any)) {
00779 ccn_buf_advance(d);
00780 ccn_buf_check_close(d);
00781 if (ccn_buf_match_dtag(d, CCN_DTAG_Component)) {
00782 ex1start = pi->offset[CCN_PI_B_Exclude] + d->decoder.token_index;
00783 ccn_buf_advance_past_element(d);
00784 ex1end = pi->offset[CCN_PI_B_Exclude] + d->decoder.token_index;
00785 if (d->decoder.state >= 0) {
00786 namebuf = ccn_charbuf_create();
00787 ccn_charbuf_append(namebuf,
00788 interest_msg + start,
00789 end - start);
00790 namebuf->length--;
00791 ccn_charbuf_append(namebuf,
00792 interest_msg + ex1start,
00793 ex1end - ex1start);
00794 ccn_charbuf_append_closer(namebuf);
00795 if (h->debug & 8)
00796 ccnd_debug_ccnb(h, __LINE__, "fastex", NULL,
00797 namebuf->buf, namebuf->length);
00798 }
00799 }
00800 }
00801 }
00802 if (namebuf == NULL) {
00803 res = content_skiplist_findbefore(h, interest_msg + start, end - start,
00804 NULL, pred);
00805 }
00806 else {
00807 res = content_skiplist_findbefore(h, namebuf->buf, namebuf->length,
00808 NULL, pred);
00809 ccn_charbuf_destroy(&namebuf);
00810 }
00811 if (res == 0)
00812 return(NULL);
00813 return(content_from_accession(h, pred[0]->buf[0]));
00814 }
00815
00816
00817
00818
00819 static int
00820 content_matches_interest_prefix(struct ccnd_handle *h,
00821 struct content_entry *content,
00822 const unsigned char *interest_msg,
00823 struct ccn_indexbuf *comps,
00824 int prefix_comps)
00825 {
00826 size_t prefixlen;
00827 if (prefix_comps < 0 || prefix_comps >= comps->n)
00828 abort();
00829
00830 if (content->ncomps < prefix_comps + 1)
00831 return(0);
00832 prefixlen = comps->buf[prefix_comps] - comps->buf[0];
00833 if (content->comps[prefix_comps] - content->comps[0] != prefixlen)
00834 return(0);
00835 if (0 != memcmp(content->key + content->comps[0],
00836 interest_msg + comps->buf[0],
00837 prefixlen))
00838 return(0);
00839 return(1);
00840 }
00841
00842
00843
00844
00845 static ccn_accession_t
00846 content_skiplist_next(struct ccnd_handle *h, struct content_entry *content)
00847 {
00848 if (content == NULL)
00849 return(0);
00850 if (content->skiplinks == NULL || content->skiplinks->n < 1)
00851 return(0);
00852 return(content->skiplinks->buf[0]);
00853 }
00854
00855
00856
00857
00858 static void
00859 consume_interest(struct ccnd_handle *h, struct interest_entry *ie)
00860 {
00861 struct hashtb_enumerator ee;
00862 struct hashtb_enumerator *e = ⅇ
00863 int res;
00864
00865 hashtb_start(h->interest_tab, e);
00866 res = hashtb_seek(e, ie->interest_msg, ie->size - 1, 1);
00867 if (res != HT_OLD_ENTRY)
00868 abort();
00869 hashtb_delete(e);
00870 hashtb_end(e);
00871 }
00872
00873
00874
00875
00876 static void
00877 finalize_nameprefix(struct hashtb_enumerator *e)
00878 {
00879 struct ccnd_handle *h = hashtb_get_param(e->ht, NULL);
00880 struct nameprefix_entry *npe = e->data;
00881 struct ielinks *head = &npe->ie_head;
00882 if (head->next != NULL) {
00883 while (head->next != head)
00884 consume_interest(h, (struct interest_entry *)(head->next));
00885 }
00886 ccn_indexbuf_destroy(&npe->forward_to);
00887 ccn_indexbuf_destroy(&npe->tap);
00888 while (npe->forwarding != NULL) {
00889 struct ccn_forwarding *f = npe->forwarding;
00890 npe->forwarding = f->next;
00891 free(f);
00892 }
00893 }
00894
00895
00896
00897
00898 static void
00899 link_interest_entry_to_nameprefix(struct ccnd_handle *h,
00900 struct interest_entry *ie, struct nameprefix_entry *npe)
00901 {
00902 struct ielinks *head = &npe->ie_head;
00903 struct ielinks *ll = &ie->ll;
00904 ll->next = head;
00905 ll->prev = head->prev;
00906 ll->prev->next = ll->next->prev = ll;
00907 ll->npe = npe;
00908 }
00909
00910
00911
00912
00913 static void
00914 finalize_interest(struct hashtb_enumerator *e)
00915 {
00916 struct pit_face_item *p = NULL;
00917 struct pit_face_item *next = NULL;
00918 struct ccnd_handle *h = hashtb_get_param(e->ht, NULL);
00919 struct interest_entry *ie = e->data;
00920 struct face *face = NULL;
00921
00922 if (ie->ev != NULL)
00923 ccn_schedule_cancel(h->sched, ie->ev);
00924 if (ie->strategy.ev != NULL)
00925 ccn_schedule_cancel(h->sched, ie->strategy.ev);
00926 if (ie->ll.next != NULL) {
00927 ie->ll.next->prev = ie->ll.prev;
00928 ie->ll.prev->next = ie->ll.next;
00929 ie->ll.next = ie->ll.prev = NULL;
00930 ie->ll.npe = NULL;
00931 }
00932 for (p = ie->pfl; p != NULL; p = next) {
00933 next = p->next;
00934 if ((p->pfi_flags & CCND_PFI_PENDING) != 0) {
00935 face = face_from_faceid(h, p->faceid);
00936 if (face != NULL)
00937 face->pending_interests -= 1;
00938 }
00939 free(p);
00940 }
00941 ie->pfl = NULL;
00942 ie->interest_msg = NULL;
00943 }
00944
00945
00946
00947
00948 static int
00949 create_local_listener(struct ccnd_handle *h, const char *sockname, int backlog)
00950 {
00951 int res;
00952 int savedmask;
00953 int sock;
00954 struct sockaddr_un a = { 0 };
00955 res = unlink(sockname);
00956 if (res == 0) {
00957 ccnd_msg(NULL, "unlinked old %s, please wait", sockname);
00958 sleep(9);
00959 }
00960 if (!(res == 0 || errno == ENOENT))
00961 ccnd_msg(NULL, "failed to unlink %s", sockname);
00962 a.sun_family = AF_UNIX;
00963 strncpy(a.sun_path, sockname, sizeof(a.sun_path));
00964 sock = socket(AF_UNIX, SOCK_STREAM, 0);
00965 if (sock == -1)
00966 return(sock);
00967 savedmask = umask(0111);
00968 res = bind(sock, (struct sockaddr *)&a, sizeof(a));
00969 umask(savedmask);
00970 if (res == -1) {
00971 close(sock);
00972 return(-1);
00973 }
00974 unlink_at_exit(sockname);
00975 res = listen(sock, backlog);
00976 if (res == -1) {
00977 close(sock);
00978 return(-1);
00979 }
00980 record_connection(h, sock, (struct sockaddr *)&a, sizeof(a),
00981 (CCN_FACE_LOCAL | CCN_FACE_PASSIVE));
00982 return(sock);
00983 }
00984
00985
00986
00987
00988 static int
00989 establish_min_recv_bufsize(struct ccnd_handle *h, int fd, int minsize)
00990 {
00991 int res;
00992 int rcvbuf;
00993 socklen_t rcvbuf_sz;
00994
00995 rcvbuf_sz = sizeof(rcvbuf);
00996 res = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &rcvbuf_sz);
00997 if (res == -1)
00998 return (res);
00999 if (rcvbuf < minsize) {
01000 rcvbuf = minsize;
01001 res = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
01002 if (res == -1)
01003 return(res);
01004 }
01005 ccnd_msg(h, "SO_RCVBUF for fd %d is %d", fd, rcvbuf);
01006 return(rcvbuf);
01007 }
01008
01009
01010
01011
01012
01013 static void
01014 init_face_flags(struct ccnd_handle *h, struct face *face, int setflags)
01015 {
01016 const struct sockaddr *addr = face->addr;
01017 const unsigned char *rawaddr = NULL;
01018
01019 if (addr->sa_family == AF_INET6) {
01020 const struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
01021 face->flags |= CCN_FACE_INET6;
01022 #ifdef IN6_IS_ADDR_LOOPBACK
01023 if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr))
01024 face->flags |= CCN_FACE_LOOPBACK;
01025 #endif
01026 }
01027 else if (addr->sa_family == AF_INET) {
01028 const struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
01029 rawaddr = (const unsigned char *)&addr4->sin_addr.s_addr;
01030 face->flags |= CCN_FACE_INET;
01031 if (rawaddr[0] == 127)
01032 face->flags |= CCN_FACE_LOOPBACK;
01033 else {
01034
01035
01036 struct sockaddr_in myaddr;
01037 socklen_t myaddrlen = sizeof(myaddr);
01038 if (0 == getsockname(face->recv_fd, (struct sockaddr *)&myaddr, &myaddrlen)) {
01039 if (addr4->sin_addr.s_addr == myaddr.sin_addr.s_addr)
01040 face->flags |= CCN_FACE_LOOPBACK;
01041 }
01042 }
01043 }
01044 else if (addr->sa_family == AF_UNIX)
01045 face->flags |= (CCN_FACE_GG | CCN_FACE_LOCAL);
01046 face->flags |= setflags;
01047 }
01048
01049
01050
01051
01052 static struct face *
01053 record_connection(struct ccnd_handle *h, int fd,
01054 struct sockaddr *who, socklen_t wholen,
01055 int setflags)
01056 {
01057 struct hashtb_enumerator ee;
01058 struct hashtb_enumerator *e = ⅇ
01059 int res;
01060 struct face *face = NULL;
01061 unsigned char *addrspace;
01062
01063 res = fcntl(fd, F_SETFL, O_NONBLOCK);
01064 if (res == -1)
01065 ccnd_msg(h, "fcntl: %s", strerror(errno));
01066 hashtb_start(h->faces_by_fd, e);
01067 if (hashtb_seek(e, &fd, sizeof(fd), wholen) == HT_NEW_ENTRY) {
01068 face = e->data;
01069 face->recv_fd = fd;
01070 face->sendface = CCN_NOFACEID;
01071 face->addrlen = e->extsize;
01072 addrspace = ((unsigned char *)e->key) + e->keysize;
01073 face->addr = (struct sockaddr *)addrspace;
01074 memcpy(addrspace, who, e->extsize);
01075 init_face_flags(h, face, setflags);
01076 res = enroll_face(h, face);
01077 if (res == -1) {
01078 hashtb_delete(e);
01079 face = NULL;
01080 }
01081 }
01082 hashtb_end(e);
01083 return(face);
01084 }
01085
01086
01087
01088
01089
01090
01091
01092
01093 static int
01094 accept_connection(struct ccnd_handle *h, int listener_fd)
01095 {
01096 struct sockaddr_storage who;
01097 socklen_t wholen = sizeof(who);
01098 int fd;
01099 struct face *face;
01100
01101 fd = accept(listener_fd, (struct sockaddr *)&who, &wholen);
01102 if (fd == -1) {
01103 ccnd_msg(h, "accept: %s", strerror(errno));
01104 return(-1);
01105 }
01106 face = record_connection(h, fd,
01107 (struct sockaddr *)&who, wholen,
01108 CCN_FACE_UNDECIDED);
01109 if (face == NULL)
01110 close_fd(&fd);
01111 else
01112 ccnd_msg(h, "accepted client fd=%d id=%u", fd, face->faceid);
01113 return(fd);
01114 }
01115
01116
01117
01118
01119 static struct face *
01120 make_connection(struct ccnd_handle *h,
01121 struct sockaddr *who, socklen_t wholen,
01122 int setflags)
01123 {
01124 struct hashtb_enumerator ee;
01125 struct hashtb_enumerator *e = ⅇ
01126 int fd;
01127 int res;
01128 struct face *face;
01129 const int checkflags = CCN_FACE_LINK | CCN_FACE_DGRAM | CCN_FACE_LOCAL |
01130 CCN_FACE_NOSEND | CCN_FACE_UNDECIDED;
01131 const int wantflags = 0;
01132
01133
01134 for (hashtb_start(h->faces_by_fd, e); e->data != NULL; hashtb_next(e)) {
01135 face = e->data;
01136 if (face->addr != NULL && face->addrlen == wholen &&
01137 ((face->flags & checkflags) == wantflags) &&
01138 0 == memcmp(face->addr, who, wholen)) {
01139 hashtb_end(e);
01140 return(face);
01141 }
01142 }
01143 face = NULL;
01144 hashtb_end(e);
01145
01146 fd = socket(who->sa_family, SOCK_STREAM, 0);
01147 if (fd == -1) {
01148 ccnd_msg(h, "socket: %s", strerror(errno));
01149 return(NULL);
01150 }
01151 res = fcntl(fd, F_SETFL, O_NONBLOCK);
01152 if (res == -1)
01153 ccnd_msg(h, "connect fcntl: %s", strerror(errno));
01154 setflags &= ~CCN_FACE_CONNECTING;
01155 res = connect(fd, who, wholen);
01156 if (res == -1 && errno == EINPROGRESS) {
01157 res = 0;
01158 setflags |= CCN_FACE_CONNECTING;
01159 }
01160 if (res == -1) {
01161 ccnd_msg(h, "connect failed: %s (errno = %d)", strerror(errno), errno);
01162 close(fd);
01163 return(NULL);
01164 }
01165 face = record_connection(h, fd, who, wholen, setflags);
01166 if (face == NULL) {
01167 close(fd);
01168 return(NULL);
01169 }
01170 if ((face->flags & CCN_FACE_CONNECTING) != 0) {
01171 ccnd_msg(h, "connecting to client fd=%d id=%u", fd, face->faceid);
01172 face->outbufindex = 0;
01173 face->outbuf = ccn_charbuf_create();
01174 }
01175 else
01176 ccnd_msg(h, "connected client fd=%d id=%u", fd, face->faceid);
01177 return(face);
01178 }
01179
01180
01181
01182
01183
01184
01185 static int
01186 ccnd_getboundsocket(void *dat, struct sockaddr *who, socklen_t wholen)
01187 {
01188 struct ccnd_handle *h = dat;
01189 struct hashtb_enumerator ee;
01190 struct hashtb_enumerator *e = ⅇ
01191 int yes = 1;
01192 int res;
01193 int ans = -1;
01194 int wantflags = (CCN_FACE_DGRAM | CCN_FACE_PASSIVE);
01195 for (hashtb_start(h->faces_by_fd, e); e->data != NULL; hashtb_next(e)) {
01196 struct face *face = e->data;
01197 if ((face->flags & wantflags) == wantflags &&
01198 wholen == face->addrlen &&
01199 0 == memcmp(who, face->addr, wholen)) {
01200 ans = face->recv_fd;
01201 break;
01202 }
01203 }
01204 hashtb_end(e);
01205 if (ans != -1)
01206 return(ans);
01207 ans = socket(who->sa_family, SOCK_DGRAM, 0);
01208 if (ans == -1)
01209 return(ans);
01210 setsockopt(ans, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
01211 res = bind(ans, who, wholen);
01212 if (res == -1) {
01213 ccnd_msg(h, "bind failed: %s (errno = %d)", strerror(errno), errno);
01214 close(ans);
01215 return(-1);
01216 }
01217 record_connection(h, ans, who, wholen,
01218 CCN_FACE_DGRAM | CCN_FACE_PASSIVE | CCN_FACE_NORECV);
01219 return(ans);
01220 }
01221
01222
01223
01224
01225
01226
01227 static unsigned
01228 faceid_from_fd(struct ccnd_handle *h, int fd)
01229 {
01230 struct face *face = hashtb_lookup(h->faces_by_fd, &fd, sizeof(fd));
01231 if (face != NULL)
01232 return(face->faceid);
01233 return(CCN_NOFACEID);
01234 }
01235
01236 typedef void (*loggerproc)(void *, const char *, ...);
01237
01238
01239
01240
01241 static struct face *
01242 setup_multicast(struct ccnd_handle *h, struct ccn_face_instance *face_instance,
01243 struct sockaddr *who, socklen_t wholen)
01244 {
01245 struct hashtb_enumerator ee;
01246 struct hashtb_enumerator *e = ⅇ
01247 struct ccn_sockets socks = { -1, -1 };
01248 int res;
01249 struct face *face = NULL;
01250 const int checkflags = CCN_FACE_LINK | CCN_FACE_DGRAM | CCN_FACE_MCAST |
01251 CCN_FACE_LOCAL | CCN_FACE_NOSEND;
01252 const int wantflags = CCN_FACE_DGRAM | CCN_FACE_MCAST;
01253
01254
01255
01256 for (hashtb_start(h->faces_by_fd, e); e->data != NULL; hashtb_next(e)) {
01257 face = e->data;
01258 if (face->addr != NULL && face->addrlen == wholen &&
01259 ((face->flags & checkflags) == wantflags) &&
01260 0 == memcmp(face->addr, who, wholen)) {
01261 hashtb_end(e);
01262 return(face);
01263 }
01264 }
01265 face = NULL;
01266 hashtb_end(e);
01267
01268 res = ccn_setup_socket(&face_instance->descr,
01269 (loggerproc)&ccnd_msg, (void *)h,
01270 &ccnd_getboundsocket, (void *)h,
01271 &socks);
01272 if (res < 0)
01273 return(NULL);
01274 establish_min_recv_bufsize(h, socks.recving, 128*1024);
01275 face = record_connection(h, socks.recving, who, wholen,
01276 (CCN_FACE_MCAST | CCN_FACE_DGRAM));
01277 if (face == NULL) {
01278 close(socks.recving);
01279 if (socks.sending != socks.recving)
01280 close(socks.sending);
01281 return(NULL);
01282 }
01283 face->sendface = faceid_from_fd(h, socks.sending);
01284 ccnd_msg(h, "multicast on fd=%d id=%u, sending on face %u",
01285 face->recv_fd, face->faceid, face->sendface);
01286 return(face);
01287 }
01288
01289
01290
01291
01292 static void
01293 shutdown_client_fd(struct ccnd_handle *h, int fd)
01294 {
01295 struct hashtb_enumerator ee;
01296 struct hashtb_enumerator *e = ⅇ
01297 struct face *face = NULL;
01298 unsigned faceid = CCN_NOFACEID;
01299 hashtb_start(h->faces_by_fd, e);
01300 if (hashtb_seek(e, &fd, sizeof(fd), 0) == HT_OLD_ENTRY) {
01301 face = e->data;
01302 if (face->recv_fd != fd) abort();
01303 faceid = face->faceid;
01304 if (faceid == CCN_NOFACEID) {
01305 ccnd_msg(h, "error indication on fd %d ignored", fd);
01306 hashtb_end(e);
01307 return;
01308 }
01309 close(fd);
01310 face->recv_fd = -1;
01311 ccnd_msg(h, "shutdown client fd=%d id=%u", fd, faceid);
01312 ccn_charbuf_destroy(&face->inbuf);
01313 ccn_charbuf_destroy(&face->outbuf);
01314 face = NULL;
01315 }
01316 hashtb_delete(e);
01317 hashtb_end(e);
01318 check_comm_file(h);
01319 }
01320
01321
01322
01323
01324
01325
01326
01327 static void
01328 send_content(struct ccnd_handle *h, struct face *face, struct content_entry *content)
01329 {
01330 int n, a, b, size;
01331 if ((face->flags & CCN_FACE_NOSEND) != 0) {
01332
01333 return;
01334 }
01335 size = content->size;
01336 if (h->debug & 4)
01337 ccnd_debug_ccnb(h, __LINE__, "content_to", face,
01338 content->key, size);
01339
01340 n = content->ncomps;
01341 if (n < 2) abort();
01342 a = content->comps[n - 2];
01343 b = content->comps[n - 1];
01344 if (b - a != 36)
01345 abort();
01346 stuff_and_send(h, face, content->key, a, content->key + b, size - b, 0, 0);
01347 ccnd_meter_bump(h, face->meter[FM_DATO], 1);
01348 h->content_items_sent += 1;
01349 }
01350
01351
01352
01353
01354 static enum cq_delay_class
01355 choose_content_delay_class(struct ccnd_handle *h, unsigned faceid, int content_flags)
01356 {
01357 struct face *face = face_from_faceid(h, faceid);
01358 if (face == NULL)
01359 return(CCN_CQ_ASAP);
01360 if ((face->flags & (CCN_FACE_LINK | CCN_FACE_MCAST)) != 0)
01361 return((content_flags & CCN_CONTENT_ENTRY_SLOWSEND) ? CCN_CQ_SLOW : CCN_CQ_NORMAL);
01362 if ((face->flags & CCN_FACE_DGRAM) != 0)
01363 return(CCN_CQ_NORMAL);
01364 if ((face->flags & (CCN_FACE_GG | CCN_FACE_LOCAL)) != 0)
01365 return(CCN_CQ_ASAP);
01366 return(CCN_CQ_NORMAL);
01367 }
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377 static unsigned
01378 randomize_content_delay(struct ccnd_handle *h, struct content_queue *q)
01379 {
01380 unsigned usec;
01381
01382 usec = q->min_usec + q->rand_usec;
01383 if (usec < 2)
01384 return(1);
01385 if (usec <= 20 || q->rand_usec < 2)
01386 return(usec);
01387 usec = q->min_usec + (nrand48(h->seed) % q->rand_usec);
01388 if (usec < 2)
01389 return(1);
01390 return(usec);
01391 }
01392
01393
01394
01395
01396 static int
01397 content_sender(struct ccn_schedule *sched,
01398 void *clienth,
01399 struct ccn_scheduled_event *ev,
01400 int flags)
01401 {
01402 int i, j;
01403 int delay;
01404 int nsec;
01405 int burst_nsec;
01406 int burst_max;
01407 struct ccnd_handle *h = clienth;
01408 struct content_entry *content = NULL;
01409 unsigned faceid = ev->evint;
01410 struct face *face = NULL;
01411 struct content_queue *q = ev->evdata;
01412 (void)sched;
01413
01414 if ((flags & CCN_SCHEDULE_CANCEL) != 0)
01415 goto Bail;
01416 face = face_from_faceid(h, faceid);
01417 if (face == NULL)
01418 goto Bail;
01419 if (q->send_queue == NULL)
01420 goto Bail;
01421 if ((face->flags & CCN_FACE_NOSEND) != 0)
01422 goto Bail;
01423
01424 if (q->ready > q->send_queue->n ||
01425 (q->ready == 0 && q->nrun >= 12 && q->nrun < 120))
01426 q->ready = q->send_queue->n;
01427 nsec = 0;
01428 burst_nsec = q->burst_nsec;
01429 burst_max = 2;
01430 if (q->ready < burst_max)
01431 burst_max = q->ready;
01432 if (burst_max == 0)
01433 q->nrun = 0;
01434 for (i = 0; i < burst_max && nsec < 1000000; i++) {
01435 content = content_from_accession(h, q->send_queue->buf[i]);
01436 if (content == NULL)
01437 q->nrun = 0;
01438 else {
01439 send_content(h, face, content);
01440
01441 if (face_from_faceid(h, faceid) == NULL)
01442 goto Bail;
01443 nsec += burst_nsec * (unsigned)((content->size + 1023) / 1024);
01444 q->nrun++;
01445 }
01446 }
01447 if (q->ready < i) abort();
01448 q->ready -= i;
01449
01450 for (j = 0; i < q->send_queue->n; i++, j++)
01451 q->send_queue->buf[j] = q->send_queue->buf[i];
01452 q->send_queue->n = j;
01453
01454 delay = (nsec + 499) / 1000 + 1;
01455 if (q->ready > 0) {
01456 if (h->debug & 8)
01457 ccnd_msg(h, "face %u ready %u delay %i nrun %u",
01458 faceid, q->ready, delay, q->nrun, face->surplus);
01459 return(delay);
01460 }
01461 q->ready = j;
01462 if (q->nrun >= 12 && q->nrun < 120) {
01463
01464 if (j == 0)
01465 delay += burst_nsec / 50;
01466 if (h->debug & 8)
01467 ccnd_msg(h, "face %u ready %u delay %i nrun %u surplus %u",
01468 (unsigned)ev->evint, q->ready, delay, q->nrun, face->surplus);
01469 return(delay);
01470 }
01471
01472 for (i = 0; i < q->send_queue->n; i++) {
01473 content = content_from_accession(h, q->send_queue->buf[i]);
01474 if (content != NULL) {
01475 q->nrun = 0;
01476 delay = randomize_content_delay(h, q);
01477 if (h->debug & 8)
01478 ccnd_msg(h, "face %u queued %u delay %i",
01479 (unsigned)ev->evint, q->ready, delay);
01480 return(delay);
01481 }
01482 }
01483 q->send_queue->n = q->ready = 0;
01484 Bail:
01485 q->sender = NULL;
01486 return(0);
01487 }
01488
01489
01490
01491
01492 static int
01493 face_send_queue_insert(struct ccnd_handle *h,
01494 struct face *face, struct content_entry *content)
01495 {
01496 int ans;
01497 int delay;
01498 enum cq_delay_class c;
01499 enum cq_delay_class k;
01500 struct content_queue *q;
01501 if (face == NULL || content == NULL || (face->flags & CCN_FACE_NOSEND) != 0)
01502 return(-1);
01503 c = choose_content_delay_class(h, face->faceid, content->flags);
01504 if (face->q[c] == NULL)
01505 face->q[c] = content_queue_create(h, face, c);
01506 q = face->q[c];
01507 if (q == NULL)
01508 return(-1);
01509
01510 for (k = 0; k < CCN_CQ_N; k++) {
01511 if (k != c && face->q[k] != NULL) {
01512 ans = ccn_indexbuf_member(face->q[k]->send_queue, content->accession);
01513 if (ans >= 0) {
01514 if (h->debug & 8)
01515 ccnd_debug_ccnb(h, __LINE__, "content_otherq", face,
01516 content->key, content->size);
01517 return(ans);
01518 }
01519 }
01520 }
01521 ans = ccn_indexbuf_set_insert(q->send_queue, content->accession);
01522 if (q->sender == NULL) {
01523 delay = randomize_content_delay(h, q);
01524 q->ready = q->send_queue->n;
01525 q->sender = ccn_schedule_event(h->sched, delay,
01526 content_sender, q, face->faceid);
01527 if (h->debug & 8)
01528 ccnd_msg(h, "face %u q %d delay %d usec", face->faceid, c, delay);
01529 }
01530 return (ans);
01531 }
01532
01533
01534
01535
01536 static int
01537 is_pending_on(struct ccnd_handle *h, struct interest_entry *ie, unsigned faceid)
01538 {
01539 struct pit_face_item *x;
01540
01541 for (x = ie->pfl; x != NULL; x = x->next) {
01542 if (x->faceid == faceid && (x->pfi_flags & CCND_PFI_PENDING) != 0)
01543 return(1);
01544
01545
01546 }
01547 return(0);
01548 }
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559 static int
01560 consume_matching_interests(struct ccnd_handle *h,
01561 struct nameprefix_entry *npe,
01562 struct content_entry *content,
01563 struct ccn_parsed_ContentObject *pc,
01564 struct face *face)
01565 {
01566 int matches = 0;
01567 struct ielinks *head;
01568 struct ielinks *next;
01569 struct ielinks *pl;
01570 struct interest_entry *p;
01571 struct pit_face_item *x;
01572 const unsigned char *content_msg;
01573 size_t content_size;
01574
01575 head = &npe->ie_head;
01576 content_msg = content->key;
01577 content_size = content->size;
01578 for (pl = head->next; pl != head; pl = next) {
01579 next = pl->next;
01580 p = (struct interest_entry *)pl;
01581 if (p->interest_msg == NULL)
01582 continue;
01583 if (face != NULL && is_pending_on(h, p, face->faceid) == 0)
01584 continue;
01585 if (ccn_content_matches_interest(content_msg, content_size, 0, pc,
01586 p->interest_msg, p->size, NULL)) {
01587 for (x = p->pfl; x != NULL; x = x->next) {
01588 if ((x->pfi_flags & CCND_PFI_PENDING) != 0)
01589 face_send_queue_insert(h, face_from_faceid(h, x->faceid),
01590 content);
01591 }
01592 matches += 1;
01593 strategy_callout(h, p, CCNST_SATISFIED);
01594 consume_interest(h, p);
01595 }
01596 }
01597 return(matches);
01598 }
01599
01600
01601
01602
01603
01604
01605
01606
01607 static void
01608 adjust_npe_predicted_response(struct ccnd_handle *h,
01609 struct nameprefix_entry *npe, int up)
01610 {
01611 unsigned t = npe->usec;
01612 if (up)
01613 t = t + (t >> 3);
01614 else
01615 t = t - (t >> 7);
01616 if (t < 127)
01617 t = 127;
01618 else if (t > 160000)
01619 t = 160000;
01620 npe->usec = t;
01621 }
01622
01623
01624
01625
01626
01627
01628
01629
01630 static void
01631 adjust_predicted_response(struct ccnd_handle *h,
01632 struct interest_entry *ie, int up)
01633 {
01634 struct nameprefix_entry *npe;
01635
01636 npe = ie->ll.npe;
01637 if (npe == NULL)
01638 return;
01639 adjust_npe_predicted_response(h, npe, up);
01640 if (npe->parent != NULL)
01641 adjust_npe_predicted_response(h, npe->parent, up);
01642 }
01643
01644
01645
01646
01647 static void
01648 note_content_from(struct ccnd_handle *h,
01649 struct nameprefix_entry *npe,
01650 unsigned from_faceid,
01651 int prefix_comps)
01652 {
01653 if (npe->src == from_faceid)
01654 adjust_npe_predicted_response(h, npe, 0);
01655 else if (npe->src == CCN_NOFACEID)
01656 npe->src = from_faceid;
01657 else {
01658 npe->osrc = npe->src;
01659 npe->src = from_faceid;
01660 }
01661 if (h->debug & 8)
01662 ccnd_msg(h, "sl.%d %u ci=%d osrc=%u src=%u usec=%d", __LINE__,
01663 from_faceid, prefix_comps, npe->osrc, npe->src, npe->usec);
01664 }
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676 static int
01677 match_interests(struct ccnd_handle *h, struct content_entry *content,
01678 struct ccn_parsed_ContentObject *pc,
01679 struct face *face, struct face *from_face)
01680 {
01681 int n_matched = 0;
01682 int new_matches;
01683 int ci;
01684 int cm = 0;
01685 unsigned c0 = content->comps[0];
01686 const unsigned char *key = content->key + c0;
01687 struct nameprefix_entry *npe = NULL;
01688 for (ci = content->ncomps - 1; ci >= 0; ci--) {
01689 int size = content->comps[ci] - c0;
01690 npe = hashtb_lookup(h->nameprefix_tab, key, size);
01691 if (npe != NULL)
01692 break;
01693 }
01694 for (; npe != NULL; npe = npe->parent, ci--) {
01695 if (npe->fgen != h->forward_to_gen)
01696 update_forward_to(h, npe);
01697 if (from_face != NULL && (npe->flags & CCN_FORW_LOCAL) != 0 &&
01698 (from_face->flags & CCN_FACE_GG) == 0)
01699 return(-1);
01700 new_matches = consume_matching_interests(h, npe, content, pc, face);
01701 if (from_face != NULL && (new_matches != 0 || ci + 1 == cm))
01702 note_content_from(h, npe, from_face->faceid, ci);
01703 if (new_matches != 0) {
01704 cm = ci;
01705 n_matched += new_matches;
01706 }
01707 }
01708 return(n_matched);
01709 }
01710
01711
01712
01713
01714
01715 static void
01716 stuff_and_send(struct ccnd_handle *h, struct face *face,
01717 const unsigned char *data1, size_t size1,
01718 const unsigned char *data2, size_t size2,
01719 const char *tag, int lineno) {
01720 struct ccn_charbuf *c = NULL;
01721
01722 if ((face->flags & CCN_FACE_LINK) != 0) {
01723 c = charbuf_obtain(h);
01724 ccn_charbuf_reserve(c, size1 + size2 + 5 + 8);
01725 ccn_charbuf_append_tt(c, CCN_DTAG_CCNProtocolDataUnit, CCN_DTAG);
01726 ccn_charbuf_append(c, data1, size1);
01727 if (size2 != 0)
01728 ccn_charbuf_append(c, data2, size2);
01729 if (tag != NULL)
01730 ccnd_debug_ccnb(h, lineno, tag, face, c->buf + 4, c->length - 4);
01731 ccn_stuff_interest(h, face, c);
01732 ccn_append_link_stuff(h, face, c);
01733 ccn_charbuf_append_closer(c);
01734 }
01735 else if (size2 != 0 || h->mtu > size1 + size2 ||
01736 (face->flags & (CCN_FACE_SEQOK | CCN_FACE_SEQPROBE)) != 0 ||
01737 face->recvcount == 0) {
01738 c = charbuf_obtain(h);
01739 ccn_charbuf_append(c, data1, size1);
01740 if (size2 != 0)
01741 ccn_charbuf_append(c, data2, size2);
01742 if (tag != NULL)
01743 ccnd_debug_ccnb(h, lineno, tag, face, c->buf, c->length);
01744 ccn_stuff_interest(h, face, c);
01745 ccn_append_link_stuff(h, face, c);
01746 }
01747 else {
01748
01749 if (tag != NULL)
01750 ccnd_debug_ccnb(h, lineno, tag, face, data1, size1);
01751 ccnd_send(h, face, data1, size1);
01752 return;
01753 }
01754 ccnd_send(h, face, c->buf, c->length);
01755 charbuf_release(h, c);
01756 return;
01757 }
01758
01759
01760
01761
01762
01763
01764 static int
01765 stuff_link_check(struct ccnd_handle *h,
01766 struct face *face, struct ccn_charbuf *c)
01767 {
01768 int checkflags = CCN_FACE_DGRAM | CCN_FACE_MCAST | CCN_FACE_GG | CCN_FACE_LC;
01769 int wantflags = CCN_FACE_DGRAM;
01770 struct ccn_charbuf *name = NULL;
01771 struct ccn_charbuf *ibuf = NULL;
01772 int res;
01773 int ans = 0;
01774 if (face->recvcount > 0)
01775 return(0);
01776 if ((face->flags & checkflags) != wantflags)
01777 return(0);
01778 name = ccn_charbuf_create();
01779 if (name == NULL) goto Bail;
01780 ccn_name_init(name);
01781 res = ccn_name_from_uri(name, CCNDID_NEIGHBOR_URI);
01782 if (res < 0) goto Bail;
01783 ibuf = ccn_charbuf_create();
01784 if (ibuf == NULL) goto Bail;
01785 ccn_charbuf_append_tt(ibuf, CCN_DTAG_Interest, CCN_DTAG);
01786 ccn_charbuf_append(ibuf, name->buf, name->length);
01787 ccnb_tagged_putf(ibuf, CCN_DTAG_Scope, "2");
01788
01789 ccn_charbuf_append_closer(ibuf);
01790 ccn_charbuf_append(c, ibuf->buf, ibuf->length);
01791 ccnd_meter_bump(h, face->meter[FM_INTO], 1);
01792 h->interests_stuffed++;
01793 face->flags |= CCN_FACE_LC;
01794 if (h->debug & 2)
01795 ccnd_debug_ccnb(h, __LINE__, "stuff_interest_to", face,
01796 ibuf->buf, ibuf->length);
01797 ans = 1;
01798 Bail:
01799 ccn_charbuf_destroy(&ibuf);
01800 ccn_charbuf_destroy(&name);
01801 return(ans);
01802 }
01803
01804
01805
01806
01807
01808
01809
01810 static int
01811 ccn_stuff_interest(struct ccnd_handle *h,
01812 struct face *face, struct ccn_charbuf *c)
01813 {
01814 int n_stuffed = 0;
01815 if (stuff_link_check(h, face, c) > 0)
01816 n_stuffed++;
01817 return(n_stuffed);
01818 }
01819
01820
01821
01822
01823
01824
01825 static void
01826 ccn_link_state_init(struct ccnd_handle *h, struct face *face)
01827 {
01828 int checkflags;
01829 int matchflags;
01830
01831 matchflags = CCN_FACE_DGRAM;
01832 checkflags = matchflags | CCN_FACE_MCAST | CCN_FACE_GG | CCN_FACE_SEQOK | \
01833 CCN_FACE_PASSIVE;
01834 if ((face->flags & checkflags) != matchflags)
01835 return;
01836
01837 face->pktseq = nrand48(h->seed);
01838 face->flags |= CCN_FACE_SEQPROBE;
01839 }
01840
01841
01842
01843
01844 static void
01845 ccn_append_link_stuff(struct ccnd_handle *h,
01846 struct face *face,
01847 struct ccn_charbuf *c)
01848 {
01849 if ((face->flags & (CCN_FACE_SEQOK | CCN_FACE_SEQPROBE)) == 0)
01850 return;
01851 ccn_charbuf_append_tt(c, CCN_DTAG_SequenceNumber, CCN_DTAG);
01852 ccn_charbuf_append_tt(c, 2, CCN_BLOB);
01853 ccn_charbuf_append_value(c, face->pktseq, 2);
01854 ccnb_element_end(c);
01855 if (0)
01856 ccnd_msg(h, "debug.%d pkt_to %u seq %u",
01857 __LINE__, face->faceid, (unsigned)face->pktseq);
01858 face->pktseq++;
01859 face->flags &= ~CCN_FACE_SEQPROBE;
01860 }
01861
01862
01863
01864
01865 static int
01866 process_incoming_link_message(struct ccnd_handle *h,
01867 struct face *face, enum ccn_dtag dtag,
01868 unsigned char *msg, size_t size)
01869 {
01870 uintmax_t s;
01871 int checkflags;
01872 int matchflags;
01873 struct ccn_buf_decoder decoder;
01874 struct ccn_buf_decoder *d = ccn_buf_decoder_start(&decoder, msg, size);
01875
01876 switch (dtag) {
01877 case CCN_DTAG_SequenceNumber:
01878 s = ccn_parse_required_tagged_binary_number(d, dtag, 1, 6);
01879 if (d->decoder.state < 0)
01880 return(d->decoder.state);
01881
01882
01883
01884
01885 matchflags = CCN_FACE_DGRAM;
01886 checkflags = matchflags | CCN_FACE_MCAST | CCN_FACE_SEQOK;
01887 if ((face->flags & checkflags) == matchflags)
01888 face->flags |= CCN_FACE_SEQOK;
01889 if (face->rrun == 0) {
01890 face->rseq = s;
01891 face->rrun = 1;
01892 return(0);
01893 }
01894 if (s == face->rseq + 1) {
01895 face->rseq = s;
01896 if (face->rrun < 255)
01897 face->rrun++;
01898 return(0);
01899 }
01900 if (s > face->rseq && s - face->rseq < 255) {
01901 ccnd_msg(h, "seq_gap %u %ju to %ju",
01902 face->faceid, face->rseq, s);
01903 face->rseq = s;
01904 face->rrun = 1;
01905 return(0);
01906 }
01907 if (s <= face->rseq) {
01908 if (face->rseq - s < face->rrun) {
01909 ccnd_msg(h, "seq_dup %u %ju", face->faceid, s);
01910 return(0);
01911 }
01912 if (face->rseq - s < 255) {
01913
01914 ccnd_msg(h, "seq_ooo %u %ju", face->faceid, s);
01915 if (s == face->rseq - face->rrun) {
01916 face->rrun++;
01917 return(0);
01918 }
01919 }
01920 }
01921 face->rseq = s;
01922 face->rrun = 1;
01923 break;
01924 default:
01925 return(-1);
01926 }
01927 return(0);
01928 }
01929
01930
01931
01932
01933
01934 static int
01935 check_dgram_faces(struct ccnd_handle *h)
01936 {
01937 struct hashtb_enumerator ee;
01938 struct hashtb_enumerator *e = ⅇ
01939 int count = 0;
01940 int checkflags = CCN_FACE_DGRAM;
01941 int wantflags = CCN_FACE_DGRAM;
01942
01943 hashtb_start(h->dgram_faces, e);
01944 while (e->data != NULL) {
01945 struct face *face = e->data;
01946 if (face->addr != NULL && (face->flags & checkflags) == wantflags) {
01947 face->flags &= ~CCN_FACE_LC;
01948 if (face->recvcount == 0) {
01949 if ((face->flags & CCN_FACE_PERMANENT) == 0) {
01950 count += 1;
01951 hashtb_delete(e);
01952 continue;
01953 }
01954 }
01955 else if (face->recvcount == 1) {
01956 face->recvcount = 0;
01957 }
01958 else {
01959 face->recvcount = 1;
01960 }
01961 }
01962 hashtb_next(e);
01963 }
01964 hashtb_end(e);
01965 return(count);
01966 }
01967
01968
01969
01970
01971
01972 int
01973 ccnd_destroy_face(struct ccnd_handle *h, unsigned faceid)
01974 {
01975 struct hashtb_enumerator ee;
01976 struct hashtb_enumerator *e = ⅇ
01977 struct face *face;
01978 int dgram_chk = CCN_FACE_DGRAM | CCN_FACE_MCAST;
01979 int dgram_want = CCN_FACE_DGRAM;
01980
01981 face = face_from_faceid(h, faceid);
01982 if (face == NULL)
01983 return(-1);
01984 if ((face->flags & dgram_chk) == dgram_want) {
01985 hashtb_start(h->dgram_faces, e);
01986 hashtb_seek(e, face->addr, face->addrlen, 0);
01987 if (e->data == face)
01988 face = NULL;
01989 hashtb_delete(e);
01990 hashtb_end(e);
01991 if (face == NULL)
01992 return(0);
01993 }
01994 shutdown_client_fd(h, face->recv_fd);
01995 face = NULL;
01996 return(0);
01997 }
01998
01999
02000
02001
02002 static void
02003 check_forward_to(struct ccnd_handle *h, struct ccn_indexbuf **ip)
02004 {
02005 struct ccn_indexbuf *ft = *ip;
02006 int i;
02007 int j;
02008 if (ft == NULL)
02009 return;
02010 for (i = 0; i < ft->n; i++)
02011 if (face_from_faceid(h, ft->buf[i]) == NULL)
02012 break;
02013 for (j = i + 1; j < ft->n; j++)
02014 if (face_from_faceid(h, ft->buf[j]) != NULL)
02015 ft->buf[i++] = ft->buf[j];
02016 if (i == 0)
02017 ccn_indexbuf_destroy(ip);
02018 else if (i < ft->n)
02019 ft->n = i;
02020 }
02021
02022
02023
02024
02025
02026 static int
02027 check_nameprefix_entries(struct ccnd_handle *h)
02028 {
02029 int count = 0;
02030 struct hashtb_enumerator ee;
02031 struct hashtb_enumerator *e = ⅇ
02032 struct ielinks *head;
02033 struct nameprefix_entry *npe;
02034
02035 hashtb_start(h->nameprefix_tab, e);
02036 for (npe = e->data; npe != NULL; npe = e->data) {
02037 if ( npe->src == CCN_NOFACEID &&
02038 npe->children == 0 &&
02039 npe->forwarding == NULL) {
02040 head = &npe->ie_head;
02041 if (head == head->next) {
02042 count += 1;
02043 if (npe->parent != NULL) {
02044 npe->parent->children--;
02045 npe->parent = NULL;
02046 }
02047 hashtb_delete(e);
02048 continue;
02049 }
02050 }
02051 check_forward_to(h, &npe->forward_to);
02052 check_forward_to(h, &npe->tap);
02053 npe->osrc = npe->src;
02054 npe->src = CCN_NOFACEID;
02055 hashtb_next(e);
02056 }
02057 hashtb_end(e);
02058 return(count);
02059 }
02060
02061 static void
02062 check_comm_file(struct ccnd_handle *h)
02063 {
02064 if (!comm_file_ok()) {
02065 ccnd_msg(h, "stopping (%s gone)", unlink_this_at_exit);
02066 unlink_this_at_exit = NULL;
02067 h->running = 0;
02068 }
02069 }
02070
02071
02072
02073
02074 static int
02075 reap(
02076 struct ccn_schedule *sched,
02077 void *clienth,
02078 struct ccn_scheduled_event *ev,
02079 int flags)
02080 {
02081 struct ccnd_handle *h = clienth;
02082 (void)(sched);
02083 (void)(ev);
02084 if ((flags & CCN_SCHEDULE_CANCEL) != 0) {
02085 h->reaper = NULL;
02086 return(0);
02087 }
02088 check_dgram_faces(h);
02089 check_nameprefix_entries(h);
02090 check_comm_file(h);
02091 return(2 * CCN_INTEREST_LIFETIME_MICROSEC);
02092 }
02093
02094 static void
02095 reap_needed(struct ccnd_handle *h, int init_delay_usec)
02096 {
02097 if (h->reaper == NULL)
02098 h->reaper = ccn_schedule_event(h->sched, init_delay_usec, reap, NULL, 0);
02099 }
02100
02101
02102
02103
02104 static int
02105 remove_content(struct ccnd_handle *h, struct content_entry *content)
02106 {
02107 struct hashtb_enumerator ee;
02108 struct hashtb_enumerator *e = ⅇ
02109 int res;
02110 if (content == NULL)
02111 return(-1);
02112 hashtb_start(h->content_tab, e);
02113 res = hashtb_seek(e, content->key,
02114 content->key_size, content->size - content->key_size);
02115 if (res != HT_OLD_ENTRY)
02116 abort();
02117 if ((content->flags & CCN_CONTENT_ENTRY_STALE) != 0)
02118 h->n_stale--;
02119 if (h->debug & 4)
02120 ccnd_debug_ccnb(h, __LINE__, "remove", NULL,
02121 content->key, content->size);
02122 hashtb_delete(e);
02123 hashtb_end(e);
02124 return(0);
02125 }
02126
02127
02128
02129
02130 static int
02131 clean_deamon(struct ccn_schedule *sched,
02132 void *clienth,
02133 struct ccn_scheduled_event *ev,
02134 int flags)
02135 {
02136 struct ccnd_handle *h = clienth;
02137 (void)(sched);
02138 (void)(ev);
02139 unsigned long n;
02140 ccn_accession_t limit;
02141 ccn_accession_t a;
02142 ccn_accession_t min_stale;
02143 int check_limit = 500;
02144 struct content_entry *content = NULL;
02145 int res = 0;
02146 int ignore;
02147 int i;
02148
02149
02150
02151
02152
02153
02154 if ((flags & CCN_SCHEDULE_CANCEL) != 0) {
02155 h->clean = NULL;
02156 return(0);
02157 }
02158 n = hashtb_n(h->content_tab);
02159 if (n <= h->capacity)
02160 return(15000000);
02161
02162 for (i = 0; i < h->unsol->n; i++) {
02163 if (i == check_limit) {
02164 for (i = check_limit; i < h->unsol->n; i++)
02165 h->unsol->buf[i-check_limit] = h->unsol->buf[i];
02166 h->unsol->n -= check_limit;
02167 return(500);
02168 }
02169 a = h->unsol->buf[i];
02170 content = content_from_accession(h, a);
02171 if (content != NULL &&
02172 (content->flags & CCN_CONTENT_ENTRY_PRECIOUS) == 0)
02173 remove_content(h, content);
02174 }
02175 n = hashtb_n(h->content_tab);
02176 h->unsol->n = 0;
02177 if (h->min_stale <= h->max_stale) {
02178
02179 limit = h->max_stale;
02180 if (limit > h->accession)
02181 limit = h->accession;
02182 min_stale = ~0;
02183 a = ev->evint;
02184 if (a <= h->min_stale || a > h->max_stale)
02185 a = h->min_stale;
02186 else
02187 min_stale = h->min_stale;
02188 for (; a <= limit && n > h->capacity; a++) {
02189 if (check_limit-- <= 0) {
02190 ev->evint = a;
02191 break;
02192 }
02193 content = content_from_accession(h, a);
02194 if (content != NULL &&
02195 (content->flags & CCN_CONTENT_ENTRY_STALE) != 0) {
02196 res = remove_content(h, content);
02197 if (res < 0) {
02198 if (a < min_stale)
02199 min_stale = a;
02200 }
02201 else {
02202 content = NULL;
02203 n -= 1;
02204 }
02205 }
02206 }
02207 if (min_stale < a)
02208 h->min_stale = min_stale;
02209 else if (a > limit) {
02210 h->min_stale = ~0;
02211 h->max_stale = 0;
02212 }
02213 else
02214 h->min_stale = a;
02215 if (check_limit <= 0)
02216 return(5000);
02217 }
02218 else {
02219
02220 limit = h->accession;
02221 ignore = CCN_CONTENT_ENTRY_STALE | CCN_CONTENT_ENTRY_PRECIOUS;
02222 for (a = h->accession_base; a <= limit && n > h->capacity; a++) {
02223 content = content_from_accession(h, a);
02224 if (content != NULL && (content->flags & ignore) == 0) {
02225 mark_stale(h, content);
02226 n--;
02227 }
02228 }
02229 ev->evint = 0;
02230 return(1000000);
02231 }
02232 ev->evint = 0;
02233 return(15000000);
02234 }
02235
02236
02237
02238
02239 static void
02240 clean_needed(struct ccnd_handle *h)
02241 {
02242 if (h->clean == NULL)
02243 h->clean = ccn_schedule_event(h->sched, 1000000, clean_deamon, NULL, 0);
02244 }
02245
02246
02247
02248
02249 static int
02250 age_forwarding(struct ccn_schedule *sched,
02251 void *clienth,
02252 struct ccn_scheduled_event *ev,
02253 int flags)
02254 {
02255 struct ccnd_handle *h = clienth;
02256 struct hashtb_enumerator ee;
02257 struct hashtb_enumerator *e = ⅇ
02258 struct ccn_forwarding *f;
02259 struct ccn_forwarding *next;
02260 struct ccn_forwarding **p;
02261 struct nameprefix_entry *npe;
02262
02263 if ((flags & CCN_SCHEDULE_CANCEL) != 0) {
02264 h->age_forwarding = NULL;
02265 return(0);
02266 }
02267 hashtb_start(h->nameprefix_tab, e);
02268 for (npe = e->data; npe != NULL; npe = e->data) {
02269 p = &npe->forwarding;
02270 for (f = npe->forwarding; f != NULL; f = next) {
02271 next = f->next;
02272 if ((f->flags & CCN_FORW_REFRESHED) == 0 ||
02273 face_from_faceid(h, f->faceid) == NULL) {
02274 if (h->debug & 2) {
02275 struct face *face = face_from_faceid(h, f->faceid);
02276 if (face != NULL) {
02277 struct ccn_charbuf *prefix = ccn_charbuf_create();
02278 ccn_name_init(prefix);
02279 ccn_name_append_components(prefix, e->key, 0, e->keysize);
02280 ccnd_debug_ccnb(h, __LINE__, "prefix_expiry", face,
02281 prefix->buf,
02282 prefix->length);
02283 ccn_charbuf_destroy(&prefix);
02284 }
02285 }
02286 *p = next;
02287 free(f);
02288 f = NULL;
02289 continue;
02290 }
02291 f->expires -= CCN_FWU_SECS;
02292 if (f->expires <= 0)
02293 f->flags &= ~CCN_FORW_REFRESHED;
02294 p = &(f->next);
02295 }
02296 hashtb_next(e);
02297 }
02298 hashtb_end(e);
02299 h->forward_to_gen += 1;
02300 return(CCN_FWU_SECS*1000000);
02301 }
02302
02303
02304
02305
02306 static void
02307 age_forwarding_needed(struct ccnd_handle *h)
02308 {
02309 if (h->age_forwarding == NULL)
02310 h->age_forwarding = ccn_schedule_event(h->sched,
02311 CCN_FWU_SECS*1000000,
02312 age_forwarding,
02313 NULL, 0);
02314 }
02315
02316
02317
02318
02319 static struct ccn_forwarding *
02320 seek_forwarding(struct ccnd_handle *h,
02321 struct nameprefix_entry *npe, unsigned faceid)
02322 {
02323 struct ccn_forwarding *f;
02324
02325 for (f = npe->forwarding; f != NULL; f = f->next)
02326 if (f->faceid == faceid)
02327 return(f);
02328 f = calloc(1, sizeof(*f));
02329 if (f != NULL) {
02330 f->faceid = faceid;
02331 f->flags = (CCN_FORW_CHILD_INHERIT | CCN_FORW_ACTIVE);
02332 f->expires = 0x7FFFFFFF;
02333 f->next = npe->forwarding;
02334 npe->forwarding = f;
02335 }
02336 return(f);
02337 }
02338
02339
02340
02341
02342
02343
02344
02345
02346
02347
02348
02349
02350
02351
02352 static int
02353 ccnd_reg_prefix(struct ccnd_handle *h,
02354 const unsigned char *msg,
02355 struct ccn_indexbuf *comps,
02356 int ncomps,
02357 unsigned faceid,
02358 int flags,
02359 int expires)
02360 {
02361 struct hashtb_enumerator ee;
02362 struct hashtb_enumerator *e = ⅇ
02363 struct ccn_forwarding *f = NULL;
02364 struct nameprefix_entry *npe = NULL;
02365 int res;
02366 struct face *face = NULL;
02367
02368 if (flags >= 0 &&
02369 (flags & CCN_FORW_PUBMASK) != flags)
02370 return(-1);
02371 face = face_from_faceid(h, faceid);
02372 if (face == NULL)
02373 return(-1);
02374
02375 if (flags >= 0 && (flags & CCN_FORW_LAST) != 0)
02376 face->flags |= CCN_FACE_DC;
02377 hashtb_start(h->nameprefix_tab, e);
02378 res = nameprefix_seek(h, e, msg, comps, ncomps);
02379 if (res >= 0) {
02380 res = (res == HT_OLD_ENTRY) ? CCN_FORW_REFRESHED : 0;
02381 npe = e->data;
02382 f = seek_forwarding(h, npe, faceid);
02383 if (f != NULL) {
02384 h->forward_to_gen += 1;
02385 f->expires = expires;
02386 if (flags < 0)
02387 flags = f->flags & CCN_FORW_PUBMASK;
02388 f->flags = (CCN_FORW_REFRESHED | flags);
02389 res |= flags;
02390 if (h->debug & (2 | 4)) {
02391 struct ccn_charbuf *prefix = ccn_charbuf_create();
02392 struct ccn_charbuf *debugtag = ccn_charbuf_create();
02393 ccn_charbuf_putf(debugtag, "prefix,ff=%s%x",
02394 flags > 9 ? "0x" : "", flags);
02395 if (f->expires < (1 << 30))
02396 ccn_charbuf_putf(debugtag, ",sec=%d", expires);
02397 ccn_name_init(prefix);
02398 ccn_name_append_components(prefix, msg,
02399 comps->buf[0], comps->buf[ncomps]);
02400 ccnd_debug_ccnb(h, __LINE__,
02401 ccn_charbuf_as_string(debugtag),
02402 face,
02403 prefix->buf,
02404 prefix->length);
02405 ccn_charbuf_destroy(&prefix);
02406 ccn_charbuf_destroy(&debugtag);
02407 }
02408 }
02409 else
02410 res = -1;
02411 }
02412 hashtb_end(e);
02413 if (res >= 0)
02414 update_npe_children(h, npe, faceid);
02415 return(res);
02416 }
02417
02418
02419
02420
02421
02422 int
02423 ccnd_reg_uri(struct ccnd_handle *h,
02424 const char *uri,
02425 unsigned faceid,
02426 int flags,
02427 int expires)
02428 {
02429 struct ccn_charbuf *name;
02430 struct ccn_buf_decoder decoder;
02431 struct ccn_buf_decoder *d;
02432 struct ccn_indexbuf *comps;
02433 int res;
02434
02435 name = ccn_charbuf_create();
02436 ccn_name_init(name);
02437 res = ccn_name_from_uri(name, uri);
02438 if (res < 0)
02439 goto Bail;
02440 comps = ccn_indexbuf_create();
02441 d = ccn_buf_decoder_start(&decoder, name->buf, name->length);
02442 res = ccn_parse_Name(d, comps);
02443 if (res < 0)
02444 goto Bail;
02445 res = ccnd_reg_prefix(h, name->buf, comps, comps->n - 1,
02446 faceid, flags, expires);
02447 Bail:
02448 ccn_charbuf_destroy(&name);
02449 ccn_indexbuf_destroy(&comps);
02450 return(res);
02451 }
02452
02453
02454
02455
02456
02457 void
02458 ccnd_reg_uri_list(struct ccnd_handle *h,
02459 struct ccn_charbuf *uris,
02460 unsigned faceid,
02461 int flags,
02462 int expires)
02463 {
02464 size_t i;
02465 const char *s;
02466 s = ccn_charbuf_as_string(uris);
02467 for (i = 0; i + 1 < uris->length; i += strlen(s + i) + 1)
02468 ccnd_reg_uri(h, s + i, faceid, flags, expires);
02469 }
02470
02471
02472
02473
02474
02475 static void
02476 register_new_face(struct ccnd_handle *h, struct face *face)
02477 {
02478 if (face->faceid != 0 && (face->flags & (CCN_FACE_UNDECIDED | CCN_FACE_PASSIVE)) == 0) {
02479 ccnd_face_status_change(h, face->faceid);
02480 if (h->flood && h->autoreg != NULL && (face->flags & CCN_FACE_GG) == 0)
02481 ccnd_reg_uri_list(h, h->autoreg, face->faceid,
02482 CCN_FORW_CAPTURE_OK | CCN_FORW_CHILD_INHERIT | CCN_FORW_ACTIVE,
02483 0x7FFFFFFF);
02484 ccn_link_state_init(h, face);
02485 }
02486 }
02487
02488
02489
02490
02491
02492
02493 static int
02494 ccnd_nack(struct ccnd_handle *h, struct ccn_charbuf *reply_body,
02495 int errcode, const char *errtext)
02496 {
02497 int res;
02498 reply_body->length = 0;
02499 res = ccn_encode_StatusResponse(reply_body, errcode, errtext);
02500 if (res == 0)
02501 res = CCN_CONTENT_NACK;
02502 return(res);
02503 }
02504
02505
02506
02507
02508
02509
02510
02511
02512 static int
02513 check_ccndid(struct ccnd_handle *h,
02514 const void *p, size_t sz, struct ccn_charbuf *reply_body)
02515 {
02516 if (sz != sizeof(h->ccnd_id) || memcmp(p, h->ccnd_id, sz) != 0)
02517 return(ccnd_nack(h, reply_body, 531, "missing or incorrect ccndid"));
02518 return(0);
02519 }
02520
02521
02522
02523
02524 static int
02525 check_face_instance_ccndid(struct ccnd_handle *h,
02526 struct ccn_face_instance *f, struct ccn_charbuf *reply_body)
02527 {
02528 return(check_ccndid(h, f->ccnd_id, f->ccnd_id_size, reply_body));
02529 }
02530
02531
02532
02533
02534 static int
02535 check_forwarding_entry_ccndid(struct ccnd_handle *h,
02536 struct ccn_forwarding_entry *f, struct ccn_charbuf *reply_body)
02537 {
02538 return(check_ccndid(h, f->ccnd_id, f->ccnd_id_size, reply_body));
02539 }
02540
02541
02542
02543
02544
02545
02546
02547
02548
02549
02550
02551
02552
02553
02554
02555
02556
02557 int
02558 ccnd_req_newface(struct ccnd_handle *h,
02559 const unsigned char *msg, size_t size,
02560 struct ccn_charbuf *reply_body)
02561 {
02562 struct ccn_parsed_ContentObject pco = {0};
02563 int res;
02564 const unsigned char *req;
02565 size_t req_size;
02566 struct ccn_face_instance *face_instance = NULL;
02567 struct addrinfo hints = {0};
02568 struct addrinfo *addrinfo = NULL;
02569 int mcast;
02570 struct face *face = NULL;
02571 struct face *reqface = NULL;
02572 struct face *newface = NULL;
02573 int save;
02574 int nackallowed = 0;
02575
02576 save = h->flood;
02577 h->flood = 0;
02578 res = ccn_parse_ContentObject(msg, size, &pco, NULL);
02579 if (res < 0)
02580 goto Finish;
02581 res = ccn_content_get_value(msg, size, &pco, &req, &req_size);
02582 if (res < 0)
02583 goto Finish;
02584 res = -1;
02585 face_instance = ccn_face_instance_parse(req, req_size);
02586 if (face_instance == NULL || face_instance->action == NULL)
02587 goto Finish;
02588 if (strcmp(face_instance->action, "newface") != 0)
02589 goto Finish;
02590
02591 reqface = face_from_faceid(h, h->interest_faceid);
02592 if (reqface == NULL ||
02593 (reqface->flags & (CCN_FACE_LOOPBACK | CCN_FACE_LOCAL)) == 0)
02594 goto Finish;
02595 nackallowed = 1;
02596 res = check_face_instance_ccndid(h, face_instance, reply_body);
02597 if (res != 0)
02598 goto Finish;
02599 if (face_instance->descr.ipproto != IPPROTO_UDP &&
02600 face_instance->descr.ipproto != IPPROTO_TCP) {
02601 res = ccnd_nack(h, reply_body, 504, "parameter error");
02602 goto Finish;
02603 }
02604 if (face_instance->descr.address == NULL) {
02605 res = ccnd_nack(h, reply_body, 504, "parameter error");
02606 goto Finish;
02607 }
02608 if (face_instance->descr.port == NULL) {
02609 res = ccnd_nack(h, reply_body, 504, "parameter error");
02610 goto Finish;
02611 }
02612 if ((reqface->flags & CCN_FACE_GG) == 0) {
02613 res = ccnd_nack(h, reply_body, 430, "not authorized");
02614 goto Finish;
02615 }
02616 hints.ai_flags |= AI_NUMERICHOST;
02617 hints.ai_protocol = face_instance->descr.ipproto;
02618 hints.ai_socktype = (hints.ai_protocol == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
02619 res = getaddrinfo(face_instance->descr.address,
02620 face_instance->descr.port,
02621 &hints,
02622 &addrinfo);
02623 if (res != 0 || (h->debug & 128) != 0)
02624 ccnd_msg(h, "ccnd_req_newface from %u: getaddrinfo(%s, %s, ...) returned %d",
02625 h->interest_faceid,
02626 face_instance->descr.address,
02627 face_instance->descr.port,
02628 res);
02629 if (res != 0 || addrinfo == NULL) {
02630 res = ccnd_nack(h, reply_body, 501, "syntax error in address");
02631 goto Finish;
02632 }
02633 if (addrinfo->ai_next != NULL)
02634 ccnd_msg(h, "ccnd_req_newface: (addrinfo->ai_next != NULL) ? ?");
02635 if (face_instance->descr.ipproto == IPPROTO_UDP) {
02636 mcast = 0;
02637 if (addrinfo->ai_family == AF_INET) {
02638 face = face_from_faceid(h, h->ipv4_faceid);
02639 mcast = IN_MULTICAST(ntohl(((struct sockaddr_in *)(addrinfo->ai_addr))->sin_addr.s_addr));
02640 }
02641 else if (addrinfo->ai_family == AF_INET6) {
02642 face = face_from_faceid(h, h->ipv6_faceid);
02643 mcast = IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)addrinfo->ai_addr)->sin6_addr);
02644 }
02645 if (mcast)
02646 face = setup_multicast(h, face_instance,
02647 addrinfo->ai_addr,
02648 addrinfo->ai_addrlen);
02649 if (face == NULL) {
02650 res = ccnd_nack(h, reply_body, 453, "could not setup multicast");
02651 goto Finish;
02652 }
02653 newface = get_dgram_source(h, face,
02654 addrinfo->ai_addr,
02655 addrinfo->ai_addrlen,
02656 0);
02657 }
02658 else if (addrinfo->ai_socktype == SOCK_STREAM) {
02659 newface = make_connection(h,
02660 addrinfo->ai_addr,
02661 addrinfo->ai_addrlen,
02662 0);
02663 }
02664 if (newface != NULL) {
02665 newface->flags |= CCN_FACE_PERMANENT;
02666 face_instance->action = NULL;
02667 face_instance->ccnd_id = h->ccnd_id;
02668 face_instance->ccnd_id_size = sizeof(h->ccnd_id);
02669 face_instance->faceid = newface->faceid;
02670 face_instance->lifetime = 0x7FFFFFFF;
02671
02672
02673
02674
02675 if ((newface->flags & CCN_FACE_CONNECTING) != 0)
02676 face_instance->lifetime = 1;
02677 res = ccnb_append_face_instance(reply_body, face_instance);
02678 if (res > 0)
02679 res = 0;
02680 }
02681 else
02682 res = ccnd_nack(h, reply_body, 450, "could not create face");
02683 Finish:
02684 h->flood = save;
02685 ccn_face_instance_destroy(&face_instance);
02686 if (addrinfo != NULL)
02687 freeaddrinfo(addrinfo);
02688 return((nackallowed || res <= 0) ? res : -1);
02689 }
02690
02691
02692
02693
02694
02695
02696
02697
02698
02699
02700
02701
02702
02703
02704 int
02705 ccnd_req_destroyface(struct ccnd_handle *h,
02706 const unsigned char *msg, size_t size,
02707 struct ccn_charbuf *reply_body)
02708 {
02709 struct ccn_parsed_ContentObject pco = {0};
02710 int res;
02711 int at = 0;
02712 const unsigned char *req;
02713 size_t req_size;
02714 struct ccn_face_instance *face_instance = NULL;
02715 struct face *reqface = NULL;
02716 int nackallowed = 0;
02717
02718 res = ccn_parse_ContentObject(msg, size, &pco, NULL);
02719 if (res < 0) { at = __LINE__; goto Finish; }
02720 res = ccn_content_get_value(msg, size, &pco, &req, &req_size);
02721 if (res < 0) { at = __LINE__; goto Finish; }
02722 res = -1;
02723 face_instance = ccn_face_instance_parse(req, req_size);
02724 if (face_instance == NULL) { at = __LINE__; goto Finish; }
02725 if (face_instance->action == NULL) { at = __LINE__; goto Finish; }
02726
02727 reqface = face_from_faceid(h, h->interest_faceid);
02728 if (reqface == NULL) { at = __LINE__; goto Finish; }
02729 if ((reqface->flags & CCN_FACE_GG) == 0) { at = __LINE__; goto Finish; }
02730 nackallowed = 1;
02731 if (strcmp(face_instance->action, "destroyface") != 0)
02732 { at = __LINE__; goto Finish; }
02733 res = check_face_instance_ccndid(h, face_instance, reply_body);
02734 if (res != 0)
02735 { at = __LINE__; goto Finish; }
02736 if (face_instance->faceid == 0) { at = __LINE__; goto Finish; }
02737 res = ccnd_destroy_face(h, face_instance->faceid);
02738 if (res < 0) { at = __LINE__; goto Finish; }
02739 face_instance->action = NULL;
02740 face_instance->ccnd_id = h->ccnd_id;
02741 face_instance->ccnd_id_size = sizeof(h->ccnd_id);
02742 face_instance->lifetime = 0;
02743 res = ccnb_append_face_instance(reply_body, face_instance);
02744 if (res < 0) {
02745 at = __LINE__;
02746 }
02747 Finish:
02748 if (at != 0) {
02749 ccnd_msg(h, "ccnd_req_destroyface failed (line %d, res %d)", at, res);
02750 if (reqface == NULL || (reqface->flags & CCN_FACE_GG) == 0)
02751 res = -1;
02752 else
02753 res = ccnd_nack(h, reply_body, 450, "could not destroy face");
02754 }
02755 ccn_face_instance_destroy(&face_instance);
02756 return((nackallowed || res <= 0) ? res : -1);
02757 }
02758
02759
02760
02761
02762 static int
02763 ccnd_req_prefix_or_self_reg(struct ccnd_handle *h,
02764 const unsigned char *msg, size_t size, int selfreg,
02765 struct ccn_charbuf *reply_body)
02766 {
02767 struct ccn_parsed_ContentObject pco = {0};
02768 int res;
02769 const unsigned char *req;
02770 size_t req_size;
02771 struct ccn_forwarding_entry *forwarding_entry = NULL;
02772 struct face *face = NULL;
02773 struct face *reqface = NULL;
02774 struct ccn_indexbuf *comps = NULL;
02775 int nackallowed = 0;
02776
02777 res = ccn_parse_ContentObject(msg, size, &pco, NULL);
02778 if (res < 0)
02779 goto Finish;
02780 res = ccn_content_get_value(msg, size, &pco, &req, &req_size);
02781 if (res < 0)
02782 goto Finish;
02783 res = -1;
02784 forwarding_entry = ccn_forwarding_entry_parse(req, req_size);
02785 if (forwarding_entry == NULL || forwarding_entry->action == NULL)
02786 goto Finish;
02787
02788 reqface = face_from_faceid(h, h->interest_faceid);
02789 if (reqface == NULL)
02790 goto Finish;
02791 if ((reqface->flags & (CCN_FACE_GG | CCN_FACE_REGOK)) == 0)
02792 goto Finish;
02793 nackallowed = 1;
02794 if (selfreg) {
02795 if (strcmp(forwarding_entry->action, "selfreg") != 0)
02796 goto Finish;
02797 if (forwarding_entry->faceid == CCN_NOFACEID)
02798 forwarding_entry->faceid = h->interest_faceid;
02799 else if (forwarding_entry->faceid != h->interest_faceid)
02800 goto Finish;
02801 }
02802 else {
02803 if (strcmp(forwarding_entry->action, "prefixreg") != 0)
02804 goto Finish;
02805 }
02806 if (forwarding_entry->name_prefix == NULL)
02807 goto Finish;
02808 if (forwarding_entry->ccnd_id_size == sizeof(h->ccnd_id)) {
02809 if (memcmp(forwarding_entry->ccnd_id,
02810 h->ccnd_id, sizeof(h->ccnd_id)) != 0)
02811 goto Finish;
02812 }
02813 else if (forwarding_entry->ccnd_id_size != 0)
02814 goto Finish;
02815 face = face_from_faceid(h, forwarding_entry->faceid);
02816 if (face == NULL)
02817 goto Finish;
02818 if (forwarding_entry->lifetime < 0)
02819 forwarding_entry->lifetime = 2000000000;
02820 else if (forwarding_entry->lifetime > 3600 &&
02821 forwarding_entry->lifetime < (1 << 30))
02822 forwarding_entry->lifetime = 300;
02823 comps = ccn_indexbuf_create();
02824 res = ccn_name_split(forwarding_entry->name_prefix, comps);
02825 if (res < 0)
02826 goto Finish;
02827 res = ccnd_reg_prefix(h,
02828 forwarding_entry->name_prefix->buf, comps, res,
02829 face->faceid,
02830 forwarding_entry->flags,
02831 forwarding_entry->lifetime);
02832 if (res < 0)
02833 goto Finish;
02834 forwarding_entry->flags = res;
02835 forwarding_entry->action = NULL;
02836 forwarding_entry->ccnd_id = h->ccnd_id;
02837 forwarding_entry->ccnd_id_size = sizeof(h->ccnd_id);
02838 res = ccnb_append_forwarding_entry(reply_body, forwarding_entry);
02839 if (res > 0)
02840 res = 0;
02841 Finish:
02842 ccn_forwarding_entry_destroy(&forwarding_entry);
02843 ccn_indexbuf_destroy(&comps);
02844 if (nackallowed && res < 0)
02845 res = ccnd_nack(h, reply_body, 450, "could not register prefix");
02846 return((nackallowed || res <= 0) ? res : -1);
02847 }
02848
02849
02850
02851
02852
02853
02854
02855
02856
02857
02858
02859
02860
02861 int
02862 ccnd_req_prefixreg(struct ccnd_handle *h,
02863 const unsigned char *msg, size_t size,
02864 struct ccn_charbuf *reply_body)
02865 {
02866 return(ccnd_req_prefix_or_self_reg(h, msg, size, 0, reply_body));
02867 }
02868
02869
02870
02871
02872
02873
02874
02875
02876
02877
02878
02879
02880
02881 int
02882 ccnd_req_selfreg(struct ccnd_handle *h,
02883 const unsigned char *msg, size_t size,
02884 struct ccn_charbuf *reply_body)
02885 {
02886 return(ccnd_req_prefix_or_self_reg(h, msg, size, 1, reply_body));
02887 }
02888
02889
02890
02891
02892
02893
02894
02895
02896
02897
02898
02899
02900
02901 int
02902 ccnd_req_unreg(struct ccnd_handle *h,
02903 const unsigned char *msg, size_t size,
02904 struct ccn_charbuf *reply_body)
02905 {
02906 struct ccn_parsed_ContentObject pco = {0};
02907 int n_name_comp = 0;
02908 int res;
02909 const unsigned char *req;
02910 size_t req_size;
02911 size_t start;
02912 size_t stop;
02913 int found;
02914 struct ccn_forwarding_entry *forwarding_entry = NULL;
02915 struct face *face = NULL;
02916 struct face *reqface = NULL;
02917 struct ccn_indexbuf *comps = NULL;
02918 struct ccn_forwarding **p = NULL;
02919 struct ccn_forwarding *f = NULL;
02920 struct nameprefix_entry *npe = NULL;
02921 int nackallowed = 0;
02922
02923 res = ccn_parse_ContentObject(msg, size, &pco, NULL);
02924 if (res < 0)
02925 goto Finish;
02926 res = ccn_content_get_value(msg, size, &pco, &req, &req_size);
02927 if (res < 0)
02928 goto Finish;
02929 res = -1;
02930 forwarding_entry = ccn_forwarding_entry_parse(req, req_size);
02931
02932 reqface = face_from_faceid(h, h->interest_faceid);
02933 if (reqface == NULL || (reqface->flags & CCN_FACE_GG) == 0)
02934 goto Finish;
02935 nackallowed = 1;
02936 if (forwarding_entry == NULL || forwarding_entry->action == NULL)
02937 goto Finish;
02938 if (strcmp(forwarding_entry->action, "unreg") != 0)
02939 goto Finish;
02940 if (forwarding_entry->faceid == CCN_NOFACEID)
02941 goto Finish;
02942 if (forwarding_entry->name_prefix == NULL)
02943 goto Finish;
02944 res = check_forwarding_entry_ccndid(h, forwarding_entry, reply_body);
02945 if (res != 0)
02946 goto Finish;
02947 res = -1;
02948 face = face_from_faceid(h, forwarding_entry->faceid);
02949 if (face == NULL)
02950 goto Finish;
02951 comps = ccn_indexbuf_create();
02952 n_name_comp = ccn_name_split(forwarding_entry->name_prefix, comps);
02953 if (n_name_comp < 0)
02954 goto Finish;
02955 if (n_name_comp + 1 > comps->n)
02956 goto Finish;
02957 start = comps->buf[0];
02958 stop = comps->buf[n_name_comp];
02959 npe = hashtb_lookup(h->nameprefix_tab,
02960 forwarding_entry->name_prefix->buf + start,
02961 stop - start);
02962 if (npe == NULL)
02963 goto Finish;
02964 found = 0;
02965 p = &npe->forwarding;
02966 for (f = npe->forwarding; f != NULL; f = f->next) {
02967 if (f->faceid == forwarding_entry->faceid) {
02968 found = 1;
02969 if (h->debug & (2 | 4))
02970 ccnd_debug_ccnb(h, __LINE__, "prefix_unreg", face,
02971 forwarding_entry->name_prefix->buf,
02972 forwarding_entry->name_prefix->length);
02973 *p = f->next;
02974 free(f);
02975 f = NULL;
02976 h->forward_to_gen += 1;
02977 break;
02978 }
02979 p = &(f->next);
02980 }
02981 if (!found)
02982 goto Finish;
02983 forwarding_entry->action = NULL;
02984 forwarding_entry->ccnd_id = h->ccnd_id;
02985 forwarding_entry->ccnd_id_size = sizeof(h->ccnd_id);
02986 res = ccnb_append_forwarding_entry(reply_body, forwarding_entry);
02987 if (res > 0)
02988 res = 0;
02989 Finish:
02990 ccn_forwarding_entry_destroy(&forwarding_entry);
02991 ccn_indexbuf_destroy(&comps);
02992 if (nackallowed && res < 0)
02993 res = ccnd_nack(h, reply_body, 450, "could not unregister prefix");
02994 return((nackallowed || res <= 0) ? res : -1);
02995 }
02996
02997
02998
02999
03000
03001
03002
03003 static void
03004 update_forward_to(struct ccnd_handle *h, struct nameprefix_entry *npe)
03005 {
03006 struct ccn_indexbuf *x = NULL;
03007 struct ccn_indexbuf *tap = NULL;
03008 struct ccn_forwarding *f = NULL;
03009 struct nameprefix_entry *p = NULL;
03010 unsigned tflags;
03011 unsigned wantflags;
03012 unsigned moreflags;
03013 unsigned lastfaceid;
03014 unsigned namespace_flags;
03015
03016 x = npe->forward_to;
03017 if (x == NULL)
03018 npe->forward_to = x = ccn_indexbuf_create();
03019 else
03020 x->n = 0;
03021 wantflags = CCN_FORW_ACTIVE;
03022 lastfaceid = CCN_NOFACEID;
03023 namespace_flags = 0;
03024 for (p = npe; p != NULL; p = p->parent) {
03025 moreflags = CCN_FORW_CHILD_INHERIT;
03026 for (f = p->forwarding; f != NULL; f = f->next) {
03027 if (face_from_faceid(h, f->faceid) == NULL)
03028 continue;
03029
03030 tflags = f->flags ^ CCN_FORW_CAPTURE_OK;
03031 if ((tflags & wantflags) == wantflags) {
03032 if (h->debug & 32)
03033 ccnd_msg(h, "fwd.%d adding %u", __LINE__, f->faceid);
03034 ccn_indexbuf_set_insert(x, f->faceid);
03035 if ((f->flags & CCN_FORW_TAP) != 0) {
03036 if (tap == NULL)
03037 tap = ccn_indexbuf_create();
03038 ccn_indexbuf_set_insert(tap, f->faceid);
03039 }
03040 if ((f->flags & CCN_FORW_LAST) != 0)
03041 lastfaceid = f->faceid;
03042 }
03043 namespace_flags |= f->flags;
03044 if ((f->flags & CCN_FORW_CAPTURE) != 0)
03045 moreflags |= CCN_FORW_CAPTURE_OK;
03046 }
03047 wantflags |= moreflags;
03048 }
03049 if (lastfaceid != CCN_NOFACEID)
03050 ccn_indexbuf_move_to_end(x, lastfaceid);
03051 npe->flags = namespace_flags;
03052 npe->fgen = h->forward_to_gen;
03053 if (x->n == 0)
03054 ccn_indexbuf_destroy(&npe->forward_to);
03055 ccn_indexbuf_destroy(&npe->tap);
03056 npe->tap = tap;
03057 }
03058
03059
03060
03061
03062
03063
03064
03065
03066
03067
03068 static struct ccn_indexbuf *
03069 get_outbound_faces(struct ccnd_handle *h,
03070 struct face *from,
03071 const unsigned char *msg,
03072 struct ccn_parsed_interest *pi,
03073 struct nameprefix_entry *npe)
03074 {
03075 int checkmask = 0;
03076 int wantmask = 0;
03077 struct ccn_indexbuf *x;
03078 struct face *face;
03079 int i;
03080 int n;
03081 unsigned faceid;
03082
03083 while (npe->parent != NULL && npe->forwarding == NULL)
03084 npe = npe->parent;
03085 if (npe->fgen != h->forward_to_gen)
03086 update_forward_to(h, npe);
03087 x = ccn_indexbuf_create();
03088 if (pi->scope == 0 || npe->forward_to == NULL || npe->forward_to->n == 0)
03089 return(x);
03090 if ((npe->flags & CCN_FORW_LOCAL) != 0)
03091 checkmask = (from != NULL && (from->flags & CCN_FACE_GG) != 0) ? CCN_FACE_GG : (~0);
03092 else if (pi->scope == 1)
03093 checkmask = CCN_FACE_GG;
03094 else if (pi->scope == 2)
03095 checkmask = from ? (CCN_FACE_GG & ~(from->flags)) : ~0;
03096 wantmask = checkmask;
03097 if (wantmask == CCN_FACE_GG)
03098 checkmask |= CCN_FACE_DC;
03099 for (n = npe->forward_to->n, i = 0; i < n; i++) {
03100 faceid = npe->forward_to->buf[i];
03101 face = face_from_faceid(h, faceid);
03102 if (face != NULL && face != from &&
03103 ((face->flags & checkmask) == wantmask)) {
03104 if (h->debug & 32)
03105 ccnd_msg(h, "outbound.%d adding %u", __LINE__, face->faceid);
03106 ccn_indexbuf_append_element(x, face->faceid);
03107 }
03108 }
03109 return(x);
03110 }
03111
03112
03113
03114
03115 static int
03116 ie_next_usec(struct ccnd_handle *h, struct interest_entry *ie,
03117 ccn_wrappedtime *expiry)
03118 {
03119 struct pit_face_item *p;
03120 ccn_wrappedtime base;
03121 ccn_wrappedtime delta;
03122 ccn_wrappedtime mn;
03123 int ans;
03124 int debug = (h->debug & 32) != 0;
03125 const int horizon = 3 * WTHZ;
03126
03127 base = h->wtnow - horizon;
03128 mn = 600 * WTHZ + horizon;
03129 for (p = ie->pfl; p != NULL; p = p->next) {
03130 delta = p->expiry - base;
03131 if (delta >= 0x80000000)
03132 debug = 1;
03133 if (debug) {
03134 static const char fmt_ie_next_usec[] =
03135 "ie_next_usec.%d now%+d i=%u f=%04x %u "
03136 " %02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X";
03137 ccnd_msg(h, fmt_ie_next_usec, __LINE__,
03138 (int)delta - horizon, ie->serial, p->pfi_flags, p->faceid,
03139 p->nonce[0], p->nonce[1], p->nonce[2], p->nonce[3],
03140 p->nonce[4], p->nonce[5], p->nonce[6], p->nonce[7],
03141 p->nonce[8], p->nonce[9], p->nonce[10], p->nonce[11]);
03142 }
03143 if (delta < mn)
03144 mn = delta;
03145 }
03146 if (mn < horizon)
03147 mn = 0;
03148 else
03149 mn -= horizon;
03150 ans = mn * (1000000 / WTHZ);
03151 if (expiry != NULL) {
03152 *expiry = h->wtnow + mn;
03153 if (debug)
03154 ccnd_msg(h, "ie_next_usec.%d expiry=%x", __LINE__,
03155 (unsigned)*expiry);
03156 }
03157 if (debug)
03158 ccnd_msg(h, "ie_next_usec.%d %d usec", __LINE__, ans);
03159 return(ans);
03160 }
03161
03162
03163 static int
03164 append_tagged_binary_number(struct ccn_charbuf *cb, enum ccn_dtag dtag, uintmax_t val) {
03165 unsigned char buf[sizeof(val)];
03166 int pos;
03167 int res = 0;
03168 for (pos = sizeof(buf); val != 0 && pos > 0; val >>= 8)
03169 buf[--pos] = val & 0xff;
03170 res |= ccnb_append_tagged_blob(cb, dtag, buf+pos, sizeof(buf)-pos);
03171 return(res);
03172 }
03173
03174
03175
03176
03177
03178
03179
03180
03181 static struct pit_face_item *
03182 send_interest(struct ccnd_handle *h, struct interest_entry *ie,
03183 struct pit_face_item *x, struct pit_face_item *p)
03184 {
03185 struct face *face = NULL;
03186 struct ccn_charbuf *c = h->send_interest_scratch;
03187 const intmax_t default_life = CCN_INTEREST_LIFETIME_SEC << 12;
03188 intmax_t lifetime = default_life;
03189 ccn_wrappedtime delta;
03190 size_t noncesize;
03191
03192 face = face_from_faceid(h, p->faceid);
03193 if (face == NULL)
03194 return(p);
03195 h->interest_faceid = x->faceid;
03196 p = pfi_copy_nonce(h, ie, p, x);
03197 delta = x->expiry - x->renewed;
03198 lifetime = (intmax_t)delta * 4096 / WTHZ;
03199
03200 lifetime = (((lifetime + 511) >> 9) << 9);
03201 p->renewed = h->wtnow;
03202 p->expiry = h->wtnow + (lifetime * WTHZ / 4096);
03203 ccn_charbuf_reset(c);
03204 if (lifetime != default_life)
03205 append_tagged_binary_number(c, CCN_DTAG_InterestLifetime, lifetime);
03206 noncesize = p->pfi_flags & CCND_PFI_NONCESZ;
03207 if (noncesize != 0)
03208 ccnb_append_tagged_blob(c, CCN_DTAG_Nonce, p->nonce, noncesize);
03209 ccn_charbuf_append_closer(c);
03210 h->interests_sent += 1;
03211 p->pfi_flags |= CCND_PFI_UPENDING;
03212 p->pfi_flags &= ~(CCND_PFI_SENDUPST | CCND_PFI_UPHUNGRY);
03213 ccnd_meter_bump(h, face->meter[FM_INTO], 1);
03214 stuff_and_send(h, face, ie->interest_msg, ie->size - 1, c->buf, c->length, (h->debug & 2) ? "interest_to" : NULL, __LINE__);
03215 return(p);
03216 }
03217
03218
03219
03220
03221 struct nameprefix_entry *
03222 get_fib_npe(struct ccnd_handle *h, struct interest_entry *ie)
03223 {
03224 struct nameprefix_entry *npe;
03225
03226 for (npe = ie->ll.npe; npe != NULL; npe = npe->parent)
03227 if (npe->forwarding != NULL)
03228 return(npe);
03229 return(NULL);
03230 }
03231
03232
03233 static int
03234 strategy_timer(struct ccn_schedule *sched,
03235 void *clienth,
03236 struct ccn_scheduled_event *ev,
03237 int flags)
03238 {
03239 struct ccnd_handle *h = clienth;
03240 struct interest_entry *ie = ev->evdata;
03241 struct ccn_strategy *s = &ie->strategy;
03242
03243 if (s->ev == ev)
03244 s->ev = NULL;
03245 if (flags & CCN_SCHEDULE_CANCEL)
03246 return(0);
03247 strategy_callout(h, ie, (enum ccn_strategy_op)ev->evint);
03248 return(0);
03249 }
03250
03251
03252
03253
03254
03255
03256 static void
03257 strategy_settimer(struct ccnd_handle *h, struct interest_entry *ie,
03258 int usec, enum ccn_strategy_op op)
03259 {
03260 struct ccn_strategy *s = &ie->strategy;
03261
03262 if (s->ev != NULL)
03263 ccn_schedule_cancel(h->sched, s->ev);
03264 if (op == CCNST_NOP)
03265 return;
03266 s->ev = ccn_schedule_event(h->sched, usec, strategy_timer, ie, op);
03267 }
03268
03269
03270
03271
03272
03273
03274 static void
03275 strategy_callout(struct ccnd_handle *h,
03276 struct interest_entry *ie,
03277 enum ccn_strategy_op op)
03278 {
03279 struct pit_face_item *x = NULL;
03280 struct pit_face_item *p = NULL;
03281 struct nameprefix_entry *npe = NULL;
03282 struct ccn_indexbuf *tap = NULL;
03283 unsigned best = CCN_NOFACEID;
03284 unsigned randlow, randrange;
03285 unsigned nleft;
03286 unsigned amt;
03287 int usec;
03288 int usefirst;
03289
03290 switch (op) {
03291 case CCNST_NOP:
03292 break;
03293 case CCNST_FIRST:
03294
03295 npe = get_fib_npe(h, ie);
03296 if (npe != NULL)
03297 tap = npe->tap;
03298 npe = ie->ll.npe;
03299 best = npe->src;
03300 if (best == CCN_NOFACEID)
03301 best = npe->src = npe->osrc;
03302
03303 for (x = ie->pfl; x != NULL; x = x->next)
03304 if ((x->pfi_flags & CCND_PFI_DNSTREAM) != 0)
03305 break;
03306 if (x == NULL || (x->pfi_flags & CCND_PFI_PENDING) == 0) {
03307 ccnd_debug_ccnb(h, __LINE__, "canthappen", NULL,
03308 ie->interest_msg, ie->size);
03309 break;
03310 }
03311 if (best == CCN_NOFACEID || npe->usec > 150000) {
03312 usefirst = 1;
03313 randlow = 4000;
03314 randrange = 75000;
03315 }
03316 else {
03317 usefirst = 0;
03318 randlow = npe->usec;
03319 randrange = (randlow + 1) / 2;
03320 }
03321 nleft = 0;
03322 for (p = ie->pfl; p!= NULL; p = p->next) {
03323 if ((p->pfi_flags & CCND_PFI_UPSTREAM) != 0) {
03324 if (p->faceid == best) {
03325 p = send_interest(h, ie, x, p);
03326 strategy_settimer(h, ie, npe->usec, CCNST_TIMER);
03327 }
03328 else if (ccn_indexbuf_member(tap, p->faceid) >= 0)
03329 p = send_interest(h, ie, x, p);
03330 else if (usefirst) {
03331 usefirst = 0;
03332 pfi_set_expiry_from_micros(h, ie, p, 0);
03333 }
03334 else if (p->faceid == npe->osrc)
03335 pfi_set_expiry_from_micros(h, ie, p, randlow);
03336 else {
03337
03338 nleft++;
03339 p->pfi_flags |= CCND_PFI_SENDUPST;
03340 }
03341 }
03342 }
03343 if (nleft > 0) {
03344
03345 amt = (2 * randrange + nleft - 1) / nleft;
03346 if (amt == 0) amt = 1;
03347 usec = randlow;
03348 for (p = ie->pfl; p!= NULL; p = p->next) {
03349 if ((p->pfi_flags & CCND_PFI_SENDUPST) != 0) {
03350 pfi_set_expiry_from_micros(h, ie, p, usec);
03351 usec += nrand48(h->seed) % amt;
03352 }
03353 }
03354 }
03355 break;
03356 case CCNST_TIMER:
03357
03358
03359
03360
03361 adjust_predicted_response(h, ie, 1);
03362 break;
03363 case CCNST_SATISFIED:
03364 break;
03365 case CCNST_TIMEOUT:
03366 break;
03367 }
03368 }
03369
03370
03371
03372
03373 static int
03374 do_propagate(struct ccn_schedule *sched,
03375 void *clienth,
03376 struct ccn_scheduled_event *ev,
03377 int flags)
03378 {
03379 struct ccnd_handle *h = clienth;
03380 struct interest_entry *ie = ev->evdata;
03381 struct face *face = NULL;
03382 struct pit_face_item *p = NULL;
03383 struct pit_face_item *next = NULL;
03384 struct pit_face_item *d[3] = { NULL, NULL, NULL };
03385 ccn_wrappedtime now;
03386 int next_delay;
03387 int i;
03388 int n;
03389 int pending;
03390 int upstreams;
03391 unsigned life;
03392 unsigned mn;
03393 unsigned rem;
03394
03395 if (ie->ev == ev)
03396 ie->ev = NULL;
03397 if (flags & CCN_SCHEDULE_CANCEL)
03398 return(0);
03399 now = h->wtnow;
03400 mn = 600 * WTHZ;
03401 pending = 0;
03402 n = 0;
03403 for (p = ie->pfl; p != NULL; p = next) {
03404 next = p->next;
03405 if ((p->pfi_flags & CCND_PFI_DNSTREAM) != 0) {
03406 if (wt_compare(p->expiry, now) <= 0) {
03407 if (h->debug & 2)
03408 ccnd_debug_ccnb(h, __LINE__, "interest_expiry",
03409 face_from_faceid(h, p->faceid),
03410 ie->interest_msg, ie->size);
03411 pfi_destroy(h, ie, p);
03412 continue;
03413 }
03414 if ((p->pfi_flags & CCND_PFI_PENDING) == 0)
03415 continue;
03416 rem = p->expiry - now;
03417 if (rem < mn)
03418 mn = rem;
03419 pending++;
03420
03421 life = p->expiry - p->renewed;
03422 if (rem * 8 <= life)
03423 continue;
03424
03425 for (i = n; i > 0 && wt_compare(d[i-1]->expiry, p->expiry) < 0; i--)
03426 d[i] = d[i-1];
03427 d[i] = p;
03428 if (n < 2)
03429 n++;
03430 }
03431 }
03432
03433 upstreams = 0;
03434 for (p = ie->pfl; p != NULL; p = next) {
03435 next = p->next;
03436 if ((p->pfi_flags & CCND_PFI_UPSTREAM) == 0)
03437 continue;
03438 face = face_from_faceid(h, p->faceid);
03439 if (face == NULL || (face->flags & CCN_FACE_NOSEND) != 0) {
03440 pfi_destroy(h, ie, p);
03441 continue;
03442 }
03443 if ((face->flags & CCN_FACE_DC) != 0 &&
03444 (p->pfi_flags & CCND_PFI_DCFACE) == 0) {
03445
03446 p->expiry += (60 * WTHZ + 999) / 1000;
03447 p->pfi_flags |= CCND_PFI_DCFACE;
03448 }
03449 if (wt_compare(now + 1, p->expiry) < 0) {
03450
03451 rem = p->expiry - now;
03452 if (rem < mn)
03453 mn = rem;
03454 upstreams++;
03455 continue;
03456 }
03457 for (i = 0; i < n; i++)
03458 if (d[i]->faceid != p->faceid)
03459 break;
03460 if (i < n) {
03461 p = send_interest(h, ie, d[i], p);
03462 upstreams++;
03463 rem = p->expiry - now;
03464 if (rem < mn)
03465 mn = rem;
03466 }
03467 else {
03468
03469 p->pfi_flags |= CCND_PFI_UPHUNGRY;
03470 }
03471 }
03472 if (pending == 0 && upstreams == 0) {
03473 strategy_callout(h, ie, CCNST_TIMEOUT);
03474 consume_interest(h, ie);
03475 return(0);
03476 }
03477
03478 if (mn == 0) abort();
03479 next_delay = mn * (1000000 / WTHZ);
03480 ev->evint = h->wtnow + mn;
03481 ie->ev = ev;
03482 return(next_delay);
03483 }
03484
03485
03486
03487
03488
03489
03490
03491
03492
03493
03494
03495
03496
03497
03498
03499
03500
03501
03502
03503 static int
03504 ccnd_debug_nonce(struct ccnd_handle *h, struct face *face, unsigned char *s) {
03505 int i;
03506
03507 for (i = 0; i < 3; i++)
03508 s[i] = h->ccnd_id[i];
03509 s[i++] = h->logpid >> 8;
03510 s[i++] = h->logpid;
03511 s[i++] = face->faceid >> 8;
03512 s[i++] = face->faceid;
03513 s[i++] = h->sec;
03514 s[i++] = h->usec * 256 / 1000000;
03515 for (; i < TYPICAL_NONCE_SIZE; i++)
03516 s[i] = nrand48(h->seed);
03517 return(i);
03518 }
03519
03520
03521
03522
03523
03524
03525 static int
03526 ccnd_plain_nonce(struct ccnd_handle *h, struct face *face, unsigned char *s) {
03527 int noncebytes = 6;
03528 int i;
03529
03530 for (i = 0; i < noncebytes; i++)
03531 s[i] = nrand48(h->seed);
03532 return(i);
03533 }
03534
03535
03536
03537
03538
03539
03540 static int
03541 wt_compare(ccn_wrappedtime a, ccn_wrappedtime b)
03542 {
03543 ccn_wrappedtime delta = a - b;
03544 if (delta >= 0x80000000)
03545 return(-1);
03546 return(delta > 0);
03547 }
03548
03549
03550 static struct pit_face_item *
03551 pfi_create(struct ccnd_handle *h,
03552 unsigned faceid, unsigned flags,
03553 const unsigned char *nonce, size_t noncesize,
03554 struct pit_face_item **pp)
03555 {
03556 struct pit_face_item *p;
03557 size_t nsize = TYPICAL_NONCE_SIZE;
03558
03559 if (noncesize > CCND_PFI_NONCESZ) return(NULL);
03560 if (noncesize > nsize)
03561 nsize = noncesize;
03562 p = calloc(1, sizeof(*p) + nsize - TYPICAL_NONCE_SIZE);
03563 if (p == NULL) return(NULL);
03564 p->faceid = faceid;
03565 p->renewed = h->wtnow;
03566 p->expiry = h->wtnow;
03567 p->pfi_flags = (flags & ~CCND_PFI_NONCESZ) + noncesize;
03568 memcpy(p->nonce, nonce, noncesize);
03569 if (pp != NULL) {
03570 p->next = *pp;
03571 *pp = p;
03572 }
03573 return(p);
03574 }
03575
03576
03577 static void
03578 pfi_destroy(struct ccnd_handle *h, struct interest_entry *ie,
03579 struct pit_face_item *p)
03580 {
03581 struct face *face = NULL;
03582 struct pit_face_item **pp;
03583
03584 for (pp = &ie->pfl; *pp != p; pp = &(*pp)->next) {
03585 if (*pp == NULL) abort();
03586 }
03587 if ((p->pfi_flags & CCND_PFI_PENDING) != 0) {
03588 face = face_from_faceid(h, p->faceid);
03589 if (face != NULL)
03590 face->pending_interests -= 1;
03591 }
03592 *pp = p->next;
03593 free(p);
03594 }
03595
03596
03597
03598
03599
03600
03601
03602 static struct pit_face_item *
03603 pfi_seek(struct ccnd_handle *h, struct interest_entry *ie,
03604 unsigned faceid, unsigned pfi_flag)
03605 {
03606 struct pit_face_item *p;
03607 struct pit_face_item **pp;
03608
03609 for (pp = &ie->pfl, p = ie->pfl; p != NULL; pp = &p->next, p = p->next) {
03610 if (p->faceid == faceid && (p->pfi_flags & pfi_flag) != 0)
03611 return(p);
03612 }
03613 p = calloc(1, sizeof(*p));
03614 if (p != NULL) {
03615 p->faceid = faceid;
03616 p->pfi_flags = pfi_flag;
03617 p->expiry = h->wtnow;
03618 *pp = p;
03619 }
03620 return(p);
03621 }
03622
03623
03624
03625
03626
03627
03628
03629
03630 static void
03631 pfi_set_expiry_from_lifetime(struct ccnd_handle *h, struct interest_entry *ie,
03632 struct pit_face_item *p, intmax_t lifetime)
03633 {
03634 ccn_wrappedtime delta;
03635 ccn_wrappedtime odelta;
03636 int minlifetime = 4096 / 4;
03637 unsigned maxlifetime = 7 * 24 * 3600 * 4096U;
03638
03639 if (lifetime < minlifetime)
03640 lifetime = minlifetime;
03641 if (lifetime > maxlifetime)
03642 lifetime = maxlifetime;
03643 lifetime = (((lifetime + 511) >> 9) << 9);
03644 delta = ((uintmax_t)lifetime * WTHZ + 4095U) / 4096U;
03645 odelta = p->expiry - h->wtnow;
03646 if (delta < odelta && odelta < 0x80000000)
03647 ccnd_msg(h, "pfi_set_expiry_from_lifetime.%d Oops", __LINE__);
03648 p->renewed = h->wtnow;
03649 p->expiry = h->wtnow + delta;
03650 }
03651
03652
03653
03654
03655
03656
03657 static void
03658 pfi_set_expiry_from_micros(struct ccnd_handle *h, struct interest_entry *ie,
03659 struct pit_face_item *p, unsigned micros)
03660 {
03661 ccn_wrappedtime delta;
03662
03663 delta = (micros + (1000000 / WTHZ - 1)) / (1000000 / WTHZ);
03664 p->expiry = h->wtnow + delta;
03665 }
03666
03667
03668
03669
03670
03671
03672 static struct pit_face_item *
03673 pfi_set_nonce(struct ccnd_handle *h, struct interest_entry *ie,
03674 struct pit_face_item *p,
03675 const unsigned char *nonce, size_t noncesize)
03676 {
03677 struct pit_face_item *q = NULL;
03678 size_t nsize;
03679
03680 nsize = (p->pfi_flags & CCND_PFI_NONCESZ);
03681 if (noncesize != nsize) {
03682 if (noncesize > TYPICAL_NONCE_SIZE) {
03683
03684 q = pfi_create(h, p->faceid, p->pfi_flags,
03685 nonce, noncesize, &p->next);
03686 if (q != NULL) {
03687 q->renewed = p->renewed;
03688 q->expiry = p->expiry;
03689 p->pfi_flags = 0;
03690 pfi_destroy(h, ie, p);
03691 }
03692 return(q);
03693 }
03694 p->pfi_flags = (p->pfi_flags & ~CCND_PFI_NONCESZ) + noncesize;
03695 }
03696 memcpy(p->nonce, nonce, noncesize);
03697 return(p);
03698 }
03699
03700
03701
03702
03703 static int
03704 pfi_nonce_matches(struct pit_face_item *p,
03705 const unsigned char *nonce, size_t size)
03706 {
03707 if (p == NULL)
03708 return(0);
03709 if (size != (p->pfi_flags & CCND_PFI_NONCESZ))
03710 return(0);
03711 if (memcmp(nonce, p->nonce, size) != 0)
03712 return(0);
03713 return(1);
03714 }
03715
03716
03717
03718
03719
03720
03721 static struct pit_face_item *
03722 pfi_copy_nonce(struct ccnd_handle *h, struct interest_entry *ie,
03723 struct pit_face_item *p, const struct pit_face_item *src)
03724 {
03725 p = pfi_set_nonce(h, ie, p, src->nonce, src->pfi_flags & CCND_PFI_NONCESZ);
03726 return(p);
03727 }
03728
03729
03730
03731
03732 static int
03733 pfi_unique_nonce(struct ccnd_handle *h, struct interest_entry *ie,
03734 struct pit_face_item *p)
03735 {
03736 struct pit_face_item *q = NULL;
03737 size_t nsize;
03738
03739 if (p == NULL)
03740 return(1);
03741 nsize = (p->pfi_flags & CCND_PFI_NONCESZ);
03742 for (q = ie->pfl; q != NULL; q = q->next) {
03743 if (q != p && pfi_nonce_matches(q, p->nonce, nsize))
03744 return(0);
03745 }
03746 return(1);
03747 }
03748
03749
03750
03751
03752 static int
03753 propagate_interest(struct ccnd_handle *h,
03754 struct face *face,
03755 unsigned char *msg,
03756 struct ccn_parsed_interest *pi,
03757 struct nameprefix_entry *npe)
03758 {
03759 struct hashtb_enumerator ee;
03760 struct hashtb_enumerator *e = ⅇ
03761 struct pit_face_item *p = NULL;
03762 struct interest_entry *ie = NULL;
03763 struct ccn_indexbuf *outbound = NULL;
03764 const unsigned char *nonce;
03765 intmax_t lifetime;
03766 ccn_wrappedtime expiry;
03767 unsigned char cb[TYPICAL_NONCE_SIZE];
03768 size_t noncesize;
03769 unsigned faceid;
03770 int i;
03771 int res;
03772 int usec;
03773
03774 faceid = face->faceid;
03775 hashtb_start(h->interest_tab, e);
03776 res = hashtb_seek(e, msg, pi->offset[CCN_PI_B_InterestLifetime], 1);
03777 if (res < 0) goto Bail;
03778 ie = e->data;
03779 if (res == HT_NEW_ENTRY) {
03780 ie->serial = ++h->iserial;
03781 ie->strategy.birth = h->wtnow;
03782 ie->strategy.renewed = h->wtnow;
03783 ie->strategy.renewals = 0;
03784 }
03785 if (ie->interest_msg == NULL) {
03786 struct ccn_parsed_interest xpi = {0};
03787 int xres;
03788 link_interest_entry_to_nameprefix(h, ie, npe);
03789 ie->interest_msg = e->key;
03790 ie->size = pi->offset[CCN_PI_B_InterestLifetime] + 1;
03791
03792 ((unsigned char *)(intptr_t)ie->interest_msg)[ie->size - 1] = 0;
03793 xres = ccn_parse_interest(ie->interest_msg, ie->size, &xpi, NULL);
03794 if (xres < 0) abort();
03795 }
03796 lifetime = ccn_interest_lifetime(msg, pi);
03797 outbound = get_outbound_faces(h, face, msg, pi, npe);
03798 if (outbound == NULL) goto Bail;
03799 nonce = msg + pi->offset[CCN_PI_B_Nonce];
03800 noncesize = pi->offset[CCN_PI_E_Nonce] - pi->offset[CCN_PI_B_Nonce];
03801 if (noncesize != 0)
03802 ccn_ref_tagged_BLOB(CCN_DTAG_Nonce, msg,
03803 pi->offset[CCN_PI_B_Nonce],
03804 pi->offset[CCN_PI_E_Nonce],
03805 &nonce, &noncesize);
03806 else {
03807
03808 noncesize = (h->noncegen)(h, face, cb);
03809 nonce = cb;
03810 }
03811 p = pfi_seek(h, ie, faceid, CCND_PFI_DNSTREAM);
03812 p = pfi_set_nonce(h, ie, p, nonce, noncesize);
03813 if (nonce == cb || pfi_unique_nonce(h, ie, p)) {
03814 ie->strategy.renewed = h->wtnow;
03815 ie->strategy.renewals += 1;
03816 if ((p->pfi_flags & CCND_PFI_PENDING) == 0) {
03817 p->pfi_flags |= CCND_PFI_PENDING;
03818 face->pending_interests += 1;
03819 }
03820 }
03821 else {
03822
03823 p->pfi_flags |= CCND_PFI_SUPDATA;
03824 }
03825 pfi_set_expiry_from_lifetime(h, ie, p, lifetime);
03826 for (i = 0; i < outbound->n; i++) {
03827 p = pfi_seek(h, ie, outbound->buf[i], CCND_PFI_UPSTREAM);
03828 if (wt_compare(p->expiry, h->wtnow) < 0) {
03829 p->expiry = h->wtnow + 1;
03830 p->pfi_flags &= ~CCND_PFI_UPHUNGRY;
03831 }
03832 }
03833 if (res == HT_NEW_ENTRY)
03834 strategy_callout(h, ie, CCNST_FIRST);
03835 usec = ie_next_usec(h, ie, &expiry);
03836 if (ie->ev != NULL && wt_compare(expiry + 2, ie->ev->evint) < 0)
03837 ccn_schedule_cancel(h->sched, ie->ev);
03838 if (ie->ev == NULL)
03839 ie->ev = ccn_schedule_event(h->sched, usec, do_propagate, ie, expiry);
03840 Bail:
03841 hashtb_end(e);
03842 ccn_indexbuf_destroy(&outbound);
03843 return(res);
03844 }
03845
03846
03847
03848
03849 static void
03850 update_npe_children(struct ccnd_handle *h, struct nameprefix_entry *npe, unsigned faceid)
03851 {
03852 struct hashtb_enumerator ee;
03853 struct hashtb_enumerator *e = ⅇ
03854 struct face *fface = NULL;
03855 struct ccn_parsed_interest pi;
03856 struct pit_face_item *p = NULL;
03857 struct interest_entry *ie = NULL;
03858 struct nameprefix_entry *x = NULL;
03859 struct ccn_indexbuf *ob = NULL;
03860 int i;
03861 unsigned usec = 6000;
03862
03863 hashtb_start(h->interest_tab, e);
03864 for (ie = e->data; ie != NULL; ie = e->data) {
03865 for (x = ie->ll.npe; x != NULL; x = x->parent) {
03866 if (x == npe) {
03867 for (fface = NULL, p = ie->pfl; p != NULL; p = p->next) {
03868 if (p->faceid == faceid) {
03869 if ((p->pfi_flags & CCND_PFI_UPSTREAM) != 0) {
03870 fface = NULL;
03871 break;
03872 }
03873 }
03874 else if ((p->pfi_flags & CCND_PFI_DNSTREAM) != 0) {
03875 if (fface == NULL || (fface->flags & CCN_FACE_GG) == 0)
03876 fface = face_from_faceid(h, p->faceid);
03877 }
03878 }
03879 if (fface != NULL) {
03880 ccn_parse_interest(ie->interest_msg, ie->size, &pi, NULL);
03881 ob = get_outbound_faces(h, fface, ie->interest_msg,
03882 &pi, ie->ll.npe);
03883 for (i = 0; i < ob->n; i++) {
03884 if (ob->buf[i] == faceid) {
03885 p = pfi_seek(h, ie, faceid, CCND_PFI_UPSTREAM);
03886 if ((p->pfi_flags & CCND_PFI_UPENDING) == 0) {
03887 p->expiry = h->wtnow + usec / (1000000 / WTHZ);
03888 usec += 200;
03889 if (ie->ev != NULL && wt_compare(p->expiry + 4, ie->ev->evint) < 0)
03890 ccn_schedule_cancel(h->sched, ie->ev);
03891 if (ie->ev == NULL)
03892 ie->ev = ccn_schedule_event(h->sched, usec, do_propagate, ie, p->expiry);
03893 }
03894 break;
03895 }
03896 }
03897 ccn_indexbuf_destroy(&ob);
03898 }
03899 break;
03900 }
03901 }
03902 hashtb_next(e);
03903 }
03904 hashtb_end(e);
03905 }
03906
03907
03908
03909
03910
03911 static int
03912 nameprefix_seek(struct ccnd_handle *h, struct hashtb_enumerator *e,
03913 const unsigned char *msg, struct ccn_indexbuf *comps, int ncomps)
03914 {
03915 int i;
03916 int base;
03917 int res = -1;
03918 struct nameprefix_entry *parent = NULL;
03919 struct nameprefix_entry *npe = NULL;
03920 struct ielinks *head = NULL;
03921
03922 if (ncomps + 1 > comps->n)
03923 return(-1);
03924 base = comps->buf[0];
03925 for (i = 0; i <= ncomps; i++) {
03926 res = hashtb_seek(e, msg + base, comps->buf[i] - base, 0);
03927 if (res < 0)
03928 break;
03929 npe = e->data;
03930 if (res == HT_NEW_ENTRY) {
03931 head = &npe->ie_head;
03932 head->next = head;
03933 head->prev = head;
03934 head->npe = NULL;
03935 npe->parent = parent;
03936 npe->forwarding = NULL;
03937 npe->fgen = h->forward_to_gen - 1;
03938 npe->forward_to = NULL;
03939 if (parent != NULL) {
03940 parent->children++;
03941 npe->flags = parent->flags;
03942 npe->src = parent->src;
03943 npe->osrc = parent->osrc;
03944 npe->usec = parent->usec;
03945 }
03946 else {
03947 npe->src = npe->osrc = CCN_NOFACEID;
03948 npe->usec = (nrand48(h->seed) % 4096U) + 8192;
03949 }
03950 }
03951 parent = npe;
03952 }
03953 return(res);
03954 }
03955
03956
03957
03958 static struct content_entry *
03959 next_child_at_level(struct ccnd_handle *h,
03960 struct content_entry *content, int level)
03961 {
03962 struct content_entry *next = NULL;
03963 struct ccn_charbuf *name;
03964 struct ccn_indexbuf *pred[CCN_SKIPLIST_MAX_DEPTH] = {NULL};
03965 int d;
03966 int res;
03967
03968 if (content == NULL)
03969 return(NULL);
03970 if (content->ncomps <= level + 1)
03971 return(NULL);
03972 name = ccn_charbuf_create();
03973 ccn_name_init(name);
03974 res = ccn_name_append_components(name, content->key,
03975 content->comps[0],
03976 content->comps[level + 1]);
03977 if (res < 0) abort();
03978 res = ccn_name_next_sibling(name);
03979 if (res < 0) abort();
03980 if (h->debug & 8)
03981 ccnd_debug_ccnb(h, __LINE__, "child_successor", NULL,
03982 name->buf, name->length);
03983 d = content_skiplist_findbefore(h, name->buf, name->length,
03984 NULL, pred);
03985 next = content_from_accession(h, pred[0]->buf[0]);
03986 if (next == content) {
03987
03988 next = content_from_accession(h, content_skiplist_next(h, content));
03989 ccnd_debug_ccnb(h, __LINE__, "bump", NULL, next->key, next->size);
03990 }
03991 ccn_charbuf_destroy(&name);
03992 return(next);
03993 }
03994
03995
03996
03997
03998 static int
03999 drop_nonlocal_interest(struct ccnd_handle *h, struct nameprefix_entry *npe,
04000 struct face *face,
04001 unsigned char *msg, size_t size)
04002 {
04003 if (npe->fgen != h->forward_to_gen)
04004 update_forward_to(h, npe);
04005 if ((npe->flags & CCN_FORW_LOCAL) != 0 &&
04006 (face->flags & CCN_FACE_GG) == 0) {
04007 ccnd_debug_ccnb(h, __LINE__, "interest_nonlocal", face, msg, size);
04008 h->interests_dropped += 1;
04009 return (1);
04010 }
04011 return(0);
04012 }
04013
04014
04015
04016
04017
04018
04019
04020
04021
04022
04023
04024
04025
04026
04027
04028 static void
04029 process_incoming_interest(struct ccnd_handle *h, struct face *face,
04030 unsigned char *msg, size_t size)
04031 {
04032 struct hashtb_enumerator ee;
04033 struct hashtb_enumerator *e = ⅇ
04034 struct ccn_parsed_interest parsed_interest = {0};
04035 struct ccn_parsed_interest *pi = &parsed_interest;
04036 size_t namesize = 0;
04037 int k;
04038 int res;
04039 int try;
04040 int matched;
04041 int s_ok;
04042 struct interest_entry *ie = NULL;
04043 struct nameprefix_entry *npe = NULL;
04044 struct content_entry *content = NULL;
04045 struct content_entry *last_match = NULL;
04046 struct ccn_indexbuf *comps = indexbuf_obtain(h);
04047 if (size > 65535)
04048 res = -__LINE__;
04049 else
04050 res = ccn_parse_interest(msg, size, pi, comps);
04051 if (res < 0) {
04052 ccnd_msg(h, "error parsing Interest - code %d", res);
04053 ccn_indexbuf_destroy(&comps);
04054 return;
04055 }
04056 ccnd_meter_bump(h, face->meter[FM_INTI], 1);
04057 if (pi->scope >= 0 && pi->scope < 2 &&
04058 (face->flags & CCN_FACE_GG) == 0) {
04059 ccnd_debug_ccnb(h, __LINE__, "interest_outofscope", face, msg, size);
04060 h->interests_dropped += 1;
04061 }
04062 else {
04063 if (h->debug & (16 | 8 | 2))
04064 ccnd_debug_ccnb(h, __LINE__, "interest_from", face, msg, size);
04065 if (pi->magic < 20090701) {
04066 if (++(h->oldformatinterests) == h->oldformatinterestgrumble) {
04067 h->oldformatinterestgrumble *= 2;
04068 ccnd_msg(h, "downrev interests received: %d (%d)",
04069 h->oldformatinterests,
04070 pi->magic);
04071 }
04072 }
04073 namesize = comps->buf[pi->prefix_comps] - comps->buf[0];
04074 h->interests_accepted += 1;
04075 ie = hashtb_lookup(h->interest_tab, msg,
04076 pi->offset[CCN_PI_B_InterestLifetime]);
04077 if (ie != NULL) {
04078
04079 indexbuf_release(h, comps);
04080 comps = NULL;
04081 npe = ie->ll.npe;
04082 if (drop_nonlocal_interest(h, npe, face, msg, size))
04083 return;
04084 propagate_interest(h, face, msg, pi, npe);
04085 return;
04086 }
04087 if (h->debug & 16) {
04088
04089
04090 ccnd_msg(h,
04091 "version: %d, "
04092 "excl: %d bytes, "
04093 "etc: %d bytes",
04094 pi->magic,
04095 pi->offset[CCN_PI_E_Exclude] - pi->offset[CCN_PI_B_Exclude],
04096 pi->offset[CCN_PI_E_OTHER] - pi->offset[CCN_PI_B_OTHER]);
04097 }
04098 s_ok = (pi->answerfrom & CCN_AOK_STALE) != 0;
04099 matched = 0;
04100 hashtb_start(h->nameprefix_tab, e);
04101 res = nameprefix_seek(h, e, msg, comps, pi->prefix_comps);
04102 npe = e->data;
04103 if (npe == NULL || drop_nonlocal_interest(h, npe, face, msg, size))
04104 goto Bail;
04105 if ((pi->answerfrom & CCN_AOK_CS) != 0) {
04106 last_match = NULL;
04107 content = find_first_match_candidate(h, msg, pi);
04108 if (content != NULL && (h->debug & 8))
04109 ccnd_debug_ccnb(h, __LINE__, "first_candidate", NULL,
04110 content->key,
04111 content->size);
04112 if (content != NULL &&
04113 !content_matches_interest_prefix(h, content, msg, comps,
04114 pi->prefix_comps)) {
04115 if (h->debug & 8)
04116 ccnd_debug_ccnb(h, __LINE__, "prefix_mismatch", NULL,
04117 msg, size);
04118 content = NULL;
04119 }
04120 for (try = 0; content != NULL; try++) {
04121 if ((s_ok || (content->flags & CCN_CONTENT_ENTRY_STALE) == 0) &&
04122 ccn_content_matches_interest(content->key,
04123 content->size,
04124 0, NULL, msg, size, pi)) {
04125 if ((pi->orderpref & 1) == 0 &&
04126 pi->prefix_comps != comps->n - 1 &&
04127 comps->n == content->ncomps &&
04128 content_matches_interest_prefix(h, content, msg,
04129 comps, comps->n - 1)) {
04130 if (h->debug & 8)
04131 ccnd_debug_ccnb(h, __LINE__, "skip_match", NULL,
04132 content->key,
04133 content->size);
04134 goto move_along;
04135 }
04136 if (h->debug & 8)
04137 ccnd_debug_ccnb(h, __LINE__, "matches", NULL,
04138 content->key,
04139 content->size);
04140 if ((pi->orderpref & 1) == 0)
04141 break;
04142 last_match = content;
04143 content = next_child_at_level(h, content, comps->n - 1);
04144 goto check_next_prefix;
04145 }
04146 move_along:
04147 content = content_from_accession(h, content_skiplist_next(h, content));
04148 check_next_prefix:
04149 if (content != NULL &&
04150 !content_matches_interest_prefix(h, content, msg,
04151 comps, pi->prefix_comps)) {
04152 if (h->debug & 8)
04153 ccnd_debug_ccnb(h, __LINE__, "prefix_mismatch", NULL,
04154 content->key,
04155 content->size);
04156 content = NULL;
04157 }
04158 }
04159 if (last_match != NULL)
04160 content = last_match;
04161 if (content != NULL) {
04162
04163 enum cq_delay_class c;
04164 for (c = 0, k = -1; c < CCN_CQ_N && k == -1; c++)
04165 if (face->q[c] != NULL)
04166 k = ccn_indexbuf_member(face->q[c]->send_queue, content->accession);
04167 if (k == -1) {
04168 k = face_send_queue_insert(h, face, content);
04169 if (k >= 0) {
04170 if (h->debug & (32 | 8))
04171 ccnd_debug_ccnb(h, __LINE__, "consume", face, msg, size);
04172 }
04173
04174 match_interests(h, content, NULL, face, NULL);
04175 }
04176 if ((pi->answerfrom & CCN_AOK_EXPIRE) != 0)
04177 mark_stale(h, content);
04178 matched = 1;
04179 }
04180 }
04181 if (!matched && npe != NULL && (pi->answerfrom & CCN_AOK_EXPIRE) == 0)
04182 propagate_interest(h, face, msg, pi, npe);
04183 Bail:
04184 hashtb_end(e);
04185 }
04186 indexbuf_release(h, comps);
04187 }
04188
04189
04190
04191
04192 static void
04193 mark_stale(struct ccnd_handle *h, struct content_entry *content)
04194 {
04195 ccn_accession_t accession = content->accession;
04196 if ((content->flags & CCN_CONTENT_ENTRY_STALE) != 0)
04197 return;
04198 if (h->debug & 4)
04199 ccnd_debug_ccnb(h, __LINE__, "stale", NULL,
04200 content->key, content->size);
04201 content->flags |= CCN_CONTENT_ENTRY_STALE;
04202 h->n_stale++;
04203 if (accession < h->min_stale)
04204 h->min_stale = accession;
04205 if (accession > h->max_stale)
04206 h->max_stale = accession;
04207 }
04208
04209
04210
04211
04212
04213
04214
04215 static int
04216 expire_content(struct ccn_schedule *sched,
04217 void *clienth,
04218 struct ccn_scheduled_event *ev,
04219 int flags)
04220 {
04221 struct ccnd_handle *h = clienth;
04222 ccn_accession_t accession = ev->evint;
04223 struct content_entry *content = NULL;
04224 int res;
04225 unsigned n;
04226 if ((flags & CCN_SCHEDULE_CANCEL) != 0)
04227 return(0);
04228 content = content_from_accession(h, accession);
04229 if (content != NULL) {
04230 n = hashtb_n(h->content_tab);
04231
04232 if ((n - (n >> 3)) > h->capacity ||
04233 (n > h->capacity && h->min_stale > h->max_stale)) {
04234 res = remove_content(h, content);
04235 if (res == 0)
04236 return(0);
04237 }
04238 mark_stale(h, content);
04239 }
04240 return(0);
04241 }
04242
04243
04244
04245
04246
04247 static void
04248 set_content_timer(struct ccnd_handle *h, struct content_entry *content,
04249 struct ccn_parsed_ContentObject *pco)
04250 {
04251 int seconds = 0;
04252 int microseconds = 0;
04253 size_t start = pco->offset[CCN_PCO_B_FreshnessSeconds];
04254 size_t stop = pco->offset[CCN_PCO_E_FreshnessSeconds];
04255 if (h->force_zero_freshness) {
04256
04257 microseconds = 8 * h->data_pause_microsec + 10000;
04258 goto Finish;
04259 }
04260 if (start == stop)
04261 seconds = h->tts_default;
04262 else
04263 seconds = ccn_fetch_tagged_nonNegativeInteger(
04264 CCN_DTAG_FreshnessSeconds,
04265 content->key,
04266 start, stop);
04267 if (seconds <= 0 || (h->tts_limit > 0 && seconds > h->tts_limit))
04268 seconds = h->tts_limit;
04269 if (seconds <= 0)
04270 return;
04271 if (seconds > ((1U<<31) / 1000000)) {
04272 ccnd_debug_ccnb(h, __LINE__, "FreshnessSeconds_too_large", NULL,
04273 content->key, pco->offset[CCN_PCO_E]);
04274 return;
04275 }
04276 microseconds = seconds * 1000000;
04277 Finish:
04278 ccn_schedule_event(h->sched, microseconds,
04279 &expire_content, NULL, content->accession);
04280 }
04281
04282
04283
04284
04285
04286
04287
04288
04289
04290
04291
04292
04293
04294
04295
04296
04297
04298
04299
04300 static void
04301 process_incoming_content(struct ccnd_handle *h, struct face *face,
04302 unsigned char *wire_msg, size_t wire_size)
04303 {
04304 unsigned char *msg;
04305 size_t size;
04306 struct hashtb_enumerator ee;
04307 struct hashtb_enumerator *e = ⅇ
04308 struct ccn_parsed_ContentObject obj = {0};
04309 int res;
04310 size_t keysize = 0;
04311 size_t tailsize = 0;
04312 unsigned char *tail = NULL;
04313 struct content_entry *content = NULL;
04314 int i;
04315 struct ccn_indexbuf *comps = indexbuf_obtain(h);
04316 struct ccn_charbuf *cb = charbuf_obtain(h);
04317
04318 msg = wire_msg;
04319 size = wire_size;
04320
04321 res = ccn_parse_ContentObject(msg, size, &obj, comps);
04322 if (res < 0) {
04323 ccnd_msg(h, "error parsing ContentObject - code %d", res);
04324 goto Bail;
04325 }
04326 ccnd_meter_bump(h, face->meter[FM_DATI], 1);
04327 if (comps->n < 1 ||
04328 (keysize = comps->buf[comps->n - 1]) > 65535 - 36) {
04329 ccnd_msg(h, "ContentObject with keysize %lu discarded",
04330 (unsigned long)keysize);
04331 ccnd_debug_ccnb(h, __LINE__, "oversize", face, msg, size);
04332 res = -__LINE__;
04333 goto Bail;
04334 }
04335
04336 ccn_digest_ContentObject(msg, &obj);
04337 if (obj.digest_bytes != 32) {
04338 ccnd_debug_ccnb(h, __LINE__, "indigestible", face, msg, size);
04339 goto Bail;
04340 }
04341 i = comps->buf[comps->n - 1];
04342 ccn_charbuf_append(cb, msg, i);
04343 ccn_charbuf_append_tt(cb, CCN_DTAG_Component, CCN_DTAG);
04344 ccn_charbuf_append_tt(cb, obj.digest_bytes, CCN_BLOB);
04345 ccn_charbuf_append(cb, obj.digest, obj.digest_bytes);
04346 ccn_charbuf_append_closer(cb);
04347 ccn_charbuf_append(cb, msg + i, size - i);
04348 msg = cb->buf;
04349 size = cb->length;
04350 res = ccn_parse_ContentObject(msg, size, &obj, comps);
04351 if (res < 0) abort();
04352
04353 if (obj.magic != 20090415) {
04354 if (++(h->oldformatcontent) == h->oldformatcontentgrumble) {
04355 h->oldformatcontentgrumble *= 10;
04356 ccnd_msg(h, "downrev content items received: %d (%d)",
04357 h->oldformatcontent,
04358 obj.magic);
04359 }
04360 }
04361 if (h->debug & 4)
04362 ccnd_debug_ccnb(h, __LINE__, "content_from", face, msg, size);
04363 keysize = obj.offset[CCN_PCO_B_Content];
04364 tail = msg + keysize;
04365 tailsize = size - keysize;
04366 hashtb_start(h->content_tab, e);
04367 res = hashtb_seek(e, msg, keysize, tailsize);
04368 content = e->data;
04369 if (res == HT_OLD_ENTRY) {
04370 if (tailsize != e->extsize ||
04371 0 != memcmp(tail, ((unsigned char *)e->key) + keysize, tailsize)) {
04372 ccnd_msg(h, "ContentObject name collision!!!!!");
04373 ccnd_debug_ccnb(h, __LINE__, "new", face, msg, size);
04374 ccnd_debug_ccnb(h, __LINE__, "old", NULL, e->key, e->keysize + e->extsize);
04375 content = NULL;
04376 hashtb_delete(e);
04377 res = -__LINE__;
04378 }
04379 else if ((content->flags & CCN_CONTENT_ENTRY_STALE) != 0) {
04380
04381
04382 content->flags &= ~CCN_CONTENT_ENTRY_STALE;
04383 h->n_stale--;
04384 set_content_timer(h, content, &obj);
04385
04386 }
04387 else {
04388 h->content_dups_recvd++;
04389 ccnd_msg(h, "received duplicate ContentObject from %u (accession %llu)",
04390 face->faceid, (unsigned long long)content->accession);
04391 ccnd_debug_ccnb(h, __LINE__, "dup", face, msg, size);
04392 }
04393 }
04394 else if (res == HT_NEW_ENTRY) {
04395 content->accession = ++(h->accession);
04396 enroll_content(h, content);
04397 if (content == content_from_accession(h, content->accession)) {
04398 content->ncomps = comps->n;
04399 content->comps = calloc(comps->n, sizeof(comps[0]));
04400 if (content->comps == NULL) {
04401 ccnd_msg(h, "could not enroll ContentObject (accession %llu)",
04402 (unsigned long long)content->accession);
04403 content = NULL;
04404 hashtb_delete(e);
04405 res = -__LINE__;
04406 hashtb_end(e);
04407 goto Bail;
04408
04409 }
04410 }
04411 content->key_size = e->keysize;
04412 content->size = e->keysize + e->extsize;
04413 content->key = e->key;
04414 for (i = 0; i < comps->n; i++)
04415 content->comps[i] = comps->buf[i];
04416 content_skiplist_insert(h, content);
04417 set_content_timer(h, content, &obj);
04418
04419 if (obj.type == CCN_CONTENT_KEY && content->accession <= (h->capacity + 7)/8)
04420 content->flags |= CCN_CONTENT_ENTRY_PRECIOUS;
04421 }
04422 hashtb_end(e);
04423 Bail:
04424 indexbuf_release(h, comps);
04425 charbuf_release(h, cb);
04426 cb = NULL;
04427 if (res >= 0 && content != NULL) {
04428 int n_matches;
04429 enum cq_delay_class c;
04430 struct content_queue *q;
04431 n_matches = match_interests(h, content, &obj, NULL, face);
04432 if (res == HT_NEW_ENTRY) {
04433 if (n_matches < 0) {
04434 remove_content(h, content);
04435 return;
04436 }
04437 if (n_matches == 0 && (face->flags & CCN_FACE_GG) == 0) {
04438 content->flags |= CCN_CONTENT_ENTRY_SLOWSEND;
04439 ccn_indexbuf_append_element(h->unsol, content->accession);
04440 }
04441 }
04442
04443 for (c = 0; c < CCN_CQ_N; c++) {
04444 q = face->q[c];
04445 if (q != NULL) {
04446 i = ccn_indexbuf_member(q->send_queue, content->accession);
04447 if (i >= 0) {
04448
04449
04450
04451
04452 if (h->debug & 8)
04453 ccnd_debug_ccnb(h, __LINE__, "content_nosend", face, msg, size);
04454 q->send_queue->buf[i] = 0;
04455 }
04456 }
04457 }
04458 }
04459 }
04460
04461
04462
04463
04464
04465
04466
04467 static void
04468 process_input_message(struct ccnd_handle *h, struct face *face,
04469 unsigned char *msg, size_t size, int pdu_ok)
04470 {
04471 struct ccn_skeleton_decoder decoder = {0};
04472 struct ccn_skeleton_decoder *d = &decoder;
04473 ssize_t dres;
04474 enum ccn_dtag dtag;
04475
04476 if ((face->flags & CCN_FACE_UNDECIDED) != 0) {
04477 face->flags &= ~CCN_FACE_UNDECIDED;
04478 if ((face->flags & CCN_FACE_LOOPBACK) != 0)
04479 face->flags |= CCN_FACE_GG;
04480
04481 register_new_face(h, face);
04482 }
04483 d->state |= CCN_DSTATE_PAUSE;
04484 dres = ccn_skeleton_decode(d, msg, size);
04485 if (d->state < 0)
04486 abort();
04487 if (CCN_GET_TT_FROM_DSTATE(d->state) != CCN_DTAG) {
04488 ccnd_msg(h, "discarding unknown message; size = %lu", (unsigned long)size);
04489
04490 return;
04491 }
04492 dtag = d->numval;
04493 switch (dtag) {
04494 case CCN_DTAG_CCNProtocolDataUnit:
04495 if (!pdu_ok)
04496 break;
04497 size -= d->index;
04498 if (size > 0)
04499 size--;
04500 msg += d->index;
04501 if ((face->flags & (CCN_FACE_LINK | CCN_FACE_GG)) != CCN_FACE_LINK) {
04502 face->flags |= CCN_FACE_LINK;
04503 face->flags &= ~CCN_FACE_GG;
04504 register_new_face(h, face);
04505 }
04506 memset(d, 0, sizeof(*d));
04507 while (d->index < size) {
04508 dres = ccn_skeleton_decode(d, msg + d->index, size - d->index);
04509 if (d->state != 0)
04510 abort();
04511
04512 process_input_message(h, face, msg + d->index - dres, dres, 0);
04513 }
04514 return;
04515 case CCN_DTAG_Interest:
04516 process_incoming_interest(h, face, msg, size);
04517 return;
04518 case CCN_DTAG_ContentObject:
04519 process_incoming_content(h, face, msg, size);
04520 return;
04521 case CCN_DTAG_SequenceNumber:
04522 process_incoming_link_message(h, face, dtag, msg, size);
04523 return;
04524 default:
04525 break;
04526 }
04527 ccnd_msg(h, "discarding unknown message; dtag=%u, size = %lu",
04528 (unsigned)dtag,
04529 (unsigned long)size);
04530 }
04531
04532
04533
04534
04535 static void
04536 ccnd_new_face_msg(struct ccnd_handle *h, struct face *face)
04537 {
04538 const struct sockaddr *addr = face->addr;
04539 int port = 0;
04540 const unsigned char *rawaddr = NULL;
04541 char printable[80];
04542 const char *peer = NULL;
04543 if (addr->sa_family == AF_INET6) {
04544 const struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
04545 rawaddr = (const unsigned char *)&addr6->sin6_addr;
04546 port = htons(addr6->sin6_port);
04547 }
04548 else if (addr->sa_family == AF_INET) {
04549 const struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
04550 rawaddr = (const unsigned char *)&addr4->sin_addr.s_addr;
04551 port = htons(addr4->sin_port);
04552 }
04553 if (rawaddr != NULL)
04554 peer = inet_ntop(addr->sa_family, rawaddr, printable, sizeof(printable));
04555 if (peer == NULL)
04556 peer = "(unknown)";
04557 ccnd_msg(h,
04558 "accepted datagram client id=%d (flags=0x%x) %s port %d",
04559 face->faceid, face->flags, peer, port);
04560 }
04561
04562
04563
04564
04565
04566
04567
04568
04569
04570
04571
04572
04573
04574 static struct sockaddr *
04575 scrub_sockaddr(struct sockaddr *addr, socklen_t addrlen,
04576 struct sockaddr_in6 *space)
04577 {
04578 struct sockaddr_in6 *src;
04579 struct sockaddr_in6 *dst;
04580 if (addr->sa_family != AF_INET6 || addrlen != sizeof(*space))
04581 return(addr);
04582 dst = space;
04583 src = (void *)addr;
04584 memset(dst, 0, addrlen);
04585
04586 ((uint8_t *)dst)[0] = ((uint8_t *)src)[0];
04587 dst->sin6_family = src->sin6_family;
04588 dst->sin6_port = src->sin6_port;
04589 dst->sin6_addr = src->sin6_addr;
04590 dst->sin6_scope_id = src->sin6_scope_id;
04591 return((struct sockaddr *)dst);
04592 }
04593
04594
04595
04596
04597 static struct face *
04598 get_dgram_source(struct ccnd_handle *h, struct face *face,
04599 struct sockaddr *addr, socklen_t addrlen, int why)
04600 {
04601 struct face *source = NULL;
04602 struct hashtb_enumerator ee;
04603 struct hashtb_enumerator *e = ⅇ
04604 struct sockaddr_in6 space;
04605 int res;
04606 if ((face->flags & CCN_FACE_DGRAM) == 0)
04607 return(face);
04608 if ((face->flags & CCN_FACE_MCAST) != 0)
04609 return(face);
04610 hashtb_start(h->dgram_faces, e);
04611 res = hashtb_seek(e, scrub_sockaddr(addr, addrlen, &space), addrlen, 0);
04612 if (res >= 0) {
04613 source = e->data;
04614 source->recvcount++;
04615 if (source->addr == NULL) {
04616 source->addr = e->key;
04617 source->addrlen = e->keysize;
04618 source->recv_fd = face->recv_fd;
04619 source->sendface = face->faceid;
04620 init_face_flags(h, source, CCN_FACE_DGRAM);
04621 if (why == 1 && (source->flags & CCN_FACE_LOOPBACK) != 0)
04622 source->flags |= CCN_FACE_GG;
04623 res = enroll_face(h, source);
04624 if (res == -1) {
04625 hashtb_delete(e);
04626 source = NULL;
04627 }
04628 else
04629 ccnd_new_face_msg(h, source);
04630 }
04631 }
04632 hashtb_end(e);
04633 return(source);
04634 }
04635
04636
04637
04638
04639
04640
04641
04642
04643 static void
04644 process_input_buffer(struct ccnd_handle *h, struct face *face)
04645 {
04646 unsigned char *msg;
04647 size_t size;
04648 ssize_t dres;
04649 struct ccn_skeleton_decoder *d;
04650
04651 if (face == NULL || face->inbuf == NULL)
04652 return;
04653 d = &face->decoder;
04654 msg = face->inbuf->buf;
04655 size = face->inbuf->length;
04656 while (d->index < size) {
04657 dres = ccn_skeleton_decode(d, msg + d->index, size - d->index);
04658 if (d->state != 0)
04659 break;
04660 process_input_message(h, face, msg + d->index - dres, dres, 0);
04661 }
04662 if (d->index != size) {
04663 ccnd_msg(h, "protocol error on face %u (state %d), discarding %d bytes",
04664 face->faceid, d->state, (int)(size - d->index));
04665
04666 }
04667 face->inbuf->length = 0;
04668 memset(d, 0, sizeof(*d));
04669 }
04670
04671
04672
04673
04674
04675
04676
04677
04678
04679 static void
04680 process_input(struct ccnd_handle *h, int fd)
04681 {
04682 struct face *face = NULL;
04683 struct face *source = NULL;
04684 ssize_t res;
04685 ssize_t dres;
04686 ssize_t msgstart;
04687 unsigned char *buf;
04688 struct ccn_skeleton_decoder *d;
04689 struct sockaddr_storage sstor;
04690 socklen_t addrlen = sizeof(sstor);
04691 struct sockaddr *addr = (struct sockaddr *)&sstor;
04692 int err = 0;
04693 socklen_t err_sz;
04694
04695 face = hashtb_lookup(h->faces_by_fd, &fd, sizeof(fd));
04696 if (face == NULL)
04697 return;
04698 if ((face->flags & (CCN_FACE_DGRAM | CCN_FACE_PASSIVE)) == CCN_FACE_PASSIVE) {
04699 accept_connection(h, fd);
04700 check_comm_file(h);
04701 return;
04702 }
04703 err_sz = sizeof(err);
04704 res = getsockopt(face->recv_fd, SOL_SOCKET, SO_ERROR, &err, &err_sz);
04705 if (res >= 0 && err != 0) {
04706 ccnd_msg(h, "error on face %u: %s (%d)", face->faceid, strerror(err), err);
04707 if (err == ETIMEDOUT && (face->flags & CCN_FACE_CONNECTING) != 0) {
04708 shutdown_client_fd(h, fd);
04709 return;
04710 }
04711 }
04712 d = &face->decoder;
04713 if (face->inbuf == NULL)
04714 face->inbuf = ccn_charbuf_create();
04715 if (face->inbuf->length == 0)
04716 memset(d, 0, sizeof(*d));
04717 buf = ccn_charbuf_reserve(face->inbuf, 8800);
04718 memset(&sstor, 0, sizeof(sstor));
04719 res = recvfrom(face->recv_fd, buf, face->inbuf->limit - face->inbuf->length,
04720 0, addr, &addrlen);
04721 if (res == -1)
04722 ccnd_msg(h, "recvfrom face %u :%s (errno = %d)",
04723 face->faceid, strerror(errno), errno);
04724 else if (res == 0 && (face->flags & CCN_FACE_DGRAM) == 0)
04725 shutdown_client_fd(h, fd);
04726 else {
04727 source = get_dgram_source(h, face, addr, addrlen, (res == 1) ? 1 : 2);
04728 ccnd_meter_bump(h, source->meter[FM_BYTI], res);
04729 source->recvcount++;
04730 source->surplus = 0;
04731 if (res <= 1 && (source->flags & CCN_FACE_DGRAM) != 0) {
04732
04733 if (h->debug & 128)
04734 ccnd_msg(h, "%d-byte heartbeat on %d", (int)res, source->faceid);
04735 return;
04736 }
04737 face->inbuf->length += res;
04738 msgstart = 0;
04739 if (((face->flags & CCN_FACE_UNDECIDED) != 0 &&
04740 face->inbuf->length >= 6 &&
04741 0 == memcmp(face->inbuf->buf, "GET ", 4))) {
04742 ccnd_stats_handle_http_connection(h, face);
04743 return;
04744 }
04745 dres = ccn_skeleton_decode(d, buf, res);
04746 while (d->state == 0) {
04747 process_input_message(h, source,
04748 face->inbuf->buf + msgstart,
04749 d->index - msgstart,
04750 (face->flags & CCN_FACE_LOCAL) != 0);
04751 msgstart = d->index;
04752 if (msgstart == face->inbuf->length) {
04753 face->inbuf->length = 0;
04754 return;
04755 }
04756 dres = ccn_skeleton_decode(d,
04757 face->inbuf->buf + d->index,
04758 res = face->inbuf->length - d->index);
04759 }
04760 if ((face->flags & CCN_FACE_DGRAM) != 0) {
04761 ccnd_msg(h, "protocol error on face %u, discarding %u bytes",
04762 source->faceid,
04763 (unsigned)(face->inbuf->length));
04764 face->inbuf->length = 0;
04765
04766 return;
04767 }
04768 else if (d->state < 0) {
04769 ccnd_msg(h, "protocol error on face %u", source->faceid);
04770 shutdown_client_fd(h, fd);
04771 return;
04772 }
04773 if (msgstart < face->inbuf->length && msgstart > 0) {
04774
04775 memmove(face->inbuf->buf, face->inbuf->buf + msgstart,
04776 face->inbuf->length - msgstart);
04777 face->inbuf->length -= msgstart;
04778 d->index -= msgstart;
04779 }
04780 }
04781 }
04782
04783
04784
04785
04786
04787
04788 static void
04789 process_internal_client_buffer(struct ccnd_handle *h)
04790 {
04791 struct face *face = h->face0;
04792 if (face == NULL)
04793 return;
04794 face->inbuf = ccn_grab_buffered_output(h->internal_client);
04795 if (face->inbuf == NULL)
04796 return;
04797 ccnd_meter_bump(h, face->meter[FM_BYTI], face->inbuf->length);
04798 process_input_buffer(h, face);
04799 ccn_charbuf_destroy(&(face->inbuf));
04800 }
04801
04802
04803
04804
04805 static int
04806 process_icb_action(
04807 struct ccn_schedule *sched,
04808 void *clienth,
04809 struct ccn_scheduled_event *ev,
04810 int flags)
04811 {
04812 struct ccnd_handle *h = clienth;
04813
04814 if ((flags & CCN_SCHEDULE_CANCEL) != 0)
04815 return(0);
04816 process_internal_client_buffer(h);
04817 return(0);
04818 }
04819
04820
04821
04822
04823
04824
04825
04826 static void
04827 process_internal_client_buffer_needed(struct ccnd_handle *h)
04828 {
04829 ccn_schedule_event(h->sched, 0, process_icb_action, NULL, 0);
04830 }
04831
04832
04833
04834
04835
04836 static int
04837 handle_send_error(struct ccnd_handle *h, int errnum, struct face *face,
04838 const void *data, size_t size)
04839 {
04840 int res = -1;
04841 if (errnum == EAGAIN) {
04842 res = 0;
04843 }
04844 else if (errnum == EPIPE) {
04845 face->flags |= CCN_FACE_NOSEND;
04846 face->outbufindex = 0;
04847 ccn_charbuf_destroy(&face->outbuf);
04848 }
04849 else {
04850 ccnd_msg(h, "send to face %u failed: %s (errno = %d)",
04851 face->faceid, strerror(errnum), errnum);
04852 if (errnum == EISCONN)
04853 res = 0;
04854 }
04855 return(res);
04856 }
04857
04858
04859
04860
04861
04862
04863
04864
04865
04866
04867
04868
04869 static int
04870 sending_fd(struct ccnd_handle *h, struct face *face)
04871 {
04872 struct face *out = NULL;
04873 if (face->sendface == face->faceid)
04874 return(face->recv_fd);
04875 out = face_from_faceid(h, face->sendface);
04876 if (out != NULL)
04877 return(out->recv_fd);
04878 face->sendface = CCN_NOFACEID;
04879 if (face->addr != NULL) {
04880 switch (face->addr->sa_family) {
04881 case AF_INET:
04882 face->sendface = h->ipv4_faceid;
04883 break;
04884 case AF_INET6:
04885 face->sendface = h->ipv6_faceid;
04886 break;
04887 default:
04888 break;
04889 }
04890 }
04891 out = face_from_faceid(h, face->sendface);
04892 if (out != NULL)
04893 return(out->recv_fd);
04894 return(-1);
04895 }
04896
04897
04898
04899
04900
04901
04902 void
04903 ccnd_send(struct ccnd_handle *h,
04904 struct face *face,
04905 const void *data, size_t size)
04906 {
04907 ssize_t res;
04908 if ((face->flags & CCN_FACE_NOSEND) != 0)
04909 return;
04910 face->surplus++;
04911 if (face->outbuf != NULL) {
04912 ccn_charbuf_append(face->outbuf, data, size);
04913 return;
04914 }
04915 if (face == h->face0) {
04916 ccnd_meter_bump(h, face->meter[FM_BYTO], size);
04917 ccn_dispatch_message(h->internal_client, (void *)data, size);
04918 process_internal_client_buffer_needed(h);
04919 return;
04920 }
04921 if ((face->flags & CCN_FACE_DGRAM) == 0)
04922 res = send(face->recv_fd, data, size, 0);
04923 else
04924 res = sendto(sending_fd(h, face), data, size, 0,
04925 face->addr, face->addrlen);
04926 if (res > 0)
04927 ccnd_meter_bump(h, face->meter[FM_BYTO], res);
04928 if (res == size)
04929 return;
04930 if (res == -1) {
04931 res = handle_send_error(h, errno, face, data, size);
04932 if (res == -1)
04933 return;
04934 }
04935 if ((face->flags & CCN_FACE_DGRAM) != 0) {
04936 ccnd_msg(h, "sendto short");
04937 return;
04938 }
04939 face->outbufindex = 0;
04940 face->outbuf = ccn_charbuf_create();
04941 if (face->outbuf == NULL) {
04942 ccnd_msg(h, "do_write: %s", strerror(errno));
04943 return;
04944 }
04945 ccn_charbuf_append(face->outbuf,
04946 ((const unsigned char *)data) + res, size - res);
04947 }
04948
04949
04950
04951
04952
04953
04954 static void
04955 do_deferred_write(struct ccnd_handle *h, int fd)
04956 {
04957
04958 ssize_t res;
04959 struct face *face = hashtb_lookup(h->faces_by_fd, &fd, sizeof(fd));
04960 if (face == NULL)
04961 return;
04962 if (face->outbuf != NULL) {
04963 ssize_t sendlen = face->outbuf->length - face->outbufindex;
04964 if (sendlen > 0) {
04965 res = send(fd, face->outbuf->buf + face->outbufindex, sendlen, 0);
04966 if (res == -1) {
04967 if (errno == EPIPE) {
04968 face->flags |= CCN_FACE_NOSEND;
04969 face->outbufindex = 0;
04970 ccn_charbuf_destroy(&face->outbuf);
04971 return;
04972 }
04973 ccnd_msg(h, "send: %s (errno = %d)", strerror(errno), errno);
04974 shutdown_client_fd(h, fd);
04975 return;
04976 }
04977 if (res == sendlen) {
04978 face->outbufindex = 0;
04979 ccn_charbuf_destroy(&face->outbuf);
04980 if ((face->flags & CCN_FACE_CLOSING) != 0)
04981 shutdown_client_fd(h, fd);
04982 return;
04983 }
04984 face->outbufindex += res;
04985 return;
04986 }
04987 face->outbufindex = 0;
04988 ccn_charbuf_destroy(&face->outbuf);
04989 }
04990 if ((face->flags & CCN_FACE_CLOSING) != 0)
04991 shutdown_client_fd(h, fd);
04992 else if ((face->flags & CCN_FACE_CONNECTING) != 0) {
04993 face->flags &= ~CCN_FACE_CONNECTING;
04994 ccnd_face_status_change(h, face->faceid);
04995 }
04996 else
04997 ccnd_msg(h, "ccnd:do_deferred_write: something fishy on %d", fd);
04998 }
04999
05000
05001
05002
05003
05004
05005
05006
05007 static void
05008 prepare_poll_fds(struct ccnd_handle *h)
05009 {
05010 struct hashtb_enumerator ee;
05011 struct hashtb_enumerator *e = ⅇ
05012 int i, j, k;
05013 if (hashtb_n(h->faces_by_fd) != h->nfds) {
05014 h->nfds = hashtb_n(h->faces_by_fd);
05015 h->fds = realloc(h->fds, h->nfds * sizeof(h->fds[0]));
05016 memset(h->fds, 0, h->nfds * sizeof(h->fds[0]));
05017 }
05018 for (i = 0, k = h->nfds, hashtb_start(h->faces_by_fd, e);
05019 i < k && e->data != NULL; hashtb_next(e)) {
05020 struct face *face = e->data;
05021 if (face->flags & CCN_FACE_MCAST)
05022 j = i++;
05023 else
05024 j = --k;
05025 h->fds[j].fd = face->recv_fd;
05026 h->fds[j].events = ((face->flags & CCN_FACE_NORECV) == 0) ? POLLIN : 0;
05027 if ((face->outbuf != NULL || (face->flags & CCN_FACE_CLOSING) != 0))
05028 h->fds[j].events |= POLLOUT;
05029 }
05030 hashtb_end(e);
05031 if (i < k)
05032 abort();
05033 }
05034
05035
05036
05037
05038 void
05039 ccnd_run(struct ccnd_handle *h)
05040 {
05041 int i;
05042 int res;
05043 int timeout_ms = -1;
05044 int prev_timeout_ms = -1;
05045 int usec;
05046 for (h->running = 1; h->running;) {
05047 process_internal_client_buffer(h);
05048 usec = ccn_schedule_run(h->sched);
05049 timeout_ms = (usec < 0) ? -1 : ((usec + 960) / 1000);
05050 if (timeout_ms == 0 && prev_timeout_ms == 0)
05051 timeout_ms = 1;
05052 process_internal_client_buffer(h);
05053 prepare_poll_fds(h);
05054 if (0) ccnd_msg(h, "at ccnd.c:%d poll(h->fds, %d, %d)", __LINE__, h->nfds, timeout_ms);
05055 res = poll(h->fds, h->nfds, timeout_ms);
05056 prev_timeout_ms = ((res == 0) ? timeout_ms : 1);
05057 if (-1 == res) {
05058 ccnd_msg(h, "poll: %s (errno = %d)", strerror(errno), errno);
05059 sleep(1);
05060 continue;
05061 }
05062 if (res > 0) {
05063
05064 struct ccn_timeval dummy;
05065 h->ticktock.gettime(&h->ticktock, &dummy);
05066 }
05067 for (i = 0; res > 0 && i < h->nfds; i++) {
05068 if (h->fds[i].revents != 0) {
05069 res--;
05070 if (h->fds[i].revents & (POLLERR | POLLNVAL | POLLHUP)) {
05071 if (h->fds[i].revents & (POLLIN))
05072 process_input(h, h->fds[i].fd);
05073 else
05074 shutdown_client_fd(h, h->fds[i].fd);
05075 continue;
05076 }
05077 if (h->fds[i].revents & (POLLOUT))
05078 do_deferred_write(h, h->fds[i].fd);
05079 else if (h->fds[i].revents & (POLLIN))
05080 process_input(h, h->fds[i].fd);
05081 }
05082 }
05083 }
05084 }
05085
05086
05087
05088
05089 static void
05090 ccnd_reseed(struct ccnd_handle *h)
05091 {
05092 int fd;
05093 ssize_t res;
05094
05095 res = -1;
05096 fd = open("/dev/urandom", O_RDONLY);
05097 if (fd != -1) {
05098 res = read(fd, h->seed, sizeof(h->seed));
05099 close(fd);
05100 }
05101 if (res != sizeof(h->seed)) {
05102 h->seed[1] = (unsigned short)getpid();
05103 h->seed[2] = (unsigned short)time(NULL);
05104 }
05105
05106
05107
05108
05109 seed48(h->seed);
05110 }
05111
05112
05113
05114
05115
05116
05117
05118 static char *
05119 ccnd_get_local_sockname(void)
05120 {
05121 struct sockaddr_un sa;
05122 ccn_setup_sockaddr_un(NULL, &sa);
05123 return(strdup(sa.sun_path));
05124 }
05125
05126
05127
05128
05129
05130
05131 static void
05132 ccnd_gettime(const struct ccn_gettime *self, struct ccn_timeval *result)
05133 {
05134 struct ccnd_handle *h = self->data;
05135 struct timeval now = {0};
05136 long int sdelta;
05137 int udelta;
05138 ccn_wrappedtime delta;
05139
05140 gettimeofday(&now, 0);
05141 result->s = now.tv_sec;
05142 result->micros = now.tv_usec;
05143 sdelta = now.tv_sec - h->sec;
05144 udelta = now.tv_usec + h->sliver - h->usec;
05145 h->sec = now.tv_sec;
05146 h->usec = now.tv_usec;
05147 while (udelta < 0) {
05148 udelta += 1000000;
05149 sdelta -= 1;
05150 }
05151
05152 if (sdelta < 0)
05153 delta = 1;
05154 else if (sdelta >= (1U << 30) / WTHZ)
05155 delta = (1U << 30) / WTHZ;
05156 else {
05157 delta = (unsigned)udelta / (1000000U / WTHZ);
05158 h->sliver = udelta - delta * (1000000U / WTHZ);
05159 delta += (unsigned)sdelta * WTHZ;
05160 }
05161 h->wtnow += delta;
05162 }
05163
05164
05165
05166
05167
05168
05169 void
05170 ccnd_setsockopt_v6only(struct ccnd_handle *h, int fd)
05171 {
05172 int yes = 1;
05173 int res = 0;
05174 #ifdef IPV6_V6ONLY
05175 res = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes));
05176 #endif
05177 if (res == -1)
05178 ccnd_msg(h, "warning - could not set IPV6_V6ONLY on fd %d: %s",
05179 fd, strerror(errno));
05180 }
05181
05182
05183
05184
05185 static const char *
05186 af_name(int family)
05187 {
05188 switch (family) {
05189 case AF_INET:
05190 return("ipv4");
05191 case AF_INET6:
05192 return("ipv6");
05193 default:
05194 return("");
05195 }
05196 }
05197
05198
05199
05200
05201 static int
05202 ccnd_listen_on_wildcards(struct ccnd_handle *h)
05203 {
05204 int fd;
05205 int res;
05206 int whichpf;
05207 struct addrinfo hints = {0};
05208 struct addrinfo *addrinfo = NULL;
05209 struct addrinfo *a;
05210
05211 hints.ai_socktype = SOCK_DGRAM;
05212 hints.ai_flags = AI_PASSIVE;
05213 for (whichpf = 0; whichpf < 2; whichpf++) {
05214 hints.ai_family = whichpf ? PF_INET6 : PF_INET;
05215 res = getaddrinfo(NULL, h->portstr, &hints, &addrinfo);
05216 if (res == 0) {
05217 for (a = addrinfo; a != NULL; a = a->ai_next) {
05218 fd = socket(a->ai_family, SOCK_DGRAM, 0);
05219 if (fd != -1) {
05220 struct face *face = NULL;
05221 int yes = 1;
05222 int rcvbuf = 0;
05223 socklen_t rcvbuf_sz;
05224 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
05225 rcvbuf_sz = sizeof(rcvbuf);
05226 getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &rcvbuf_sz);
05227 if (a->ai_family == AF_INET6)
05228 ccnd_setsockopt_v6only(h, fd);
05229 res = bind(fd, a->ai_addr, a->ai_addrlen);
05230 if (res != 0) {
05231 close(fd);
05232 continue;
05233 }
05234 face = record_connection(h, fd,
05235 a->ai_addr, a->ai_addrlen,
05236 CCN_FACE_DGRAM | CCN_FACE_PASSIVE);
05237 if (face == NULL) {
05238 close(fd);
05239 continue;
05240 }
05241 if (a->ai_family == AF_INET)
05242 h->ipv4_faceid = face->faceid;
05243 else
05244 h->ipv6_faceid = face->faceid;
05245 ccnd_msg(h, "accepting %s datagrams on fd %d rcvbuf %d",
05246 af_name(a->ai_family), fd, rcvbuf);
05247 }
05248 }
05249 for (a = addrinfo; a != NULL; a = a->ai_next) {
05250 fd = socket(a->ai_family, SOCK_STREAM, 0);
05251 if (fd != -1) {
05252 int yes = 1;
05253 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
05254 if (a->ai_family == AF_INET6)
05255 ccnd_setsockopt_v6only(h, fd);
05256 res = bind(fd, a->ai_addr, a->ai_addrlen);
05257 if (res != 0) {
05258 close(fd);
05259 continue;
05260 }
05261 res = listen(fd, 30);
05262 if (res == -1) {
05263 close(fd);
05264 continue;
05265 }
05266 record_connection(h, fd,
05267 a->ai_addr, a->ai_addrlen,
05268 CCN_FACE_PASSIVE);
05269 ccnd_msg(h, "accepting %s connections on fd %d",
05270 af_name(a->ai_family), fd);
05271 }
05272 }
05273 freeaddrinfo(addrinfo);
05274 }
05275 }
05276 return(0);
05277 }
05278
05279
05280
05281
05282 static int
05283 ccnd_listen_on_address(struct ccnd_handle *h, const char *addr)
05284 {
05285 int fd;
05286 int res;
05287 struct addrinfo hints = {0};
05288 struct addrinfo *addrinfo = NULL;
05289 struct addrinfo *a;
05290 int ok = 0;
05291
05292 ccnd_msg(h, "listen_on %s", addr);
05293 hints.ai_socktype = SOCK_DGRAM;
05294 hints.ai_flags = AI_PASSIVE;
05295 res = getaddrinfo(addr, h->portstr, &hints, &addrinfo);
05296 if (res == 0) {
05297 for (a = addrinfo; a != NULL; a = a->ai_next) {
05298 fd = socket(a->ai_family, SOCK_DGRAM, 0);
05299 if (fd != -1) {
05300 struct face *face = NULL;
05301 int yes = 1;
05302 int rcvbuf = 0;
05303 socklen_t rcvbuf_sz;
05304 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
05305 rcvbuf_sz = sizeof(rcvbuf);
05306 getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &rcvbuf_sz);
05307 if (a->ai_family == AF_INET6)
05308 ccnd_setsockopt_v6only(h, fd);
05309 res = bind(fd, a->ai_addr, a->ai_addrlen);
05310 if (res != 0) {
05311 close(fd);
05312 continue;
05313 }
05314 face = record_connection(h, fd,
05315 a->ai_addr, a->ai_addrlen,
05316 CCN_FACE_DGRAM | CCN_FACE_PASSIVE);
05317 if (face == NULL) {
05318 close(fd);
05319 continue;
05320 }
05321 if (a->ai_family == AF_INET)
05322 h->ipv4_faceid = face->faceid;
05323 else
05324 h->ipv6_faceid = face->faceid;
05325 ccnd_msg(h, "accepting %s datagrams on fd %d rcvbuf %d",
05326 af_name(a->ai_family), fd, rcvbuf);
05327 ok++;
05328 }
05329 }
05330 for (a = addrinfo; a != NULL; a = a->ai_next) {
05331 fd = socket(a->ai_family, SOCK_STREAM, 0);
05332 if (fd != -1) {
05333 int yes = 1;
05334 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
05335 if (a->ai_family == AF_INET6)
05336 ccnd_setsockopt_v6only(h, fd);
05337 res = bind(fd, a->ai_addr, a->ai_addrlen);
05338 if (res != 0) {
05339 close(fd);
05340 continue;
05341 }
05342 res = listen(fd, 30);
05343 if (res == -1) {
05344 close(fd);
05345 continue;
05346 }
05347 record_connection(h, fd,
05348 a->ai_addr, a->ai_addrlen,
05349 CCN_FACE_PASSIVE);
05350 ccnd_msg(h, "accepting %s connections on fd %d",
05351 af_name(a->ai_family), fd);
05352 ok++;
05353 }
05354 }
05355 freeaddrinfo(addrinfo);
05356 }
05357 return(ok > 0 ? 0 : -1);
05358 }
05359
05360
05361
05362
05363
05364
05365 static int
05366 ccnd_listen_on(struct ccnd_handle *h, const char *addrs)
05367 {
05368 unsigned char ch;
05369 unsigned char dlm;
05370 int res = 0;
05371 int i;
05372 struct ccn_charbuf *addr = NULL;
05373
05374 if (addrs == NULL || !*addrs || 0 == strcmp(addrs, "*"))
05375 return(ccnd_listen_on_wildcards(h));
05376 addr = ccn_charbuf_create();
05377 for (i = 0, ch = addrs[i]; addrs[i] != 0;) {
05378 addr->length = 0;
05379 dlm = 0;
05380 if (ch == '[') {
05381 dlm = ']';
05382 ch = addrs[++i];
05383 }
05384 for (; ch > ' ' && ch != ',' && ch != ';' && ch != dlm; ch = addrs[++i])
05385 ccn_charbuf_append_value(addr, ch, 1);
05386 if (ch && ch == dlm)
05387 ch = addrs[++i];
05388 if (addr->length > 0) {
05389 res |= ccnd_listen_on_address(h, ccn_charbuf_as_string(addr));
05390 }
05391 while ((0 < ch && ch <= ' ') || ch == ',' || ch == ';')
05392 ch = addrs[++i];
05393 }
05394 ccn_charbuf_destroy(&addr);
05395 return(res);
05396 }
05397
05398
05399
05400
05401
05402
05403
05404
05405
05406
05407
05408 static struct ccn_charbuf *
05409 ccnd_parse_uri_list(struct ccnd_handle *h, const char *what, const char *uris)
05410 {
05411 struct ccn_charbuf *ans;
05412 struct ccn_charbuf *name;
05413 int i;
05414 size_t j;
05415 int res;
05416 unsigned char ch;
05417 const char *uri;
05418
05419 if (uris == NULL)
05420 return(NULL);
05421 ans = ccn_charbuf_create();
05422 name = ccn_charbuf_create();
05423 for (i = 0, ch = uris[0]; ch != 0;) {
05424 while ((0 < ch && ch <= ' ') || ch == ',' || ch == ';')
05425 ch = uris[++i];
05426 j = ans->length;
05427 while (ch > ' ' && ch != ',' && ch != ';') {
05428 ccn_charbuf_append_value(ans, ch, 1);
05429 ch = uris[++i];
05430 }
05431 if (j < ans->length) {
05432 ccn_charbuf_append_value(ans, 0, 1);
05433 uri = (const char *)ans->buf + j;
05434 name->length = 0;
05435 res = ccn_name_from_uri(name, uri);
05436 if (res < 0) {
05437 ccnd_msg(h, "%s: invalid ccnx URI: %s", what, uri);
05438 ans->length = j;
05439 }
05440 }
05441 }
05442 ccn_charbuf_destroy(&name);
05443 if (ans->length == 0)
05444 ccn_charbuf_destroy(&ans);
05445 return(ans);
05446 }
05447
05448
05449
05450
05451
05452
05453
05454 struct ccnd_handle *
05455 ccnd_create(const char *progname, ccnd_logger logger, void *loggerdata)
05456 {
05457 char *sockname;
05458 const char *portstr;
05459 const char *debugstr;
05460 const char *entrylimit;
05461 const char *mtu;
05462 const char *data_pause;
05463 const char *tts_default;
05464 const char *tts_limit;
05465 const char *autoreg;
05466 const char *listen_on;
05467 int fd;
05468 struct ccnd_handle *h;
05469 struct hashtb_param param = {0};
05470
05471 sockname = ccnd_get_local_sockname();
05472 h = calloc(1, sizeof(*h));
05473 if (h == NULL)
05474 return(h);
05475 h->logger = logger;
05476 h->loggerdata = loggerdata;
05477 h->noncegen = &ccnd_plain_nonce;
05478 h->logpid = (int)getpid();
05479 h->progname = progname;
05480 h->debug = -1;
05481 h->skiplinks = ccn_indexbuf_create();
05482 param.finalize_data = h;
05483 h->face_limit = 1024;
05484 h->faces_by_faceid = calloc(h->face_limit, sizeof(h->faces_by_faceid[0]));
05485 param.finalize = &finalize_face;
05486 h->faces_by_fd = hashtb_create(sizeof(struct face), ¶m);
05487 h->dgram_faces = hashtb_create(sizeof(struct face), ¶m);
05488 param.finalize = &finalize_content;
05489 h->content_tab = hashtb_create(sizeof(struct content_entry), ¶m);
05490 param.finalize = &finalize_nameprefix;
05491 h->nameprefix_tab = hashtb_create(sizeof(struct nameprefix_entry), ¶m);
05492 param.finalize = &finalize_interest;
05493 h->interest_tab = hashtb_create(sizeof(struct interest_entry), ¶m);
05494 param.finalize = 0;
05495 h->sparse_straggler_tab = hashtb_create(sizeof(struct sparse_straggler_entry), NULL);
05496 h->min_stale = ~0;
05497 h->max_stale = 0;
05498 h->send_interest_scratch = ccn_charbuf_create();
05499 h->unsol = ccn_indexbuf_create();
05500 h->ticktock.descr[0] = 'C';
05501 h->ticktock.micros_per_base = 1000000;
05502 h->ticktock.gettime = &ccnd_gettime;
05503 h->ticktock.data = h;
05504 h->sched = ccn_schedule_create(h, &h->ticktock);
05505 h->starttime = h->sec;
05506 h->starttime_usec = h->usec;
05507 h->wtnow = 0xFFFF0000;
05508 h->oldformatcontentgrumble = 1;
05509 h->oldformatinterestgrumble = 1;
05510 debugstr = getenv("CCND_DEBUG");
05511 if (debugstr != NULL && debugstr[0] != 0) {
05512 h->debug = atoi(debugstr);
05513 if (h->debug == 0 && debugstr[0] != '0')
05514 h->debug = 1;
05515 }
05516 else
05517 h->debug = 1;
05518 portstr = getenv(CCN_LOCAL_PORT_ENVNAME);
05519 if (portstr == NULL || portstr[0] == 0 || strlen(portstr) > 10)
05520 portstr = CCN_DEFAULT_UNICAST_PORT;
05521 h->portstr = portstr;
05522 entrylimit = getenv("CCND_CAP");
05523 h->capacity = ~0;
05524 if (entrylimit != NULL && entrylimit[0] != 0) {
05525 h->capacity = atol(entrylimit);
05526 if (h->capacity == 0)
05527 h->force_zero_freshness = 1;
05528 if (h->capacity <= 0)
05529 h->capacity = 10;
05530 }
05531 ccnd_msg(h, "CCND_DEBUG=%d CCND_CAP=%lu", h->debug, h->capacity);
05532 h->mtu = 0;
05533 mtu = getenv("CCND_MTU");
05534 if (mtu != NULL && mtu[0] != 0) {
05535 h->mtu = atol(mtu);
05536 if (h->mtu < 0)
05537 h->mtu = 0;
05538 if (h->mtu > 8800)
05539 h->mtu = 8800;
05540 }
05541 h->data_pause_microsec = 10000;
05542 data_pause = getenv("CCND_DATA_PAUSE_MICROSEC");
05543 if (data_pause != NULL && data_pause[0] != 0) {
05544 h->data_pause_microsec = atol(data_pause);
05545 if (h->data_pause_microsec == 0)
05546 h->data_pause_microsec = 1;
05547 if (h->data_pause_microsec > 1000000)
05548 h->data_pause_microsec = 1000000;
05549 }
05550 h->tts_default = -1;
05551 tts_default = getenv("CCND_DEFAULT_TIME_TO_STALE");
05552 if (tts_default != NULL && tts_default[0] != 0) {
05553 h->tts_default = atoi(tts_default);
05554 if (h->tts_default <= 0)
05555 h->tts_default = -1;
05556 ccnd_msg(h, "CCND_DEFAULT_TIME_TO_STALE=%d", h->tts_default);
05557 }
05558 h->tts_limit = ~0U;
05559 tts_limit = getenv("CCND_MAX_TIME_TO_STALE");
05560 if (tts_limit != NULL && tts_limit[0] != 0) {
05561 h->tts_limit = atoi(tts_limit);
05562 if (h->tts_limit <= 0)
05563 h->tts_limit = -1;
05564 else if (h->tts_limit > ((1U<<31) / 1000000))
05565 h->tts_limit = (1U<<31) / 1000000;
05566 ccnd_msg(h, "CCND_MAX_TIME_TO_STALE=%d", h->tts_limit);
05567 }
05568 listen_on = getenv("CCND_LISTEN_ON");
05569 autoreg = getenv("CCND_AUTOREG");
05570
05571 if (autoreg != NULL && autoreg[0] != 0) {
05572 h->autoreg = ccnd_parse_uri_list(h, "CCND_AUTOREG", autoreg);
05573 if (h->autoreg != NULL)
05574 ccnd_msg(h, "CCND_AUTOREG=%s", autoreg);
05575 }
05576 if (listen_on != NULL && listen_on[0] != 0)
05577 ccnd_msg(h, "CCND_LISTEN_ON=%s", listen_on);
05578
05579 h->noncegen = &ccnd_debug_nonce;
05580
05581 ccnd_init_internal_keystore(h);
05582 ccnd_reseed(h);
05583 if (h->face0 == NULL) {
05584 struct face *face;
05585 face = calloc(1, sizeof(*face));
05586 face->recv_fd = -1;
05587 face->sendface = 0;
05588 face->flags = (CCN_FACE_GG | CCN_FACE_LOCAL);
05589 h->face0 = face;
05590 }
05591 enroll_face(h, h->face0);
05592 fd = create_local_listener(h, sockname, 42);
05593 if (fd == -1)
05594 ccnd_msg(h, "%s: %s", sockname, strerror(errno));
05595 else
05596 ccnd_msg(h, "listening on %s", sockname);
05597 h->flood = (h->autoreg != NULL);
05598 h->ipv4_faceid = h->ipv6_faceid = CCN_NOFACEID;
05599 ccnd_listen_on(h, listen_on);
05600 clean_needed(h);
05601 reap_needed(h, 55000);
05602 age_forwarding_needed(h);
05603 ccnd_internal_client_start(h);
05604 free(sockname);
05605 sockname = NULL;
05606 return(h);
05607 }
05608
05609
05610
05611
05612 static void
05613 ccnd_shutdown_listeners(struct ccnd_handle *h)
05614 {
05615 struct hashtb_enumerator ee;
05616 struct hashtb_enumerator *e = ⅇ
05617 for (hashtb_start(h->faces_by_fd, e); e->data != NULL;) {
05618 struct face *face = e->data;
05619 if ((face->flags & (CCN_FACE_MCAST | CCN_FACE_PASSIVE)) != 0)
05620 hashtb_delete(e);
05621 else
05622 hashtb_next(e);
05623 }
05624 hashtb_end(e);
05625 }
05626
05627
05628
05629
05630 void
05631 ccnd_destroy(struct ccnd_handle **pccnd)
05632 {
05633 struct ccnd_handle *h = *pccnd;
05634 if (h == NULL)
05635 return;
05636 ccnd_shutdown_listeners(h);
05637 ccnd_internal_client_stop(h);
05638 ccn_schedule_destroy(&h->sched);
05639 hashtb_destroy(&h->dgram_faces);
05640 hashtb_destroy(&h->faces_by_fd);
05641 hashtb_destroy(&h->content_tab);
05642 hashtb_destroy(&h->interest_tab);
05643 hashtb_destroy(&h->nameprefix_tab);
05644 hashtb_destroy(&h->sparse_straggler_tab);
05645 if (h->fds != NULL) {
05646 free(h->fds);
05647 h->fds = NULL;
05648 h->nfds = 0;
05649 }
05650 if (h->faces_by_faceid != NULL) {
05651 free(h->faces_by_faceid);
05652 h->faces_by_faceid = NULL;
05653 h->face_limit = h->face_gen = 0;
05654 }
05655 if (h->content_by_accession != NULL) {
05656 free(h->content_by_accession);
05657 h->content_by_accession = NULL;
05658 h->content_by_accession_window = 0;
05659 }
05660 ccn_charbuf_destroy(&h->send_interest_scratch);
05661 ccn_charbuf_destroy(&h->scratch_charbuf);
05662 ccn_charbuf_destroy(&h->autoreg);
05663 ccn_indexbuf_destroy(&h->skiplinks);
05664 ccn_indexbuf_destroy(&h->scratch_indexbuf);
05665 ccn_indexbuf_destroy(&h->unsol);
05666 if (h->face0 != NULL) {
05667 ccn_charbuf_destroy(&h->face0->inbuf);
05668 ccn_charbuf_destroy(&h->face0->outbuf);
05669 free(h->face0);
05670 h->face0 = NULL;
05671 }
05672 free(h);
05673 *pccnd = NULL;
05674 }