ccnpoke.c

Go to the documentation of this file.
00001 /**
00002  * @file ccnpoke.c
00003  * Injects one chunk of data from stdin into ccn.
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 <errno.h>
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <unistd.h>
00025 #include <ccn/ccn.h>
00026 #include <ccn/uri.h>
00027 #include <ccn/keystore.h>
00028 #include <ccn/signing.h>
00029 
00030 static ssize_t
00031 read_full(int fd, unsigned char *buf, size_t size)
00032 {
00033     size_t i;
00034     ssize_t res = 0;
00035     for (i = 0; i < size; i += res) {
00036         res = read(fd, buf + i, size - i);
00037         if (res == -1) {
00038             if (errno == EAGAIN || errno == EINTR)
00039                 res = 0;
00040             else
00041                 return(res);
00042         }
00043         else if (res == 0)
00044             break;
00045     }
00046     return(i);
00047 }
00048 
00049 static void
00050 usage(const char *progname)
00051 {
00052     fprintf(stderr,
00053             "%s [-hflv] [-k key_uri] [-t type] [-V seg] [-w timeout] [-x freshness_seconds]"
00054             " ccnx:/some/place\n"
00055             " Reads data from stdin and sends it to the local ccnd"
00056             " as a single ContentObject under the given URI\n"
00057             "  -h - print this message and exit\n"
00058             "  -f - force - send content even if no interest received\n"
00059             "  -l - set FinalBlockId from last segment of URI\n"
00060             "  -v - verbose\n"
00061             "  -k key_uri - use this name for key locator\n"
00062             "  -p n - limit registration to n (>=0) components of the given URI in the interest filter.\n"
00063             "  -t ( DATA | ENCR | GONE | KEY | LINK | NACK ) - set type\n"
00064             "  -V seg - generate version, use seg as name suffix\n"
00065             "  -w seconds - fail after this long if no interest arrives\n"
00066             "  -x seconds - set FreshnessSeconds\n"
00067             , progname);
00068     exit(1);
00069 }
00070 
00071 enum ccn_upcall_res
00072 incoming_interest(
00073     struct ccn_closure *selfp,
00074     enum ccn_upcall_kind kind,
00075     struct ccn_upcall_info *info)
00076 {
00077     struct ccn_charbuf *cob = selfp->data;
00078     int res;
00079     
00080     switch (kind) {
00081         case CCN_UPCALL_FINAL:
00082             break;
00083         case CCN_UPCALL_INTEREST:
00084             if (ccn_content_matches_interest(cob->buf, cob->length,
00085                     1, NULL,
00086                     info->interest_ccnb, info->pi->offset[CCN_PI_E],
00087                     info->pi)) {
00088                 res = ccn_put(info->h, cob->buf, cob->length);
00089                 if (res >= 0) {
00090                     selfp->intdata = 1;
00091                     ccn_set_run_timeout(info->h, 0);
00092                     return(CCN_UPCALL_RESULT_INTEREST_CONSUMED);
00093                 }
00094             }
00095             break;
00096         default:
00097             break;
00098     }
00099     return(CCN_UPCALL_RESULT_OK);
00100 }
00101 
00102 int
00103 main(int argc, char **argv)
00104 {
00105     const char *progname = argv[0];
00106     struct ccn *ccn = NULL;
00107     struct ccn_charbuf *name = NULL;
00108     struct ccn_charbuf *pname = NULL;
00109     struct ccn_charbuf *temp = NULL;
00110     long expire = -1;
00111     int versioned = 0;
00112     size_t blocksize = 8*1024;
00113     int status = 0;
00114     int res;
00115     ssize_t read_res;
00116     unsigned char *buf = NULL;
00117     enum ccn_content_type content_type = CCN_CONTENT_DATA;
00118     struct ccn_closure in_interest = {.p=&incoming_interest};
00119     const char *postver = NULL;
00120     const char *key_uri = NULL;
00121     int force = 0;
00122     int verbose = 0;
00123     int timeout = -1;
00124     int setfinal = 0;
00125     int prefixcomps = -1;
00126     struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
00127     
00128     while ((res = getopt(argc, argv, "fhk:lvV:p:t:w:x:")) != -1) {
00129         switch (res) {
00130             case 'f':
00131                 force = 1;
00132                 break;
00133             case 'l':
00134                 setfinal = 1; // set FinalBlockID to last comp of name
00135                 break;
00136             case 'k':
00137                 key_uri = optarg;
00138                 break;
00139             case 'p':
00140                 prefixcomps = atoi(optarg);
00141                 if (prefixcomps < 0)
00142                     usage(progname);
00143                 break;
00144             case 'x':
00145                 expire = atol(optarg);
00146                 if (expire <= 0)
00147                     usage(progname);
00148                 break;
00149             case 'v':
00150                 verbose = 1;
00151                 break;
00152             case 'V':
00153                 versioned = 1;
00154                 postver = optarg;
00155                 if (0 == memcmp(postver, "%00", 3))
00156                     setfinal = 1;
00157                 break;
00158             case 'w':
00159                 timeout = atol(optarg);
00160                 if (timeout <= 0)
00161                     usage(progname);
00162                 timeout *= 1000;
00163                 break;
00164             case 't':
00165                 if (0 == strcasecmp(optarg, "DATA")) {
00166                     content_type = CCN_CONTENT_DATA;
00167                     break;
00168                 }
00169                 if (0 == strcasecmp(optarg, "ENCR")) {
00170                     content_type = CCN_CONTENT_ENCR;
00171                     break;
00172                 }
00173                 if (0 == strcasecmp(optarg, "GONE")) {
00174                     content_type = CCN_CONTENT_GONE;
00175                     break;
00176                 }
00177                 if (0 == strcasecmp(optarg, "KEY")) {
00178                     content_type = CCN_CONTENT_KEY;
00179                     break;
00180                 }
00181                 if (0 == strcasecmp(optarg, "LINK")) {
00182                     content_type = CCN_CONTENT_LINK;
00183                     break;
00184                 }
00185                 if (0 == strcasecmp(optarg, "NACK")) {
00186                     content_type = CCN_CONTENT_NACK;
00187                     break;
00188                 }
00189                 content_type = atoi(optarg);
00190                 if (content_type > 0 && content_type <= 0xffffff)
00191                     break;
00192                 fprintf(stderr, "Unknown content type %s\n", optarg);
00193                 /* FALLTHRU */
00194             default:
00195             case 'h':
00196                 usage(progname);
00197                 break;
00198         }
00199     }
00200     argc -= optind;
00201     argv += optind;
00202     if (argv[0] == NULL)
00203         usage(progname);
00204     name = ccn_charbuf_create();
00205     res = ccn_name_from_uri(name, argv[0]);
00206     if (res < 0) {
00207         fprintf(stderr, "%s: bad ccn URI: %s\n", progname, argv[0]);
00208         exit(1);
00209     }
00210     if (argv[1] != NULL)
00211         fprintf(stderr, "%s warning: extra arguments ignored\n", progname);
00212     
00213     /* Preserve the original prefix, in case we add versioning,
00214      * but trim it down if requested for the interest filter registration
00215      */
00216     pname = ccn_charbuf_create();
00217     ccn_charbuf_append(pname, name->buf, name->length);
00218     if (prefixcomps >= 0) {
00219         res = ccn_name_chop(pname, NULL, prefixcomps);
00220         if (res < 0) {
00221             fprintf(stderr, "%s: unable to trim name to %d component%s.\n",
00222                     progname, prefixcomps, prefixcomps == 1 ? "" : "s");
00223             exit(1);
00224         }
00225     }
00226     /* Connect to ccnd */
00227     ccn = ccn_create();
00228     if (ccn_connect(ccn, NULL) == -1) {
00229         perror("Could not connect to ccnd");
00230         exit(1);
00231     }
00232 
00233     /* Read the actual user data from standard input */
00234     buf = calloc(1, blocksize);
00235     read_res = read_full(0, buf, blocksize);
00236     if (read_res < 0) {
00237         perror("read");
00238         read_res = 0;
00239         status = 1;
00240     }
00241         
00242     /* Tack on the version component if requested */
00243     if (versioned) {
00244         res = ccn_create_version(ccn, name, CCN_V_REPLACE | CCN_V_NOW | CCN_V_HIGH, 0, 0);
00245         if (res < 0) {
00246             fprintf(stderr, "%s: ccn_create_version() failed\n", progname);
00247             exit(1);
00248         }
00249         if (postver != NULL) {
00250             res = ccn_name_from_uri(name, postver);
00251             if (res < 0) {
00252                 fprintf(stderr, "-V %s: invalid name suffix\n", postver);
00253                 exit(0);
00254             }
00255         }
00256     }
00257     temp = ccn_charbuf_create();
00258     
00259     /* Ask for a FinalBlockID if appropriate. */
00260     if (setfinal)
00261         sp.sp_flags |= CCN_SP_FINAL_BLOCK;
00262     
00263     if (res < 0) {
00264         fprintf(stderr, "Failed to create signed_info (res == %d)\n", res);
00265         exit(1);
00266     }
00267     
00268     /* Set content type */
00269     sp.type = content_type;
00270     
00271     /* Set freshness */
00272     if (expire >= 0) {
00273         if (sp.template_ccnb == NULL) {
00274             sp.template_ccnb = ccn_charbuf_create();
00275             ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_SignedInfo, CCN_DTAG);
00276         }
00277         else if (sp.template_ccnb->length > 0) {
00278             sp.template_ccnb->length--;
00279         }
00280         ccnb_tagged_putf(sp.template_ccnb, CCN_DTAG_FreshnessSeconds, "%ld", expire);
00281         sp.sp_flags |= CCN_SP_TEMPL_FRESHNESS;
00282         ccn_charbuf_append_closer(sp.template_ccnb);
00283     }
00284     
00285     /* Set key locator, if supplied */
00286     if (key_uri != NULL) {
00287         struct ccn_charbuf *c = ccn_charbuf_create();
00288         res = ccn_name_from_uri(c, key_uri);
00289         if (res < 0) {
00290             fprintf(stderr, "%s is not a valid ccnx URI\n", key_uri);
00291             exit(1);
00292         }
00293         if (sp.template_ccnb == NULL) {
00294             sp.template_ccnb = ccn_charbuf_create();
00295             ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_SignedInfo, CCN_DTAG);
00296         }
00297         else if (sp.template_ccnb->length > 0) {
00298             sp.template_ccnb->length--;
00299         }
00300         ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_KeyLocator, CCN_DTAG);
00301         ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_KeyName, CCN_DTAG);
00302         ccn_charbuf_append(sp.template_ccnb, c->buf, c->length);
00303         ccn_charbuf_append_closer(sp.template_ccnb);
00304         ccn_charbuf_append_closer(sp.template_ccnb);
00305         sp.sp_flags |= CCN_SP_TEMPL_KEY_LOCATOR;
00306         ccn_charbuf_append_closer(sp.template_ccnb);
00307         ccn_charbuf_destroy(&c);
00308     }
00309     
00310     /* Create the signed content object, ready to go */
00311     temp->length = 0;
00312     res = ccn_sign_content(ccn, temp, name, &sp, buf, read_res);
00313     if (res != 0) {
00314         fprintf(stderr, "Failed to encode ContentObject (res == %d)\n", res);
00315         exit(1);
00316     }
00317     if (read_res == blocksize) {
00318         read_res = read_full(0, buf, 1);
00319         if (read_res == 1) {
00320             fprintf(stderr, "%s: warning - truncated data\n", argv[0]);
00321             status = 1;
00322         }
00323     }
00324     free(buf);
00325     buf = NULL;
00326     if (force) {
00327         /* At user request, send without waiting to see an interest */
00328         res = ccn_put(ccn, temp->buf, temp->length);
00329         if (res < 0) {
00330             fprintf(stderr, "ccn_put failed (res == %d)\n", res);
00331             exit(1);
00332         }
00333     }
00334     else {
00335         in_interest.data = temp;
00336         /* Set up a handler for interests */
00337         res = ccn_set_interest_filter(ccn, pname, &in_interest);
00338         if (res < 0) {
00339             fprintf(stderr, "Failed to register interest (res == %d)\n", res);
00340             exit(1);
00341         }
00342         res = ccn_run(ccn, timeout);
00343         if (in_interest.intdata == 0) {
00344             if (verbose)
00345                 fprintf(stderr, "Nobody's interested\n");
00346             exit(1);
00347         }
00348     }
00349     
00350     if (verbose) {
00351         struct ccn_charbuf *uri = ccn_charbuf_create();
00352         uri->length = 0;
00353         ccn_uri_append(uri, name->buf, name->length, 1);
00354         printf("wrote %s\n", ccn_charbuf_as_string(uri));
00355         ccn_charbuf_destroy(&uri);
00356     }
00357     ccn_destroy(&ccn);
00358     ccn_charbuf_destroy(&name);
00359     ccn_charbuf_destroy(&pname);
00360     ccn_charbuf_destroy(&temp);
00361     ccn_charbuf_destroy(&sp.template_ccnb);
00362     exit(status);
00363 }
Generated on Tue Aug 21 14:54:17 2012 for Content-Centric Networking in C by  doxygen 1.6.3