Пример #1
0
static int
append_signature_bits(struct ccn_charbuf *signature,
		PyObject *py_obj_Signature)
{
	PyObject *py_signatureBits = NULL;
	const char *blob;
	Py_ssize_t blobsize;
	int r;

	if (!PyObject_HasAttrString(py_obj_Signature, "signatureBits"))
		return 0;

	py_signatureBits = PyObject_GetAttrString(py_obj_Signature,
			"signatureBits");
	JUMP_IF_NULL(py_signatureBits, error);

	if (py_signatureBits != Py_None) {
		blob = PyBytes_AsString(py_signatureBits);
		JUMP_IF_NULL(blob, error);
		blobsize = PyBytes_GET_SIZE(py_signatureBits);

		r = ccnb_append_tagged_blob(signature, CCN_DTAG_SignatureBits, blob,
				blobsize);
		JUMP_IF_NEG_MEM(r, error);
	}
	Py_DECREF(py_signatureBits);

	return 0;

error:
	Py_XDECREF(py_signatureBits);
	return -1;
}
Пример #2
0
int
ccnb_append_forwarding_entry(struct ccn_charbuf *c,
                             const struct ccn_forwarding_entry *fe)
{
    int res;
    res = ccnb_element_begin(c, CCN_DTAG_ForwardingEntry);
    if (fe->action != NULL)
        res |= ccnb_tagged_putf(c, CCN_DTAG_Action, "%s",
                                   fe->action);
    if (fe->name_prefix != NULL && fe->name_prefix->length > 0)
        res |= ccn_charbuf_append(c, fe->name_prefix->buf,
                                     fe->name_prefix->length);
    if (fe->ccnd_id_size != 0)
        res |= ccnb_append_tagged_blob(c, CCN_DTAG_PublisherPublicKeyDigest,
                                          fe->ccnd_id, fe->ccnd_id_size);
    if (fe->faceid != ~0)
        res |= ccnb_tagged_putf(c, CCN_DTAG_FaceID, "%u",
                                   fe->faceid);
    if (fe->flags >= 0)
        res |= ccnb_tagged_putf(c, CCN_DTAG_ForwardingFlags, "%d",
                                   fe->flags);
    if (fe->lifetime >= 0)
        res |= ccnb_tagged_putf(c, CCN_DTAG_FreshnessSeconds, "%d",
                                   fe->lifetime);
    res |= ccnb_element_end(c);
    return(res);
}
Пример #3
0
static int
append_digest_algorithm(struct ccn_charbuf *signature,
		PyObject *py_obj_Signature)
{
	PyObject *py_digestAlgorithm = NULL;
	PyObject *py_o;
	char *str;
	Py_ssize_t str_len;
	int r;

	if (!PyObject_HasAttrString(py_obj_Signature, "digestAlgorithm"))
		return 0;

	py_digestAlgorithm = PyObject_GetAttrString(py_obj_Signature,
			"digestAlgorithm");
	JUMP_IF_NULL(py_digestAlgorithm, error);

	if (py_digestAlgorithm != Py_None) {
		py_o = _pyccn_unicode_to_utf8(py_digestAlgorithm, &str, &str_len);
		assert((Py_ssize_t) strlen(str) == str_len);
		JUMP_IF_NULL(py_o, error);

		r = ccnb_append_tagged_blob(signature, CCN_DTAG_DigestAlgorithm,
				str, str_len);
		Py_DECREF(py_o);
		JUMP_IF_NEG_MEM(r, error);
	}
	Py_DECREF(py_digestAlgorithm);

	return 0;

error:
	Py_XDECREF(py_digestAlgorithm);
	return -1;
}
Пример #4
0
/*
 * This appends a tagged, valid, fully-saturated Bloom filter, useful for
 * excluding everything between two 'fenceposts' in an Exclude construct.
 */
