SyncTest.c

Go to the documentation of this file.
00001 /**
00002  * @file sync/SyncTest.c
00003  * 
00004  * Part of CCNX Sync.
00005  *
00006  * Copyright (C) 2011 Palo Alto Research Center, Inc.
00007  *
00008  * This library is free software; you can redistribute it and/or modify it
00009  * under the terms of the GNU Lesser General Public License version 2.1
00010  * as published by the Free Software Foundation.
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00014  * Lesser General Public License for more details. You should have received
00015  * a copy of the GNU Lesser General Public License along with this library;
00016  * if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
00017  * Fifth Floor, Boston, MA 02110-1301 USA.
00018  */
00019 
00020 
00021 #include "SyncActions.h"
00022 #include "SyncBase.h"
00023 #include "SyncHashCache.h"
00024 #include "SyncNode.h"
00025 #include "SyncPrivate.h"
00026 #include "SyncRoot.h"
00027 #include "SyncUtil.h"
00028 #include "SyncTreeWorker.h"
00029 #include "IndexSorter.h"
00030 
00031 #include <errno.h>
00032 #include <stdarg.h>
00033 #include <stdlib.h>
00034 #include <stdio.h>
00035 #include <string.h>
00036 #include <strings.h>
00037 #include <unistd.h>
00038 #include <sys/stat.h>
00039 #include <sys/time.h>
00040 
00041 #include <ccn/ccn.h>
00042 #include <ccn/charbuf.h>
00043 #include <ccn/digest.h>
00044 #include <ccn/fetch.h>
00045 #include <ccn/seqwriter.h>
00046 #include <ccn/uri.h>
00047 
00048 struct SyncTestParms {
00049     struct SyncBaseStruct *base;
00050     struct SyncRootStruct *root;
00051     int mode;
00052     int mark;
00053     int scope;
00054     int life;
00055     int sort;
00056     int bufs;
00057     int verbose;
00058     int resolve;
00059     int segmented;
00060     int blockSize;
00061     char *inputName;
00062     char *target;
00063     char *topoPrefix;
00064     char *namingPrefix;
00065     int nSplits;
00066     int *splits;
00067     struct timeval startTime;
00068     struct timeval stopTime;
00069     intmax_t fSize;
00070 };
00071 
00072 //////////////////////////////////////////////////////////////////////
00073 // Dummy for ccnr routines (needed to avoid link errors)
00074 //////////////////////////////////////////////////////////////////////
00075 
00076 #include <ccnr/ccnr_private.h>
00077 
00078 #include <ccnr/ccnr_sync.h>
00079 
00080 
00081 // this one is a stub, but it actually produces output, too
00082 PUBLIC void
00083 ccnr_msg(struct ccnr_handle *h, const char *fmt, ...)
00084 {
00085     struct timeval t;
00086     va_list ap;
00087     struct ccn_charbuf *b = ccn_charbuf_create();
00088     ccn_charbuf_reserve(b, 1024);
00089     gettimeofday(&t, NULL);
00090     ccn_charbuf_putf(b, "%s\n", fmt);
00091     char *fb = ccn_charbuf_as_string(b);
00092     va_start(ap, fmt);
00093     vfprintf(stdout, fb, ap);
00094     va_end(ap);
00095     fflush(stdout);
00096     ccn_charbuf_destroy(&b);
00097 }
00098 
00099 PUBLIC int
00100 ccnr_msg_level_from_string(char *s) {
00101     // like 
00102     if (s == NULL)
00103     return -1;
00104     if (strcasecmp(s, "NONE") == 0)
00105     return 0;
00106     if (strcasecmp(s, "SEVERE") == 0)
00107     return 3;
00108     if (strcasecmp(s, "ERROR") == 0)
00109     return 5;
00110     if (strcasecmp(s, "WARNING") == 0)
00111     return 7;
00112     if (strcasecmp(s, "INFO") == 0)
00113     return 9;
00114     if (strcasecmp(s, "FINE") == 0)
00115     return 11;
00116     if (strcasecmp(s, "FINER") == 0)
00117     return 13;
00118     if (strcasecmp(s, "FINEST") == 0)
00119     return 15;
00120     return -1;
00121 }
00122 
00123 PUBLIC void
00124 r_sync_notify_after(struct ccnr_handle *ccnr, ccnr_hwm item)
00125 {
00126     // TBD: fix this if the one in ccnr_sync.c changes!
00127     ccnr->notify_after = (ccnr_accession) item;
00128 }
00129 
00130 PUBLIC int
00131 r_sync_enumerate(struct ccnr_handle *ccnr,
00132                  struct ccn_charbuf *interest)
00133 {
00134     int ans = -1;
00135     return(ans);
00136 }
00137 
00138 
00139 PUBLIC int
00140 r_sync_lookup(struct ccnr_handle *ccnr,
00141               struct ccn_charbuf *interest,
00142               struct ccn_charbuf *content_ccnb)
00143 {
00144     int ans = -1;
00145     return(ans);
00146 }
00147 
00148 /**
00149  * Called when a content object is received by sync and needs to be
00150  * committed to stable storage by the repo.
00151  */
00152 PUBLIC enum ccn_upcall_res
00153 r_sync_upcall_store(struct ccnr_handle *ccnr,
00154                     enum ccn_upcall_kind kind,
00155                     struct ccn_upcall_info *info)
00156 {
00157     enum ccn_upcall_res ans = CCN_UPCALL_RESULT_ERR;
00158     return(ans);
00159 }
00160 
00161 /**
00162  * Called when a content object has been constructed locally by sync
00163  * and needs to be committed to stable storage by the repo.
00164  * returns 0 for success, -1 for error.
00165  */
00166 
00167 PUBLIC int
00168 r_sync_local_store(struct ccnr_handle *ccnr,
00169                    struct ccn_charbuf *content)
00170 {
00171     int ans = -1;
00172     return(ans);
00173 }
00174 
00175 PUBLIC uintmax_t
00176 ccnr_accession_encode(struct ccnr_handle *ccnr, ccnr_accession a)
00177 {
00178     return(a);
00179 }
00180 
00181 PUBLIC ccnr_accession
00182 ccnr_accession_decode(struct ccnr_handle *ccnr, uintmax_t encoded)
00183 {
00184     return(encoded);
00185 }
00186 
00187 PUBLIC int
00188 ccnr_accession_compare(struct ccnr_handle *ccnr, ccnr_accession x, ccnr_accession y)
00189 {
00190     if (x > y) return 1;
00191     if (x == y) return 0;
00192     if (x < y) return -1;
00193     return CCNR_NOT_COMPARABLE;
00194 }
00195 
00196 PUBLIC uintmax_t
00197 ccnr_hwm_encode(struct ccnr_handle *ccnr, ccnr_hwm hwm)
00198 {
00199     return(hwm);
00200 }
00201 
00202 PUBLIC ccnr_hwm
00203 ccnr_hwm_decode(struct ccnr_handle *ccnr, uintmax_t encoded)
00204 {
00205     return(encoded);
00206 }
00207 
00208 PUBLIC int
00209 ccnr_acc_in_hwm(struct ccnr_handle *ccnr, ccnr_accession a, ccnr_hwm hwm)
00210 {
00211     return(a <= hwm);
00212 }
00213 
00214 PUBLIC ccnr_hwm
00215 ccnr_hwm_update(struct ccnr_handle *ccnr, ccnr_hwm hwm, ccnr_accession a)
00216 {
00217     return(a <= hwm ? hwm : a);
00218 }
00219 
00220 PUBLIC ccnr_hwm
00221 ccnr_hwm_merge(struct ccnr_handle *ccnr, ccnr_hwm x, ccnr_hwm y)
00222 {
00223     return(x < y ? y : x);
00224 }
00225 
00226 PUBLIC int
00227 ccnr_hwm_compare(struct ccnr_handle *ccnr, ccnr_hwm x, ccnr_hwm y)
00228 {
00229     if (x > y) return 1;
00230     if (x == y) return 0;
00231     if (x < y) return -1;
00232     return CCNR_NOT_COMPARABLE;
00233 }
00234 
00235 
00236 ////////////////////////////////////////
00237 // Error reporting
00238 ////////////////////////////////////////
00239 
00240 static int
00241 noteErr(const char *fmt, ...) {
00242     struct timeval t;
00243     va_list ap;
00244     struct ccn_charbuf *b = ccn_charbuf_create();
00245     ccn_charbuf_reserve(b, 1024);
00246     gettimeofday(&t, NULL);
00247     ccn_charbuf_putf(b, "** ERROR: %s\n", fmt);
00248     char *fb = ccn_charbuf_as_string(b);
00249     va_start(ap, fmt);
00250     vfprintf(stderr, fb, ap);
00251     va_end(ap);
00252     fflush(stderr);
00253     ccn_charbuf_destroy(&b);
00254     return -1;
00255 }
00256 
00257 ////////////////////////////////////////
00258 // Simple builder
00259 ////////////////////////////////////////
00260 
00261 static int 
00262 parseAndAccumName(char *s, struct SyncNameAccum *na) {
00263     int i = 0;
00264     for (;;) {
00265         char c = s[i];
00266         int d = SyncDecodeUriChar(c);
00267         if (d <= 0) break;
00268         i++;
00269     }
00270     char save = s[i];
00271     s[i] = 0;
00272     struct ccn_charbuf *cb = ccn_charbuf_create();
00273     int skip = ccn_name_from_uri(cb, (const char *) s);
00274     s[i] = save;
00275     if (skip <= 0) {
00276         // not legal, so don't append the name
00277         ccn_charbuf_destroy(&cb);
00278         return skip;
00279     }
00280     // extract the size, which is the next numeric string
00281     // (no significant checking here)
00282     intmax_t size = 0;
00283     for (;;) {
00284         char c = s[i];
00285         if (c >= '0' && c <= '9') break;
00286         if (c < ' ') break;
00287         i++;
00288     }
00289     for (;;) {
00290         char c = s[i];
00291         if (c < '0' || c > '9') break;
00292         size = size * 10 + SyncDecodeHexDigit(c);
00293         i++;
00294     }
00295     // finally, append the name in the order it arrived
00296     SyncNameAccumAppend(na, cb, size);
00297     return skip;    
00298 }
00299 
00300 static struct SyncNameAccum *
00301 readAndAccumNames(FILE *input, int rem) {
00302     struct SyncNameAccum *na = SyncAllocNameAccum(4);
00303     static int tempLim = 4*1024;
00304     char *temp = NEW_ANY(tempLim+4, char);
00305     while (rem > 0) {
00306         // first, read a line
00307         int len = 0;
00308         while (len < tempLim) {
00309             int c = fgetc(input);
00310             if (c < 0 || c == '\n') break;
00311             temp[len] = c;
00312             len++;
00313         }
00314         temp[len] = 0;
00315         if (len == 0)
00316         // blank line stops us
00317         break;
00318         // now grab the name we found
00319         int pos = 0;
00320         static char *key = "ccnx:";
00321         int keyLen = strlen(key);
00322         int found = 0;
00323         while (pos < len) {
00324             if (strncasecmp(temp+pos, key, keyLen) == 0) {
00325                 // found the name start
00326                 parseAndAccumName(temp+pos, na);
00327                 found++;
00328                 break;
00329             }
00330             pos++;
00331         }
00332         if (found == 0) {
00333             // did not get "ccnx:" so try for "/" start
00334             for (pos = 0; pos < len; pos++) {
00335                 if (temp[pos]== '/') {
00336                     parseAndAccumName(temp+pos, na);
00337                     break;
00338                 }
00339             }
00340         }
00341         rem--;
00342     }
00343     free(temp);
00344     return na;
00345 }
00346 
00347 ////////////////////////////////////////
00348 // Tree print routines
00349 ////////////////////////////////////////
00350 
00351 static void
00352 printTreeInner(struct SyncTreeWorkerHead *head,
00353                struct ccn_charbuf *tmpB,
00354                struct ccn_charbuf *tmpD,
00355                FILE *f) {
00356     int i = 0;
00357     struct SyncTreeWorkerEntry *ent = SyncTreeWorkerTop(head);
00358     struct SyncHashCacheEntry *ce = ent->cacheEntry;
00359     if (ce == NULL) {
00360         fprintf(f, "?? no cacheEntry ??\n");
00361         return;
00362     }
00363     struct SyncNodeComposite *nc = ((head->remote > 0) ? ce->ncR : ce->ncL);
00364     if (nc == NULL) {
00365         fprintf(f, "?? no cacheEntry->nc ??\n");
00366         return;
00367     }
00368     for (i = 1; i < head->level; i++) fprintf(f, "  | ");
00369     char *hex = SyncHexStr(nc->hash->buf, nc->hash->length);
00370     fprintf(f, "node, depth = %d, refs = %d, leaves = %d, hash = %s\n",
00371             (int) nc->treeDepth, (int) nc->refLen, (int) nc->leafCount, hex);
00372     free(hex);
00373     ssize_t pos = 0;
00374     while (pos < nc->refLen) {
00375         struct SyncNodeElem *ep = &nc->refs[pos];
00376         ent->pos = pos;
00377         if (ep->kind & SyncElemKind_leaf) {
00378             // a leaf, so the element name is inline
00379             struct ccn_buf_decoder nameDec;
00380             struct ccn_buf_decoder *nameD = NULL;
00381             nameD = SyncInitDecoderFromOffset(&nameDec, nc, ep->start, ep->stop);
00382             ccn_charbuf_reset(tmpB);
00383             ccn_charbuf_reset(tmpD);
00384             SyncAppendElementInner(tmpB, nameD);
00385             ccn_uri_append(tmpD, tmpB->buf, tmpB->length, 1);
00386             for (i = 0; i < head->level; i++) fprintf(f, "  | ");
00387             fprintf(f, "%s\n", ccn_charbuf_as_string(tmpD));
00388         } else {
00389             // a node, so try this recursively
00390             SyncTreeWorkerPush(head);
00391             printTreeInner(head, tmpB, tmpD, f);
00392             SyncTreeWorkerPop(head);
00393         }
00394         pos++;
00395     }
00396 }
00397 
00398 static void
00399 printTree(struct SyncTreeWorkerHead *head, FILE *f) {
00400     struct ccn_charbuf *tmpB = ccn_charbuf_create();
00401     struct ccn_charbuf *tmpD = ccn_charbuf_create();
00402     printTreeInner(head, tmpB, tmpD, f);
00403     ccn_charbuf_destroy(&tmpB);
00404     ccn_charbuf_destroy(&tmpD);
00405 }
00406 
00407 static void putMark(FILE *f) {
00408     struct timeval mark;
00409     gettimeofday(&mark, 0);
00410     fprintf(f, "%ju.%06u: ",
00411             (uintmax_t) mark.tv_sec,
00412             (unsigned) mark.tv_usec);
00413 }
00414 
00415 ////////////////////////////////////////
00416 // Test routines
00417 ////////////////////////////////////////
00418 
00419 // generate the encoding of a test object 
00420 static struct SyncNodeComposite *
00421 testGenComposite(struct SyncBaseStruct *base, int nRefs) {
00422     int res = 0;
00423     struct SyncNodeComposite *nc = SyncAllocComposite(base);
00424     struct ccn_charbuf *tmp = ccn_charbuf_create();
00425     
00426     // append the references
00427     while (nRefs > 0 && res == 0) {
00428         ccn_charbuf_reset(tmp);
00429         res |= SyncAppendRandomName(tmp, 5, 12);
00430         SyncNodeAddName(nc, tmp);
00431         nRefs--;
00432     }
00433     
00434     SyncEndComposite(nc); // appends finals counts
00435     ccn_charbuf_destroy(&tmp);
00436     
00437     nc->err = res;
00438     return nc;
00439 }
00440 
00441 static int
00442 testEncodeDecode(struct SyncTestParms *parms) {
00443     struct SyncBaseStruct *base = parms->base;
00444     struct ccn_charbuf *cb = ccn_charbuf_create();
00445     cb->length = 0;
00446     ccnb_element_begin(cb, CCN_DTAG_Content); // artificial!  only for testing!
00447     fwrite(cb->buf, sizeof(unsigned char), cb->length, stdout);
00448     
00449     struct SyncNodeComposite *nc = testGenComposite(base, 4);
00450     
00451     SyncWriteComposite(nc, stdout);
00452     
00453     struct ccn_buf_decoder ds;
00454     struct ccn_buf_decoder *d = SyncInitDecoderFromCharbuf(&ds, nc->cb, 0);
00455     struct SyncNodeComposite *chk = SyncAllocComposite(base);
00456     SyncParseComposite(chk, d);
00457     SyncWriteComposite(chk, stdout);
00458     SyncFreeComposite(chk);
00459     
00460     int pos = cb->length;
00461     ccnb_element_end(cb);  // CCN_DTAG_Content
00462     fwrite(cb->buf+pos, sizeof(unsigned char), cb->length-pos, stdout);
00463     fflush(stdout);
00464     
00465     SyncFreeComposite(nc);
00466     
00467     cb->length = 0;
00468     ccn_charbuf_destroy(&cb);
00469     
00470     return 0;
00471 }
00472 
00473 static int
00474 testReader(struct SyncTestParms *parms) {
00475     char *fn = parms->inputName;
00476     int sort = parms->sort;
00477     FILE *f = fopen(fn, "r");
00478     int res = 0;
00479     if (f != NULL) {
00480         sync_time startTime = SyncCurrentTime();
00481         struct SyncNameAccum *na = readAndAccumNames(f, 1000000);
00482         fclose(f);
00483         struct ccn_charbuf *tmp = ccn_charbuf_create();
00484         int i = 0;
00485         IndexSorter_Base ixBase = NULL;
00486         int accumNameBytes = 0;
00487         int accumContentBytes = 0;
00488         if (sort > 0) {
00489             IndexSorter_Index ixLim = na->len;
00490             ixBase = IndexSorter_New(ixLim, -1);
00491             ixBase->sorter = SyncNameAccumSorter;
00492             ixBase->client = na;
00493             IndexSorter_Index ix = 0;
00494             for (; ix < ixLim; ix++) IndexSorter_Add(ixBase, ix);
00495         }
00496         struct ccn_charbuf *lag = NULL;
00497         for (;i < na->len; i++) {
00498             int j = i;
00499             if (ixBase != NULL) j = IndexSorter_Rem(ixBase);
00500             struct ccn_charbuf *each = na->ents[j].name;
00501             if (sort == 1 && lag != NULL) {
00502                 int cmp = SyncCmpNames(each, lag);
00503                 if (cmp < 0)
00504                 return noteErr("bad sort (order)!");
00505                 if (cmp == 0)
00506                 return noteErr("bad sort (duplicate)!");
00507             }
00508             struct ccn_charbuf *repl = each;
00509             accumNameBytes = accumNameBytes + repl->length;
00510             ssize_t size = na->ents[j].data;
00511             accumContentBytes = accumContentBytes + size;
00512             ccn_charbuf_reset(tmp);
00513             ccn_uri_append(tmp, repl->buf, repl->length, 1);
00514             if (sort != 2) {
00515                 fprintf(stdout, "%4d", i);
00516                 if (sort) fprintf(stdout, ", %4d", j);
00517                 fprintf(stdout, ", %8zd, ", size);
00518             }
00519             fprintf(stdout, "%s\n", ccn_charbuf_as_string(tmp));
00520             lag = each;
00521             if (repl != each) ccn_charbuf_destroy(&repl);
00522         }
00523         int64_t dt = SyncDeltaTime(startTime, SyncCurrentTime());
00524         dt = (dt + 500)/ 1000;
00525         fprintf(stdout, "-- %d names, %d name bytes, %d content bytes, %d.%03d seconds\n",
00526                 na->len, accumNameBytes, accumContentBytes,
00527                 (int) (dt / 1000), (int) (dt % 1000));
00528         if (ixBase != NULL) IndexSorter_Free(&ixBase);
00529         ccn_charbuf_destroy(&tmp);
00530         na = SyncFreeNameAccum(na);
00531     } else {
00532         return noteErr("testReader, could not open %s", fn);
00533     }
00534     return res;
00535 }
00536 
00537 static struct SyncRootStruct *
00538 newDefaultRoot(struct SyncTestParms *parms, struct SyncNameAccum *filter) {
00539     int res = 0;
00540     struct SyncRootStruct *root = NULL;
00541     struct ccn_charbuf *topo = ccn_charbuf_create();
00542     struct ccn_charbuf *prefix = ccn_charbuf_create();
00543     for (;;) {
00544         res = ccn_name_from_uri(topo, parms->topoPrefix);
00545         if (res < 0) {noteErr("invalid topo prefix"); break; }
00546         
00547         res = ccn_name_from_uri(prefix, parms->namingPrefix);
00548         if (res < 0) {noteErr("invalid naming prefix"); break; }
00549         
00550         root = SyncAddRoot(parms->base, topo, prefix, filter);
00551         break;
00552     }
00553     ccn_charbuf_destroy(&topo);
00554     ccn_charbuf_destroy(&prefix);
00555     return root;
00556 }
00557 
00558 static int
00559 testReadBuilder(struct SyncTestParms *parms) {
00560     FILE *f = fopen(parms->inputName, "r");
00561     int ns = parms->nSplits;
00562     int res = 0;
00563     
00564     if (f != NULL) {
00565         struct SyncRootStruct *root = parms->root;
00566         
00567         if (root == NULL) {
00568             // need a new root (no clauses)
00569             root = newDefaultRoot(parms, NULL);
00570         }
00571         
00572         if (root->namesToAdd != NULL)
00573         SyncFreeNameAccum(root->namesToAdd);
00574         
00575         struct SyncLongHashStruct longHash;
00576         int split = 0;
00577         memset(&longHash, 0, sizeof(longHash));
00578         longHash.pos = MAX_HASH_BYTES;
00579         for (;;) {
00580             int i = 0;
00581             if (ns == 0) {
00582                 root->namesToAdd = readAndAccumNames(f, 1000000);
00583             } else {
00584                 int p = 0;
00585                 int k = parms->splits[split];
00586                 if (split > 0) p = parms->splits[split-1];
00587                 if (k <= 0 || k >= ns) {
00588                     return noteErr("splits: bad k %d", k);
00589                     break;
00590                 }
00591                 if (p < 0 || p >= k) {
00592                     return noteErr("splits: bad p %d", k);
00593                     break;
00594                 }
00595                 root->namesToAdd = readAndAccumNames(f, k-p);
00596             }
00597             
00598             if (root->namesToAdd == NULL || root->namesToAdd->len <= 0)
00599             // the data ran out first
00600             break;
00601             
00602             for (i = 0; i < root->namesToAdd->len; i++) {
00603                 SyncAccumHash(&longHash, root->namesToAdd->ents[i].name);
00604             }
00605             SyncUpdateRoot(root);
00606             
00607             struct ccn_charbuf *hb = SyncLongHashToBuf(&longHash);
00608             struct ccn_charbuf *rb = root->currentHash;
00609             if (rb->length != hb->length
00610                 || memcmp(rb->buf, hb->buf, hb->length) != 0) {
00611                 // this is not right!
00612                 char *hexL = SyncHexStr(hb->buf, hb->length);
00613                 char *hexR = SyncHexStr(rb->buf, rb->length);
00614                 res = noteErr("hexL %s, hexR %s", hexL, hexR);
00615                 free(hexL);
00616                 free(hexR);
00617                 return res;
00618             }
00619             ccn_charbuf_destroy(&hb);
00620             
00621             struct SyncHashCacheEntry *ce = SyncRootTopEntry(root);
00622             struct SyncTreeWorkerHead *tw = SyncTreeWorkerCreate(root->ch, ce, 0);
00623             switch (parms->mode) {
00624                 case 0: {
00625                     // no output
00626                     break;
00627                 }
00628                 case 1: {
00629                     // binary output
00630                     SyncWriteComposite(ce->ncL, stdout);
00631                     break;
00632                 }
00633                 case 2: {
00634                     // text output
00635                     SyncTreeWorkerInit(tw, ce, 0);
00636                     printTree(tw, stdout);
00637                     fprintf(stdout, "-----------------------\n");
00638                     break;
00639                 }
00640                 default: {
00641                     // no output
00642                     break;
00643                 }
00644             }
00645             
00646             // release intermediate resources
00647             tw = SyncTreeWorkerFree(tw);
00648             split++;
00649             if (ns > 0 && split >= ns) break;
00650         }
00651         
00652         fclose(f);
00653         return 0;
00654         
00655     } else {
00656         return noteErr("testReadBuilder, could not open %s", parms->inputName);
00657     }
00658 }
00659 
00660 static struct SyncRootStruct *
00661 testRootCoding(struct SyncTestParms *parms, struct SyncRootStruct *root) {
00662     struct SyncBaseStruct *base = parms->base;
00663     struct ccn_charbuf *cb1 = ccn_charbuf_create();
00664     int res = 0;
00665     SyncRootAppendSlice(cb1, root);  // generate the encoding
00666     
00667     SyncRemRoot(root);  // smoke test the removal
00668     
00669     struct ccn_buf_decoder ds;
00670     struct ccn_buf_decoder *d = SyncInitDecoderFromCharbuf(&ds, cb1, 0);
00671     root = SyncRootDecodeAndAdd(base, d);
00672     if (root == NULL) {
00673         res = noteErr("SyncRootDecodeAndAdd, failed");
00674     }
00675     if (res ==0) {
00676         // we have a root
00677         struct ccn_charbuf *cb2 = ccn_charbuf_create();
00678         SyncRootAppendSlice(cb2, root);
00679         
00680         if (res == 0) {
00681             // compare the encoding lengths
00682             if (cb1->length == 0 || cb1->length != cb2->length) {
00683                 res = noteErr("testRootCoding, bad encoding lengths, %d != %d",
00684                               (int) cb1->length, (int) cb2->length);
00685             }
00686         }
00687         if (res == 0) {
00688             // compare the encoding contents
00689             ssize_t cmp = memcmp(cb1->buf, cb2->buf, cb1->length);
00690             if (cmp != 0) {
00691                 res = noteErr("testRootCoding, bad encoding data",
00692                               (int) cb1->length, (int) cb2->length);
00693                 res = -1;
00694             }
00695         }
00696         ccn_charbuf_destroy(&cb2);
00697     }
00698     ccn_charbuf_destroy(&cb1);
00699     
00700     if (res == 0) return root;
00701     
00702     SyncRemRoot(root);
00703     return NULL;
00704     
00705 }
00706 
00707 static int
00708 testRootLookup (struct SyncTestParms *parms, struct SyncRootStruct *root,
00709                 char * goodName, char * badName) {
00710     int res = 0;
00711     // now try a few lookups
00712     struct ccn_charbuf *name = ccn_charbuf_create();
00713     ccn_name_from_uri(name, goodName);
00714     enum SyncRootLookupCode ec = SyncRootLookupName(root, name);
00715     if (ec != SyncRootLookupCode_covered) {
00716         res = noteErr("testRootLookup, good name not covered, %s",
00717                       goodName);
00718     }
00719     ccn_charbuf_reset(name);
00720     ccn_name_from_uri(name, badName);
00721     ec = SyncRootLookupName(root, name);
00722     if (ec != SyncRootLookupCode_none) {
00723         res = noteErr("testRootLookup, bad name not rejected, %s",
00724                       badName);
00725     }
00726     return res;
00727 }
00728 
00729 static int
00730 testRootBasic(struct SyncTestParms *parms) {
00731     int res = 0;
00732     struct SyncRootStruct *root = NULL;
00733     
00734     struct ccn_charbuf *cb = ccn_charbuf_create();
00735     uintmax_t val = 37;
00736     res |= SyncAppendTaggedNumber(cb, CCN_DTAG_SyncVersion, val);
00737     
00738     if (res == 0) {
00739         struct ccn_buf_decoder ds;
00740         struct ccn_buf_decoder *d = ccn_buf_decoder_start(&ds, cb->buf, cb->length);
00741         if (SyncParseUnsigned(d, CCN_DTAG_SyncVersion) != val
00742             || d->decoder.state < 0)
00743         res = -__LINE__;
00744     }
00745     
00746     if (res < 0) {
00747         return noteErr("testRootBasic, basic numbers failed, %d", res);
00748     }
00749     
00750     // test no filter
00751     
00752     root = newDefaultRoot(parms, NULL);
00753     if (root == NULL) return noteErr("testRootBasic, newDefaultRoot");
00754     root = testRootCoding(parms, root);
00755     if (root == NULL) return noteErr("testRootBasic, testRootCoding");
00756     char goodName[1024];
00757     char *badName = "ccnx:/bogus/XXX";
00758     snprintf(goodName, sizeof(goodName), "%s/PARC/XXX", parms->namingPrefix);
00759     res = testRootLookup(parms, root,
00760                          goodName,
00761                          badName);
00762     if (res < 0) noteErr("testRootBasic, lookup");
00763     SyncRemRoot(root);
00764     
00765     struct SyncNameAccum *filter = SyncAllocNameAccum(4);
00766     struct ccn_charbuf *clause = ccn_charbuf_create();
00767     ccn_name_from_uri(clause, "/PARC");
00768     SyncNameAccumAppend(filter, clause, 0);
00769     root = newDefaultRoot(parms, filter);
00770     ccn_charbuf_destroy(&clause);
00771     SyncFreeNameAccum(filter);
00772     if (root == NULL) {
00773         return noteErr("testRootBasic, newDefaultRoot with filter");
00774     }
00775     
00776     res = testRootLookup(parms, root,
00777                          goodName,
00778                          badName);
00779     if (res < 0) noteErr("testRootBasic, lookup with filter");
00780     SyncRemRoot(root);
00781     
00782     return res;
00783 }
00784 
00785 static int
00786 localStore(struct ccn *ccn, struct ccn_charbuf *nm, struct ccn_charbuf *cb) {
00787     struct ccn_charbuf *tmp = ccn_charbuf_create();
00788     ccn_create_version(ccn, nm, CCN_V_NOW, 0, 0);
00789     ccn_charbuf_append_charbuf(tmp, nm);
00790     ccn_name_from_uri(tmp, "%C1.R.sw");
00791     ccn_name_append_nonce(tmp);
00792     ccn_get(ccn, tmp, NULL, 6000, NULL, NULL, NULL, 0);
00793     ccn_charbuf_destroy(&tmp);
00794     
00795     struct ccn_charbuf *cob = ccn_charbuf_create();
00796     struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
00797     const void *cp = NULL;
00798     size_t cs = 0;
00799     int res = 0;
00800     if (cb != NULL) {
00801         sp.type = CCN_CONTENT_DATA;
00802         cp = (const void *) cb->buf;
00803         cs = cb->length;
00804     } else {
00805         sp.type = CCN_CONTENT_GONE;
00806     }
00807     ccn_name_append_numeric(nm, CCN_MARKER_SEQNUM, 0);
00808     sp.sp_flags |= CCN_SP_FINAL_BLOCK;
00809     res |= ccn_sign_content(ccn,
00810                             cob,
00811                             nm,
00812                             &sp,
00813                             cp,
00814                             cs);
00815     res |= ccn_put(ccn, (const void *) cob->buf, cob->length);
00816     // ccn_run(ccn, 150);
00817     ccn_charbuf_destroy(&cob);
00818     return res;
00819 }
00820 
00821 static int
00822 sendSlice(struct SyncTestParms *parms,
00823           char *topo, char *prefix,
00824           int count, char **clauses) {
00825     // constructs a simple config slice and sends it to an attached repo
00826     struct ccn_charbuf *cb = ccn_charbuf_create();
00827     struct ccn_charbuf *hash = ccn_charbuf_create();
00828     struct ccn_charbuf *nm = ccn_charbuf_create();
00829     int i = 0;
00830     int res = 0;
00831     res |= ccnb_element_begin(cb, CCN_DTAG_SyncConfigSlice);
00832     res |= SyncAppendTaggedNumber(cb, CCN_DTAG_SyncVersion, SLICE_VERSION);
00833     res |= ccn_name_from_uri(nm, topo);
00834     res |= ccn_charbuf_append_charbuf(cb, nm);
00835     res |= ccn_name_from_uri(nm, prefix);
00836     res |= ccn_charbuf_append_charbuf(cb, nm);
00837     res |= ccnb_element_begin(cb, CCN_DTAG_SyncConfigSliceList);
00838     for (i = 0; i < count ; i++) {
00839         res |= SyncAppendTaggedNumber(cb, CCN_DTAG_SyncConfigSliceOp, 0);
00840         res |= ccn_name_from_uri(nm, clauses[i]);
00841         res |= ccn_charbuf_append_charbuf(cb, nm);
00842     }
00843     res |= ccnb_element_end(cb);
00844     res |= ccnb_element_end(cb);
00845     
00846     if (res >= 0) {
00847         // now we have the encoding, so make the hash
00848         struct ccn *ccn = NULL;
00849         struct ccn_digest *cow = ccn_digest_create(CCN_DIGEST_DEFAULT);
00850         size_t sz = ccn_digest_size(cow);
00851         unsigned char *dst = ccn_charbuf_reserve(hash, sz);
00852         ccn_digest_init(cow);
00853         ccn_digest_update(cow, cb->buf, cb->length);
00854         ccn_digest_final(cow, dst, sz);
00855         hash->length = sz;
00856         ccn_digest_destroy(&cow);
00857         
00858         // form the Sync protocol name
00859         static char *localLit = "\xC1.M.S.localhost";
00860         static char *sliceCmd = "\xC1.S.cs";
00861         res |= ccn_name_init(nm);
00862         res |= ccn_name_append_str(nm, localLit);
00863         res |= ccn_name_append_str(nm, sliceCmd);
00864         res |= ccn_name_append(nm, hash->buf, hash->length);
00865         
00866         if (res >= 0) {
00867             // first line shows the root hash
00868             struct ccn_charbuf *hashOnly = ccn_charbuf_create();
00869             ccn_name_init(hashOnly);
00870             ccn_name_append(hashOnly, hash->buf, hash->length);
00871             struct ccn_charbuf *uri = SyncUriForName(hashOnly);
00872             fprintf(stdout, "sendSlice, root hash %s\n",
00873                     ccn_charbuf_as_string(uri));
00874             ccn_charbuf_destroy(&uri);
00875         }
00876         
00877         ccn = ccn_create();
00878         if (ccn_connect(ccn, NULL) == -1) {
00879             perror("Could not connect to ccnd");
00880             exit(1);
00881         }
00882         if (res >= 0) res |= localStore(ccn, nm, cb);
00883         if (res < 0) {
00884             res = noteErr("sendSlice, failed");
00885         } else {
00886             struct ccn_charbuf *uri = SyncUriForName(nm);
00887             if (parms->mode != 0) {
00888                 if (parms->mark) putMark(stdout);
00889                 fprintf(stdout, "sendSlice, sent %s\n",
00890                         ccn_charbuf_as_string(uri));
00891             }
00892             ccn_charbuf_destroy(&uri);
00893         }
00894         
00895         ccn_destroy(&ccn);
00896     }
00897     
00898     ccn_charbuf_destroy(&cb);
00899     ccn_charbuf_destroy(&hash);
00900     ccn_charbuf_destroy(&nm);
00901     if (res > 0) res = 0;
00902     return res;
00903 }
00904 
00905 struct storeFileStruct {
00906     struct SyncTestParms *parms;
00907     struct ccn_charbuf *nm;
00908     struct ccn_charbuf *cb;
00909     struct ccn *ccn;
00910     off_t bs;
00911     off_t fSize;
00912     FILE *file;
00913     unsigned char *segData;
00914     int nSegs;
00915     int stored;
00916 };
00917 
00918 static int64_t
00919 segFromInfo(struct ccn_upcall_info *info) {
00920         // gets the current segment number for the info
00921         // returns -1 if not known
00922         if (info == NULL) return -1;
00923         const unsigned char *ccnb = info->content_ccnb;
00924         struct ccn_indexbuf *cc = info->content_comps;
00925         if (cc == NULL || ccnb == NULL) {
00926                 // go back to the interest
00927                 cc = info->interest_comps;
00928                 ccnb = info->interest_ccnb;
00929                 if (cc == NULL || ccnb == NULL) return -1;
00930         }
00931         int ns = cc->n;
00932         if (ns > 2) {
00933                 // assume that the segment number is the last component
00934                 int start = cc->buf[ns - 2];
00935                 int stop = cc->buf[ns - 1];
00936                 if (start < stop) {
00937                         size_t len = 0;
00938                         const unsigned char *data = NULL;
00939                         ccn_ref_tagged_BLOB(CCN_DTAG_Component, ccnb, start, stop, &data, &len);
00940                         if (len > 0 && data != NULL) {
00941                                 // parse big-endian encoded number
00942                                 // TBD: where is this in the library?
00943                                 if (data[0] != CCN_MARKER_SEQNUM) return -1;
00944                                 int64_t n = 0;
00945                 int i = 0;
00946                                 for (i = 1; i < len; i++) {
00947                                         n = n * 256 + data[i];
00948                                 }
00949                                 return n;
00950                         }
00951                 }
00952         }
00953         return -1;
00954 }
00955 
00956 static enum ccn_upcall_res
00957 storeHandler(struct ccn_closure *selfp,
00958              enum ccn_upcall_kind kind,
00959              struct ccn_upcall_info *info) {
00960     struct storeFileStruct *sfd = selfp->data;
00961     enum ccn_upcall_res ret = CCN_UPCALL_RESULT_OK;
00962     switch (kind) {
00963         case CCN_UPCALL_FINAL:
00964         free(selfp);
00965         break;
00966         case CCN_UPCALL_INTEREST: {
00967             int64_t seg = segFromInfo(info);
00968             struct ccn_charbuf *uri = ccn_charbuf_create();
00969             ccn_uri_append(uri, sfd->nm->buf, sfd->nm->length, 0);
00970             char *str = ccn_charbuf_as_string(uri);
00971             if (seg >= 0 && seg < sfd->nSegs) {
00972                 struct ccn_charbuf *name = SyncCopyName(sfd->nm);
00973                 struct ccn_charbuf *cb = ccn_charbuf_create();
00974                 struct ccn_charbuf *cob = ccn_charbuf_create();
00975                 off_t bs = sfd->bs;
00976                 off_t pos = seg * bs;
00977                 off_t rs = sfd->fSize - pos;
00978                 if (rs > bs) rs = bs;
00979                 
00980                 ccn_charbuf_reserve(cb, rs);
00981                 cb->length = rs;
00982                 char *cp = ccn_charbuf_as_string(cb);
00983                 
00984                 // fill in the contents
00985                 int res = fseeko(sfd->file, pos, SEEK_SET);
00986                 if (res >= 0) {
00987                     res = fread(cp, rs, 1, sfd->file);
00988                     if (res < 0) {
00989                         char *eMess = strerror(errno);
00990                         fprintf(stderr, "ERROR in fread, %s, seg %d, %s\n",
00991                                 eMess, (int) seg, str);
00992                     }
00993                 } else {
00994                     char *eMess = strerror(errno);
00995                     fprintf(stderr, "ERROR in fseeko, %s, seg %d, %s\n",
00996                             eMess, (int) seg, str);
00997                 }
00998                 
00999                 if (res >= 0) {
01000                     struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
01001                     const void *cp = NULL;
01002                     size_t cs = 0;
01003                     sp.type = CCN_CONTENT_DATA;
01004                     cp = (const void *) cb->buf;
01005                     cs = cb->length;
01006                     if (seg+1 == sfd->nSegs) sp.sp_flags |= CCN_SP_FINAL_BLOCK;
01007                     ccn_name_append_numeric(name, CCN_MARKER_SEQNUM, seg);
01008                     res |= ccn_sign_content(sfd->ccn,
01009                                             cob,
01010                                             name,
01011                                             &sp,
01012                                             cp,
01013                                             rs);
01014                     res |= ccn_put(sfd->ccn, (const void *) cob->buf, cob->length);
01015                     
01016                     if (res < 0) {
01017                         return noteErr("seg %d, %s",
01018                                        (int) seg,
01019                                        str);
01020                     } else if (sfd->parms->verbose) {
01021                         if (sfd->parms->mark) putMark(stdout);
01022                         fprintf(stdout, "put seg %d, %s\n",
01023                                 (int) seg,
01024                                 str);
01025                     }
01026                     
01027                     // update the tracking
01028                     unsigned char uc = sfd->segData[seg];
01029                     if (uc == 0) {
01030                         uc++;
01031                         sfd->stored++;
01032                     } else if (uc < 255) uc++;
01033                     sfd->segData[seg] = uc;
01034                 }
01035                 
01036                 ccn_charbuf_destroy(&name);
01037                 ccn_charbuf_destroy(&cb);
01038                 ccn_charbuf_destroy(&cob);
01039                 
01040             }
01041             ccn_charbuf_destroy(&uri);
01042             ret = CCN_UPCALL_RESULT_INTEREST_CONSUMED;
01043             break;
01044         }
01045         default:
01046         ret = CCN_UPCALL_RESULT_ERR;
01047         break;
01048     }
01049     return ret;
01050 }
01051 
01052 static void
01053 formatStats(struct SyncTestParms *parms) {
01054     int64_t dt = (1000000*(parms->stopTime.tv_sec-parms->startTime.tv_sec)
01055                   + parms->stopTime.tv_usec-parms->startTime.tv_usec);
01056     if (dt <= 0) dt = 1;
01057     int64_t rate = 0;
01058     
01059     switch (parms->mode) {
01060         case 0: {
01061             // silent
01062             break;
01063         }
01064         case 3: {
01065             // catchunks2 compatible
01066             const char *expid = getenv("CCN_EXPERIMENT_ID");
01067             const char *sep = " ";
01068             if (expid == NULL) {
01069                 expid = "";
01070                 sep = "";
01071             }
01072             rate = (parms->fSize * 1000000) / dt;
01073             if (parms->mark) putMark(stderr);
01074             fprintf(stderr,
01075                     "%ld.%06u SyncTest[%d]: %s%s"
01076                     "%jd bytes transferred in %ld.%06u seconds (%ld bytes/sec)"
01077                     "\n",
01078                     (long) parms->stopTime.tv_sec,
01079                     (unsigned) parms->stopTime.tv_usec,
01080                     (int)getpid(),
01081                     expid,
01082                     sep,
01083                     (intmax_t) parms->fSize,
01084                     (long) (dt / 1000000),
01085                     (unsigned) (dt % 1000000),
01086                     (long) rate
01087                     );
01088             break;
01089         }
01090         default: {
01091             // brief mode
01092             dt = (dt + 500) / 1000;
01093             if (dt <= 0) dt = 1;
01094             rate = parms->fSize / dt;
01095             
01096             if (parms->mark) putMark(stdout);
01097             fprintf(stdout, "transferred %jd bytes in %d.%03d seconds = %d.%03d MB/sec\n",
01098                     (intmax_t) parms->fSize,
01099                     (int) (dt / 1000), (int) dt % 1000,
01100                     (int) (rate / 1000), (int) rate % 1000);
01101             break;
01102         }
01103         
01104     }
01105 }
01106 
01107 static int
01108 getFile(struct SyncTestParms *parms, char *src, char *dst) {
01109     // gets the file, stores it to stdout
01110     
01111     FILE *file = NULL;
01112     
01113     if (dst != NULL) {
01114         file = fopen(dst, "w");
01115         if (file == NULL) {
01116             perror("fopen failed");
01117             return -1;
01118         }
01119     }
01120     
01121     struct ccn *ccn = NULL;
01122     ccn = ccn_create();
01123 #if (CCN_API_VERSION >= 4004)
01124     // special case to remove verification overhead
01125     if (dst == NULL)
01126     ccn_defer_verification(ccn, 1);
01127 #endif
01128     if (ccn_connect(ccn, NULL) == -1) {
01129         perror("Could not connect to ccnd");
01130         return -1;
01131     }
01132     struct ccn_charbuf *cb = ccn_charbuf_create();
01133     struct ccn_charbuf *nm = ccn_charbuf_create();
01134     int bs = parms->blockSize;
01135     
01136     int res = ccn_name_from_uri(nm, src);
01137     if (res < 0) {
01138         perror("ccn_name_from_uri failed");
01139         return -1;
01140     }
01141     
01142     if (parms->resolve) {
01143         res = ccn_resolve_version(ccn, nm, CCN_V_HIGH, parms->life*1000);
01144         // TBD: use parms to determine versioning_flags and timeout_ms?
01145         if (res < 0) {
01146             perror("ccn_resolve_version failed");
01147             return -1;
01148         }
01149     }
01150     
01151     struct ccn_fetch *cf = ccn_fetch_new(ccn);
01152     struct ccn_charbuf *template = SyncGenInterest(NULL,
01153                                                    parms->scope,
01154                                                    parms->life,
01155                                                    -1, -1, NULL);
01156     
01157     if (parms->verbose) {
01158         ccn_fetch_set_debug(cf, stderr,
01159                             ccn_fetch_flags_NoteOpenClose
01160                             | ccn_fetch_flags_NoteNeed
01161                             | ccn_fetch_flags_NoteFill
01162                             | ccn_fetch_flags_NoteTimeout
01163                             | ccn_fetch_flags_NoteFinal);
01164     }
01165     gettimeofday(&parms->startTime, 0);
01166     
01167     if (parms->segmented == 0) {
01168         // no segments, so use a single get
01169         struct ccn_parsed_ContentObject pcos;
01170         res = ccn_get(ccn, nm, template,
01171                       parms->life*1000,
01172                       cb, &pcos, NULL, 0);
01173         if (res < 0) {
01174             perror("get failed");
01175             return -1;
01176         }
01177         if (file != NULL) {
01178             size_t nItems = fwrite(ccn_charbuf_as_string(cb), cb->length, 1, file);
01179             if (nItems < 1) {
01180                 perror("fwrite failed");
01181                 return -1;
01182             }
01183         }
01184         parms->fSize = parms->fSize + cb->length;
01185         
01186     } else {
01187         // segmented, so use fetch.h
01188         struct ccn_fetch_stream *fs = ccn_fetch_open(cf, nm,
01189                                                      "SyncTest",
01190                                                      template,
01191                                                      parms->bufs,
01192                                                      0, 0);
01193         ccn_charbuf_destroy(&template);
01194         if (fs == NULL) {
01195             perror("ccn_fetch_open failed");
01196             return -1;
01197         }
01198         ccn_charbuf_reserve(cb, bs);
01199         cb->length = bs;
01200         char *cp = ccn_charbuf_as_string(cb);
01201         
01202         for (;;) {
01203             intmax_t av = ccn_fetch_avail(fs);
01204             if (av == CCN_FETCH_READ_NONE) {
01205                 ccn_run(ccn, 1);
01206                 continue;
01207             }
01208             int nb = ccn_fetch_read(fs, cp, bs);
01209             if (nb > 0) {
01210                 if (file != NULL) {
01211                     size_t nItems = fwrite(cp, nb, 1, file);
01212                     if (nItems < 1) {
01213                         perror("fwrite failed");
01214                         exit(1);
01215                     }
01216                 }
01217                 parms->fSize = parms->fSize + nb;
01218             } else if (nb == CCN_FETCH_READ_NONE) {
01219                 // try again
01220                 ccn_run(ccn, 1);
01221             } else {
01222                 if (nb == CCN_FETCH_READ_END) break;
01223                 if (nb == CCN_FETCH_READ_TIMEOUT) {
01224                     perror("read failed, timeout");
01225                     exit(1);
01226                 }
01227                 char temp[256];
01228                 snprintf(temp, sizeof(temp), "ccn_fetch_read failed: %d", nb);
01229                 perror(temp);
01230                 return -1;
01231             }
01232         }
01233         ccn_fetch_close(fs);
01234     }
01235     
01236     gettimeofday(&parms->stopTime, 0);
01237     
01238     if (file != NULL)
01239     fclose(file);
01240     
01241     ccn_fetch_destroy(cf);
01242     
01243     ccn_destroy(&ccn);
01244     ccn_charbuf_destroy(&cb);
01245     ccn_charbuf_destroy(&nm);
01246     
01247     formatStats(parms);
01248     
01249     if (res > 0) res = 0;
01250     return res;
01251 }
01252 
01253 static int
01254 putFile(struct SyncTestParms *parms, char *src, char *dst) {
01255     // stores the src file to the dst file (in the repo)
01256     
01257     struct stat myStat;
01258     int res = stat(src, &myStat);
01259     if (res < 0) {
01260         perror("putFile failed, stat");
01261         return -1;
01262     }
01263     off_t fSize = myStat.st_size;
01264     
01265     if (fSize == 0) {
01266         return noteErr("stat failed, empty src");
01267     }
01268     FILE *file = fopen(src, "r");
01269     if (file == NULL) {
01270         perror("putFile failed, fopen");
01271         return -1;
01272     }
01273     
01274     struct ccn *ccn = NULL;
01275     ccn = ccn_create();
01276     if (ccn_connect(ccn, NULL) == -1) {
01277         return noteErr("Could not connect to ccnd");
01278     }
01279     struct ccn_charbuf *cb = ccn_charbuf_create();
01280     struct ccn_charbuf *nm = ccn_charbuf_create();
01281     struct ccn_charbuf *cmd = ccn_charbuf_create();
01282     int bs = parms->blockSize;
01283     
01284     res = ccn_name_from_uri(nm, dst);
01285     if (res < 0) {
01286         return noteErr("ccn_name_from_uri failed");
01287     }
01288     ccn_create_version(ccn, nm, CCN_V_NOW, 0, 0);
01289     
01290     struct storeFileStruct *sfData = NEW_STRUCT(1, storeFileStruct);
01291     sfData->parms = parms;
01292     sfData->file = file;
01293     sfData->bs = bs;
01294     sfData->nm = nm;
01295     sfData->cb = cb;
01296     sfData->ccn = ccn;
01297     sfData->fSize = fSize;
01298     sfData->nSegs = (fSize + bs -1) / bs;
01299     sfData->segData = NEW_ANY(sfData->nSegs, unsigned char);
01300     
01301     struct ccn_charbuf *template = SyncGenInterest(NULL,
01302                                                    parms->scope,
01303                                                    parms->life,
01304                                                    -1, -1, NULL);
01305     struct ccn_closure *action = NEW_STRUCT(1, ccn_closure);
01306     action->p = storeHandler;
01307     action->data = sfData;
01308     
01309     parms->fSize = fSize;
01310     
01311     // fire off a listener
01312     res = ccn_set_interest_filter(ccn, nm, action);
01313     if (res < 0) {
01314         return noteErr("ccn_set_interest_filter failed");
01315     }
01316     ccn_run(ccn, 40);
01317     // initiate the write
01318     // construct the store request and "send" it as an interest
01319     ccn_charbuf_append_charbuf(cmd, nm);
01320     ccn_name_from_uri(cmd, "%C1.R.sw");
01321     ccn_name_append_nonce(cmd);
01322     
01323     if (parms->verbose) {
01324         if (parms->mark) putMark(stdout);
01325         fprintf(stdout, "put init, %s\n",
01326                 ccn_charbuf_as_string(cmd));
01327     }
01328     gettimeofday(&parms->startTime, 0);
01329     ccn_get(ccn, cmd, template, 6000, NULL, NULL, NULL, 0);
01330     
01331     // wait for completion
01332     while (sfData->stored < sfData->nSegs) {
01333         ccn_run(ccn, 2);
01334     }
01335     
01336     gettimeofday(&parms->stopTime, 0);
01337     
01338     res = ccn_set_interest_filter(ccn, nm, NULL);
01339     if (res < 0) {
01340         return noteErr("ccn_set_interest_filter failed (removal)");
01341     }
01342     ccn_run(ccn, 40);
01343     
01344     free(sfData->segData);
01345     free(sfData);
01346     ccn_destroy(&ccn);
01347     fclose(file);
01348     ccn_charbuf_destroy(&cb);
01349     ccn_charbuf_destroy(&cmd);
01350     ccn_charbuf_destroy(&nm);
01351     
01352     formatStats(parms);
01353     
01354     if (res > 0) res = 0;
01355     return res;
01356 }
01357 
01358 static int
01359 existingRootOp(struct SyncTestParms *parms,
01360                char *topo, char *prefix,
01361                int delete) {
01362     // constructs a simple config slice and sends it to an attached repo
01363     // now we have the encoding, so make the hash
01364     struct ccn *ccn = NULL;
01365     int res = 0;
01366     
01367     ccn = ccn_create();
01368     if (ccn_connect(ccn, NULL) == -1) {
01369         perror("Could not connect to ccnd");
01370         exit(1);
01371     }
01372     
01373     // form the Sync protocol name
01374     static char *cmdLit = "\xC1.S.rs";
01375     struct ccn_charbuf *nm = ccn_charbuf_create();
01376     if (delete) cmdLit = "\xC1.S.cs";
01377     
01378     res |= ccn_name_init(nm);
01379     res |= ccn_name_from_uri(nm, topo);
01380     if (prefix != NULL) {
01381         struct ccn_charbuf *pre = ccn_charbuf_create();
01382         res |= ccn_name_from_uri(pre, prefix);
01383         res |= ccn_name_append_str(nm, cmdLit);
01384         res |= SyncAppendAllComponents(nm, pre);
01385         ccn_charbuf_destroy(&pre);
01386     }
01387     
01388     struct ccn_charbuf *cb = ccn_charbuf_create();
01389     if (delete) {
01390         // requesting deletion
01391         res |= localStore(ccn, nm, NULL);
01392         if (res < 0) {
01393             res = noteErr("requestDelete, failed");
01394         } else {
01395             // claimed success 
01396             struct ccn_charbuf *uri = SyncUriForName(nm);
01397             if (parms->mark) putMark(stdout);
01398             fprintf(stdout, "requestDelete, sent %s\n",
01399                     ccn_charbuf_as_string(uri));
01400             ccn_charbuf_destroy(&uri);
01401         }
01402     } else {
01403         // requesting stats
01404         struct ccn_charbuf *tmpl = SyncGenInterest(NULL, 1, 2, -1, 1, NULL);
01405         res |= ccn_get(ccn, nm, tmpl, 6000, cb, NULL, NULL, 0);
01406         
01407         const unsigned char *xp = NULL;
01408         size_t xs = 0;
01409         if (res < 0) {
01410             res = noteErr("requestStats, ccn_get failed");
01411         } else {
01412             res |= SyncPointerToContent(cb, NULL, &xp, &xs);
01413             
01414             if (res < 0 || xs == 0) {
01415                 res = noteErr("requestStats, failed");
01416             } else {
01417                 if (parms->mark) putMark(stdout);
01418                 fwrite(xp, xs, sizeof(char), stdout);
01419                 fprintf(stdout, "\n");
01420             }
01421         }
01422         ccn_charbuf_destroy(&tmpl);
01423     }
01424     ccn_charbuf_destroy(&cb);
01425     ccn_charbuf_destroy(&nm);
01426     ccn_destroy(&ccn);
01427     if (res > 0) res = 0;
01428     return res;
01429 }
01430 
01431 int
01432 main(int argc, char **argv) {
01433     int i = 1;
01434     int seen = 0;
01435     int res = 0;
01436     struct SyncTestParms parmStore;
01437     struct SyncTestParms *parms = &parmStore;
01438     struct SyncBaseStruct *base = SyncNewBase(NULL, NULL, NULL);
01439     
01440     memset(parms, 0, sizeof(parmStore));
01441     
01442     parms->mode = 1;
01443     parms->scope = 1;
01444     parms->life = 4;
01445     parms->bufs = 4;
01446     parms->blockSize = 4096;
01447     parms->base = base;
01448     parms->resolve = 1;
01449     parms->segmented = 1;
01450     parms->topoPrefix = "/Topo";
01451     parms->namingPrefix = "/Naming";
01452     
01453     while (i < argc && res >= 0) {
01454         char * sw = argv[i];
01455         i++;
01456         char *arg1 = NULL;
01457         char *arg2 = NULL;
01458         if (i < argc) arg1 = argv[i];
01459         if (i+1 < argc) arg2 = argv[i+1];
01460         if (strcasecmp(sw, "-debug") == 0 || strcasecmp(sw, "-d") == 0) {
01461             i++;
01462             base->debug = ccnr_msg_level_from_string(arg1);
01463             if (base->debug < 0) {
01464                 res = noteErr("invalid debug level %s", arg1);
01465             }
01466         } else if (strcasecmp(sw, "-v") == 0) {
01467             parms->verbose = 1;
01468         } else if (strcasecmp(sw, "-cat2") == 0) {
01469             parms->mode = 3;
01470         } else if (strcasecmp(sw, "-mark") == 0) {
01471             parms->mark = 1;
01472         } else if (strcasecmp(sw, "-null") == 0) {
01473             parms->mode = 0;
01474         } else if (strcasecmp(sw, "-binary") == 0) {
01475             parms->mode = 1;
01476         } else if (strcasecmp(sw, "-ccnb") == 0) {
01477             parms->mode = 1;
01478         } else if (strcasecmp(sw, "-text") == 0) {
01479             parms->mode = 2;
01480         } else if (strcasecmp(sw, "-nores") == 0) {
01481             parms->resolve = 0;
01482         } else if (strcasecmp(sw, "-noseg") == 0) {
01483             parms->segmented = 0;
01484         } else if (strcasecmp(sw, "-bs") == 0) {
01485             i++;
01486             if (arg1 != NULL) {
01487                 int bs = atoi(arg1);
01488                 if (bs <= 0 || bs > 64*1024) {
01489                     res = noteErr("invalid block size %s", arg1);
01490                 }
01491                 parms->blockSize = bs;
01492             } else
01493             res = noteErr("missing block size");
01494             seen++;
01495         } else if (strcasecmp(sw, "-bufs") == 0) {
01496             if (arg1 != NULL) {
01497                 i++;
01498                 int bufs = atoi(arg1);
01499                 if (bufs <= 0 || bufs > 1024) {
01500                     res = noteErr("invalid number of buffers %s", arg1);
01501                     break;
01502                 }
01503                 parms->bufs = bufs;
01504             } else 
01505             res = noteErr("missing number of buffers");
01506         } else if (strcasecmp(sw, "-scope") == 0) {
01507             if (arg1 != NULL) {
01508                 int scope = atoi(arg1);
01509                 if (scope < -1 || scope > 2) {
01510                     res = noteErr("invalid scope %s", arg1);
01511                     break;
01512                 }
01513                 parms->scope = scope;
01514                 i++;
01515             } else
01516             res = noteErr("missing scope");
01517             seen++;
01518         } else if (strcasecmp(sw, "-life") == 0) {
01519             if (arg1 != NULL) {
01520                 int life = atoi(arg1);
01521                 if (life < -1 || life > 30) {
01522                     res = noteErr("invalid interest lifetime %s", arg1);
01523                     break;
01524                 }
01525                 parms->life = life;
01526                 i++;
01527             } else
01528             res = noteErr("missing interest lifetime");
01529             seen++;
01530         } else if (strcasecmp(sw, "-basic") == 0) {
01531             res = testRootBasic(parms);
01532             seen++;
01533         } else if (strcasecmp(sw, "-topo") == 0) {
01534             if (arg1 != NULL) {
01535                 parms->topoPrefix = arg1;
01536                 i++;
01537             } else
01538             res = noteErr("missing topo prefix");
01539             seen++;
01540         } else if (strcasecmp(sw, "-prefix") == 0) {
01541             if (arg1 != NULL) {
01542                 parms->namingPrefix = arg1;
01543                 i++;
01544             } else
01545             res = noteErr("missing naming prefix");
01546             seen++;
01547         } else if (strcasecmp(sw, "-target") == 0) {
01548             if (arg1 != NULL) {
01549                 parms->target = arg1;
01550                 i++;
01551             } else
01552             res = noteErr("missing target");
01553             seen++;
01554         } else if (strcasecmp(sw, "-build") == 0) {
01555             if (arg1 != NULL) {
01556                 i++;
01557                 parms->inputName = arg1;
01558                 res = testReadBuilder(parms);
01559             } else
01560             res = noteErr("missing file name");
01561             seen++;
01562         } else if (strcasecmp(sw, "-read") == 0) {
01563             if (arg1 != NULL) {
01564                 i++;
01565                 parms->inputName = arg1;
01566                 parms->sort = 0;
01567                 res = testReader(parms);
01568             } else
01569             res = noteErr("missing file name");
01570             seen++;
01571         } else if (strcasecmp(sw, "-sort") == 0) {
01572             if (arg1 != NULL) {
01573                 i++;
01574                 parms->inputName = arg1;
01575                 parms->sort = 1;
01576                 res = testReader(parms);
01577             } else
01578             res = noteErr("missing file name");
01579             seen++;
01580         } else if (strcasecmp(sw, "-abs") == 0) {
01581             if (arg1 != NULL) {
01582                 i++;
01583                 parms->inputName = arg1;
01584                 parms->sort = 2;
01585                 res = testReader(parms);
01586             } else
01587             res = noteErr("missing file name");
01588             seen++;
01589         } else if (strcasecmp(sw, "-splits") == 0) {
01590             int n = 0;
01591             while (i >= argc) {
01592                 char *x = argv[i];
01593                 char c = x[0];
01594                 if (c < '0' || c > '9') break;
01595                 n++;
01596                 i++;
01597             }
01598             parms->nSplits = n;
01599             if (parms->splits != NULL) free(parms->splits);
01600             parms->splits = NULL;
01601             if (n > 0) {
01602                 int j = 0;
01603                 parms->splits = NEW_ANY(n, int);
01604                 i = i - n;
01605                 while (j < n) {
01606                     parms->splits[j] = atoi(argv[i]);
01607                     i++;
01608                     j++;
01609                 }
01610             }
01611             seen++;
01612         } else if (strcasecmp(sw, "-encode") == 0) {
01613             res = testEncodeDecode(parms);
01614             seen++;
01615         } else if (strcasecmp(sw, "-slice") == 0) {
01616             char **clauses = NEW_ANY(argc, char *);
01617             int count = 0;
01618             if (arg1 != NULL && arg2 != NULL) {
01619                 i++;
01620                 i++;
01621                 while (i < argc) {
01622                     char *clause = argv[i];
01623                     if (clause[0] == '-' || clause[0] == 0) break;
01624                     i++;
01625                     clauses[count] = clause;
01626                     count++;
01627                 }
01628                 res = sendSlice(parms, arg1, arg2, count, clauses);
01629             } else
01630             res = noteErr("missing slice topo or prefix");
01631             seen++;
01632         } else if (strcasecmp(sw, "-get") == 0) {
01633             if (arg1 != NULL) {
01634                 i++;
01635                 if (arg2 != NULL) {
01636                     // dst is optional, elide if it looks like a switch
01637                     if (arg2[0] != '-') i++;
01638                     else arg2 = NULL;
01639                 }
01640                 res = getFile(parms, arg1, arg2);
01641             } else {
01642                 res = noteErr("missing src file");
01643             }
01644             seen++;
01645         } else if (strcasecmp(sw, "-put") == 0) {
01646             if (arg1 == NULL) {
01647                 res = noteErr("missing src file");
01648             } else if (arg2 == NULL) {
01649                 res = noteErr("missing dst file");
01650             } else {
01651                 i++;
01652                 i++;
01653                 res = putFile(parms, arg1, arg2);
01654             }
01655             seen++;
01656         } else if (strcasecmp(sw, "-stats") == 0) {
01657             if (arg1 != NULL && arg2 != NULL) {
01658                 i++;
01659                 i++;
01660                 res = existingRootOp(parms, arg1, arg2, 0);
01661             } else
01662             res = noteErr("missing topo or hash");
01663             seen++;
01664         } else if (strcasecmp(sw, "-delete") == 0) {
01665             if (arg1 != NULL && arg2 != NULL) {
01666                 i++;
01667                 i++;
01668                 res = existingRootOp(parms, arg1, arg2, 1);
01669             } else
01670             res = noteErr("missing topo or hash");
01671             seen++;
01672                 } else {
01673             // can't understand this sw
01674             noteErr("invalid switch: %s", sw);
01675             seen = 0;
01676             break;
01677         }
01678     }
01679     if (parms->splits != NULL) free(parms->splits);
01680     if (parms->root != NULL) SyncRemRoot(parms->root);
01681     SyncFreeBase(&base);
01682     if (seen == 0 && res >= 0) {
01683         printf("usage: \n");
01684         printf("    -debug S        set debug level {NONE, SEVERE, ERROR, WARNING, INFO, FINE, FINER, FINEST}\n");
01685         printf("    -v              verbose\n");
01686         printf("    -null           no output\n");
01687         printf("    -ccnb           use binary output\n");
01688         printf("    -binary         use binary output\n");
01689         printf("    -text           use text output\n");
01690         printf("    -cat2           use ccncatchunks2 format\n");
01691         printf("    -mark           print a time code prefix\n");
01692         printf("    -nores          avoid resolve version\n");
01693         printf("    -noseg          no segments\n");
01694         printf("    -scope N        scope=N for repo commands (default 1)\n");
01695         printf("    -life N         life=N for interests (default 4)\n");
01696         printf("    -bs N           set block size for put (default 4096)\n");
01697         printf("    -bufs N         number of buffers for get (default 4)\n");
01698         printf("    -topo T         set default topo prefix to T\n");
01699         printf("    -prefix P       set default naming prefix to P\n");
01700         printf("    -basic          some very basic tests\n");
01701         printf("    -read F         read names from file F\n");
01702         printf("    -sort F         read names from file F, sort them\n");
01703         printf("    -encode         simple encode/decode test\n");
01704         printf("    -build F        build tree from file F\n");
01705         printf("    -get src [dst]  src is uri in repo, dst is file name (optional)\n");
01706         printf("    -put src dst    src is file name, dst is uri in repo\n");
01707         printf("    -slice T P C*   topo, prefix, clause ... (send slice to repo)\n");
01708         printf("    -delete T H     delete root with topo T, hash H from the repo\n");
01709         printf("    -stats T H      print statistics for root with topo T, hash H\n");
01710     }
01711     return res;
01712 }

Generated on Thu Feb 16 00:44:01 2012 for Content-Centric Networking in C by  doxygen 1.5.6