ccncatchunks.c

Go to the documentation of this file.
00001 /**
00002  * @file ccncatchunks.c
00003  * Reads stuff written by ccnsendchunks, writes to stdout.
00004  *
00005  * A CCNx command-line utility.
00006  *
00007  * Copyright (C) 2008-2010 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 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include <unistd.h>
00024 #include <ccn/ccn.h>
00025 #include <ccn/charbuf.h>
00026 #include <ccn/uri.h>
00027 
00028 static void
00029 usage(const char *progname)
00030 {
00031     fprintf(stderr,
00032             "%s [-a] ccnx:/a/b\n"
00033             "   Reads stuff written by ccnsendchunks under"
00034             " the given uri and writes to stdout\n"
00035             "   -a - allow stale data\n",
00036             progname);
00037     exit(1);
00038 }
00039 
00040 struct mydata {
00041     int allow_stale;
00042 };
00043 
00044 struct ccn_charbuf *
00045 make_template(struct mydata *md, struct ccn_upcall_info *info)
00046 {
00047     struct ccn_charbuf *templ = ccn_charbuf_create();
00048     ccn_charbuf_append_tt(templ, CCN_DTAG_Interest, CCN_DTAG);
00049     ccn_charbuf_append_tt(templ, CCN_DTAG_Name, CCN_DTAG);
00050     ccn_charbuf_append_closer(templ); /* </Name> */
00051     // XXX - use pubid if possible
00052     ccn_charbuf_append_tt(templ, CCN_DTAG_MaxSuffixComponents, CCN_DTAG);
00053     ccnb_append_number(templ, 1);
00054     ccn_charbuf_append_closer(templ); /* </MaxSuffixComponents> */
00055     if (md->allow_stale) {
00056         ccn_charbuf_append_tt(templ, CCN_DTAG_AnswerOriginKind, CCN_DTAG);
00057         ccnb_append_number(templ, CCN_AOK_DEFAULT | CCN_AOK_STALE);
00058         ccn_charbuf_append_closer(templ); /* </AnswerOriginKind> */
00059     }
00060     ccn_charbuf_append_closer(templ); /* </Interest> */
00061     return(templ);
00062 }
00063 
00064 #define CHUNK_SIZE 1024
00065 
00066 enum ccn_upcall_res
00067 incoming_content(
00068     struct ccn_closure *selfp,
00069     enum ccn_upcall_kind kind,
00070     struct ccn_upcall_info *info)
00071 {
00072     struct ccn_charbuf *name = NULL;
00073     struct ccn_charbuf *templ = NULL;
00074     struct ccn_charbuf *temp = NULL;
00075     const unsigned char *ccnb = NULL;
00076     size_t ccnb_size = 0;
00077     const unsigned char *data = NULL;
00078     size_t data_size = 0;
00079     size_t written;
00080     const unsigned char *ib = NULL; /* info->interest_ccnb */
00081     struct ccn_indexbuf *ic = NULL;
00082     int res;
00083     struct mydata *md = selfp->data;
00084     
00085     if (kind == CCN_UPCALL_FINAL) {
00086         if (md != NULL) {
00087             selfp->data = NULL;
00088             free(md);
00089             md = NULL;
00090         }
00091         return(CCN_UPCALL_RESULT_OK);
00092     }
00093     if (kind == CCN_UPCALL_INTEREST_TIMED_OUT)
00094         return(CCN_UPCALL_RESULT_REEXPRESS);
00095     if (kind != CCN_UPCALL_CONTENT && kind != CCN_UPCALL_CONTENT_UNVERIFIED)
00096         return(CCN_UPCALL_RESULT_ERR);
00097     if (md == NULL)
00098         selfp->data = md = calloc(1, sizeof(*md));
00099     ccnb = info->content_ccnb;
00100     ccnb_size = info->pco->offset[CCN_PCO_E];
00101     ib = info->interest_ccnb;
00102     ic = info->interest_comps;
00103     /* XXX - must verify sig, and make sure it is LEAF content */
00104     res = ccn_content_get_value(ccnb, ccnb_size, info->pco, &data, &data_size);
00105     if (res < 0) abort();
00106     if (data_size > CHUNK_SIZE) {
00107         /* For us this is spam. Give up now. */
00108         fprintf(stderr, "*** Segment %d found with a data size of %d."
00109                         " This program only works with segments of 1024 bytes."
00110                         " Try ccncatchunks2 instead.\n",
00111                         (int)selfp->intdata, (int)data_size);
00112         exit(1);
00113     }
00114     
00115     /* OK, we will accept this block. */
00116     
00117     written = fwrite(data, data_size, 1, stdout);
00118     if (written != 1)
00119         exit(1);
00120     
00121     /* A short block signals EOF for us. */
00122     if (data_size < CHUNK_SIZE)
00123         exit(0);
00124     
00125     /* Ask for the next one */
00126     name = ccn_charbuf_create();
00127     ccn_name_init(name);
00128     if (ic->n < 2) abort();
00129     res = ccn_name_append_components(name, ib, ic->buf[0], ic->buf[ic->n - 2]);
00130     if (res < 0) abort();
00131     temp = ccn_charbuf_create();
00132     ccn_charbuf_putf(temp, "%d", ++(selfp->intdata));
00133     ccn_name_append(name, temp->buf, temp->length);
00134     ccn_charbuf_destroy(&temp);
00135     templ = make_template(md, info);
00136     
00137     res = ccn_express_interest(info->h, name, selfp, templ);
00138     if (res < 0) abort();
00139     
00140     ccn_charbuf_destroy(&templ);
00141     ccn_charbuf_destroy(&name);
00142     
00143     return(CCN_UPCALL_RESULT_OK);
00144 }
00145 
00146 int
00147 main(int argc, char **argv)
00148 {
00149     struct ccn *ccn = NULL;
00150     struct ccn_charbuf *name = NULL;
00151     struct ccn_charbuf *templ = NULL;
00152     struct ccn_closure *incoming = NULL;
00153     const char *arg = NULL;
00154     int res;
00155     int opt;
00156     struct mydata *mydata;
00157     int allow_stale = 0;
00158     
00159     while ((opt = getopt(argc, argv, "ha")) != -1) {
00160         switch (opt) {
00161             case 'a':
00162                 allow_stale = 1;
00163                 break;
00164             case 'h':
00165             default:
00166                 usage(argv[0]);
00167         }
00168     }
00169     arg = argv[optind];
00170     if (arg == NULL)
00171         usage(argv[0]);
00172     name = ccn_charbuf_create();
00173     res = ccn_name_from_uri(name, arg);
00174     if (res < 0) {
00175         fprintf(stderr, "%s: bad ccn URI: %s\n", argv[0], arg);
00176         exit(1);
00177     }
00178     if (argv[optind + 1] != NULL)
00179         fprintf(stderr, "%s warning: extra arguments ignored\n", argv[0]);
00180     ccn = ccn_create();
00181     if (ccn_connect(ccn, NULL) == -1) {
00182         perror("Could not connect to ccnd");
00183         exit(1);
00184     }
00185     ccn_name_append(name, "0", 1);
00186     incoming = calloc(1, sizeof(*incoming));
00187     incoming->p = &incoming_content;
00188     mydata = calloc(1, sizeof(*mydata));
00189     mydata->allow_stale = allow_stale;
00190     incoming->data = mydata;
00191     templ = make_template(mydata, NULL);
00192     ccn_express_interest(ccn, name, incoming, templ);
00193     ccn_charbuf_destroy(&templ);
00194     ccn_charbuf_destroy(&name);
00195     /* Run a little while to see if there is anything there */
00196     res = ccn_run(ccn, 200);
00197     if (incoming->intdata == 0) {
00198         fprintf(stderr, "%s: not found: %s\n", argv[0], arg);
00199         exit(1);
00200     }
00201     /* We got something, run until end of data or somebody kills us */
00202     while (res >= 0) {
00203         fflush(stdout);
00204         res = ccn_run(ccn, 200);
00205     }
00206     ccn_destroy(&ccn);
00207     exit(res < 0);
00208 }

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