00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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;
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
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
00214
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
00227 ccn = ccn_create();
00228 if (ccn_connect(ccn, NULL) == -1) {
00229 perror("Could not connect to ccnd");
00230 exit(1);
00231 }
00232
00233
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
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
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
00269 sp.type = content_type;
00270
00271
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
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
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
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
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 }