ccnput.c

Go to the documentation of this file.
00001 /**
00002  * @file ccnput.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 [-fhv] [-V seg] [-x freshness_seconds] [-t type]"
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"
00057             "\n"
00058             "  -h - print this message and exit"
00059             "\n"
00060             "  -k key_uri - use this name for key locator"
00061             "\n"
00062             "  -f - force - send content even if no interest received"
00063             "\n"
00064             "  -v - verbose"
00065             "\n"
00066             "  -V seg - generate version, use seg as name suffix"
00067             "\n"
00068             "  -w seconds - fail after this long if no interest arrives"
00069             "\n"
00070             "  -x seconds - set FreshnessSeconds"
00071             "\n"
00072             "  -t ( DATA | ENCR | GONE | KEY | LINK | NACK ) - set type"
00073             "\n", progname);
00074     exit(1);
00075 }
00076 
00077 enum ccn_upcall_res
00078 incoming_interest(
00079     struct ccn_closure *selfp,
00080     enum ccn_upcall_kind kind,
00081     struct ccn_upcall_info *info)
00082 {
00083     struct ccn_charbuf *cob = selfp->data;
00084     int res;
00085     
00086     switch (kind) {
00087         case CCN_UPCALL_FINAL:
00088             break;
00089         case CCN_UPCALL_INTEREST:
00090             if (ccn_content_matches_interest(cob->buf, cob->length,
00091                     1, NULL,
00092                     info->interest_ccnb, info->pi->offset[CCN_PI_E],
00093                     info->pi)) {
00094                 res = ccn_put(info->h, cob->buf, cob->length);
00095                 if (res >= 0) {
00096                     selfp->intdata = 1;
00097                     ccn_set_run_timeout(info->h, 0);
00098                     return(CCN_UPCALL_RESULT_INTEREST_CONSUMED);
00099                 }
00100             }
00101             break;
00102         default:
00103             break;
00104     }
00105     return(CCN_UPCALL_RESULT_OK);
00106 }
00107 
00108 int
00109 main(int argc, char **argv)
00110 {
00111     const char *progname = argv[0];
00112     struct ccn *ccn = NULL;
00113     struct ccn_charbuf *name = NULL;
00114     struct ccn_charbuf *pname = NULL;
00115     struct ccn_charbuf *temp = NULL;
00116     long expire = -1;
00117     int versioned = 0;
00118     size_t blocksize = 8*1024;
00119     int status = 0;
00120     int res;
00121     ssize_t read_res;
00122     unsigned char *buf = NULL;
00123     enum ccn_content_type content_type = CCN_CONTENT_DATA;
00124     struct ccn_closure in_interest = {.p=&incoming_interest};
00125     const char *postver = NULL;
00126     const char *key_uri = NULL;
00127     int force = 0;
00128     int verbose = 0;
00129     int timeout = -1;
00130     int setfinal = 0;
00131     struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
00132     
00133     while ((res = getopt(argc, argv, "fhk:lvV:t:w:x:")) != -1) {
00134         switch (res) {
00135             case 'f':
00136                 force = 1;
00137                 break;
00138             case 'l':
00139                 setfinal = 1; // set FinalBlockID to last comp of name
00140                 break;
00141             case 'k':
00142                 key_uri = optarg;
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     pname = ccn_charbuf_create();
00215     ccn_charbuf_append(pname, name->buf, name->length);
00216 
00217     /* Connect to ccnd */
00218     ccn = ccn_create();
00219     if (ccn_connect(ccn, NULL) == -1) {
00220         perror("Could not connect to ccnd");
00221         exit(1);
00222     }
00223 
00224     /* Read the actual user data from standard input */
00225     buf = calloc(1, blocksize);
00226     read_res = read_full(0, buf, blocksize);
00227     if (read_res < 0) {
00228         perror("read");
00229         read_res = 0;
00230         status = 1;
00231     }
00232         
00233     /* Tack on the version component if requested */
00234     if (versioned) {
00235         res = ccn_create_version(ccn, name, CCN_V_REPLACE | CCN_V_NOW | CCN_V_HIGH, 0, 0);
00236         if (res < 0) {
00237             fprintf(stderr, "%s: ccn_create_version() failed\n", progname);
00238             exit(1);
00239         }
00240         if (postver != NULL) {
00241             res = ccn_name_from_uri(name, postver);
00242             if (res < 0) {
00243                 fprintf(stderr, "-V %s: invalid name suffix\n", postver);
00244                 exit(0);
00245             }
00246         }
00247     }
00248     temp = ccn_charbuf_create();
00249     
00250     /* Ask for a FinalBlockID if appropriate. */
00251     if (setfinal)
00252         sp.sp_flags |= CCN_SP_FINAL_BLOCK;
00253     
00254     if (res < 0) {
00255         fprintf(stderr, "Failed to create signed_info (res == %d)\n", res);
00256         exit(1);
00257     }
00258     
00259     /* Set content type */
00260     sp.type = content_type;
00261     
00262     /* Set freshness */
00263     if (expire >= 0) {
00264         if (sp.template_ccnb == NULL) {
00265             sp.template_ccnb = ccn_charbuf_create();
00266             ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_SignedInfo, CCN_DTAG);
00267         }
00268         else if (sp.template_ccnb->length > 0) {
00269             sp.template_ccnb->length--;
00270         }
00271         ccnb_tagged_putf(sp.template_ccnb, CCN_DTAG_FreshnessSeconds, "%ld", expire);
00272         sp.sp_flags |= CCN_SP_TEMPL_FRESHNESS;
00273         ccn_charbuf_append_closer(sp.template_ccnb);
00274     }
00275     
00276     /* Set key locator, if supplied */
00277     if (key_uri != NULL) {
00278         struct ccn_charbuf *c = ccn_charbuf_create();
00279         res = ccn_name_from_uri(c, key_uri);
00280         if (res < 0) {
00281             fprintf(stderr, "%s is not a valid ccnx URI\n", key_uri);
00282             exit(1);
00283         }
00284         if (sp.template_ccnb == NULL) {
00285             sp.template_ccnb = ccn_charbuf_create();
00286             ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_SignedInfo, CCN_DTAG);
00287         }
00288         else if (sp.template_ccnb->length > 0) {
00289             sp.template_ccnb->length--;
00290         }
00291         ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_KeyLocator, CCN_DTAG);
00292         ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_KeyName, CCN_DTAG);
00293         ccn_charbuf_append(sp.template_ccnb, c->buf, c->length);
00294         ccn_charbuf_append_closer(sp.template_ccnb);
00295         ccn_charbuf_append_closer(sp.template_ccnb);
00296         sp.sp_flags |= CCN_SP_TEMPL_KEY_LOCATOR;
00297         ccn_charbuf_append_closer(sp.template_ccnb);
00298         ccn_charbuf_destroy(&c);
00299     }
00300     
00301     /* Create the signed content object, ready to go */
00302     temp->length = 0;
00303     res = ccn_sign_content(ccn, temp, name, &sp, buf, read_res);
00304     if (res != 0) {
00305         fprintf(stderr, "Failed to encode ContentObject (res == %d)\n", res);
00306         exit(1);
00307     }
00308     if (read_res == blocksize) {
00309         read_res = read_full(0, buf, 1);
00310         if (read_res == 1) {
00311             fprintf(stderr, "%s: warning - truncated data\n", argv[0]);
00312             status = 1;
00313         }
00314     }
00315     free(buf);
00316     buf = NULL;
00317     if (force) {
00318         /* At user request, send without waiting to see an interest */
00319         res = ccn_put(ccn, temp->buf, temp->length);
00320         if (res < 0) {
00321             fprintf(stderr, "ccn_put failed (res == %d)\n", res);
00322             exit(1);
00323         }
00324     }
00325     else {
00326         in_interest.data = temp;
00327         /* Set up a handler for interests */
00328         res = ccn_set_interest_filter(ccn, pname, &in_interest);
00329         if (res < 0) {
00330             fprintf(stderr, "Failed to register interest (res == %d)\n", res);
00331             exit(1);
00332         }
00333         res = ccn_run(ccn, timeout);
00334         if (in_interest.intdata == 0) {
00335             if (verbose)
00336                 fprintf(stderr, "Nobody's interested\n");
00337             exit(1);
00338         }
00339     }
00340     
00341     if (verbose) {
00342         struct ccn_charbuf *uri = ccn_charbuf_create();
00343         uri->length = 0;
00344         ccn_uri_append(uri, name->buf, name->length, 1);
00345         printf("wrote %s\n", ccn_charbuf_as_string(uri));
00346         ccn_charbuf_destroy(&uri);
00347     }
00348     ccn_destroy(&ccn);
00349     ccn_charbuf_destroy(&name);
00350     ccn_charbuf_destroy(&pname);
00351     ccn_charbuf_destroy(&temp);
00352     ccn_charbuf_destroy(&sp.template_ccnb);
00353     exit(status);
00354 }
Generated on Fri May 13 16:27:01 2011 for Content-Centric Networking in C by  doxygen 1.6.3