static void
append_bf_all(struct ccn_charbuf *c)
{
    unsigned char bf_all[9] = { 3, 1, 'A', 0, 0, 0, 0, 0, 0xFF };
    const struct ccn_bloom_wire *b = ccn_bloom_validate_wire(bf_all, sizeof(bf_all));
    if (b == NULL) abort();
    ccnb_append_tagged_blob(c, CCN_DTAG_Bloom, bf_all, sizeof(bf_all));
}
Пример #5
0
static void append_lifetime(ccn_charbuf *templ) {
	unsigned int nonce = rand() % MAXNONCE;
	unsigned int lifetime = INTEREST_LIFETIME * 4096 + nonce;
	unsigned char buf[3] = {0};
	for (int i = sizeof(buf) - 1; i >= 0; i--, lifetime >>=8) {
		buf[i] = lifetime & 0xff;
	}
	ccnb_append_tagged_blob(templ, CCN_DTAG_InterestLifetime, buf, sizeof(buf));
}
Пример #6
0
int 
get_content_by_content_name(char *content_name, unsigned char **content_data,
							char *orig_router)
{
	
	int ret=-1;
	struct ccn_charbuf *name = NULL;
	struct ccn_charbuf *templ = NULL;
	struct ccn_charbuf *resultbuf = NULL;
	struct ccn_parsed_ContentObject pcobuf = { 0 };
	int res;
	int allow_stale = 1;
	int content_only = 1;
	int scope = -1;
	const unsigned char *ptr,*ptr_in; 
	size_t length,length_in;
	int resolve_version = CCN_V_HIGHEST;
	int timeout_ms = 3000;
	const unsigned lifetime_default = CCN_INTEREST_LIFETIME_SEC << 12;
	unsigned lifetime_l12 = lifetime_default;
	int get_flags = 0;

	name = ccn_charbuf_create();
	res = ccn_name_from_uri(name,content_name);
	if (res < 0) {
		fprintf(stderr, "Bad ccn URI: %s\n", content_name);
		ccn_charbuf_destroy(&name);
		return ret;
	}

	if (allow_stale || lifetime_l12 != lifetime_default || scope != -1) {
		templ = ccn_charbuf_create();
		ccn_charbuf_append_tt(templ, CCN_DTAG_Interest, CCN_DTAG);
		ccn_charbuf_append_tt(templ, CCN_DTAG_Name, CCN_DTAG);
		ccn_charbuf_append_closer(templ); /* </Name> */
		if (allow_stale) {
			ccn_charbuf_append_tt(templ, CCN_DTAG_AnswerOriginKind, CCN_DTAG);
			ccnb_append_number(templ,
					CCN_AOK_DEFAULT | CCN_AOK_STALE);
			ccn_charbuf_append_closer(templ); /* </AnswerOriginKind> */
		}
		if (scope != -1) {
			ccnb_tagged_putf(templ, CCN_DTAG_Scope, "%d", scope);
		}
		if (lifetime_l12 != lifetime_default) {
			/*
			 * Choose the interest lifetime so there are at least 3
			 * expressions (in the unsatisfied case).
			 */
			unsigned char buf[3] = { 0 };
			int i;
			for (i = sizeof(buf) - 1; i >= 0; i--, lifetime_l12 >>= 8)
				buf[i] = lifetime_l12 & 0xff;
			ccnb_append_tagged_blob(templ, CCN_DTAG_InterestLifetime, buf, 
					sizeof(buf));
		}
Пример #7
0
/**
 * Append a tagged binary number as a blob containing the integer value
 *
 * This is a ccnb-encoded element holding a 
 * @param cb is the buffer to append to.
 * @param dtag is the element's dtab
 * @param val is the unsigned integer to be appended
 * @returns 0 for success or -1 for error.
 */
int
ccnb_append_tagged_binary_number(struct ccn_charbuf *cb,
                                 enum ccn_dtag dtag,
                                 uintmax_t val) {
    unsigned char buf[sizeof(val)];
    int pos;
    int res = 0;
    for (pos = sizeof(buf); val != 0 && pos > 0; val >>= 8)
        buf[--pos] = val & 0xff;
    res |= ccnb_append_tagged_blob(cb, dtag, buf+pos, sizeof(buf)-pos);
    return(res);
}
Пример #8
0
// replace_name()
// Helper function to replace names in content objects
// Could build another version that works on already parsed content objects
// But as seen below it would be better to use a modified encoding call that
// didn't include the name at all.
//
int replace_name(struct ccn_charbuf* dest, unsigned char* src,  size_t src_size, struct ccn_charbuf* name) {
	struct ccn_parsed_ContentObject* pco = (struct ccn_parsed_ContentObject*) calloc(sizeof(struct ccn_parsed_ContentObject), 1);
	int res = 0;
	res = ccn_parse_ContentObject(src,src_size, pco, NULL);
    if (res < 0) {
    	free(pco);
    	return (res);
    }
	ccn_charbuf_append_tt(dest, CCN_DTAG_ContentObject, CCN_DTAG);
	ccn_charbuf_append(dest, &src[pco->offset[CCN_PCO_B_Signature]], pco->offset[CCN_PCO_E_Signature] - pco->offset[CCN_PCO_B_Signature]);
	ccn_charbuf_append_charbuf(dest, name); // Already tagged
	ccn_charbuf_append(dest, &src[pco->offset[CCN_PCO_B_SignedInfo]], pco->offset[CCN_PCO_E_SignedInfo] - pco->offset[CCN_PCO_B_SignedInfo]);
	ccnb_append_tagged_blob(dest, CCN_DTAG_Content, NULL, 0);
	ccn_charbuf_append_closer(dest);
	free(pco);
	return (0);
}
Пример #9
0
int
ccnb_append_strategy_selection(struct ccn_charbuf *c,
                               const struct ccn_strategy_selection *ss)
{
    int ch;
    int i;
    int len;
    int res;
    
    res = ccnb_element_begin(c, CCN_DTAG_StrategySelection);
    if (ss->action != NULL)
        res |= ccnb_tagged_putf(c, CCN_DTAG_Action, "%s",
                                   ss->action);
    if (ss->name_prefix != NULL && ss->name_prefix->length > 0)
        res |= ccn_charbuf_append(c, ss->name_prefix->buf,
                                     ss->name_prefix->length);
    if (ss->ccnd_id_size != 0)
        res |= ccnb_append_tagged_blob(c, CCN_DTAG_PublisherPublicKeyDigest,
                                          ss->ccnd_id, ss->ccnd_id_size);
    if (ss->strategyid != NULL) {
        len = strlen(ss->strategyid);
        for (i = 0; i < len; i++) {
            ch = ss->strategyid[i];
            if (!(('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') ||
                  ('0' <= ch && ch <= '9') || (ch == '_')))
                res |= -1;
        }
        if (len > 0) {
            res |= ccnb_tagged_putf(c, CCN_DTAG_StrategyID, "%.15s",
                                       ss->strategyid);
            if (len >= STRATEGY_ID_MAX_SIZE)
                res |= -1;
        }
    }
    if (ss->parameters != NULL)
        res |= ccnb_tagged_putf(c, CCN_DTAG_StrategyParameters, "%s",
                                   ss->parameters);
    if (ss->lifetime >= 0)
        res |= ccnb_tagged_putf(c, CCN_DTAG_FreshnessSeconds, "%d",
                                   ss->lifetime);
    res |= ccnb_element_end(c);
    return(res);
}
Пример #10
0
/**
 * Marshal an internal face instance representation into ccnb form
 */
int
ccnb_append_face_instance(struct ccn_charbuf *c,
                          const struct ccn_face_instance *fi)
{
    int res;
    res = ccnb_element_begin(c, CCN_DTAG_FaceInstance);
    if (fi->action != NULL)
        res |= ccnb_tagged_putf(c, CCN_DTAG_Action, "%s",
                                fi->action);
    if (fi->ccnd_id_size != 0)
        res |= ccnb_append_tagged_blob(c, CCN_DTAG_PublisherPublicKeyDigest,
                                          fi->ccnd_id, fi->ccnd_id_size);
    if (fi->faceid != ~0)
        res |= ccnb_tagged_putf(c, CCN_DTAG_FaceID, "%u",
                                   fi->faceid);
    if (fi->descr.ipproto >= 0)
        res |= ccnb_tagged_putf(c, CCN_DTAG_IPProto, "%d",
                                   fi->descr.ipproto);
    if (fi->descr.address != NULL)
        res |= ccnb_tagged_putf(c, CCN_DTAG_Host, "%s",
                                   fi->descr.address);
    if (fi->descr.port != NULL)
        res |= ccnb_tagged_putf(c, CCN_DTAG_Port, "%s",
                                   fi->descr.port);    
    if (fi->descr.source_address != NULL)
        res |= ccnb_tagged_putf(c, CCN_DTAG_MulticastInterface, "%s",
                                   fi->descr.source_address);
    if (fi->descr.mcast_ttl >= 0 && fi->descr.mcast_ttl != 1)
        res |= ccnb_tagged_putf(c, CCN_DTAG_MulticastTTL, "%d",
                                   fi->descr.mcast_ttl);
    if (fi->lifetime >= 0)
        res |= ccnb_tagged_putf(c, CCN_DTAG_FreshnessSeconds, "%d",
                                   fi->lifetime);    
    res |= ccnb_element_end(c);
    return(res);
}
Пример #11
0
/**
 * Encode and sign a ContentObject.
 * @param buf is the output buffer where encoded object is written.
 * @param Name is the ccnb-encoded name from ccn_name_init and friends.
 * @param SignedInfo is the ccnb-encoded info from ccn_signed_info_create.
 * @param data pintes to the raw data to be encoded.
 * @param size is the size, in bytes, of the raw data to be encoded.
 * @param digest_algorithm may be NULL for default.
 * @param private_key is the private key to use for signing.
 * @returns 0 for success or -1 for error.
 */
int
ccn_encode_ContentObject(struct ccn_charbuf *buf,
                         const struct ccn_charbuf *Name,
                         const struct ccn_charbuf *SignedInfo,
                         const void *data,
                         size_t size,
                         const char *digest_algorithm,
                         const struct ccn_pkey *private_key
                         )
{
    int res = 0;
    struct ccn_sigc *sig_ctx;
    struct ccn_signature *signature;
    size_t signature_size;
    struct ccn_charbuf *content_header;
    size_t closer_start;

    content_header = ccn_charbuf_create();
    res |= ccn_charbuf_append_tt(content_header, CCN_DTAG_Content, CCN_DTAG);
    if (size != 0)
        res |= ccn_charbuf_append_tt(content_header, size, CCN_BLOB);
    closer_start = content_header->length;
    res |= ccn_charbuf_append_closer(content_header);
    if (res < 0)
        return(-1);
    sig_ctx = ccn_sigc_create();
    if (sig_ctx == NULL)
        return(-1);
    if (0 != ccn_sigc_init(sig_ctx, digest_algorithm, private_key))
        return(-1);
    if (0 != ccn_sigc_update(sig_ctx, Name->buf, Name->length))
        return(-1);
    if (0 != ccn_sigc_update(sig_ctx, SignedInfo->buf, SignedInfo->length))
        return(-1);
    if (0 != ccn_sigc_update(sig_ctx, content_header->buf, closer_start))
        return(-1);
    if (0 != ccn_sigc_update(sig_ctx, data, size))
        return(-1);
    if (0 != ccn_sigc_update(sig_ctx, content_header->buf + closer_start,
                             content_header->length - closer_start))
        return(-1);
    signature = calloc(1, ccn_sigc_signature_max_size(sig_ctx, private_key));
    if (signature == NULL)
        return(-1);
    res = ccn_sigc_final(sig_ctx, signature, &signature_size, private_key);
    if (0 != res) {
        free(signature);
        return(-1);
    }
    ccn_sigc_destroy(&sig_ctx);
    res |= ccn_charbuf_append_tt(buf, CCN_DTAG_ContentObject, CCN_DTAG);
    res |= ccn_encode_Signature(buf, digest_algorithm,
                                NULL, 0, signature, signature_size);
    res |= ccn_charbuf_append_charbuf(buf, Name);
    res |= ccn_charbuf_append_charbuf(buf, SignedInfo);
    res |= ccnb_append_tagged_blob(buf, CCN_DTAG_Content, data, size);
    res |= ccn_charbuf_append_closer(buf);
    free(signature);
    ccn_charbuf_destroy(&content_header);
    return(res == 0 ? 0 : -1);
}
Пример #12
0
static PyObject *
Interest_obj_to_ccn(PyObject *py_obj_Interest)
{
	struct ccn_charbuf *interest;
	PyObject *py_interest, *py_o;
	int r;

	py_interest = CCNObject_New_charbuf(INTEREST, &interest);
	if (!py_interest)
		return NULL;

	r = ccn_charbuf_append_tt(interest, CCN_DTAG_Interest, CCN_DTAG);
	JUMP_IF_NEG_MEM(r, error);

	/* Name */
	{
		struct ccn_charbuf *name;
		PyObject *py_name;

		r = is_attr_set(py_obj_Interest, "name", &py_o);
		JUMP_IF_NEG(r, error);

		if (r) {
			py_name = Name_obj_to_ccn(py_o);
			Py_DECREF(py_o);
			JUMP_IF_NULL(py_name, error);
			name = CCNObject_Get(NAME, py_name);

			r = ccn_charbuf_append_charbuf(interest, name);
			Py_DECREF(py_name);
			JUMP_IF_NEG_MEM(r, error);
		} else {
			// Even though Name is mandatory we still use this code to generate
			// templates, so it is ok if name is not given, the code below
			// creates an empty tag
			r = ccn_charbuf_append_tt(interest, CCN_DTAG_Name, CCN_DTAG);
			JUMP_IF_NEG(r, error);

			r = ccn_charbuf_append_closer(interest); /* </Name> */
			JUMP_IF_NEG(r, error);
		}
	}

	r = process_int_attribute(interest, CCN_DTAG_MinSuffixComponents,
			py_obj_Interest, "minSuffixComponents");
	JUMP_IF_NEG(r, error);

	r = process_int_attribute(interest, CCN_DTAG_MaxSuffixComponents,
			py_obj_Interest, "maxSuffixComponents");
	JUMP_IF_NEG(r, error);

	r = is_attr_set(py_obj_Interest, "publisherPublicKeyDigest", &py_o);
	JUMP_IF_NEG(r, error);
	if (r) {
		const char *blob;
		Py_ssize_t blobsize;

		blob = PyBytes_AsString(py_o);
		if (!blob) {
			Py_DECREF(py_o);
			goto error;
		}
		blobsize = PyBytes_GET_SIZE(py_o);

		r = ccnb_append_tagged_blob(interest, CCN_DTAG_PublisherPublicKeyDigest,
				blob, blobsize);
		Py_DECREF(py_o);
		JUMP_IF_NEG_MEM(r, error);
	}

	r = is_attr_set(py_obj_Interest, "exclude", &py_o);
	JUMP_IF_NEG(r, error);
	if (r) {
		PyObject *py_exclusions;
		struct ccn_charbuf *exclusion_filter;

		if (!PyObject_IsInstance(py_o, g_type_ExclusionFilter)) {
			Py_DECREF(py_o);
			PyErr_SetString(PyExc_TypeError, "Expected ExclusionFilter");
			goto error;
		}

		r = is_attr_set(py_o, "ccn_data", &py_exclusions);
		Py_DECREF(py_o);
		JUMP_IF_NEG(r, error);

		exclusion_filter = CCNObject_Get(EXCLUSION_FILTER, py_exclusions);
		r = ccn_charbuf_append_charbuf(interest, exclusion_filter);
		Py_DECREF(py_exclusions);
		JUMP_IF_NEG(r, error);
	}

	r = process_int_attribute(interest, CCN_DTAG_ChildSelector,
			py_obj_Interest, "childSelector");
	JUMP_IF_NEG(r, error);

	r = process_int_attribute(interest, CCN_DTAG_AnswerOriginKind,
			py_obj_Interest, "answerOriginKind");
	JUMP_IF_NEG(r, error);

	r = process_int_attribute(interest, CCN_DTAG_Scope, py_obj_Interest,
			"scope");
	JUMP_IF_NEG(r, error);

	r = is_attr_set(py_obj_Interest, "interestLifetime", &py_o);
	if (r) {
		unsigned char buf[3] = {0};
		double lifetime;
		unsigned long i_lifetime;

		if (!PyFloat_Check(py_o)) {
			Py_DECREF(py_o);
			PyErr_SetString(PyExc_TypeError, "expected float type in interest"
					" lifetime");
			goto error;
		}

		lifetime = PyFloat_AS_DOUBLE(py_o);
		Py_DECREF(py_o);

		i_lifetime = lifetime * 4096;

		/* XXX: probably won't work in bigendian */
		for (int i = sizeof(buf) - 1; i >= 0; i--, i_lifetime >>= 8)
			buf[i] = i_lifetime & 0xff;

		r = ccnb_append_tagged_blob(interest, CCN_DTAG_InterestLifetime,
				buf, sizeof(buf));
		JUMP_IF_NEG_MEM(r, error);
	}

	r = is_attr_set(py_obj_Interest, "nonce", &py_o);
	if (r) {
		char *s;
		Py_ssize_t len;

		r = PyBytes_AsStringAndSize(py_o, &s, &len);
		if (r < 0) {
			Py_DECREF(py_o);
			goto error;
		}

		r = ccnb_append_tagged_blob(interest, CCN_DTAG_Nonce, s, len);
		Py_DECREF(py_o);
		JUMP_IF_NEG_MEM(r, error);
	}

	r = ccn_charbuf_append_closer(interest); /* </Interest> */
	JUMP_IF_NEG_MEM(r, error);

	return py_interest;

error:
	Py_DECREF(py_interest);

	return NULL;
}
Пример #13
0
int
main(int argc, char **argv)
{
    struct ccn *h = NULL;
    struct ccn_charbuf *name = NULL;
    struct ccn_charbuf *templ = NULL;
    struct ccn_charbuf *resultbuf = NULL;
    const char *arg = NULL;
    struct ccn_parsed_ContentObject pcobuf = { 0 };
    int res;
    char ch;
    int allow_stale = 0;
    int content_only = 0;
    const unsigned char *ptr;
    size_t length;
    int resolve_version = 0;
    const char *env_timeout = getenv("CCN_LINGER");
    int timeout_ms = 3000;
    
    while ((ch = getopt(argc, argv, "hacv")) != -1) {
        switch (ch) {
            case 'a':
                allow_stale = 1;
                break;
            case 'c':
                content_only = 1;
                break;
            case 'v':
                if (resolve_version == 0)
                    resolve_version = CCN_V_HIGHEST;
                else
                    resolve_version = CCN_V_HIGH;
                break;
            case 'h':
            default:
                usage(argv[0]);
        }
    }
    arg = argv[optind];
    if (arg == NULL)
        usage(argv[0]);
    name = ccn_charbuf_create();
    res = ccn_name_from_uri(name, arg);
    if (res < 0) {
        fprintf(stderr, "%s: bad ccn URI: %s\n", argv[0], arg);
        exit(1);
    }
    if (argv[optind + 1] != NULL)
        fprintf(stderr, "%s warning: extra arguments ignored\n", argv[0]);
    h = ccn_create();
    res = ccn_connect(h, NULL);
    if (res < 0) {
        ccn_perror(h, "ccn_connect");
        exit(1);
    }
    if (res < 0) {
        fprintf(stderr, "%s: bad ccn URI: %s\n", argv[0], arg);
        exit(1);
    }
    if (env_timeout != NULL && (res = atoi(env_timeout)) > 0) {
		timeout_ms = res * 1000;
    }
	if (allow_stale || env_timeout != NULL) {
        templ = ccn_charbuf_create();
        ccn_charbuf_append_tt(templ, CCN_DTAG_Interest, CCN_DTAG);
        ccn_charbuf_append_tt(templ, CCN_DTAG_Name, CCN_DTAG);
        ccn_charbuf_append_closer(templ); /* </Name> */
		if (allow_stale) {
			ccn_charbuf_append_tt(templ, CCN_DTAG_AnswerOriginKind, CCN_DTAG);
			ccnb_append_number(templ,
							   CCN_AOK_DEFAULT | CCN_AOK_STALE);
			ccn_charbuf_append_closer(templ); /* </AnswerOriginKind> */
		}
		if (env_timeout != NULL) {
			/*
			 * Choose the interest lifetime so there are at least 3
			 * expressions (in the unsatisfied case).
			 */
			unsigned char buf[3] = { 0 };
			unsigned lifetime;
			int i;
			if (timeout_ms > 60000)
				lifetime = 30 << 12;
			else {
				lifetime = timeout_ms * 2 / 5 * 4096 / 1000;
			}
			for (i = sizeof(buf) - 1; i >= 0; i--, lifetime >>= 8)
				buf[i] = lifetime & 0xff;
			ccnb_append_tagged_blob(templ, CCN_DTAG_InterestLifetime, buf, sizeof(buf));
		}
Пример #14
0
int
main(int argc, char **argv)
{
    const char *progname = argv[0];
    struct ccn *ccn = NULL;
    struct ccn_charbuf *name = NULL;
    struct ccn_charbuf *pname = NULL;
    struct ccn_charbuf *temp = NULL;
    struct ccn_charbuf *extopt = NULL;
    long expire = -1;
    int versioned = 0;
    size_t blocksize = 8*1024;
    int status = 0;
    int res;
    ssize_t read_res;
    unsigned char *buf = NULL;
    enum ccn_content_type content_type = CCN_CONTENT_DATA;
    struct ccn_closure in_interest = {.p=&incoming_interest};
    const char *postver = NULL;
    const char *key_uri = NULL;
    int force = 0;
    int verbose = 0;
    int timeout = -1;
    int setfinal = 0;
    int prefixcomps = -1;
    int fd;
    struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
    
    while ((res = getopt(argc, argv, "e:fhk:lvV:p:t:w:x:")) != -1) {
        switch (res) {
            case 'e':
                if (extopt == NULL)
                    extopt = ccn_charbuf_create();
                fd = open(optarg, O_RDONLY);
                if (fd < 0) {
                    perror(optarg);
                    exit(1);
                }
                for (;;) {
                    read_res = read(fd, ccn_charbuf_reserve(extopt, 64), 64);
                    if (read_res <= 0)
                        break;
                    extopt->length += read_res;
                }
                if (read_res < 0)
                    perror(optarg);
                close(fd);
                break;
            case 'f':
                force = 1;
                break;
            case 'l':
                setfinal = 1; // set FinalBlockID to last comp of name
                break;
            case 'k':
                key_uri = optarg;
                break;
            case 'p':
                prefixcomps = atoi(optarg);
                if (prefixcomps < 0)
                    usage(progname);
                break;
            case 'x':
                expire = atol(optarg);
                if (expire <= 0)
                    usage(progname);
                break;
            case 'v':
                verbose = 1;
                break;
            case 'V':
                versioned = 1;
                postver = optarg;
                if (0 == memcmp(postver, "%00", 3))
                    setfinal = 1;
                break;
            case 'w':
                timeout = atol(optarg);
                if (timeout <= 0)
                    usage(progname);
                timeout *= 1000;
                break;
            case 't':
                if (0 == strcasecmp(optarg, "DATA")) {
                    content_type = CCN_CONTENT_DATA;
                    break;
                }
                if (0 == strcasecmp(optarg, "ENCR")) {
                    content_type = CCN_CONTENT_ENCR;
                    break;
                }
                if (0 == strcasecmp(optarg, "GONE")) {
                    content_type = CCN_CONTENT_GONE;
                    break;
                }
                if (0 == strcasecmp(optarg, "KEY")) {
                    content_type = CCN_CONTENT_KEY;
                    break;
                }
                if (0 == strcasecmp(optarg, "LINK")) {
                    content_type = CCN_CONTENT_LINK;
                    break;
                }
                if (0 == strcasecmp(optarg, "NACK")) {
                    content_type = CCN_CONTENT_NACK;
                    break;
                }
                content_type = atoi(optarg);
                if (content_type > 0 && content_type <= 0xffffff)
                    break;
                fprintf(stderr, "Unknown content type %s\n", optarg);
                /* FALLTHRU */
            default:
            case 'h':
                usage(progname);
                break;
        }
    }
    argc -= optind;
    argv += optind;
    if (argv[0] == NULL)
        usage(progname);
    name = ccn_charbuf_create();
    res = ccn_name_from_uri(name, argv[0]);
    if (res < 0) {
        fprintf(stderr, "%s: bad ccn URI: %s\n", progname, argv[0]);
        exit(1);
    }
    if (argv[1] != NULL)
        fprintf(stderr, "%s warning: extra arguments ignored\n", progname);
    
    /* Preserve the original prefix, in case we add versioning,
     * but trim it down if requested for the interest filter registration
     */
    pname = ccn_charbuf_create();
    ccn_charbuf_append(pname, name->buf, name->length);
    if (prefixcomps >= 0) {
        res = ccn_name_chop(pname, NULL, prefixcomps);
        if (res < 0) {
            fprintf(stderr, "%s: unable to trim name to %d component%s.\n",
                    progname, prefixcomps, prefixcomps == 1 ? "" : "s");
            exit(1);
        }
    }
    /* Connect to ccnd */
    ccn = ccn_create();
    if (ccn_connect(ccn, NULL) == -1) {
        perror("Could not connect to ccnd");
        exit(1);
    }

    /* Read the actual user data from standard input */
    buf = calloc(1, blocksize);
    read_res = read_full(0, buf, blocksize);
    if (read_res < 0) {
        perror("read");
        read_res = 0;
        status = 1;
    }
        
    /* Tack on the version component if requested */
    if (versioned) {
        res = ccn_create_version(ccn, name, CCN_V_REPLACE | CCN_V_NOW | CCN_V_HIGH, 0, 0);
        if (res < 0) {
            fprintf(stderr, "%s: ccn_create_version() failed\n", progname);
            exit(1);
        }
        if (postver != NULL) {
            res = ccn_name_from_uri(name, postver);
            if (res < 0) {
                fprintf(stderr, "-V %s: invalid name suffix\n", postver);
                exit(0);
            }
        }
    }
    temp = ccn_charbuf_create();
    
    /* Ask for a FinalBlockID if appropriate. */
    if (setfinal)
        sp.sp_flags |= CCN_SP_FINAL_BLOCK;
    
    if (res < 0) {
        fprintf(stderr, "Failed to create signed_info (res == %d)\n", res);
        exit(1);
    }
    
    /* Set content type */
    sp.type = content_type;
    
    /* Set freshness */
    if (expire >= 0) {
        if (sp.template_ccnb == NULL) {
            sp.template_ccnb = ccn_charbuf_create();
            ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_SignedInfo, CCN_DTAG);
        }
        else if (sp.template_ccnb->length > 0) {
            sp.template_ccnb->length--;
        }
        ccnb_tagged_putf(sp.template_ccnb, CCN_DTAG_FreshnessSeconds, "%ld", expire);
        sp.sp_flags |= CCN_SP_TEMPL_FRESHNESS;
        ccn_charbuf_append_closer(sp.template_ccnb);
    }
    
    /* Set key locator, if supplied */
    if (key_uri != NULL) {
        struct ccn_charbuf *c = ccn_charbuf_create();
        res = ccn_name_from_uri(c, key_uri);
        if (res < 0) {
            fprintf(stderr, "%s is not a valid ccnx URI\n", key_uri);
            exit(1);
        }
        if (sp.template_ccnb == NULL) {
            sp.template_ccnb = ccn_charbuf_create();
            ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_SignedInfo, CCN_DTAG);
        }
        else if (sp.template_ccnb->length > 0) {
            sp.template_ccnb->length--;
        }
        ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_KeyLocator, CCN_DTAG);
        ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_KeyName, CCN_DTAG);
        ccn_charbuf_append(sp.template_ccnb, c->buf, c->length);
        ccn_charbuf_append_closer(sp.template_ccnb);
        ccn_charbuf_append_closer(sp.template_ccnb);
        sp.sp_flags |= CCN_SP_TEMPL_KEY_LOCATOR;
        ccn_charbuf_append_closer(sp.template_ccnb);
        ccn_charbuf_destroy(&c);
    }

    if (extopt != NULL && extopt->length > 0) {
        if (sp.template_ccnb == NULL) {
            sp.template_ccnb = ccn_charbuf_create();
            ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_SignedInfo, CCN_DTAG);
        }
        else if (sp.template_ccnb->length > 0) {
            sp.template_ccnb->length--;
        }
        ccnb_append_tagged_blob(sp.template_ccnb, CCN_DTAG_ExtOpt,
                                extopt->buf, extopt->length);
        sp.sp_flags |= CCN_SP_TEMPL_EXT_OPT;
        ccn_charbuf_append_closer(sp.template_ccnb);
    }
    
    /* Create the signed content object, ready to go */
    temp->length = 0;
    res = ccn_sign_content(ccn, temp, name, &sp, buf, read_res);
    if (res != 0) {
        fprintf(stderr, "Failed to encode ContentObject (res == %d)\n", res);
        exit(1);
    }
    if (read_res == blocksize) {
        read_res = read_full(0, buf, 1);
        if (read_res == 1) {
            fprintf(stderr, "%s: warning - truncated data\n", argv[0]);
            status = 1;
        }
    }
    free(buf);
    buf = NULL;
    if (force) {
        /* At user request, send without waiting to see an interest */
        res = ccn_put(ccn, temp->buf, temp->length);
        if (res < 0) {
            fprintf(stderr, "ccn_put failed (res == %d)\n", res);
            exit(1);
        }
    }
    else {
        in_interest.data = temp;
        /* Set up a handler for interests */
        res = ccn_set_interest_filter(ccn, pname, &in_interest);
        if (res < 0) {
            fprintf(stderr, "Failed to register interest (res == %d)\n", res);
            exit(1);
        }
        res = ccn_run(ccn, timeout);
        if (in_interest.intdata == 0) {
            if (verbose)
                fprintf(stderr, "Nobody's interested\n");
            exit(1);
        }
    }
    
    if (verbose) {
        struct ccn_charbuf *uri = ccn_charbuf_create();
        uri->length = 0;
        ccn_uri_append(uri, name->buf, name->length, 1);
        printf("wrote %s\n", ccn_charbuf_as_string(uri));
        ccn_charbuf_destroy(&uri);
    }
    ccn_destroy(&ccn);
    ccn_charbuf_destroy(&name);
    ccn_charbuf_destroy(&pname);
    ccn_charbuf_destroy(&temp);
    ccn_charbuf_destroy(&sp.template_ccnb);
    ccn_charbuf_destroy(&extopt);
    exit(status);
}