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

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