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 " -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;
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
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
00207 pname = ccn_charbuf_create();
00208 ccn_charbuf_append(pname, name->buf, name->length);
00209
00210
00211 ccn = ccn_create();
00212 if (ccn_connect(ccn, NULL) == -1) {
00213 perror("Could not connect to ccnd");
00214 exit(1);
00215 }
00216
00217
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
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
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
00253 sp.type = content_type;
00254
00255
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
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
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
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
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 }