ccn_sync.c

Go to the documentation of this file.
00001 /**
00002  * @file csrc/ccn_sync.c
00003  *
00004  * Sync library interface.
00005  * Implements a library interface to the Sync protocol facilities implemented
00006  * by the Repository
00007  *
00008  * Part of the CCNx C Library.
00009  *
00010  * Copyright (C) 2012 Palo Alto Research Center, Inc.
00011  *
00012  * This library is free software; you can redistribute it and/or modify it
00013  * under the terms of the GNU Lesser General Public License version 2.1
00014  * as published by the Free Software Foundation.
00015  * This library is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * Lesser General Public License for more details. You should have received
00019  * a copy of the GNU Lesser General Public License along with this library;
00020  * if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
00021  * Fifth Floor, Boston, MA 02110-1301 USA.
00022  */
00023 
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 #include <string.h>
00027 #include <sys/time.h>
00028 #include <ccn/ccn.h>
00029 #include <ccn/coding.h>
00030 #include <ccn/digest.h>
00031 #include <ccn/sync.h>
00032 #include <ccn/uri.h>
00033 
00034 #include <sync/SyncActions.h>
00035 #include <sync/SyncNode.h>
00036 #include <sync/SyncPrivate.h>
00037 #include <sync/SyncTreeWorker.h>
00038 
00039 #define CCNL_NONE       0   /**< No logging at all */
00040 #define CCNL_SEVERE     3   /**< Severe errors */
00041 #define CCNL_ERROR      5   /**< Configuration errors */
00042 #define CCNL_WARNING    7   /**< Something might be wrong */
00043 #define CCNL_INFO       9   /**< Low-volume informational */
00044 #define CCNL_FINE      11   /**< Debugging */
00045 #define CCNL_FINER     13   /**< More debugging */
00046 #define CCNL_FINEST    15   /**< MORE DEBUGGING YET */
00047 
00048 #define CACHE_PURGE_TRIGGER 60     // cache entry purge, in seconds
00049 #define CACHE_CLEAN_BATCH 16       // seconds between cleaning batches
00050 #define CACHE_CLEAN_DELTA 8        // cache clean batch size
00051 #define ADVISE_NEED_RESET 1        // reset value for adviseNeed
00052 #define UPDATE_STALL_DELTA 15      // seconds used to determine stalled update
00053 #define UPDATE_NEED_DELTA 6        // seconds for adaptive update
00054 #define SHORT_DELAY_MICROS 500    // short delay for quick reschedule
00055 #define COMPARE_ASSUME_BAD 20      // secs since last fetch OK to assume compare failed
00056 #define NODE_SPLIT_TRIGGER 400    // in bytes, triggers node split
00057 #define EXCLUSION_LIMIT 1000       // in bytes, limits exclusion list size
00058 #define EXCLUSION_TRIG 5           // trigger for including root hashes in excl list (secs)
00059 #define STABLE_TIME_TRIG 10        // trigger for storing stable point (secs)
00060 #define HASH_SPLIT_TRIGGER 17      // trigger for splitting based on hash (n/255)
00061 #define NAMES_YIELD_INC 100        // number of names to inc between yield tests
00062 #define NAMES_YIELD_MICROS 20*1000 // number of micros to use as yield trigger
00063 
00064 static ccnr_hwm ccns_hwm_update(struct ccnr_handle *ccnr, ccnr_hwm hwm, ccnr_accession a);
00065 static uintmax_t ccns_accession_encode(struct ccnr_handle *ccnr, ccnr_accession a);
00066 
00067 struct ccns_slice {
00068     unsigned version;
00069     unsigned nclauses;
00070     struct ccn_charbuf *topo;
00071     struct ccn_charbuf *prefix;
00072     struct ccn_charbuf **clauses; // contents defined in documentation, need utils
00073 };
00074 
00075 #define CCNS_FLAGS_SC 1      // start at current root hash.
00076 
00077 struct ccns_handle {
00078     struct SyncBaseStruct *base;
00079     struct SyncRootStruct *root;
00080     struct ccn_scheduled_event *ev;
00081     ccns_callback callback;
00082     unsigned flags;
00083 };
00084 
00085 /*
00086  * Utility routines to allocate/deallocate ccns_slice structures
00087  */
00088 struct ccns_slice *
00089 ccns_slice_create()
00090 {
00091     struct ccns_slice *s = calloc(1, sizeof(*s));
00092     if (s == NULL)
00093         return(NULL);
00094     s->version = SLICE_VERSION;
00095     s->topo = ccn_charbuf_create_n(8); // name encoding requires minimum 2
00096     s->prefix = ccn_charbuf_create_n(8);
00097     if (s->topo == NULL || s->prefix == NULL) {
00098         ccn_charbuf_destroy(&s->topo);
00099         ccn_charbuf_destroy(&s->prefix);
00100         free(s);
00101         s = NULL;
00102     } else {
00103         ccn_name_init(s->topo);
00104         ccn_name_init(s->prefix);
00105     }
00106     return(s);
00107 }
00108 void
00109 ccns_slice_destroy(struct ccns_slice **sp)
00110 {
00111     struct ccns_slice *s = *sp;
00112     if (s != NULL) {
00113         ccn_charbuf_destroy(&(s->topo));
00114         ccn_charbuf_destroy(&(s->prefix));
00115         if (s->clauses != NULL) {
00116             while(s->nclauses > 0) {
00117                 s->nclauses--;
00118                 ccn_charbuf_destroy(&(s->clauses[s->nclauses]));
00119             }
00120             free(s->clauses);
00121         }
00122         free(s);
00123         *sp = NULL;
00124     }
00125 }
00126 /*
00127  * Utility routine to add a clause to a ccns_slice structure
00128  */
00129 int
00130 ccns_slice_add_clause(struct ccns_slice *s, struct ccn_charbuf *c)
00131 {
00132     struct ccn_charbuf **clauses = NULL;
00133     struct ccn_charbuf *clause;
00134     clause = ccn_charbuf_create_n(c->length);
00135     if (clause == NULL)
00136         return(-1);
00137     if (s->clauses == NULL) {
00138         s->clauses = calloc(1, sizeof(s->clauses[0]));
00139         if (s->clauses == NULL)
00140             goto Cleanup;
00141     } else {
00142         clauses = realloc(s->clauses, (s->nclauses + 1) * sizeof(s->clauses[0]));
00143         if (clauses == NULL)
00144             goto Cleanup;
00145         s->clauses = clauses;
00146     }
00147     ccn_charbuf_append_charbuf(clause, c);
00148     s->clauses[s->nclauses++] = clause;
00149     return (0);
00150 
00151 Cleanup:
00152     ccn_charbuf_destroy(&clause);
00153     return (-1);
00154 }
00155 /*
00156  * Utility routine to set the topo and prefix fields to copies of the
00157  * passed in charbufs
00158  */
00159 int
00160 ccns_slice_set_topo_prefix(struct ccns_slice *s, struct ccn_charbuf *t,
00161                            struct ccn_charbuf *p)
00162 {
00163     int res = 0;
00164     if (t != NULL) {
00165         ccn_charbuf_reset(s->topo);
00166         res |= ccn_charbuf_append_charbuf(s->topo, t);
00167     }
00168     if (p != NULL) {
00169         ccn_charbuf_reset(s->prefix);
00170         res |= ccn_charbuf_append_charbuf(s->prefix, p);
00171     }
00172     return(res);
00173 }
00174 /*
00175  * utility, may need to be exported, to append the encoding of a
00176  * slice to a charbuf
00177  */
00178 static int
00179 append_slice(struct ccn_charbuf *c, struct ccns_slice *s)
00180 {
00181     int res = 0;
00182     int i;
00183 
00184     res |= ccnb_element_begin(c, CCN_DTAG_SyncConfigSlice);
00185     res |= ccnb_tagged_putf(c, CCN_DTAG_SyncVersion, "%u", SLICE_VERSION);
00186     res |= ccn_charbuf_append_charbuf(c, s->topo);
00187     res |= ccn_charbuf_append_charbuf(c, s->prefix);
00188     res |= ccnb_element_begin(c, CCN_DTAG_SyncConfigSliceList);
00189     for (i = 0; i < s->nclauses ; i++) {
00190         res |= ccnb_tagged_putf(c, CCN_DTAG_SyncConfigSliceOp, "%u", 0);
00191         res |= ccn_charbuf_append_charbuf(c, s->clauses[i]);
00192     }
00193     res |= ccnb_element_end(c);
00194     res |= ccnb_element_end(c);
00195     return (res);
00196 }
00197 /*
00198  * utility, may need to be exported, to parse the buffer into a given slice
00199  * structure.
00200  */
00201 static int
00202 slice_parse(struct ccns_slice *s, const unsigned char *p, size_t size)
00203 {
00204     int res = 0;
00205     struct ccn_buf_decoder decoder;
00206     struct ccn_buf_decoder *d = ccn_buf_decoder_start(&decoder, p, size);
00207     uintmax_t version;
00208     int op;
00209     int start;
00210     struct ccn_charbuf *clause = NULL;
00211 
00212     if (!ccn_buf_match_dtag(d, CCN_DTAG_SyncConfigSlice))
00213         return (-1);
00214     ccn_buf_advance(d);
00215     if (!ccn_buf_match_dtag(d, CCN_DTAG_SyncVersion))
00216         return (-1);
00217     ccn_buf_advance(d);
00218     ccn_parse_uintmax(d, &version);
00219     ccn_buf_check_close(d);
00220     if (version != SLICE_VERSION)
00221         return (-1);
00222     start = d->decoder.token_index;
00223     if (ccn_parse_Name(d, NULL) < 0)
00224         return(-1);
00225     ccn_charbuf_reset(s->topo);
00226     res = ccn_charbuf_append(s->topo, p + start, d->decoder.token_index - start);
00227     if (res < 0)
00228         return(-1);
00229     start = d->decoder.token_index;
00230     if (ccn_parse_Name(d, NULL) < 0)
00231         return(-1);
00232     ccn_charbuf_reset(s->prefix);
00233     res = ccn_charbuf_append(s->prefix, p + start, d->decoder.token_index - start);
00234     if (res < 0)
00235         return(-1);
00236     if (!ccn_buf_match_dtag(d, CCN_DTAG_SyncConfigSliceList))
00237         return(-1);
00238     ccn_buf_advance(d);
00239     clause = ccn_charbuf_create();
00240     if (clause == NULL)
00241         return(-1);
00242     while (ccn_buf_match_dtag(d, CCN_DTAG_SyncConfigSliceOp)) {
00243         ccn_buf_advance(d);
00244         op = ccn_parse_nonNegativeInteger(d); // op is a small integer
00245         ccn_buf_check_close(d);
00246         if (op != 0)
00247             break;
00248         ccn_charbuf_reset(clause);
00249         start = d->decoder.token_index;
00250         if (ccn_parse_Name(d, NULL) < 0)
00251             break;
00252         res = ccn_charbuf_append(clause, p + start, d->decoder.token_index - start);
00253         ccns_slice_add_clause(s, clause);
00254     }
00255     ccn_charbuf_destroy(&clause);
00256     ccn_buf_check_close(d); /* </SyncConfigSliceList> */
00257     ccn_buf_check_close(d); /* </SyncConfigSlice> */
00258     if (d->decoder.index != size || !CCN_FINAL_DSTATE(d->decoder.state))
00259         return(-1);
00260     return(0);
00261 }
00262 /**
00263  * Construct the name of a Sync configuration slice based on the parameters.
00264  * @param nm is the ccn_charbuf which will be set to the ccnb encoded Name
00265  * @param s is the definition of the slice for which the name is required.
00266  * @returns a ccn_charbuf with the ccnb encoded Name of the slice.
00267  */
00268 
00269 int
00270 ccns_slice_name(struct ccn_charbuf *nm, struct ccns_slice *s)
00271 {
00272     struct ccn_charbuf *c;
00273     struct ccn_digest *digest = NULL;
00274     struct ccn_charbuf *hash = NULL;
00275     int res = 0;
00276 
00277     c = ccn_charbuf_create();
00278     if (c == NULL)
00279         return (-1);
00280     res = append_slice(c, s);
00281     if (res < 0)
00282         goto Cleanup;
00283 
00284     digest = ccn_digest_create(CCN_DIGEST_SHA256);
00285     hash = ccn_charbuf_create_n(ccn_digest_size(digest));
00286     if (hash == NULL)
00287         goto Cleanup;
00288     ccn_digest_init(digest);
00289     res |= ccn_digest_update(digest, c->buf, c->length);
00290     res |= ccn_digest_final(digest, hash->buf, hash->limit);
00291     if (res < 0)
00292         goto Cleanup;
00293     hash->length = hash->limit;
00294     if (ccn_name_from_uri(nm, "ccnx:/%C1.M.S.localhost/%C1.S.cs") < 0)
00295         res = -1;
00296     res |= ccn_name_append(nm, hash->buf, hash->length);
00297 
00298 Cleanup:
00299     ccn_charbuf_destroy(&c);
00300     ccn_digest_destroy(&digest);
00301     ccn_charbuf_destroy(&hash);
00302     return (res);
00303 }
00304 
00305 /**
00306  * Read a slice (from a repository) given the name.
00307  * @param h is the ccn_handle on which to read.
00308  * @param name is the charbuf containing the name of the sync slice to be read.
00309  * @param slice is a pointer to a ccns_slice object which will be filled in
00310  *  on successful return.
00311  * @returns 0 on success, -1 otherwise.
00312  */
00313 int
00314 ccns_read_slice(struct ccn *h, struct ccn_charbuf *name,
00315                 struct ccns_slice *slice)
00316 {
00317     struct ccn_parsed_ContentObject pco_space = { 0 };
00318     struct ccn_parsed_ContentObject *pco = &pco_space;
00319     struct ccn_charbuf *nc = ccn_charbuf_create_n(name->length);
00320     struct ccn_charbuf *cob = ccn_charbuf_create();
00321     const unsigned char *content;
00322     size_t content_length;
00323     int res = -1;
00324 
00325     if (nc == NULL || cob == NULL)
00326         goto Cleanup;
00327 
00328     ccn_charbuf_append_charbuf(nc, name);
00329     res = ccn_resolve_version(h, nc,  CCN_V_HIGHEST, 100); // XXX: timeout
00330     if (res < 0)
00331         goto Cleanup;
00332     if (res == 0) {
00333         // TODO: check if the last component is a segment number, chop it off, try again.
00334     }
00335     res = ccn_get(h, nc, NULL, 100, cob, pco, NULL, 0);
00336     if (res < 0)
00337         goto Cleanup;
00338     if (pco->type != CCN_CONTENT_DATA) {
00339         res = -1;
00340         goto Cleanup;
00341     }
00342     res = ccn_content_get_value(cob->buf, cob->length, pco,
00343                                 &content, &content_length);
00344     if (res < 0)
00345         goto Cleanup;
00346     res = slice_parse(slice, content, content_length);
00347 
00348 Cleanup:
00349     ccn_charbuf_destroy(&nc);
00350     ccn_charbuf_destroy(&cob);
00351     return (res);
00352 }
00353 
00354 struct ccn_charbuf *
00355 make_scope1_template(void)
00356 {
00357     struct ccn_charbuf *templ = NULL;
00358     templ = ccn_charbuf_create_n(16);
00359     ccnb_element_begin(templ, CCN_DTAG_Interest);
00360     ccnb_element_begin(templ, CCN_DTAG_Name);
00361     ccnb_element_end(templ); /* </Name> */
00362     ccnb_tagged_putf(templ, CCN_DTAG_Scope, "%u", 1);
00363     ccnb_element_end(templ); /* </Interest> */
00364     return(templ);
00365 }
00366 
00367 static enum ccn_upcall_res
00368 write_interest_handler (struct ccn_closure *selfp,
00369                         enum ccn_upcall_kind kind,
00370                         struct ccn_upcall_info *info)
00371 {
00372     struct ccn_charbuf *cob = selfp->data;
00373     struct ccn *h = info->h;
00374 
00375     if (kind != CCN_UPCALL_INTEREST)
00376         return(CCN_UPCALL_RESULT_OK);
00377     if (ccn_content_matches_interest(cob->buf, cob->length, 1, NULL,
00378                                      info->interest_ccnb,
00379                                      info->pi->offset[CCN_PI_E],
00380                                      info->pi)) {
00381         ccn_put(info->h, cob->buf, cob->length);
00382         selfp->intdata = 1;
00383         ccn_set_run_timeout(h, 0);
00384         return(CCN_UPCALL_RESULT_INTEREST_CONSUMED);
00385     }
00386     return(CCN_UPCALL_RESULT_OK);
00387 }
00388 
00389 static int
00390 write_slice(struct ccn *h, struct ccns_slice *slice,
00391             struct ccn_charbuf *name)
00392 {
00393     struct ccn_charbuf *content = NULL;
00394     unsigned char *cbuf = NULL;
00395     size_t clength = 0;
00396     struct ccn_charbuf *sw = NULL;
00397     struct ccn_charbuf *templ = NULL;
00398     struct ccn_charbuf *cob = NULL;
00399     struct ccn_signing_params sparm = CCN_SIGNING_PARAMS_INIT;
00400     struct ccn_closure *wc = NULL;
00401     int res;
00402 
00403     sw = ccn_charbuf_create_n(32 + name->length);
00404     if (sw == NULL) {
00405         res = -1;
00406         goto Cleanup;
00407     }
00408     ccn_charbuf_append_charbuf(sw, name);
00409     ccn_name_chop(sw, NULL, -1); // remove segment number
00410     ccn_name_from_uri(sw, "%C1.R.sw");
00411     ccn_name_append_nonce(sw);
00412 
00413     // create and sign the content object
00414     cob = ccn_charbuf_create();
00415     if (cob == NULL) {
00416         res = -1;
00417         goto Cleanup;
00418     }
00419     if (slice != NULL) {
00420         content = ccn_charbuf_create();
00421         if (content == NULL) {
00422             res = -1;
00423             goto Cleanup;
00424         }
00425         res = append_slice(content, slice);
00426         if (res < 0)
00427             goto Cleanup;
00428         cbuf = content->buf;
00429         clength = content->length;
00430     } else {
00431         sparm.type = CCN_CONTENT_GONE;
00432     }
00433 
00434     sparm.sp_flags = CCN_SP_FINAL_BLOCK;
00435     res = ccn_sign_content(h, cob, name, &sparm, cbuf, clength);
00436     if (res < 0)
00437         goto Cleanup;
00438     // establish handler for interest in the slice content object
00439     wc = calloc(1, sizeof(*wc));
00440     if (wc == NULL) {
00441         res = -1;
00442         goto Cleanup;
00443     }
00444     wc->p = &write_interest_handler;
00445     wc->data = cob;
00446     res = ccn_set_interest_filter(h, name, wc);
00447     if (res < 0)
00448         goto Cleanup;
00449     templ = make_scope1_template();
00450     if (templ == NULL) {
00451         res = -1;
00452         goto Cleanup;
00453     }
00454     res = ccn_get(h, sw, templ, 1000, NULL, NULL, NULL, 0);
00455     if (res < 0)
00456         goto Cleanup;
00457     ccn_run(h, 1000); // give the repository a chance to fetch the data
00458     if (wc->intdata != 1) {
00459         res = -1;
00460         goto Cleanup;
00461     }
00462     res = 0;
00463 Cleanup:
00464     ccn_set_interest_filter(h, name, NULL);
00465     if (wc != NULL)
00466         free(wc);
00467     ccn_charbuf_destroy(&cob);
00468     ccn_charbuf_destroy(&content);
00469     ccn_charbuf_destroy(&sw);
00470     ccn_charbuf_destroy(&templ);
00471     return (res);
00472 }
00473 /**
00474  * Write a ccns_slice object to a repository.
00475  * @param h is the ccn_handle on which to write.
00476  * @param slice is a pointer to a ccns_slice object to be written.
00477  * @param name, if non-NULL, is a pointer to a charbuf which will be filled
00478  *  in with the name of the slice that was written.
00479  * @returns 0 on success, -1 otherwise.
00480  */
00481 int
00482 ccns_write_slice(struct ccn *h, struct ccns_slice *slice,
00483                  struct ccn_charbuf *name)
00484 {
00485     struct ccn_charbuf *n = NULL;
00486     int res;
00487     // calculate versioned and segmented name for the slice
00488     n = ccn_charbuf_create();
00489     if (n == NULL)
00490         return(-1);
00491     res = ccns_slice_name(n, slice);
00492     if (res < 0)
00493         goto Cleanup;
00494     res |= ccn_create_version(h, n, CCN_V_NOW, 0, 0);
00495     if (name != NULL) {
00496         ccn_charbuf_reset(name);
00497         res |= ccn_charbuf_append_charbuf(name, n);
00498     }
00499     res |= ccn_name_append_numeric(n, CCN_MARKER_SEQNUM, 0);
00500     if (res < 0)
00501         goto Cleanup;
00502     res = write_slice(h, slice, n);
00503 
00504 Cleanup:
00505     ccn_charbuf_destroy(&n);
00506     return (res);
00507 }
00508 /**
00509  * Delete a ccns_slice object from a repository.
00510  * @param h is the ccn_handle on which to write.
00511  * @param name is a pointer to a charbuf naming the slice to be deleted.
00512  * @returns 0 on success, -1 otherwise.
00513  */
00514 int
00515 ccns_delete_slice(struct ccn *h, struct ccn_charbuf *name)
00516 {
00517     struct ccn_charbuf *n = NULL;
00518     int res;
00519 
00520     // calculate versioned and segmented name for the slice
00521     n = ccn_charbuf_create_n(32 + name->length);
00522     if (n == NULL)
00523         return(-1);
00524     res = ccn_charbuf_append_charbuf(n, name);
00525     res |= ccn_create_version(h, n, CCN_V_NOW | CCN_V_REPLACE, 0, 0);
00526     res |= ccn_name_append_numeric(n, CCN_MARKER_SEQNUM, 0);
00527     if (res < 0)
00528         return(-1);
00529     res = write_slice(h, NULL, n);
00530     ccn_charbuf_destroy(&n);
00531     return (res);
00532 }
00533 
00534 /*
00535  * local time source for event schedule
00536  */
00537 static void
00538 gettime(const struct ccn_gettime *self, struct ccn_timeval *result)
00539 {
00540     struct timeval now = {0};
00541     gettimeofday(&now, 0);
00542     result->s = now.tv_sec;
00543     result->micros = now.tv_usec;
00544 }
00545 
00546 static int HeartbeatAction(struct ccn_schedule *sched,
00547                            void *clienth,
00548                            struct ccn_scheduled_event *ev,
00549                            int flags);
00550 
00551 static int ccns_send_root_advise_interest(struct SyncRootStruct *root);
00552 
00553 /**
00554  * Start notification of addition of names to a sync slice.
00555  * @param h is the ccn_handle on which to communicate
00556  * @param slice is the slice to be opened.
00557  * @param callback is the procedure which will be called for each new name,
00558  *  and returns 0 to continue enumeration, -1 to stop further enumeration.
00559  *  NOTE: It is not safe to call ccns_close from within the callback.
00560  * @param rhash
00561  *      If NULL, indicates that the enumeration should start from the empty set.
00562  *      If non-NULL but empty, indicates that the enumeration should start from
00563  *      the current root.
00564  *      If non-NULL, and not empty, indicates that the enumeration should start
00565  *      from the specified root hash
00566  * @param pname if non-NULL represents the starting name for enumeration within
00567  *  the sync tree represented by the root hash rhash.
00568  * @returns a pointer to a new sync handle, which will be freed at close.
00569  */
00570 struct ccns_handle *
00571 ccns_open(struct ccn *h,
00572           struct ccns_slice *slice,
00573           ccns_callback callback,
00574           struct ccn_charbuf *rhash,
00575           struct ccn_charbuf *pname)
00576 {
00577     struct ccn_schedule *schedule;
00578     struct ccn_gettime *timer;
00579     struct ccns_handle *ccns = calloc(1, sizeof(*ccns));
00580     struct SyncHashCacheEntry *ceL = NULL;
00581     if (ccns == NULL)
00582         return(NULL);
00583     schedule = ccn_get_schedule(h);
00584     if (schedule == NULL) {
00585         timer = calloc(1, sizeof(*timer));
00586         timer->descr[0]='S';
00587         timer->micros_per_base = 1000000;
00588         timer->gettime = &gettime;
00589         timer->data = h;
00590         schedule = ccn_schedule_create(h, timer);
00591         ccn_set_schedule(h, schedule);
00592     }
00593     ccns->callback = callback;
00594     ccns->base = SyncNewBase((void *)ccns, h, schedule); // use ccns instead of ccnr handle
00595     ccns->base->priv->heartbeatMicros = 1000000;
00596     ccns->base->priv->rootAdviseLifetime = 20;
00597     ccns->base->priv->maxComparesBusy = 8;
00598     ccns->base->debug = CCNL_WARNING;
00599     ccns->root = SyncAddRoot(ccns->base, ccns->base->priv->syncScope,
00600                              slice->topo, slice->prefix, NULL);
00601     // TODO: no filters yet
00602 
00603     // starting at given root hash -- need to sanity check rhash, check node fetch works
00604     // current behavior on unknown hash is to report failure.
00605     if (rhash != NULL) {
00606         if (rhash->length > 0) {
00607             ccn_charbuf_reset(ccns->root->currentHash);
00608             ccn_charbuf_append_charbuf(ccns->root->currentHash, rhash);
00609             ceL = SyncHashEnter(ccns->root->ch, rhash->buf, rhash->length, 0);
00610         } else {
00611             ccns->flags |= CCNS_FLAGS_SC;
00612         }
00613     }
00614 
00615     ccns_send_root_advise_interest(ccns->root);
00616     ccns->ev = ccn_schedule_event(ccns->base->sched,
00617                                   ccns->base->priv->heartbeatMicros,
00618                                   &HeartbeatAction,
00619                                   ccns->base,
00620                                   0);
00621 
00622     return(ccns);
00623 }
00624 /**
00625  * Stop notification of changes of names in a sync slice and free the handle.
00626  * @param sh is a pointer (to a pointer) to the sync handle returned
00627  *  by ccns_open, which will be freed and set to NULL.
00628  * @param rhash if non-NULL will be filled in with the current root hash.
00629  * @param pname if non-NULL will be filled in with the starting name
00630  *  for enumeration within the sync tree represented by the root hash rhash.
00631  */
00632 void ccns_close(struct ccns_handle **ccnsp, struct ccn_charbuf *rhash, struct ccn_charbuf *pname)
00633 {
00634     struct ccns_handle *ccns = *ccnsp;
00635     ccn_schedule_cancel(ccns->base->sched, ccns->ev);
00636     // pick up current root hash if rhash is non-NULL
00637     if (rhash != NULL) {
00638         ccn_charbuf_reset(rhash);
00639         ccn_charbuf_append_charbuf(rhash, ccns->root->currentHash);
00640     }
00641     SyncFreeBase(&(*ccnsp)->base);
00642     free(*ccnsp);
00643     *ccnsp = NULL;
00644     return;
00645 }
00646 
00647 void
00648 ccns_msg(struct ccnr_handle *h, const char *fmt, ...)
00649 {
00650     struct timeval t;
00651     va_list ap;
00652     struct ccn_charbuf *b = ccn_charbuf_create();
00653     ccn_charbuf_reserve(b, 1024);
00654     gettimeofday(&t, NULL);
00655     ccn_charbuf_putf(b, "%s\n", fmt);
00656     char *fb = ccn_charbuf_as_string(b);
00657     va_start(ap, fmt);
00658     vfprintf(stdout, fb, ap);
00659     va_end(ap);
00660     fflush(stdout);
00661     ccn_charbuf_destroy(&b);
00662 }
00663 
00664 enum SyncCompareState {
00665     SyncCompare_init,
00666     SyncCompare_preload,
00667     SyncCompare_busy,
00668     SyncCompare_waiting,
00669     SyncCompare_done
00670 };
00671 
00672 struct SyncCompareData {
00673     struct SyncRootStruct *root;    /**< parent root for this comparison */
00674     struct SyncTreeWorkerHead *twL; /**< local tree walker state */
00675     struct SyncTreeWorkerHead *twR; /**< remote tree walker state */
00676     struct ccn_charbuf *hashL;      /**< hash for root of local sync tree */
00677     struct ccn_charbuf *hashR;      /**< hash for root of remote sync tree */
00678     struct ccn_charbuf *cbL;        /**< local tree scratch */
00679     struct ccn_charbuf *cbR;        /**< remote tree scratch */
00680     struct ccn_charbuf *lagL;       /**< local lag name */
00681     int *lagMatch;                  /**< lagging # of matching components */
00682     struct SyncActionData *errList; /**< actions that had errors for this compare */
00683     int errsQueued;                 /**< names added during this comparison */
00684     int namesAdded;                 /**< names added during this comparison */
00685     int nodeFetchBusy;              /**< number of busy remote node fetches */
00686     int nodeFetchFailed;            /**< number of failed remote node fetches */
00687     int contentPos;                 /**< position of next content to fetch */
00688     int contentFetchBusy;           /**< number of busy content fetches */
00689     int contentFetchFailed;         /**< number of failed content fetches */
00690     struct ccn_scheduled_event *ev; /**< progress event */
00691     enum SyncCompareState state;    /**< summary state of comparison */
00692     int64_t lastFetchOK;          /**< time marker for last successul node/content fetch */
00693     int64_t startTime;            /**< time marker for compare data creation */
00694     int64_t lastEnter;            /**< time marker for last compare step entry */
00695     int64_t lastMark;             /**< time marker for stall determination */
00696     int64_t maxHold;                /**< max time thread was held by compare */
00697 };
00698 
00699 static void
00700 delinkActionData(struct SyncActionData *data) {
00701     if (data == NULL) return;
00702     if (data->state == SyncActionState_sent) {
00703         // remove from the action chain in the root
00704         struct SyncRootStruct *root = data->root;
00705         if (root == NULL) return;
00706         struct SyncActionData *each = root->actions;
00707         struct SyncActionData *lag = NULL;
00708         data->state = SyncActionState_loose;
00709         while (each != NULL) {
00710             struct SyncActionData *next = each->next;
00711             if (data == each) {
00712                 data->next = NULL;
00713                 if (lag == NULL) root->actions = next;
00714                 else lag->next = next;
00715                 break;
00716             }
00717             lag = each;
00718             each = next;
00719         }
00720     } else {
00721         if (data->state == SyncActionState_error) {
00722             // remove from the errList chain in the comparison
00723             struct SyncCompareData *comp = data->comp;
00724             if (comp == NULL) return;
00725             struct SyncActionData *each = comp->errList;
00726             struct SyncActionData *lag = NULL;
00727             data->state = SyncActionState_loose;
00728             while (each != NULL) {
00729                 struct SyncActionData *next = each->next;
00730                 if (data == each) {
00731                     data->next = NULL;
00732                     if (comp->errsQueued > 0) comp->errsQueued--;
00733                     if (lag == NULL) comp->errList = next;
00734                     else lag->next = next;
00735                     break;
00736                 }
00737                 lag = each;
00738                 each = next;
00739             }
00740         }
00741     }
00742 }
00743 
00744 static int
00745 moveActionData(struct SyncActionData *data, enum SyncActionState dstState) {
00746     // moves the action data to the given state queue
00747     // (must be SyncActionState_sent or SyncActionState_error)
00748     // returns 1 for success, 0 for not possible
00749     if (data == NULL) return 0;
00750     if (dstState == SyncActionState_error && data->state != SyncActionState_sent)
00751         return 0;
00752     if (dstState == SyncActionState_sent && data->state != SyncActionState_error)
00753         return 0;
00754     struct SyncRootStruct *root = data->root;
00755     struct SyncCompareData *comp = data->comp;
00756     if (root == NULL || comp == NULL) return 0;
00757     delinkActionData(data);
00758     if (dstState == SyncActionState_sent) {
00759         data->next = root->actions;
00760         root->actions = data;
00761     } else {
00762         data->next = comp->errList;
00763         comp->errList = data;
00764         comp->errsQueued++;
00765     }
00766     data->state = dstState;
00767     return 1;
00768 }
00769 
00770 static struct SyncActionData *
00771 destroyActionData(struct SyncActionData *data) {
00772     if (data != NULL) {
00773         delinkActionData(data);
00774         // remove any resources
00775         if (data->prefix != NULL)
00776             ccn_charbuf_destroy(&data->prefix);
00777         if (data->hash != NULL)
00778             ccn_charbuf_destroy(&data->hash);
00779         data->next = NULL;
00780         data->root = NULL;
00781         data->comp = NULL;
00782         free(data);
00783     }
00784     return NULL;
00785 }
00786 
00787 static struct SyncActionData *
00788 newActionData(enum SyncRegisterActionKind kind) {
00789     struct SyncActionData *data = calloc(1, sizeof(*data));
00790     data->startTime = SyncCurrentTime();
00791     data->kind = kind;
00792     data->state = SyncActionState_init;
00793     return data;
00794 }
00795 
00796 static void
00797 linkActionData(struct SyncRootStruct *root, struct SyncActionData *data) {
00798     data->root = root;
00799     data->next = root->actions;
00800     data->client_handle = root->base->client_handle;
00801     data->state = SyncActionState_sent;
00802     root->actions = data;
00803 }
00804 
00805 static void
00806 setCovered(struct SyncHashCacheEntry *ce) {
00807     char *here = "Sync.setCovered";
00808     if (ce->state & SyncHashState_covered) {
00809         // nothing to do, already covered
00810     } else if (ce->state & SyncHashState_remote) {
00811         // only set this bit if a remote hash has been entered
00812         struct SyncRootStruct *root = ce->head->root;
00813         if (root->base->debug >= CCNL_FINER) {
00814             char *hex = SyncHexStr(ce->hash->buf, ce->hash->length);
00815             SyncNoteSimple(root, here, hex);
00816             free(hex);
00817         }
00818         ce->state |= SyncHashState_covered;
00819     }
00820 }
00821 
00822 static int
00823 isCovered(struct SyncHashCacheEntry *ce) {
00824     if (ce->state & SyncHashState_covered) return 1;
00825     if (ce->state & SyncHashState_local) {
00826         setCovered(ce);
00827         return 1;
00828     }
00829     return 0;
00830 }
00831 
00832 static int
00833 compareHash(struct ccn_charbuf *hashX, struct ccn_charbuf *hashY) {
00834     if (hashX == hashY) return 0;
00835     if (hashX == NULL) return -1;
00836     if (hashY == NULL) return 1;
00837     size_t lenX = hashX->length;
00838     size_t lenY = hashY->length;
00839     if (lenX < lenY) return -1;
00840     if (lenX > lenY) return 1;
00841     return memcmp(hashX->buf, hashY->buf, lenX);
00842 }
00843 
00844 static struct SyncActionData *
00845 SyncFindAction(struct SyncRootStruct *root, enum SyncRegisterActionKind kind) {
00846     struct SyncActionData *each = root->actions;
00847     while (each != NULL) {
00848         if (each->kind == kind) return each;
00849         each = each->next;
00850     }
00851     return NULL;
00852 }
00853 
00854 extern int
00855 SyncAddName(struct SyncBaseStruct *base,
00856             struct ccn_charbuf *name,
00857             ccnr_accession item) {
00858     static char *here = "Sync.SyncAddName";
00859     struct SyncPrivate *priv = base->priv;
00860     int debug = base->debug;
00861     struct SyncRootStruct *root = priv->rootHead;
00862     int count = 0;
00863     while (root != NULL) {
00864         if (SyncRootLookupName(root, name) == SyncRootLookupCode_covered) {
00865             // ANY matching root gets an addition
00866             // add the name for later processing
00867             struct ccn_charbuf *prev = NULL;
00868             int pos = root->namesToAdd->len;
00869             if (pos > 0) prev = root->namesToAdd->ents[pos-1].name;
00870             if (prev != NULL && SyncCmpNames(name, prev) == 0) {
00871                 // this is a duplicate, so forget it!
00872                 if (debug >= CCNL_FINE) {
00873                     SyncNoteUri(root, here, "ignore dup", name);
00874                 }
00875             } else {
00876                 // not obviously a duplicate
00877                 uintmax_t itemNum = ccns_accession_encode(base->client_handle, item);
00878                 SyncNameAccumAppend(root->namesToAdd, SyncCopyName(name), itemNum);
00879                 if (item != CCNR_NULL_ACCESSION)
00880                     root->priv->highWater = ccns_hwm_update(base->client_handle,
00881                                                             root->priv->highWater,
00882                                                             item);
00883                 count++;
00884                 if (debug >= CCNL_FINE) {
00885                     char temp[64];
00886                     // TBD: improve item reporting?
00887                     if (item >= CCNR_MIN_ACCESSION && item <= CCNR_MAX_ACCESSION) {
00888                         snprintf(temp, sizeof(temp), "added, %ju", itemNum);
00889                     } else {
00890                         snprintf(temp, sizeof(temp), "no accession");
00891                     }
00892                     SyncNoteUri(root, here, temp, name);
00893                 }
00894             }
00895         }
00896         root = root->next;
00897     }
00898     if (item != CCNR_NULL_ACCESSION)
00899         base->highWater = ccns_hwm_update(base->client_handle, base->highWater, item);
00900     return count;
00901 }
00902 
00903 static struct SyncNodeComposite *
00904 extractNode(struct SyncRootStruct *root, struct ccn_upcall_info *info) {
00905     // first, find the content
00906     char *here = "Sync.extractNode";
00907     const unsigned char *cp = NULL;
00908     size_t cs = 0;
00909     size_t ccnb_size = info->pco->offset[CCN_PCO_E];
00910     const unsigned char *ccnb = info->content_ccnb;
00911     int res = ccn_content_get_value(ccnb, ccnb_size, info->pco,
00912                                     &cp, &cs);
00913     if (res < 0 || cs < DEFAULT_HASH_BYTES) {
00914         SyncNoteFailed(root, here, "ccn_content_get_value", __LINE__);
00915         return NULL;
00916     }
00917 
00918     // second, parse the object
00919     struct SyncNodeComposite *nc = SyncAllocComposite(root->base);
00920     struct ccn_buf_decoder ds;
00921     struct ccn_buf_decoder *d = ccn_buf_decoder_start(&ds, cp, cs);
00922     res |= SyncParseComposite(nc, d);
00923     if (res < 0) {
00924         // failed, so back out of the allocations
00925         SyncNoteFailed(root, here, "bad parse", -res);
00926         SyncFreeComposite(nc);
00927         nc = NULL;
00928     }
00929     return nc;
00930 }
00931 
00932 static int
00933 noteRemoteHash(struct SyncRootStruct *root, struct SyncHashCacheEntry *ce, int add) {
00934     char *here = "Sync.noteRemoteHash";
00935     int debug = root->base->debug;
00936     struct ccnr_handle *ccnr = root->base->client_handle;
00937     struct ccn_charbuf *hash = ce->hash;
00938     int hl = hash->length;
00939     if (hl == 0) return 0;
00940     struct SyncHashInfoList *head = root->priv->remoteSeen;
00941     struct SyncHashInfoList *each = head;
00942     struct SyncHashInfoList *lag = NULL;
00943     int64_t mark = SyncCurrentTime();
00944     ce->lastUsed = mark;
00945     ce->lastRemoteFetch = mark;
00946     if (ce->state & SyncHashState_local)
00947         setCovered(ce);
00948     while (each != NULL) {
00949         if (ce == each->ce) {
00950             if (lag != NULL) {
00951                 // move it to the front
00952                 lag->next = each->next;
00953                 each->next = head;
00954                 root->priv->remoteSeen = each;
00955             }
00956             break;
00957         }
00958         lag = each;
00959         each = each->next;
00960     }
00961     if (each == NULL && add) {
00962         // need a new entry
00963         each = calloc(1, sizeof(*each));
00964         each->next = head;
00965         root->priv->remoteSeen = each;
00966     }
00967     if (debug >= CCNL_FINE) {
00968         char *hex = SyncHexStr(hash->buf, hash->length);
00969         char *extra = "";
00970         if (ce->state & SyncHashState_covered) extra = "covered, ";
00971         ccns_msg(ccnr, "%s, root#%u, %s%s", here, root->rootId, extra, hex);
00972         free(hex);
00973     }
00974     if (each != NULL) {
00975         each->ce = ce;
00976         ce->busy++;
00977         each->lastSeen = mark;
00978     }
00979     return 1;
00980 }
00981 
00982 static char *
00983 getCmdStr(enum SyncRegisterActionKind kind) {
00984     switch (kind) {
00985         case SRI_Kind_AdviseInt:
00986         case SRI_Kind_RootAdvise:
00987             return "\xC1.S.ra";
00988         case SRI_Kind_FetchInt:
00989         case SRI_Kind_NodeFetch:
00990             return "\xC1.S.nf";
00991         case SRI_Kind_RootStats:
00992             return "\xC1.S.rs";
00993         default:
00994             return NULL;
00995     }
00996 }
00997 
00998 // take a list of names and sort them, removing duplicates!
00999 // should leave src empty
01000 static struct SyncNameAccum *
01001 sortNames(struct SyncRootStruct *root, struct SyncNameAccum *src) {
01002     char *here = "Sync.sortNames";
01003     IndexSorter_Index ixLim = src->len;
01004     IndexSorter_Base ixBase = IndexSorter_New(ixLim, -1);
01005     ixBase->sorter = SyncNameAccumSorter;
01006     ixBase->client = src;
01007     IndexSorter_Index ix = 0;
01008     for (ix = 0; ix < ixLim; ix++) IndexSorter_Add(ixBase, ix);
01009     struct SyncNameAccum *dst = SyncAllocNameAccum(ixLim);
01010     struct ccn_charbuf *lag = NULL;
01011     for (ix = 0; ix < ixLim; ix++) {
01012         IndexSorter_Index j = IndexSorter_Rem(ixBase);
01013         if (j >= ixLim) {
01014             SyncNoteFailed(root, here, "rem failed", __LINE__);
01015             break;
01016         }
01017         struct ccn_charbuf *name = src->ents[j].name;
01018         src->ents[j].name = NULL;
01019         if (name == NULL) {
01020             SyncNoteFailed(root, here, "name == NULL", __LINE__);
01021             break;
01022         }
01023         if (lag == NULL || SyncCmpNames(lag, name) != 0) {
01024             // only append the name if it is not a duplicate
01025             SyncNameAccumAppend(dst, name, src->ents[j].data); // XXXXXX
01026             lag = name;
01027         } else {
01028             // this name needs to be destroyed
01029             ccn_charbuf_destroy(&name);
01030         }
01031     }
01032     src->len = 0;
01033     IndexSorter_Free(&ixBase);
01034     return dst;
01035 }
01036 
01037 static struct SyncNameAccum *
01038 exclusionsFromHashList(struct SyncRootStruct *root, struct SyncHashInfoList *list) {
01039     struct SyncNameAccum *acc = SyncAllocNameAccum(0);
01040     int count = 0;
01041     int limit = 1000;   // exclusionLimit
01042     int64_t now = SyncCurrentTime();
01043     int64_t limitMicros = 1000000 * 5; // exclusionTrig
01044 
01045     if (root->currentHash->length > 0) {
01046         // if the current hash is not empty, start there
01047         struct ccn_charbuf *hash = root->currentHash;
01048         struct ccn_charbuf *name = ccn_charbuf_create();
01049         count = count + hash->length + 8;
01050         ccn_name_init(name);
01051         ccn_name_append(name, hash->buf, hash->length);
01052         SyncNameAccumAppend(acc, name, 0);
01053     }
01054 
01055     while (list != NULL) {
01056         struct SyncHashCacheEntry *ce = list->ce;
01057         if (ce != NULL && (ce->state & SyncHashState_remote)
01058             && (ce->state & SyncHashState_covered)
01059             && SyncDeltaTime(ce->lastUsed, now) < limitMicros) {
01060             // any remote root known to be covered is excluded
01061             struct ccn_charbuf *hash = ce->hash;
01062             count = count + hash->length + 8;
01063             if (count > limit)
01064                 // exclusion list is getting too long, so ignore earlier roots
01065                 break;
01066             struct ccn_charbuf *name = ccn_charbuf_create();
01067             ccn_name_init(name);
01068             ccn_name_append(name, hash->buf, hash->length);
01069             SyncNameAccumAppend(acc, name, 0);
01070         }
01071         list = list->next;
01072     }
01073     if (acc->len == 0) {
01074         SyncFreeNameAccum(acc);
01075         return NULL;
01076     }
01077     struct SyncNameAccum *lag = acc;
01078     if (acc->len == 0) {
01079         // empty liust convention is NULL
01080         acc = NULL;
01081     } else {
01082         // exclusion list must be sorted
01083         acc = sortNames(root, acc);
01084     }
01085     SyncFreeNameAccum(lag);
01086     return acc;
01087 }
01088 
01089 static struct ccn_charbuf *
01090 constructCommandPrefix(struct SyncRootStruct *root,
01091                        enum SyncRegisterActionKind kind) {
01092     struct ccn_charbuf *prefix = ccn_charbuf_create();
01093     int res = 0;
01094     ccn_name_init(prefix);
01095     if (root->topoPrefix != NULL && root->topoPrefix->length > 0) {
01096         // the topo (if any) always comes first
01097         res |= SyncAppendAllComponents(prefix, root->topoPrefix);
01098     }
01099     // the command comes after the topo
01100     ccn_name_append_str(prefix, getCmdStr(kind));
01101     res |= ccn_name_append(prefix, root->sliceHash->buf, root->sliceHash->length);
01102 
01103     if (res < 0) {
01104         ccn_charbuf_destroy(&prefix);
01105     }
01106     return prefix;
01107 }
01108 
01109 // callback for when a root advise interest gets a response
01110 enum ccn_upcall_res
01111 ccns_root_advise_response(struct ccn_closure *selfp,
01112                           enum ccn_upcall_kind kind,
01113                           struct ccn_upcall_info *info) {
01114     static char *here = "Sync.SyncRootAdviseResponse";
01115     struct SyncActionData *data = selfp->data;
01116     enum ccn_upcall_res ret = CCN_UPCALL_RESULT_OK;
01117     switch (kind) {
01118         case CCN_UPCALL_FINAL:
01119             data = destroyActionData(data);
01120             free(selfp);
01121             break;
01122         case CCN_UPCALL_CONTENT_UNVERIFIED:
01123             ret = CCN_UPCALL_RESULT_VERIFY;
01124             break;
01125         case CCN_UPCALL_CONTENT_KEYMISSING:
01126             ret = CCN_UPCALL_RESULT_FETCHKEY;
01127             break;
01128         case CCN_UPCALL_INTEREST_TIMED_OUT:
01129             if (data == NULL || info == NULL ||
01130                 data->root == NULL || data->kind != SRI_Kind_RootAdvise) {
01131                 // not active, no useful info
01132             } else {
01133                 int64_t now = SyncCurrentTime();
01134                 struct SyncRootStruct *root = data->root;
01135                 int debug = root->base->debug;
01136                 // root->priv->stats->rootAdviseTimeout++;
01137                 if (debug >= CCNL_INFO) {
01138                     char temp[64];
01139                     int64_t dt = SyncDeltaTime(data->startTime, now);
01140                     dt = (dt + 500) / 1000;
01141                     snprintf(temp, sizeof(temp),
01142                              "timeout, %d.%03d secs",
01143                              (int) (dt / 1000), (int) (dt % 1000));
01144                     SyncNoteUri(root, here, temp, data->prefix);
01145                 }
01146                 data->startTime = now;
01147                 // as long as we need a response, keep expressing it
01148                 ret = CCN_UPCALL_RESULT_REEXPRESS;
01149             }
01150             break;
01151         case CCN_UPCALL_CONTENT_RAW:
01152         case CCN_UPCALL_CONTENT:
01153             if (data == NULL || info == NULL ||
01154                 data->root == NULL || data->kind != SRI_Kind_RootAdvise) {
01155                 // not active, no useful info
01156                 break;
01157             }
01158             struct SyncRootStruct *root = data->root;
01159             int debug = root->base->debug;
01160             if (debug >= CCNL_INFO) {
01161                 struct ccn_charbuf *nm = SyncNameForIndexbuf(info->content_ccnb,
01162                                                              info->content_comps);
01163                 size_t bytes = info->pco->offset[CCN_PCO_E];
01164                 char temp[64];
01165                 int64_t dt = SyncDeltaTime(data->startTime, SyncCurrentTime());
01166                 dt = (dt + 500) / 1000;
01167                 snprintf(temp, sizeof(temp),
01168                          "content, %d.%03d secs, %u bytes",
01169                          (int) (dt / 1000), (int) (dt % 1000),
01170                          (unsigned) bytes);
01171                 SyncNoteUri(root, here, temp, nm);
01172                 ccn_charbuf_destroy(&nm);
01173             }
01174 
01175             const unsigned char *hp = NULL;
01176             size_t hs = 0;
01177             size_t bytes = 0;
01178             int failed = 0;
01179             int cres = ccn_name_comp_get(info->content_ccnb,
01180                                          info->content_comps,
01181                                          data->skipToHash, &hp, &hs);
01182             if (cres < 0 || hp == NULL) {
01183                 // bad hash, so complain
01184                 failed++;
01185                 SyncNoteFailed(root, here, "bad hash", __LINE__);
01186                 //            } else if (fauxError(root->base)) {
01187                 //                failed++;
01188                 //                if (debug >= CCNL_WARNING)
01189                 //                    SyncNoteSimple(root, here, "faux error");
01190             } else {
01191                 struct SyncHashCacheEntry *ce = SyncHashEnter(root->ch, hp, hs,
01192                                                               SyncHashState_remote);
01193                 noteRemoteHash(root, ce, 1);
01194                 if (!isCovered(ce)) {
01195                     // may need to make an entry
01196                     struct SyncNodeComposite *nc = NULL;
01197                     char *hex = SyncHexStr(hp, hs);
01198                     if (ce != NULL && ce->ncR != NULL) {
01199                         nc = ce->ncR;
01200                         if (debug >= CCNL_INFO)
01201                             SyncNoteSimple2(root, here, "existing but not covered", hex);
01202                     } else {
01203                         nc = extractNode(root, info);
01204                         if (nc == NULL) {
01205                             // this is bad news, the parsing failed
01206                             failed++;
01207                             if (debug >= CCNL_SEVERE)
01208                                 SyncNoteSimple2(root, here, "extractNode failed", hex);
01209                         } else {
01210                             // new entry
01211                             ce->ncR = nc;
01212                             SyncNodeIncRC(nc);
01213                             bytes = info->pco->offset[CCN_PCO_E];
01214                             if (debug >= CCNL_INFO)
01215                                 SyncNoteSimple2(root, here, "remote entered", hex);
01216                         }
01217                     }
01218                     free(hex);
01219                 }
01220             }
01221             if (failed) {
01222                 root->priv->stats->rootAdviseFailed++;
01223             } else {
01224                 root->priv->stats->rootAdviseReceived++;
01225                 root->priv->stats->rootAdviseBytes += bytes;
01226             }
01227             break;
01228         default:
01229             // SHOULD NOT HAPPEN
01230             ret = CCN_UPCALL_RESULT_ERR;
01231             break;
01232     }
01233     return ret;
01234 }
01235 
01236 static int
01237 ccns_send_root_advise_interest(struct SyncRootStruct *root) {
01238     static char *here = "Sync.SyncSendRootAdviseInterest";
01239     enum SyncRegisterActionKind kind = SRI_Kind_RootAdvise;
01240     int debug = root->base->debug;
01241     struct SyncActionData *data = SyncFindAction(root, kind);
01242     struct SyncHashCacheEntry *ce = NULL;
01243     if (root->currentHash->length > 0) {
01244         ce = SyncHashLookup(root->ch,
01245                             root->currentHash->buf,
01246                             root->currentHash->length);
01247     }
01248     if (data != NULL) {
01249         // don't override exiting interest for this root unless the root has changed
01250         if (ce == NULL || ce == root->priv->lastLocalSent)
01251             return 0;
01252         // mark this as inactive, response to be ignored
01253         data->kind = SRI_Kind_None;
01254         if (debug >= CCNL_FINE)
01255             SyncNoteSimple(root, here, "marked old interest as inactive");
01256     }
01257     struct ccn_closure *action = calloc(1, sizeof(*action));
01258     struct ccn_charbuf *prefix = constructCommandPrefix(root, kind);
01259     struct ccn_charbuf *hash = ccn_charbuf_create();
01260 
01261     ccn_charbuf_append_charbuf(hash, root->currentHash);
01262     ccn_name_append(prefix, hash->buf, hash->length);
01263 
01264     data = newActionData(kind);
01265     data->skipToHash = SyncComponentCount(prefix);
01266     data->hash = hash;
01267     data->prefix = prefix;
01268     action->data = data;
01269     action->p = &ccns_root_advise_response;
01270 
01271     struct SyncNameAccum *excl = exclusionsFromHashList(root, root->priv->remoteSeen);
01272     struct ccn_charbuf *template = SyncGenInterest(NULL,
01273                                                    1, // scope
01274                                                    root->base->priv->rootAdviseLifetime,
01275                                                    -1, -1,
01276                                                    excl);
01277     int res = ccn_express_interest(root->base->ccn,
01278                                    prefix,
01279                                    action,
01280                                    template);
01281     SyncFreeNameAccumAndNames(excl);
01282     ccn_charbuf_destroy(&template);
01283     if (res >= 0) {
01284         // link the request into the root
01285         if (root->priv->adviseNeed > 0) root->priv->adviseNeed--;
01286         linkActionData(root, data);
01287         root->priv->lastAdvise = SyncCurrentTime();
01288         root->priv->lastLocalSent = ce;
01289         root->priv->stats->rootAdviseSent++;
01290         if (debug >= CCNL_INFO)
01291             SyncNoteUri(root, here, "sent", prefix);
01292         return 1;
01293     } else {
01294         // failed, so return the storage
01295         data = destroyActionData(data);
01296         free(action);
01297         if (debug >= CCNL_ERROR)
01298             SyncNoteSimple(root, here, "ccn_express_interest failed");
01299         return -1;
01300     }
01301 }
01302 
01303 static int
01304 CompareAction(struct ccn_schedule *sched,
01305               void *clienth,
01306               struct ccn_scheduled_event *ev,
01307               int flags);
01308 
01309 static struct SyncHashInfoList *
01310 chooseRemoteHash(struct SyncRootStruct *root) {
01311     struct SyncHashInfoList *each = root->priv->remoteSeen;
01312     int64_t now = SyncCurrentTime();
01313     int64_t limit = ((int64_t)root->base->priv->rootAdviseLifetime)*3*1000000;
01314     struct SyncHashInfoList *lag = NULL;
01315     while (each != NULL) {
01316         struct SyncHashCacheEntry *ce = each->ce;
01317         struct SyncHashInfoList *next = each->next;
01318         if (ce != NULL
01319             && (ce->state & SyncHashState_remote)
01320             && ((ce->state & SyncHashState_covered) == 0)) {
01321             // choose the first entry that is remote and not covered
01322             int64_t dt = SyncDeltaTime(ce->lastUsed, now);
01323             if (dt < limit) return each;
01324             ce = NULL;
01325         }
01326         if (ce == NULL || (ce->state & SyncHashState_covered)) {
01327             // prune this entry
01328             if (lag == NULL) root->priv->remoteSeen = next;
01329             else lag->next = next;
01330             free(each);
01331         } else
01332             lag = each;
01333         each = next;
01334     }
01335     return NULL;
01336 }
01337 
01338 static void
01339 destroyCompareData(struct SyncCompareData *data) {
01340     if (data == NULL) return;
01341     struct SyncRootStruct *root = data->root;
01342     struct SyncPrivate *priv = root->base->priv;
01343     if (root != NULL) {
01344         while (data->errList != NULL) {
01345             struct SyncActionData *sad = data->errList;
01346             destroyActionData(sad);
01347         }
01348         root->namesToFetch = SyncFreeNameAccumAndNames(root->namesToFetch);
01349         root->compare = NULL;
01350         struct SyncActionData *each = root->actions;
01351         // break the link from the action to the compare
01352         while (each != NULL) {
01353             if (each->comp == data) each->comp = NULL;
01354             each = each->next;
01355         }
01356     }
01357     if (priv->comparesBusy > 0) priv->comparesBusy--;
01358     ccn_charbuf_destroy(&data->hashL);
01359     ccn_charbuf_destroy(&data->hashR);
01360     ccn_charbuf_destroy(&data->cbL);
01361     ccn_charbuf_destroy(&data->cbR);
01362     data->twL = SyncTreeWorkerFree(data->twL);
01363     data->twR = SyncTreeWorkerFree(data->twR);
01364     if (data->ev != NULL && root != NULL) {
01365         data->ev->evdata = NULL;
01366         ccn_schedule_cancel(root->base->sched, data->ev);
01367     }
01368     free(data);
01369 }
01370 
01371 
01372 static void
01373 abortCompare(struct SyncCompareData *data, char *why) {
01374     // this compare failed due to a node fetch or content fetch failure
01375     // we could get repeated failures if we try the same remote node,
01376     // so remove it from the seen remote nodes, then destroy the compare data
01377     if (data == NULL) return;
01378     struct SyncRootStruct *root = data->root;
01379     if (root != NULL) {
01380         char *here = "Sync.abortCompare";
01381         struct SyncBaseStruct *base = root->base;
01382         struct SyncRootPrivate *priv = root->priv;
01383         struct SyncHashInfoList *list = priv->remoteSeen;
01384         struct SyncHashInfoList *lag = NULL;
01385         struct ccn_charbuf *hash = data->hashR;
01386         while (list != NULL) {
01387             struct SyncHashInfoList *next = list->next;
01388             struct SyncHashCacheEntry *ce = list->ce;
01389             if (ce != NULL && compareHash(ce->hash, hash) == 0) {
01390                 // found the failed root, so remove the remote entry
01391                 // if we really needed it it will come back via root advise
01392                 if (base->debug >= CCNL_INFO) {
01393                     // maybe this should be a warning?
01394                     char *hex = SyncHexStr(hash->buf, hash->length);
01395                     ccns_msg(root->base->client_handle,
01396                              "%s, root#%u, remove remote hash %s",
01397                              here, root->rootId, hex);
01398                     free(hex);
01399                 }
01400                 list->next = NULL;
01401                 list->ce = NULL;
01402                 if (ce->busy > 0) ce->busy--;
01403                 if (lag == NULL) priv->remoteSeen = next;
01404                 else lag->next = next;
01405                 free(list);
01406                 break;
01407             }
01408             lag = list;
01409             list = next;
01410         }
01411         if (root->base->debug >= CCNL_WARNING)
01412             SyncNoteSimple(root, here, why);
01413     }
01414     destroyCompareData(data);
01415 }
01416 
01417 static int
01418 comparisonFailed(struct SyncCompareData *data, char *why, int line) {
01419     SyncNoteFailed(data->root, "Sync.CompareAction", why, line);
01420     data->state = SyncCompare_waiting;
01421     return -1;
01422 }
01423 
01424 static int
01425 extractBuf(struct ccn_charbuf *cb, struct SyncNodeComposite *nc, struct SyncNodeElem *ne) {
01426     struct ccn_buf_decoder ds;
01427     struct ccn_buf_decoder *d = SyncInitDecoderFromElem(&ds, nc, ne);
01428     ccn_charbuf_reset(cb);
01429     int res = SyncAppendElementInner(cb, d);
01430     return res;
01431 }
01432 
01433 static struct SyncHashCacheEntry *
01434 ensureRemoteEntry(struct SyncCompareData *data,
01435                   const unsigned char * xp,
01436                   ssize_t xs) {
01437     char *here = "Sync.ensureRemoteEntry";
01438     struct SyncRootStruct *root = data->root;
01439     struct SyncHashCacheEntry *ce = SyncHashEnter(root->ch, xp, xs, SyncHashState_remote);
01440     if (ce == NULL) {
01441         // and why did this fail?
01442         SyncNoteFailed(root, here, "bad enter", __LINE__);
01443         return ce;
01444     }
01445     if (ce->state & SyncHashState_local) setCovered(ce);
01446     return ce;
01447 }
01448 
01449 static struct SyncHashCacheEntry *
01450 cacheEntryForElem(struct SyncCompareData *data,
01451                   struct SyncNodeComposite *nc,
01452                   struct SyncNodeElem *ne,
01453                   int remote) {
01454     char *here = "Sync.cacheEntryForElem";
01455     struct SyncRootStruct *root = data->root;
01456     struct ccn_buf_decoder ds;
01457     struct ccn_buf_decoder *d = SyncInitDecoderFromOffset(&ds, nc,
01458                                                           ne->start,
01459                                                           ne->stop);
01460     const unsigned char * xp = NULL;
01461     ssize_t xs = 0;
01462     SyncGetHashPtr(d, &xp, &xs);
01463     if (xs == 0 || xp == NULL) {
01464         // no hash?  this could be a problem
01465         SyncNoteFailed(root, here, "no hash", __LINE__);
01466         return NULL;
01467     }
01468     struct SyncHashCacheEntry *ce = NULL;
01469     if (remote > 0) {
01470         // the entry should be remote
01471         ce = ensureRemoteEntry(data, xp, xs);
01472     } else {
01473         // local entry, fetch it if missing
01474         ce = SyncHashLookup(root->ch, xp, xs);
01475         if (SyncCacheEntryFetch(ce) < 0) {
01476             SyncNoteFailed(root, here, "bad fetch", __LINE__);
01477             return NULL;
01478         }
01479     }
01480     if (ce == NULL) {
01481         // this entry should already exist
01482         SyncNoteFailed(root, here, "bad lookup", __LINE__);
01483         return ce;
01484     }
01485     ce->lastUsed = data->lastEnter;
01486     return ce;
01487 }
01488 
01489 static void
01490 kickCompare(struct SyncCompareData *scd, struct SyncActionData *action) {
01491     // we just got content for a particular action
01492     // may need to restart CompareAction
01493     if (scd != NULL && scd->ev == NULL) {
01494         struct ccn_scheduled_event *ev = ccn_schedule_event(scd->root->base->sched,
01495                                                             2000,
01496                                                             CompareAction,
01497                                                             scd,
01498                                                             0);
01499         scd->ev = ev;
01500     }
01501 }
01502 
01503 // callback for when an interest gets a response
01504 // used when fetching a remote content object by explicit name
01505 // or when fetching a remote node
01506 extern enum ccn_upcall_res
01507 SyncRemoteFetchResponse(struct ccn_closure *selfp,
01508                         enum ccn_upcall_kind kind,
01509                         struct ccn_upcall_info *info) {
01510     static char *here = "Sync.SyncRemoteFetchResponse";
01511     struct SyncActionData *data = selfp->data;
01512     enum ccn_upcall_res ret = CCN_UPCALL_RESULT_OK;
01513     switch (kind) {
01514         case CCN_UPCALL_FINAL:
01515             selfp->data = destroyActionData(data);
01516             free(selfp);
01517             break;
01518         case CCN_UPCALL_CONTENT_UNVERIFIED:
01519             // TBD: fix this when we can actually verify
01520             // return CCN_UPCALL_RESULT_VERIFY;
01521 #if (CCN_API_VERSION >= 4004)
01522         case CCN_UPCALL_CONTENT_RAW:
01523         case CCN_UPCALL_CONTENT_KEYMISSING:
01524 #endif
01525         case CCN_UPCALL_INTEREST_TIMED_OUT:
01526         case CCN_UPCALL_CONTENT: {
01527             if (data == NULL) break;
01528             struct ccnr_handle *ccnr = data->client_handle;
01529             struct SyncRootStruct *root = data->root;
01530             struct SyncCompareData *comp = data->comp;
01531             if (root == NULL) break;
01532             int debug = root->base->debug;
01533             struct SyncRootStats *stats = root->priv->stats;
01534             size_t bytes = 0;
01535             int64_t now = SyncCurrentTime();
01536             if (ccnr != NULL && info != NULL && info->pco != NULL
01537                 && kind != CCN_UPCALL_INTEREST_TIMED_OUT)
01538                 bytes = info->pco->offset[CCN_PCO_E];
01539             if (debug >= CCNL_INFO) {
01540                 char temp[64];
01541                 char *ns = "node";
01542                 char *ks = "ok";
01543                 if (data->kind == SRI_Kind_Content) ns = "content";
01544                 if (kind == CCN_UPCALL_INTEREST_TIMED_OUT) ks = "timeout!";
01545                 int64_t dt = SyncDeltaTime(data->startTime, now);
01546                 dt = (dt + 500) / 1000;
01547                 if (bytes > 0)
01548                     snprintf(temp, sizeof(temp),
01549                              "%s, %s, %d.%03d secs, %u bytes",
01550                              ns, ks, (int) (dt / 1000), (int) (dt % 1000),
01551                              (unsigned) bytes);
01552                 else
01553                     snprintf(temp, sizeof(temp),
01554                              "%s, %s, %d.%03d secs",
01555                              ns, ks, (int) (dt / 1000), (int) (dt % 1000));
01556                 SyncNoteUri(root, here, temp, data->prefix);
01557             }
01558 
01559             switch (data->kind) {
01560                 case SRI_Kind_NodeFetch: {
01561                     // node fetch response
01562                     const unsigned char *xp = data->hash->buf;
01563                     ssize_t xs = data->hash->length;
01564                     char *hex = SyncHexStr(xp, xs);
01565                     struct SyncHashCacheEntry *ce = SyncHashLookup(root->ch, xp, xs);
01566                     if (bytes <= 0) {
01567                         // did not get the node at all
01568                     } else if (ce != NULL && (isCovered(ce) || ce->ncR != NULL)) {
01569                         // there was a race, and we no longer need this
01570                         // for stats, count this as a success
01571                         if (debug >= CCNL_FINE) {
01572                             SyncNoteSimple2(root, here, "remote node covered", hex);
01573                         }
01574                     } else {
01575                         // we actually need the node that arrived
01576                         struct SyncNodeComposite *ncR = extractNode(root, info);
01577                         if (ncR == NULL) {
01578                             // decoding error, so can't use
01579                             if (debug >= CCNL_SEVERE)
01580                                 SyncNoteSimple2(root, here, "extractNode failed", hex);
01581                             bytes = 0;
01582                         } else {
01583                             // the entry can now be completed
01584                             ce = SyncHashEnter(root->ch, xp, xs, SyncHashState_remote);
01585                             ce->ncR = ncR;
01586                             SyncNodeIncRC(ncR);
01587                             // for the library, need to duplicate into the Local side
01588                             if (ce->ncL == NULL) {
01589                                 ce->ncL = ncR;
01590                                 SyncNodeIncRC(ncR);
01591                             }
01592                             // end
01593                             if (debug >= CCNL_INFO) {
01594                                 SyncNoteSimple2(root, here, "remote node entered", hex);
01595                             }
01596                             if (comp == NULL) {
01597                                 if (debug >= CCNL_ERROR)
01598                                     SyncNoteSimple(root, here, "remote node comp == NULL");
01599                             }
01600                         }
01601                     }
01602                     if (comp != NULL && comp->nodeFetchBusy > 0)
01603                         comp->nodeFetchBusy--;
01604                     if (bytes > 0) {
01605                         // node fetch wins
01606                         stats->nodeFetchReceived++;
01607                         stats->nodeFetchBytes += bytes;
01608                         if (comp != NULL)
01609                             comp->lastFetchOK = now;
01610                     } else {
01611                         // node fetch fails
01612                         if (kind == CCN_UPCALL_INTEREST_TIMED_OUT)
01613                             stats->nodeFetchTimeout++;
01614                         else stats->nodeFetchFailed++;
01615                         if (comp != NULL) {
01616                             // remember that this one failed
01617                             if (!moveActionData(data, SyncActionState_error))
01618                                 SyncNoteFailed(root, here, "moveActionData", __LINE__);
01619                             comp->nodeFetchFailed++;
01620                             selfp->data = NULL;
01621                         }
01622                     }
01623                     if (ce != NULL && (ce->state & SyncHashState_fetching))
01624                         // we are no longer fetching this node
01625                         ce->state -= SyncHashState_fetching;
01626                     kickCompare(comp, data);
01627                     free(hex);
01628                     break;
01629                 }
01630                 default:
01631                     // SHOULD NOT HAPPEN
01632                     ret = CCN_UPCALL_RESULT_ERR;
01633                     break;
01634             }
01635             break;
01636         }
01637         default:
01638             // SHOULD NOT HAPPEN
01639             ret = CCN_UPCALL_RESULT_ERR;
01640             break;
01641     }
01642     return ret;
01643 }
01644 
01645 extern int
01646 SyncStartNodeFetch(struct SyncRootStruct *root,
01647                    struct SyncHashCacheEntry *ce,
01648                    struct SyncCompareData *comp) {
01649     static char *here = "Sync.SyncStartNodeFetch";
01650     enum SyncRegisterActionKind kind = SRI_Kind_NodeFetch;
01651     struct SyncBaseStruct *base = root->base;
01652     int debug = base->debug;
01653     struct ccn *ccn = base->ccn;
01654     if (ccn == NULL)
01655         return SyncNoteFailed(root, here, "bad ccn handle", __LINE__);
01656     // first, check for existing fetch of same hash
01657     struct ccn_charbuf *hash = ce->hash;
01658     struct SyncActionData *data = root->actions;
01659     if (ce->state & SyncHashState_fetching)
01660         // already busy
01661         return 0;
01662     while (data != NULL) {
01663         if (data->kind == kind && compareHash(data->hash, hash) == 0)
01664             return 0;
01665         data = data->next;
01666     }
01667 
01668     struct ccn_closure *action = calloc(1, sizeof(*action));
01669     data = newActionData(kind);
01670     struct ccn_charbuf *name = constructCommandPrefix(root, kind);
01671     int res = -1;
01672     char *why = "constructCommandPrefix";
01673     if (name != NULL) {
01674         data->skipToHash = SyncComponentCount(name);
01675         ccn_name_append(name, hash->buf, hash->length);
01676         data->prefix = name;
01677         data->hash = ccn_charbuf_create();
01678         ccn_charbuf_append_charbuf(data->hash, hash);
01679         data->comp = comp;
01680         action->data = data;
01681         action->p = &SyncRemoteFetchResponse;
01682 
01683         struct ccn_charbuf *template = SyncGenInterest(NULL,
01684                                                        1,
01685                                                        base->priv->fetchLifetime,
01686                                                        -1, 1, NULL);
01687         res = ccn_express_interest(ccn, name, action, template);
01688         if (res < 0) {
01689             why = "ccn_express_interest";
01690             if (debug >= CCNL_SEVERE) {
01691                 char *hex = SyncHexStr(hash->buf, hash->length);
01692                 SyncNoteSimple2(root, here, "failed to express interest", hex);
01693                 free(hex);
01694             }
01695         } else {
01696             root->priv->stats->nodeFetchSent++;
01697             if (debug >= CCNL_INFO) {
01698                 char *hex = SyncHexStr(hash->buf, hash->length);
01699                 SyncNoteSimple2(root, here, "fetching", hex);
01700                 free(hex);
01701             }
01702         }
01703         ccn_charbuf_destroy(&template);
01704     }
01705     if (res >= 0) {
01706         // link the request into the root
01707         linkActionData(root, data);
01708         comp->nodeFetchBusy++;
01709         ce->state |= SyncHashState_fetching;
01710         res = 1;
01711     } else {
01712         // return the storage
01713         comp->nodeFetchFailed++;
01714         data = destroyActionData(data);
01715         free(action);
01716         if (debug >= CCNL_SEVERE)
01717             SyncNoteFailed(root, here, why, __LINE__);
01718     }
01719     return res;
01720 }
01721 
01722 /*
01723  * doPreload(data) walks the remote tree, and requests a fetch for every remote
01724  * node that is not covered locally and has not been fetched,
01725  * and is not being fetched.  This allows large trees to be fetched in parallel,
01726  * speeding up the load process.
01727  */
01728 static int
01729 doPreload(struct SyncCompareData *data, struct SyncTreeWorkerHead *twHead) {
01730     struct SyncRootStruct *root = data->root;
01731     int busyLim = root->base->priv->maxFetchBusy;
01732     for (;;) {
01733         if (data->nodeFetchBusy > busyLim) return 0;
01734         if (twHead->level <= 0) break;
01735         struct SyncTreeWorkerEntry *ent = SyncTreeWorkerTop(twHead);
01736         if (ent->cacheEntry == NULL)
01737             return -1;
01738         struct SyncHashCacheEntry *ceR = ent->cacheEntry;
01739         if (ceR == NULL
01740             || ceR->state & SyncHashState_fetching
01741             || ceR->state & SyncHashState_covered
01742             || ceR->state & SyncHashState_local) {
01743             // not a needed node, so pop it
01744         } else if (ceR->ncR != NULL) {
01745             // visit the children
01746             struct SyncNodeComposite *ncR = ceR->ncR;
01747             int lim = ncR->refLen;
01748             while (ent->pos < lim) {
01749                 struct SyncNodeElem *ep = &ncR->refs[ent->pos];
01750                 if ((ep->kind & SyncElemKind_leaf) == 0)
01751                     break;
01752                 ent->pos++;
01753             }
01754             if (ent->pos < lim) {
01755                 struct SyncNodeElem *ep = &ncR->refs[ent->pos];
01756                 struct SyncHashCacheEntry *sub = cacheEntryForElem(data, ncR, ep, 1);
01757                 if (sub == NULL)
01758                     return -1;
01759                 ent = SyncTreeWorkerPush(twHead);
01760                 if (ent == NULL)
01761                     return -1;
01762                 continue;
01763             }
01764         } else {
01765             // init the fetch, then pop
01766             SyncStartNodeFetch(root, ceR, data);
01767         }
01768         // common exit to pop and iterate
01769         ent = SyncTreeWorkerPop(twHead);
01770         if (ent != NULL) ent->pos++;
01771     }
01772     while (data->nodeFetchBusy < busyLim) {
01773         // restart the failed node fetches (while we can)
01774         struct SyncActionData *sad = data->errList;
01775         if (sad == NULL) break;
01776         struct SyncHashCacheEntry *ceR = SyncHashLookup(root->ch,
01777                                                         sad->hash->buf,
01778                                                         sad->hash->length);
01779         SyncStartNodeFetch(root, ceR, data);
01780         destroyActionData(sad);
01781     }
01782 
01783     if (data->nodeFetchBusy > 0) return 0;
01784     if (data->errList != NULL) return 0;
01785     if (twHead->level > 0) return 0;
01786     return 1;
01787 }
01788 
01789 static int
01790 addNameFromCompare(struct SyncCompareData *data) {
01791     char *here = "Sync.addNameFromCompare";
01792     struct SyncRootStruct *root = data->root;
01793     struct ccns_handle *ccns = (struct ccns_handle *)root->base->client_handle;
01794     int debug = root->base->debug;
01795     struct ccn_charbuf *name = data->cbR;
01796     int res;
01797     // callback for new name
01798     struct SyncTreeWorkerEntry *tweR = SyncTreeWorkerTop(data->twR);
01799     tweR->pos++;
01800     tweR->count++;
01801     data->namesAdded++;
01802     res = ccns->callback(ccns, root->currentHash, data->hashR, name);
01803     if (debug >= CCNL_FINE) {
01804         SyncNoteUri(root, here, "added", name);
01805     }
01806     return 0;
01807 }
01808 
01809 /*
01810  * doComparison(data) is a key routine, because it determines what is
01811  * present in data->twR that is not present in data->twL.  It does so by
01812  * walking the two trees, L and R, in increasing name order.  To gain efficiency
01813  * doComparison avoids examining nodes in R that are already covered, and nodes
01814  * in L that have been bypassed in the walk of R.
01815  *
01816  * Ideally doComparison allows determination of k differences in O(k*log(N))
01817  * steps, where N is the number of names in the union of L and R.  However, if
01818  * the tree structures differ significantly the cost can be as high as O(N).
01819  */
01820 static int
01821 doComparison(struct SyncCompareData *data) {
01822     struct SyncRootStruct *root = data->root;
01823     struct SyncTreeWorkerHead *twL = data->twL;
01824     struct SyncTreeWorkerHead *twR = data->twR;
01825 
01826     for (;;) {
01827         struct SyncTreeWorkerEntry *tweR = SyncTreeWorkerTop(twR);
01828         if (tweR == NULL) {
01829             // the remote is done, so no more names to add
01830             return 1;
01831         }
01832         struct SyncHashCacheEntry *ceR = tweR->cacheEntry;
01833         if (ceR == NULL)
01834             return comparisonFailed(data, "bad cache entry for R", __LINE__);
01835         ceR->lastUsed = data->lastEnter;
01836         if (tweR->pos == 0 && isCovered(ceR)) {
01837             // short cut, nothing in R we don't have
01838             size_t c = tweR->count;
01839             tweR = SyncTreeWorkerPop(twR);
01840             if (tweR != NULL) {
01841                 tweR->pos++;
01842                 tweR->count += c;
01843             }
01844             continue;
01845         }
01846         struct SyncNodeComposite *ncR = ceR->ncR;
01847         if (ncR == NULL) {
01848             // top remote node not present, so go get it
01849             int nf = SyncStartNodeFetch(root, ceR, data);
01850             if (nf == 0) {
01851                 // TBD: duplicate, so ignore the fetch?
01852                 // for now, this is an error!
01853                 return comparisonFailed(data, "node fetch duplicate?", __LINE__);
01854             } else if (nf > 0) {
01855                 // node fetch started OK
01856             } else {
01857                 // node fetch failed to initiate
01858                 return comparisonFailed(data, "bad node fetch for R", __LINE__);
01859             }
01860             return 0;
01861         }
01862         if (tweR->pos >= ncR->refLen) {
01863             // we just went off the end of the current remote node, so pop it
01864             // skip over the processed element if we still have a node
01865             size_t c = tweR->count;
01866             if (c == 0) {
01867                 // nothing was added, so this node must be covered
01868                 setCovered(ceR);
01869             }
01870             tweR = SyncTreeWorkerPop(twR);
01871             if (tweR != NULL) {
01872                 tweR->pos++;
01873                 tweR->count += c;
01874             }
01875             continue;
01876         }
01877         struct SyncNodeElem *neR = SyncTreeWorkerGetElem(twR);
01878         if (neR == NULL)
01879             return comparisonFailed(data, "bad element for R", __LINE__);
01880 
01881         if (extractBuf(data->cbR, ncR, neR) < 0)
01882             // the remote name/hash extract failed
01883             return comparisonFailed(data, "bad extract for R", __LINE__);
01884 
01885         struct SyncTreeWorkerEntry *tweL = SyncTreeWorkerTop(twL);
01886         if (tweL == NULL) {
01887             // L is now empty, so add R
01888             if (neR->kind == SyncElemKind_node) {
01889                 // to add a node R, push into it
01890                 struct SyncHashCacheEntry *subR = cacheEntryForElem(data, ncR, neR, 1);
01891                 if (subR == NULL || SyncTreeWorkerPush(twR) == NULL)
01892                     return comparisonFailed(data, "bad cache entry for R", __LINE__);
01893             } else {
01894                 // R is a leaf
01895                 addNameFromCompare(data);
01896             }
01897         } else {
01898             struct SyncHashCacheEntry *ceL = tweL->cacheEntry;
01899             //// Need to duplicate what happens for remote
01900             struct SyncNodeComposite *ncL = ceL->ncL;
01901             if (ncL == NULL) {
01902                 // top remote node not present, so go get it
01903                 int nf = SyncStartNodeFetch(root, ceL, data);
01904                 if (nf == 0) {
01905                     // TBD: duplicate, so ignore the fetch?
01906                     // for now, this is an error!
01907                     return comparisonFailed(data, "node fetch duplicate?", __LINE__);
01908                 } else if (nf > 0) {
01909                     // node fetch started OK
01910                 } else {
01911                     // node fetch failed to initiate
01912                     return comparisonFailed(data, "bad node fetch for R", __LINE__);
01913                 }
01914                 return 0;
01915             }
01916             /////
01917             ceL->lastUsed = data->lastEnter;
01918             if (tweL->pos >= ncL->refLen) {
01919                 // we just went off the end of the current local node, so pop it
01920                 tweL = SyncTreeWorkerPop(twL);
01921                 if (tweL != NULL) tweL->pos++;
01922                 continue;
01923             }
01924             struct SyncNodeElem *neL = SyncTreeWorkerGetElem(twL);
01925             if (neL == NULL || extractBuf(data->cbL, ncL, neL) < 0) {
01926                 // the local name/hash extract failed
01927                 return comparisonFailed(data, "bad extract for L", __LINE__);
01928             }
01929             if (neR->kind == SyncElemKind_node) {
01930                 // quick kill for a remote node?
01931                 struct SyncHashCacheEntry *subR = cacheEntryForElem(data, ncR, neR, 1);
01932                 if (subR == NULL)
01933                     return comparisonFailed(data, "bad element for R", __LINE__);
01934                 if (isCovered(subR)) {
01935                     // nothing to add, this node is already covered
01936                     // note: this works even if the remote node is not present!
01937                     tweR->pos++;
01938                     continue;
01939                 }
01940                 if (subR->ncR == NULL) {
01941                     // there is a remote hash, but no node present,
01942                     // so push into it to force the fetch
01943                     if (SyncTreeWorkerPush(twR) == NULL)
01944                         return comparisonFailed(data, "bad push for R", __LINE__);
01945                     continue;
01946                 }
01947 
01948                 if (neL->kind == SyncElemKind_leaf) {
01949                     // L is a leaf, R is a node that is present
01950                     enum SyncCompareResult scr = SyncNodeCompareMinMax(subR->ncR, data->cbL);
01951                     switch (scr) {
01952                         case SCR_before:
01953                             // L < Min(R), so advance L
01954                             tweL->pos++;
01955                             break;
01956                         case SCR_max:
01957                             // L == Max(R), advance both
01958                             tweL->pos++;
01959                             tweR->pos++;
01960                             break;
01961                         default:
01962                             // in all other cases, dive into R
01963                             if (SyncTreeWorkerPush(twR) == NULL)
01964                                 return comparisonFailed(data, "bad push for R", __LINE__);
01965                             break;
01966                     }
01967 
01968                 } else {
01969                     // both L and R are nodes, test for L being present
01970                     struct SyncHashCacheEntry *subL = cacheEntryForElem(data, ncL, neL, 1); // HACK it's remote.
01971                     if (subL == NULL || subL->ncL == NULL)
01972                         return comparisonFailed(data, "bad cache entry for L", __LINE__);
01973                     // both L and R are nodes, and both are present
01974                     struct SyncNodeComposite *ncL = subL->ncL;
01975                     struct SyncNodeComposite *ncR = subR->ncR;
01976                     int cmp = SyncCmpNames(ncR->minName, ncL->maxName);
01977                     if (cmp > 0) {
01978                         // Min(R) > Max(L), so advance L
01979                         tweL->pos++;
01980                     } else {
01981                         // dive into both nodes
01982                         if (SyncTreeWorkerPush(twL) == NULL)
01983                             return comparisonFailed(data, "bad push for L", __LINE__);
01984                         if (SyncTreeWorkerPush(twR) == NULL)
01985                             return comparisonFailed(data, "bad push for R", __LINE__);
01986                     }
01987                 }
01988             } else {
01989                 // R is a leaf
01990                 if (neL->kind == SyncElemKind_leaf) {
01991                     // both L and R are names, so the compare is simple
01992                     int cmp = SyncCmpNames(data->cbL, data->cbR);
01993                     if (cmp == 0) {
01994                         // L == R, so advance both
01995                         tweL->pos++;
01996                         tweR->pos++;
01997                     } else if (cmp < 0) {
01998                         // L < R, advance L
01999                         tweL->pos++;
02000                     } else {
02001                         // L > R, so add R
02002                         addNameFromCompare(data);
02003                     }
02004                 } else {
02005                     // R is a leaf, but L is a node
02006                     struct SyncHashCacheEntry *subL = cacheEntryForElem(data, ncL, neL, 1);  // HACK, it's remote
02007                     if (subL == NULL || subL->ncL == NULL)
02008                         return comparisonFailed(data, "bad cache entry for L", __LINE__);
02009                     enum SyncCompareResult scr = SyncNodeCompareMinMax(subL->ncL, data->cbR);
02010                     switch (scr) {
02011                         case SCR_before:
02012                             // R < Min(L), so add R
02013                             addNameFromCompare(data);
02014                             break;
02015                         case SCR_max:
02016                             // R == Max(L), advance both
02017                             tweL->pos++;
02018                             tweR->pos++;
02019                             break;
02020                         case SCR_min:
02021                             // R == Min(L), advance R
02022                             tweR->pos++;
02023                             break;
02024                         case SCR_after:
02025                             // R > Max(L), advance L
02026                             tweL->pos++;
02027                             break;
02028                         case SCR_inside:
02029                             // Min(L) < R < Max(L), so dive into L
02030                             if (SyncTreeWorkerPush(twL) == NULL)
02031                                 return comparisonFailed(data, "bad push for L", __LINE__);
02032                             break;
02033                         default:
02034                             // this is really broken
02035                             return comparisonFailed(data, "bad min/max compare", __LINE__);
02036                     }
02037 
02038                 }
02039             }
02040         }
02041     }
02042 }
02043 
02044 static int
02045 CompareAction(struct ccn_schedule *sched,
02046               void *clienth,
02047               struct ccn_scheduled_event *ev,
02048               int flags) {
02049     char *here = "Sync.CompareAction";
02050     struct SyncCompareData *data = (struct SyncCompareData *) ev->evdata;
02051     int res;
02052 
02053     if (data == NULL || data->root == NULL) {
02054         // invalid, not sure how we got here
02055         return -1;
02056     }
02057     data->lastEnter = SyncCurrentTime();
02058     struct SyncRootStruct *root = data->root;
02059     struct ccns_handle *ccns = (struct ccns_handle *)root->base->client_handle;
02060     int debug = root->base->debug;
02061     if (data->ev != ev || flags & CCN_SCHEDULE_CANCEL) {
02062         // orphaned or cancelled
02063         if (debug >= CCNL_FINE)
02064             SyncNoteSimple(root, here, "orphan?");
02065         data->ev = NULL;
02066         return -1;
02067     }
02068 
02069     int delay = 2000;
02070     switch (data->state) {
02071         case SyncCompare_init:
02072             // nothing to do, flow into next state
02073             if (debug >= CCNL_FINE)
02074                 SyncNoteSimple(root, here, "init");
02075             data->state = SyncCompare_preload;
02076         case SyncCompare_preload:
02077             // nothing to do (yet), flow into next state
02078             if (debug >= CCNL_FINE)
02079                 SyncNoteSimple(root, here, "preload");
02080             // For library, need to preload for Local as well as Remote.
02081             struct SyncHashCacheEntry *ceL = SyncHashLookup(root->ch,
02082                                                             data->hashL->buf,
02083                                                             data->hashL->length);
02084             if (ceL != NULL) {
02085                 SyncTreeWorkerInit(data->twL, ceL, 1);
02086                 res = doPreload(data, data->twL);
02087                 if (res < 0) {
02088                     abortCompare(data, "doPreloadL failed");
02089                     return -1;
02090                 }
02091                 if (res == 0) {
02092                     // not yet preloaded
02093                     if (data->nodeFetchBusy > 0) {
02094                         // rely on SyncRemoteFetchResponse to restart us
02095                         data->ev = NULL;
02096                         delay = -1;
02097                     }
02098                     break;
02099                 }
02100                 // before switch to busy, reset the remote tree walker
02101                 SyncTreeWorkerInit(data->twL, ceL, 1);
02102             }
02103             struct SyncHashCacheEntry *ceR = SyncHashLookup(root->ch,
02104                                                             data->hashR->buf,
02105                                                             data->hashR->length);
02106             SyncTreeWorkerInit(data->twR, ceR, 1);
02107             res = doPreload(data, data->twR);
02108             if (res < 0) {
02109                 abortCompare(data, "doPreloadR failed");
02110                 return -1;
02111             }
02112             if (res == 0) {
02113                 // not yet preloaded
02114                 if (data->nodeFetchBusy > 0) {
02115                     // rely on SyncRemoteFetchResponse to restart us
02116                     data->ev = NULL;
02117                     delay = -1;
02118                 }
02119                 break;
02120             }
02121             // before switch to busy, reset the remote tree walker
02122             SyncTreeWorkerInit(data->twR, ceR, 1);
02123             // If library indicates start at current root, skip to done and
02124             // reset the restart at current root flag
02125             if (ccns->flags & CCNS_FLAGS_SC) {
02126                 ccns->flags &= ~CCNS_FLAGS_SC;
02127                 data->state = SyncCompare_done;
02128                 delay = 20;  // reschedule in a short time.
02129                 break; 
02130             }
02131             data->state = SyncCompare_busy;
02132         case SyncCompare_busy:
02133             // come here when we are comparing the trees
02134             if (debug >= CCNL_FINE)
02135                 SyncNoteSimple(root, here, "busy");
02136             res = doComparison(data);
02137             if (res < 0) {
02138                 abortCompare(data, "doComparison failed");
02139                 return -1;
02140             }
02141             if (data->errList != NULL) {
02142                 // we had a load started during compare, so retreat a state
02143                 data->state = SyncCompare_preload;
02144                 if (debug >= CCNL_WARNING)
02145                     SyncNoteSimple(root, here, "retreat one state");
02146                 break;
02147             }
02148             if (res == 0)
02149                 // comparison not yet complete
02150                 break;
02151             // either full success or failure gets here
02152             data->state = SyncCompare_waiting;
02153         case SyncCompare_waiting:
02154             if (debug >= CCNL_FINE)
02155                 SyncNoteSimple(root, here, "waiting");
02156             data->state = SyncCompare_done;
02157         case SyncCompare_done: {
02158             // for library, when we're done, we copy the remote to the local hash
02159             struct SyncHashCacheEntry *ce = SyncHashLookup(root->ch,
02160                                                            data->hashR->buf,
02161                                                            data->hashR->length);
02162             ccn_charbuf_reset(root->currentHash);
02163             ccn_charbuf_append_charbuf(root->currentHash, data->hashR);
02164             SyncNodeIncRC(ce->ncR);
02165             if (ce->ncL != NULL)
02166                 SyncNodeDecRC(ce->ncL);
02167             ce->ncL = ce->ncR;
02168             // cleanup
02169             int64_t now = SyncCurrentTime();
02170             int64_t mh = SyncDeltaTime(data->lastEnter, now);
02171             int64_t dt = SyncDeltaTime(data->startTime, now);
02172             root->priv->stats->comparesDone++;
02173             root->priv->stats->lastCompareMicros = dt;
02174             if (mh > data->maxHold) data->maxHold = mh;
02175             mh = (mh + 500) / 1000;
02176             dt = (dt + 500) / 1000;
02177 
02178             if (debug >= CCNL_INFO) {
02179                 int reportStats = 1;
02180                 char temp[64];
02181                 snprintf(temp, sizeof(temp)-2,
02182                          "%d.%03d secs [%d.%03d], %d names added",
02183                          (int) (dt / 1000), (int) (dt % 1000),
02184                          (int) (mh / 1000), (int) (mh % 1000),
02185                          (int) data->namesAdded);
02186                 SyncNoteSimple2(root, here, "done", temp);
02187                 if (reportStats) {
02188                     struct ccn_charbuf *cb = ccn_charbuf_create();
02189                     // formatStats(root, cb);
02190                     char *str = ccn_charbuf_as_string(cb);
02191                     ccns_msg(root->base->client_handle, "%s, %s", here, str);
02192                     ccn_charbuf_destroy(&cb);
02193                 }
02194             }
02195             destroyCompareData(data);
02196             return -1;
02197         }
02198         default: break;
02199     }
02200     int64_t mh = SyncDeltaTime(data->lastEnter, SyncCurrentTime());
02201     if (mh > data->maxHold) data->maxHold = mh;
02202     return delay;
02203 }
02204 
02205 int
02206 SyncStartCompareAction(struct SyncRootStruct *root, struct ccn_charbuf *hashR) {
02207     char *here = "Sync.SyncStartCompareAction";
02208     struct SyncPrivate *priv = root->base->priv;
02209     if (root->compare != NULL
02210         || priv->comparesBusy >= priv->maxComparesBusy)
02211         return 0;
02212 
02213     struct ccn_charbuf *hashL = root->currentHash;
02214     struct SyncHashCacheEntry *ceL = NULL;
02215 
02216     if (hashL->length > 0) {
02217         // if L is not empty, check the cache entry
02218         ceL = SyncHashLookup(root->ch, hashL->buf, hashL->length);
02219         if (ceL == NULL)
02220             return SyncNoteFailed(root, here, "bad lookup for L", __LINE__);
02221     }
02222     struct SyncHashCacheEntry *ceR = SyncHashEnter(root->ch,
02223                                                    hashR->buf,
02224                                                    hashR->length,
02225                                                    SyncHashState_remote);
02226     if (ceR == NULL)
02227         return SyncNoteFailed(root, here, "bad lookup for R", __LINE__);
02228 
02229     int debug = root->base->debug;
02230     struct ccnr_handle *ccnr = root->base->client_handle;
02231     struct SyncCompareData *data = calloc(1, sizeof(*data));
02232     int64_t mark = SyncCurrentTime();
02233     data->startTime = mark;
02234     data->lastEnter = mark;
02235     data->lastMark = mark;
02236     data->lastFetchOK = mark;
02237     data->root = root;
02238     root->compare = data;
02239     root->namesToFetch = SyncFreeNameAccumAndNames(root->namesToFetch);
02240     data->twL = SyncTreeWorkerCreate(root->ch, ceL, 0);
02241     if (ceL != NULL) ceL->lastUsed = mark;
02242     data->twR = SyncTreeWorkerCreate(root->ch, ceR, 1);
02243     ceR->lastUsed = mark;
02244     data->hashL = ccn_charbuf_create();
02245     ccn_charbuf_append_charbuf(data->hashL, hashL);
02246     data->hashR = ccn_charbuf_create();
02247     ccn_charbuf_append_charbuf(data->hashR, hashR);
02248 
02249     data->cbL = ccn_charbuf_create();
02250     data->cbR = ccn_charbuf_create();
02251 
02252     data->state = SyncCompare_init;
02253     priv->comparesBusy++;
02254 
02255     kickCompare(data, NULL);
02256 
02257     if (debug >= CCNL_INFO) {
02258         char *hexL = SyncHexStr(hashL->buf, hashL->length);
02259         char *msgL = ((hashL->length > 0) ? hexL : "empty");
02260         char *hexR = SyncHexStr(hashR->buf, hashR->length);
02261         char *msgR = ((hashR->length > 0) ? hexR : "empty");
02262         ccns_msg(ccnr, "%s, root#%u, L %s, R %s",
02263                  here, root->rootId, msgL, msgR);
02264         free(hexL);
02265         free(hexR);
02266     }
02267 
02268     return 1;
02269 }
02270 
02271 static int
02272 HeartbeatAction(struct ccn_schedule *sched,
02273                 void *clienth,
02274                 struct ccn_scheduled_event *ev,
02275                 int flags) {
02276     char *here = "Sync.HeartbeatAction";
02277     struct SyncBaseStruct *base = (struct SyncBaseStruct *) ev->evdata;
02278     if (base == NULL || base->priv == NULL || (flags & CCN_SCHEDULE_CANCEL)) {
02279         // TBD: and why did this happen? (can't report it, though)
02280         return -1;
02281     }
02282 
02283     struct SyncPrivate *priv = base->priv;
02284     int64_t now = SyncCurrentTime();
02285     struct SyncRootStruct *root = priv->rootHead;
02286 
02287     while (root != NULL) {
02288         struct SyncCompareData *comp = root->compare;
02289         if (comp == NULL) {
02290             // only run the update when not comparing
02291             struct SyncHashInfoList *x = chooseRemoteHash(root);
02292             if (x != NULL) {
02293                 SyncStartCompareAction(root, x->ce->hash);
02294             }
02295         } else {
02296             // running a compare, check for stall or excessive time since last fetch
02297             int64_t dt = SyncDeltaTime(comp->lastMark, now);
02298             if (dt > 15*1000000) {  // updateStallDelta
02299                 // periodic stall warning
02300                 if (base->debug >= CCNL_WARNING)
02301                     SyncNoteSimple(root, here, "compare stalled?");
02302                 comp->lastMark = now;
02303             }
02304             // test for fatal stall (based on last fetch time)
02305             dt = SyncDeltaTime(comp->lastFetchOK, now);
02306             if (dt > 20*1000000) {  // compareAssumeBad
02307                 abortCompare(comp, "no progress");
02308             }
02309         }
02310         // TBD: prune eldest remote roots from list
02311         // TBD: prune old remote node entries from cache
02312         root = root->next;
02313     }
02314     return priv->heartbeatMicros;
02315 }
02316 extern enum ccn_upcall_res
02317 SyncInterestArrived(struct ccn_closure *selfp,
02318                     enum ccn_upcall_kind kind,
02319                     struct ccn_upcall_info *info) {
02320     static char *here = "Sync.SyncInterestArrived";
02321     struct SyncActionData *data = selfp->data;
02322     enum ccn_upcall_res ret = CCN_UPCALL_RESULT_OK;
02323     switch (kind) {
02324         case CCN_UPCALL_FINAL:
02325             data = destroyActionData(data);
02326             free(selfp);
02327             break;
02328         case CCN_UPCALL_INTEREST: {
02329             struct SyncRootStruct *root = data->root;
02330             if (root == NULL) break;
02331             struct SyncRootPrivate *rp = root->priv;
02332             struct SyncBaseStruct *base = root->base;
02333             int debug = base->debug;
02334             int skipToHash = data->skipToHash;
02335             const unsigned char *buf = info->interest_ccnb;
02336             struct ccn_indexbuf *comps = info->interest_comps;
02337             char *hexL = NULL;
02338             char *hexR = NULL;
02339             if ((info->pi->answerfrom & CCN_AOK_NEW) == 0) {
02340                 // TBD: is this the right thing to do?
02341                 if (debug >= CCNL_INFO)
02342                     SyncNoteUri(root, here, "CCN_AOK_NEW = 0", data->prefix);
02343                 break;
02344             }
02345             switch (data->kind) {
02346                 case SRI_Kind_None:
02347                     // not an active request, so ignore
02348                     break;
02349                 case SRI_Kind_AdviseInt: {
02350                     const unsigned char *bufR = NULL;
02351                     size_t lenR = 0;
02352                     struct SyncHashCacheEntry *ceR = NULL;
02353                     const unsigned char *bufL = root->currentHash->buf;
02354                     char *who = "RootAdvise";
02355                     size_t lenL = root->currentHash->length;
02356                     ccn_name_comp_get(buf, comps, skipToHash, &bufR, &lenR);
02357                     if (bufR == NULL || lenR == 0) {
02358                         if (data->kind == SRI_Kind_FetchInt) {
02359                             // not well-formed, so ignore it
02360                             if (debug >= CCNL_SEVERE)
02361                                 SyncNoteSimple2(root, here, who, "failed, no remote hash");
02362                             return ret;
02363                         }
02364                     } else hexR = SyncHexStr(bufR, lenR);
02365 
02366                     if (debug >= CCNL_INFO) {
02367                         if (hexR == NULL)
02368                             SyncNoteSimple2(root, here, who, "empty remote hash");
02369                         else SyncNoteSimple3(root, here, who, "remote hash", hexR);
02370                     }
02371                     if (data->kind == SRI_Kind_AdviseInt) {
02372                         // SYNC LIBRARY - no, it's not worth pulling in the exclude printer for this
02373                         // worth noting the remote root
02374                         //if (debug >= CCNL_FINER) {
02375                         //    ssize_t start = info->pi->offset[CCN_PI_B_Exclude];
02376                         //    ssize_t stop = info->pi->offset[CCN_PI_E_Exclude];
02377                         //    if (stop > start) {
02378                         //// we appear to have an exclusion
02379                         //        struct ccn_buf_decoder ds;
02380                         //        struct ccn_buf_decoder *d = &ds;
02381                         //         ccn_buf_decoder_start(d, buf+start, stop - start);
02382                         //         reportExclude(root, d);
02383                         //     }
02384                         //  }
02385                         if (lenR != 0) {
02386                             ceR = SyncHashEnter(root->ch, bufR, lenR, SyncHashState_remote);
02387                             int64_t lastMark = ceR->lastRemoteFetch;
02388                             noteRemoteHash(root, ceR, 1);
02389                             rp->adviseNeed = ADVISE_NEED_RESET;
02390                             // force any old interest to be inactive
02391                             if (lastMark == 0) {
02392                                 // not entered, so we need to do a RootAdvise
02393                                 struct SyncActionData *data = SyncFindAction(root, SRI_Kind_RootAdvise);
02394                                 if (data != NULL) data->kind = SRI_Kind_None;
02395                             }
02396                         }
02397                         rp->stats->rootAdviseSeen++;
02398                     } else {
02399                         rp->stats->nodeFetchSeen++;
02400                     }
02401 
02402                     if (lenL == 0) {
02403                         if (debug >= CCNL_INFO)
02404                             SyncNoteSimple2(root, here, who, "ignored (empty local root)");
02405                         if (lenR == 0) {
02406                             // both L and R are empty, so suppress short-term thrashing
02407                             rp->adviseNeed = 0;
02408                         } else if (root->namesToAdd->len > 0) {
02409                             if (debug >= CCNL_FINE)
02410                                 SyncNoteSimple2(root, here, who, "new tree needed");
02411                         }
02412                         break;
02413                     }
02414                     // SYNC LIBRARY, just return after noting the hash, don't gen response
02415                     break;
02416 
02417                     if (data->kind == SRI_Kind_AdviseInt
02418                         && lenR == lenL && memcmp(bufL, bufR, lenR) == 0) {
02419                         // hash given is same as our root hash, so ignore the request
02420                         if (debug >= CCNL_INFO)
02421                             SyncNoteSimple2(root, here, who, "ignored (same hash)");
02422                         //purgeOldEntries(root);
02423                         break;
02424                     }
02425                     break;
02426                 }
02427                 default:
02428                     // SHOULD NOT HAPPEN
02429                     ret = CCN_UPCALL_RESULT_ERR;
02430                     break;
02431             }
02432             if (hexL != NULL) free(hexL);
02433             if (hexR != NULL) free(hexR);
02434             break;
02435         }
02436         default:
02437             // SHOULD NOT HAPPEN
02438             ret = CCN_UPCALL_RESULT_ERR;
02439             break;
02440     }
02441     return ret;
02442 }
02443 
02444 int
02445 SyncRegisterInterests(struct SyncRootStruct *root) {
02446     char *here = "Sync.SyncRegisterInterests";
02447     struct SyncBaseStruct *base = root->base;
02448     struct ccn *ccn = base->ccn;
02449     struct ccn_charbuf *prefix;
02450     struct ccn_closure *action;
02451     struct SyncActionData *data;
02452 
02453     if (ccn == NULL) return -1;
02454     int res = 0;
02455 
02456     prefix = constructCommandPrefix(root, SRI_Kind_AdviseInt);
02457     if (prefix == NULL) {
02458         res = SyncNoteFailed(root, here, "bad prefix", __LINE__);
02459         return(res);
02460     }
02461     action = calloc(1, sizeof(*action));
02462     data = newActionData(SRI_Kind_AdviseInt);
02463     data->prefix = prefix;
02464     data->skipToHash = SyncComponentCount(prefix);
02465     action->data = data;
02466     action->p = &SyncInterestArrived;
02467     res |= ccn_set_interest_filter(root->base->ccn, prefix, action);
02468     if (res < 0) {
02469         if (base->debug >= CCNL_SEVERE)
02470             SyncNoteUri(root, here, "ccn_set_interest_filter failed", prefix);
02471         data = destroyActionData(data);
02472     } else {
02473         linkActionData(root, data);
02474         if (base->debug >= CCNL_INFO)
02475             SyncNoteUri(root, here, "RootAdvise", prefix);
02476     }
02477     return(res);
02478 }
02479 
02480 int
02481 SyncHandleSlice(struct SyncBaseStruct *base, struct ccn_charbuf *name) {
02482     return(0);
02483 }
02484 
02485 int
02486 SyncStartSliceEnum(struct SyncRootStruct *root) {
02487     return(0);
02488 }
02489 
02490 int
02491 SyncStartHeartbeat(struct SyncBaseStruct *base) {
02492     return(0);
02493 }
02494 /*
02495  * Functions that are reference directly from the Sync code that should
02496  * along with some others, be turned into methods
02497  */
02498 
02499 static int
02500 r_sync_lookup(struct ccnr_handle *ccnr,
02501               struct ccn_charbuf *interest,
02502               struct ccn_charbuf *content_ccnb)
02503 {
02504     int ans = -1;
02505     ccns_msg(ccnr, "WARNING: r_sync_lookup should not be called in sync library");
02506     return(ans);
02507 }
02508 
02509 /**
02510  * Called when a content object has been constructed locally by sync
02511  * and needs to be committed to stable storage by the repo.
02512  * returns 0 for success, -1 for error.
02513  */
02514 
02515 static int
02516 r_sync_local_store(struct ccnr_handle *ccnr,
02517                    struct ccn_charbuf *content)
02518 {
02519     int ans = -1;
02520     ccns_msg(ccnr, "WARNING: r_sync_local_store should not be called in sync library");
02521     return(ans);
02522 }
02523 
02524 static uintmax_t
02525 ccns_accession_encode(struct ccnr_handle *ccnr, ccnr_accession a)
02526 {
02527     return(a);
02528 }
02529 
02530 static ccnr_hwm
02531 ccns_hwm_update(struct ccnr_handle *ccnr, ccnr_hwm hwm, ccnr_accession a)
02532 {
02533     return(a <= hwm ? hwm : a);
02534 }
02535 #define extern
02536 #define SYNCLIBRARY
02537 #define ccnr_msg ccns_msg
02538 #define ccnr_hwm_update ccns_hwm_update
02539 #include <sync/IndexSorter.c>
02540 #include <sync/SyncBase.c>
02541 #include <sync/SyncHashCache.c>
02542 #include <sync/SyncNode.c>
02543 #include <sync/SyncRoot.c>
02544 #include <sync/SyncTreeWorker.c>
02545 #include <sync/SyncUtil.c>
02546 #undef extern
Generated on Tue Aug 21 14:54:18 2012 for Content-Centric Networking in C by  doxygen 1.6.3