00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <assert.h>
00021 #include <stdint.h>
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025
00026 #include <ccn/bloom.h>
00027 #include <ccn/ccn.h>
00028 #include <ccn/charbuf.h>
00029 #include <ccn/uri.h>
00030
00031
00032
00033
00034
00035
00036
00037 struct ccn_traversal {
00038 int magic;
00039 long *counter;
00040 unsigned warn;
00041 int flags;
00042 int n_excl;
00043 struct ccn_charbuf **excl;
00044
00045 };
00046
00047 #define EXCLUDE_LOW 1
00048 #define EXCLUDE_HIGH 2
00049 #define MUST_VERIFY 4
00050 #define LOCAL_SCOPE 8
00051 #define ALLOW_STALE 0x10
00052
00053
00054 static int namecompare(const void *a, const void *b);
00055 static struct ccn_traversal *get_my_data(struct ccn_closure *selfp);
00056 static void append_Any_filter(struct ccn_charbuf *c);
00057 static int express_my_interest(struct ccn *h,
00058 struct ccn_closure *selfp,
00059 struct ccn_charbuf *name);
00060 static struct ccn_closure *split_my_excludes(struct ccn_closure *selfp);
00061 static enum ccn_upcall_res incoming_content(struct ccn_closure *selfp,
00062 enum ccn_upcall_kind kind,
00063 struct ccn_upcall_info *);
00064 static struct ccn_charbuf *ccn_charbuf_duplicate(struct ccn_charbuf *);
00065 static void answer_passive(struct ccn_charbuf *templ, int allow_stale);
00066 static void local_scope(struct ccn_charbuf *templ);
00067
00068
00069
00070
00071
00072
00073
00074 static int
00075 namecompare(const void *a, const void *b)
00076 {
00077 const struct ccn_charbuf *aa = *(const struct ccn_charbuf **)a;
00078 const struct ccn_charbuf *bb = *(const struct ccn_charbuf **)b;
00079 int ans = ccn_compare_names(aa->buf, aa->length, bb->buf, bb->length);
00080 if (ans == 0)
00081 abort();
00082 return (ans);
00083 }
00084
00085 static struct ccn_traversal *get_my_data(struct ccn_closure *selfp)
00086 {
00087 struct ccn_traversal *data = selfp->data;
00088 if (data->magic != 68955871) abort();
00089 return(data);
00090 }
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 static enum ccn_upcall_res
00125 incoming_content(
00126 struct ccn_closure *selfp,
00127 enum ccn_upcall_kind kind,
00128 struct ccn_upcall_info *info)
00129 {
00130 struct ccn_charbuf *c = NULL;
00131 struct ccn_charbuf *comp = NULL;
00132 struct ccn_charbuf *uri = NULL;
00133 const unsigned char *ccnb = NULL;
00134 size_t ccnb_size = 0;
00135 struct ccn_indexbuf *comps = NULL;
00136 int matched_comps = 0;
00137 int res;
00138 int i;
00139 struct ccn_traversal *data = get_my_data(selfp);
00140
00141 if (kind == CCN_UPCALL_FINAL) {
00142 for (i = 0; i < data->n_excl; i++)
00143 ccn_charbuf_destroy(&(data->excl[i]));
00144 if (data->excl != NULL)
00145 free(data->excl);
00146 free(data);
00147 free(selfp);
00148 return(0);
00149 }
00150 if (kind == CCN_UPCALL_INTEREST_TIMED_OUT)
00151 return(0);
00152 if (kind == CCN_UPCALL_CONTENT_BAD)
00153 return(0);
00154 if (kind == CCN_UPCALL_CONTENT_UNVERIFIED) {
00155 if ((data->flags & MUST_VERIFY) != 0)
00156 return(CCN_UPCALL_RESULT_VERIFY);
00157 }
00158 if (kind != CCN_UPCALL_CONTENT && kind != CCN_UPCALL_CONTENT_UNVERIFIED) abort();
00159
00160 ccnb = info->content_ccnb;
00161 ccnb_size = info->pco->offset[CCN_PCO_E];
00162 comps = info->content_comps;
00163 matched_comps = info->pi->prefix_comps;
00164 c = ccn_charbuf_create();
00165 uri = ccn_charbuf_create();
00166
00167 if (matched_comps + 1 > comps->n) {
00168 ccn_uri_append(c, ccnb, ccnb_size, 1);
00169 fprintf(stderr, "How did this happen? %s\n", ccn_charbuf_as_string(uri));
00170 exit(1);
00171 }
00172
00173 data->counter[0]++;
00174
00175
00176 ccn_name_init(c);
00177 ccn_name_append_components(c, ccnb, comps->buf[0], comps->buf[matched_comps]);
00178
00179 comp = ccn_charbuf_create();
00180 ccn_name_init(comp);
00181 if (matched_comps + 1 == comps->n) {
00182
00183 ccn_digest_ContentObject(ccnb, info->pco);
00184 ccn_name_append(comp, info->pco->digest, info->pco->digest_bytes);
00185 }
00186 else {
00187 ccn_name_append_components(comp, ccnb,
00188 comps->buf[matched_comps],
00189 comps->buf[matched_comps + 1]);
00190 }
00191 data->excl = realloc(data->excl, (data->n_excl + 1) * sizeof(data->excl[0]));
00192 data->excl[data->n_excl++] = comp;
00193 comp = NULL;
00194 qsort(data->excl, data->n_excl, sizeof(data->excl[0]), &namecompare);
00195 res = express_my_interest(info->h, selfp, c);
00196 if (res == -1) {
00197 struct ccn_closure *high = split_my_excludes(selfp);
00198 if (high == NULL) abort();
00199 express_my_interest(info->h, selfp, c);
00200 express_my_interest(info->h, high, c);
00201 }
00202
00203 if (matched_comps + 2 < comps->n) {
00204 struct ccn_traversal *newdat = NULL;
00205 struct ccn_closure *cl;
00206 newdat = calloc(1, sizeof(*newdat));
00207 newdat->magic = 68955871;
00208 newdat->warn = 1492;
00209 newdat->counter = data->counter;
00210 newdat->flags = data->flags & ~(EXCLUDE_LOW | EXCLUDE_HIGH);
00211 newdat->n_excl = 0;
00212 newdat->excl = NULL;
00213 cl = calloc(1, sizeof(*cl));
00214 cl->p = &incoming_content;
00215 cl->data = newdat;
00216 ccn_name_init(c);
00217 ccn_name_append_components(c, ccnb,
00218 comps->buf[0],
00219 comps->buf[matched_comps + 1]);
00220 express_my_interest(info->h, cl, c);
00221 }
00222 else {
00223 res = ccn_uri_append(uri, info->content_ccnb, info->pco->offset[CCN_PCO_E], 1);
00224 if (res < 0)
00225 fprintf(stderr, "*** Error: ccn_traverse line %d res=%d\n", __LINE__, res);
00226 else
00227 printf("%s\n", ccn_charbuf_as_string(uri));
00228 }
00229 ccn_charbuf_destroy(&c);
00230 ccn_charbuf_destroy(&uri);
00231 return(0);
00232 }
00233
00234
00235
00236
00237
00238 static int
00239 express_my_interest(struct ccn *h,
00240 struct ccn_closure *selfp,
00241 struct ccn_charbuf *name)
00242 {
00243 int ans;
00244 struct ccn_charbuf *templ = NULL;
00245 int i;
00246 struct ccn_traversal *data = get_my_data(selfp);
00247
00248 templ = ccn_charbuf_create();
00249 ccn_charbuf_append_tt(templ, CCN_DTAG_Interest, CCN_DTAG);
00250 ccn_charbuf_append_tt(templ, CCN_DTAG_Name, CCN_DTAG);
00251 ccn_charbuf_append_closer(templ);
00252 if (data->n_excl != 0) {
00253 ccn_charbuf_append_tt(templ, CCN_DTAG_Exclude, CCN_DTAG);
00254 if ((data->flags & EXCLUDE_LOW) != 0)
00255 append_Any_filter(templ);
00256 for (i = 0; i < data->n_excl; i++) {
00257 struct ccn_charbuf *comp = data->excl[i];
00258 if (comp->length < 4) abort();
00259 ccn_charbuf_append(templ, comp->buf + 1, comp->length - 2);
00260 }
00261 if ((data->flags & EXCLUDE_HIGH) != 0)
00262 append_Any_filter(templ);
00263 ccn_charbuf_append_closer(templ);
00264 }
00265 answer_passive(templ, (data->flags & ALLOW_STALE) != 0);
00266 if ((data->flags & LOCAL_SCOPE) != 0)
00267 local_scope(templ);
00268 ccn_charbuf_append_closer(templ);
00269 if (templ->length + name->length > data->warn + 2) {
00270 fprintf(stderr, "*** Interest packet is %d bytes\n", (int)templ->length);
00271 data->warn = data->warn * 8 / 5;
00272 }
00273 if (templ->length + name->length > 1450 && data->n_excl > 3)
00274 ans = -1;
00275 else {
00276 ccn_express_interest(h, name, selfp, templ);
00277 ans = 0;
00278 }
00279 ccn_charbuf_destroy(&templ);
00280 return(ans);
00281 }
00282
00283
00284
00285
00286
00287 static struct ccn_closure *
00288 split_my_excludes(struct ccn_closure *selfp)
00289 {
00290 int i;
00291 int m;
00292 struct ccn_traversal *newdat = NULL;
00293 struct ccn_closure *cl;
00294 struct ccn_traversal *data = get_my_data(selfp);
00295
00296 if (data->n_excl < 3)
00297 return NULL;
00298 m = data->n_excl / 2;
00299 newdat = calloc(1, sizeof(*newdat));
00300 newdat->magic = 68955871;
00301 newdat->warn = 1492;
00302 newdat->counter = data->counter;
00303 newdat->n_excl = data->n_excl - m;
00304 newdat->excl = calloc(newdat->n_excl, sizeof(newdat->excl[0]));
00305 if (newdat->excl == NULL) {
00306 free(newdat);
00307 return(NULL);
00308 }
00309 newdat->excl[0] = ccn_charbuf_duplicate(data->excl[m]);
00310 newdat->flags = data->flags | EXCLUDE_LOW;
00311 for (i = 1; i < newdat->n_excl; i++) {
00312 newdat->excl[i] = data->excl[m + i];
00313 data->excl[m + i] = NULL;
00314 }
00315 data->n_excl = m + 1;
00316 data->flags |= EXCLUDE_HIGH;
00317 cl = calloc(1, sizeof(*cl));
00318 cl->p = &incoming_content;
00319 cl->data = newdat;
00320 return(cl);
00321 }
00322
00323
00324
00325
00326
00327 static void
00328 append_Any_filter(struct ccn_charbuf *c)
00329 {
00330 ccn_charbuf_append_tt(c, CCN_DTAG_Any, CCN_DTAG);
00331 ccn_charbuf_append_closer(c);
00332 }
00333
00334 static struct ccn_charbuf *
00335 ccn_charbuf_duplicate(struct ccn_charbuf *c)
00336 {
00337 struct ccn_charbuf *ans = ccn_charbuf_create();
00338 ccn_charbuf_append(ans, c->buf, c->length);
00339 return(ans);
00340 }
00341
00342
00343
00344
00345
00346 static void
00347 answer_passive(struct ccn_charbuf *templ, int allow_stale)
00348 {
00349 int aok = CCN_AOK_CS;
00350 if (allow_stale)
00351 aok |= CCN_AOK_STALE;
00352 ccnb_tagged_putf(templ, CCN_DTAG_AnswerOriginKind, "%d", aok);
00353 }
00354
00355
00356
00357
00358
00359 static void
00360 local_scope(struct ccn_charbuf *templ)
00361 {
00362 ccn_charbuf_append_tt(templ, CCN_DTAG_Scope, CCN_DTAG);
00363 ccn_charbuf_append_tt(templ, 1, CCN_UDATA);
00364 ccn_charbuf_append(templ, "0", 1);
00365 ccn_charbuf_append_closer(templ);
00366 }
00367
00368
00369
00370
00371
00372 void
00373 ccn_dump_names(struct ccn *h, struct ccn_charbuf *name_prefix, int local_scope, int allow_stale)
00374 {
00375 long *counter;
00376 int i;
00377 long n;
00378 int res;
00379 struct ccn_traversal *data = NULL;
00380 struct ccn_closure *cl = NULL;
00381
00382 counter = calloc(1, sizeof(*counter));
00383 data = calloc(1, sizeof(*data));
00384 data->magic = 68955871;
00385 data->warn = 1492;
00386 data->flags = 0;
00387 data->counter = counter;
00388 if (local_scope)
00389 data->flags |= LOCAL_SCOPE;
00390 if (allow_stale)
00391 data->flags |= ALLOW_STALE;
00392
00393 cl = calloc(1, sizeof(*cl));
00394 cl->p = &incoming_content;
00395 cl->data = data;
00396
00397 express_my_interest(h, cl, name_prefix);
00398 cl = NULL;
00399 data = NULL;
00400 for (i = 0;; i++) {
00401 n = *counter;
00402 res = ccn_run(h, 1000);
00403 fflush(stdout);
00404 if (*counter == n || res < 0)
00405 break;
00406 }
00407 exit(0);
00408 }