ccnsimplecat.c

Go to the documentation of this file.
00001 /**
00002  * @file ccnsimplecat.c
00003  * Reads streams at the given CCNx URIs and writes to stdout
00004  *
00005  * A CCNx command-line utility.
00006  *
00007  * Copyright (C) 2009-2011 Palo Alto Research Center, Inc.
00008  *
00009  * This work is free software; you can redistribute it and/or modify it under
00010  * the terms of the GNU General Public License version 2 as published by the
00011  * Free Software Foundation.
00012  * This work is distributed in the hope that it will be useful, but WITHOUT ANY
00013  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
00015  * for more details. You should have received a copy of the GNU General Public
00016  * License along with this program; if not, write to the
00017  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019  */
00020 
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <unistd.h>
00025 #include <ccn/ccn.h>
00026 #include <ccn/charbuf.h>
00027 #include <ccn/uri.h>
00028 
00029 /**
00030  * Provide usage hints for the program and then exit with a non-zero status.
00031  */
00032 static void
00033 usage(const char *progname)
00034 {
00035     fprintf(stderr,
00036             "%s [-a] ccnx:/a/b ...\n"
00037             "   Reads streams at"
00038             " the given ccn URIs and writes to stdout\n"
00039             "   -a - allow stale data\n",
00040             progname);
00041     exit(1);
00042 }
00043 
00044 struct mydata {
00045     int *done;
00046     int allow_stale;
00047 };
00048 
00049 /**
00050  * Construct a template suitable for use with ccn_express_interest
00051  * indicating at least one suffix component, and stale data if so
00052  * requested.
00053  */
00054 struct ccn_charbuf *
00055 make_template(struct mydata *md, struct ccn_upcall_info *info)
00056 {
00057     struct ccn_charbuf *templ = ccn_charbuf_create();
00058     ccn_charbuf_append_tt(templ, CCN_DTAG_Interest, CCN_DTAG);
00059     ccn_charbuf_append_tt(templ, CCN_DTAG_Name, CCN_DTAG);
00060     ccn_charbuf_append_closer(templ); /* </Name> */
00061     // XXX - use pubid if possible
00062     ccn_charbuf_append_tt(templ, CCN_DTAG_MinSuffixComponents, CCN_DTAG);
00063     ccnb_append_number(templ, 1);
00064     ccn_charbuf_append_closer(templ); /* </MinSuffixComponents> */
00065     if (md->allow_stale) {
00066         ccn_charbuf_append_tt(templ, CCN_DTAG_AnswerOriginKind, CCN_DTAG);
00067         ccnb_append_number(templ, CCN_AOK_DEFAULT | CCN_AOK_STALE);
00068         ccn_charbuf_append_closer(templ); /* </AnswerOriginKind> */
00069     }
00070     ccn_charbuf_append_closer(templ); /* </Interest> */
00071     return(templ);
00072 }
00073 
00074 /**
00075  * Handle the incoming content messages. Extracts the data, and
00076  * requests the next block in sequence if the received block was
00077  * not the final one.
00078  */
00079 enum ccn_upcall_res
00080 incoming_content(struct ccn_closure *selfp,
00081                  enum ccn_upcall_kind kind,
00082                  struct ccn_upcall_info *info)
00083 {
00084     struct ccn_charbuf *name = NULL;
00085     struct ccn_charbuf *templ = NULL;
00086     const unsigned char *ccnb = NULL;
00087     size_t ccnb_size = 0;
00088     const unsigned char *data = NULL;
00089     size_t data_size = 0;
00090     size_t written;
00091     const unsigned char *ib = NULL; /* info->interest_ccnb */
00092     struct ccn_indexbuf *ic = NULL;
00093     int res;
00094     struct mydata *md = selfp->data;
00095     
00096     if (kind == CCN_UPCALL_FINAL) {
00097         if (md != NULL) {
00098             selfp->data = NULL;
00099             free(md);
00100             md = NULL;
00101         }
00102         return(CCN_UPCALL_RESULT_OK);
00103     }
00104     if (kind == CCN_UPCALL_INTEREST_TIMED_OUT)
00105         return(CCN_UPCALL_RESULT_REEXPRESS);
00106     if (kind == CCN_UPCALL_CONTENT_UNVERIFIED)
00107         return(CCN_UPCALL_RESULT_VERIFY);
00108     if (kind != CCN_UPCALL_CONTENT)
00109         return(CCN_UPCALL_RESULT_ERR);
00110     if (md == NULL)
00111         selfp->data = md = calloc(1, sizeof(*md));
00112     ccnb = info->content_ccnb;
00113     ccnb_size = info->pco->offset[CCN_PCO_E];
00114     ib = info->interest_ccnb;
00115     ic = info->interest_comps;
00116     res = ccn_content_get_value(ccnb, ccnb_size, info->pco, &data, &data_size);
00117     if (res < 0) abort();
00118     if (info->pco->type != CCN_CONTENT_DATA) {
00119         /* For us this is spam. For now, give up. */
00120         fprintf(stderr, "*** spammed at block %d\n", (int)selfp->intdata);
00121         exit(1);
00122     }
00123     
00124     /* OK, we will accept this block. */
00125     if (data_size == 0)
00126         *(md->done) = 1;
00127     else {
00128         written = fwrite(data, data_size, 1, stdout);
00129         if (written != 1)
00130             exit(1);
00131     }
00132     // XXX The test below should get refactored into the library
00133     if (info->pco->offset[CCN_PCO_B_FinalBlockID] !=
00134         info->pco->offset[CCN_PCO_E_FinalBlockID]) {
00135         const unsigned char *finalid = NULL;
00136         size_t finalid_size = 0;
00137         const unsigned char *nameid = NULL;
00138         size_t nameid_size = 0;
00139         struct ccn_indexbuf *cc = info->content_comps;
00140         ccn_ref_tagged_BLOB(CCN_DTAG_FinalBlockID, ccnb,
00141                             info->pco->offset[CCN_PCO_B_FinalBlockID],
00142                             info->pco->offset[CCN_PCO_E_FinalBlockID],
00143                             &finalid,
00144                             &finalid_size);
00145         if (cc->n < 2) abort();
00146         ccn_ref_tagged_BLOB(CCN_DTAG_Component, ccnb,
00147                             cc->buf[cc->n - 2],
00148                             cc->buf[cc->n - 1],
00149                             &nameid,
00150                             &nameid_size);
00151         if (finalid_size == nameid_size &&
00152               0 == memcmp(finalid, nameid, nameid_size))
00153             *(md->done) = 1;
00154     }
00155     
00156     if (*(md->done)) {
00157         ccn_set_run_timeout(info->h, 0);
00158         return(CCN_UPCALL_RESULT_OK);
00159     }
00160     
00161     /* Ask for the next fragment */
00162     name = ccn_charbuf_create();
00163     ccn_name_init(name);
00164     if (ic->n < 2) abort();
00165     res = ccn_name_append_components(name, ib, ic->buf[0], ic->buf[ic->n - 2]);
00166     if (res < 0) abort();
00167     ccn_name_append_numeric(name, CCN_MARKER_SEQNUM, ++(selfp->intdata));
00168     templ = make_template(md, info);
00169     
00170     res = ccn_express_interest(info->h, name, selfp, templ);
00171     if (res < 0) abort();
00172     
00173     ccn_charbuf_destroy(&templ);
00174     ccn_charbuf_destroy(&name);
00175     
00176     return(CCN_UPCALL_RESULT_OK);
00177 }
00178 
00179 /**
00180  * Process options and then loop through command line CCNx URIs retrieving
00181  * the data and writing it to stdout.
00182  */
00183 int
00184 main(int argc, char **argv)
00185 {
00186     struct ccn *ccn = NULL;
00187     struct ccn_charbuf *name = NULL;
00188     struct ccn_charbuf *templ = NULL;
00189     struct ccn_closure *incoming = NULL;
00190     const char *arg = NULL;
00191     int i;
00192     int res;
00193     int opt;
00194     struct mydata *mydata;
00195     int allow_stale = 0;
00196     int *done;
00197     int exit_status = 0;
00198     
00199     done = calloc(1, sizeof(*done));
00200     
00201     while ((opt = getopt(argc, argv, "ha")) != -1) {
00202         switch (opt) {
00203             case 'a':
00204                 allow_stale = 1;
00205                 break;
00206             case 'h':
00207             default:
00208                 usage(argv[0]);
00209         }
00210     }
00211     arg = argv[optind];
00212     if (arg == NULL)
00213         usage(argv[0]);
00214     name = ccn_charbuf_create();
00215     /* Check the args first */
00216     for (i = optind; argv[i] != NULL; i++) {
00217         name->length = 0;
00218         res = ccn_name_from_uri(name, argv[i]);
00219         if (res < 0) {
00220             fprintf(stderr, "%s: bad ccn URI: %s\n", argv[0], argv[i]);
00221             exit(1);
00222         }
00223     }
00224     for (i = optind; (arg = argv[i]) != NULL; i++) {
00225         *done = 0;
00226         name->length = 0;
00227         res = ccn_name_from_uri(name, arg);
00228         ccn = ccn_create();
00229         if (ccn_connect(ccn, NULL) == -1) {
00230             perror("Could not connect to ccnd");
00231             exit(1);
00232         }
00233         ccn_resolve_version(ccn, name, CCN_V_HIGHEST, 50);
00234         ccn_name_append_numeric(name, CCN_MARKER_SEQNUM, 0);
00235         incoming = calloc(1, sizeof(*incoming));
00236         incoming->p = &incoming_content;
00237         mydata = calloc(1, sizeof(*mydata));
00238         mydata->allow_stale = allow_stale;
00239         mydata->done = done;
00240         incoming->data = mydata;
00241         templ = make_template(mydata, NULL);
00242         ccn_express_interest(ccn, name, incoming, templ);
00243         ccn_charbuf_destroy(&templ);
00244         /* Run a little while to see if there is anything there */
00245         res = ccn_run(ccn, 200);
00246         if ((!*done) && incoming->intdata == 0) {
00247             fprintf(stderr, "%s: not found: %s\n", argv[0], arg);
00248             res = -1;
00249         }
00250         /* We got something; run until end of data or somebody kills us */
00251         while (res >= 0 && !*done) {
00252             fflush(stdout);
00253             res = ccn_run(ccn, 333);
00254         }
00255         if (res < 0)
00256             exit_status = 1;
00257         ccn_destroy(&ccn);
00258         fflush(stdout);
00259         free(incoming);
00260         incoming = NULL;
00261     }
00262     ccn_charbuf_destroy(&name);
00263     free(done);
00264     exit(exit_status);
00265 }

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