SyncTest.c

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