/**
* Initiates a stream to download metadata (relations)
*
* @param id identifier of the ccn stream
* @param pname name of the object containing the metadata
* @param pmetaname name of the meta object to download
* @param pipeline number of parallel requisitions for chunks
*/
bool CCNGet::initMetaStream(string id, string pname, string pmetaname, int pipeline)
{
	name = ccn_charbuf_create();
	name->length = 0;
	ccn_name_from_uri(name, pname.c_str());
	templ = make_template(0,-1);
	ccn = ccn_create();
	if (ccn_connect(ccn,NULL) == -1) return false;
	if (ccn_resolve_version(ccn, name, CCN_V_HIGHEST, 1000) < 1) return false;
	ccn_name_append(name, meta, sizeof(meta));
	ccn_name_append_str(name, pmetaname.c_str());
	fetch = ccn_fetch_new(ccn);
	stream = ccn_fetch_open(fetch, name, id.c_str(), templ, pipeline, CCN_V_HIGHEST, ASSUMEFIXED);
	if (stream == NULL) return false;
	else return true;
}
Пример #2
0
/**
 * Read a slice (from a repository) given the name.
 * @param h is the ccn_handle on which to read.
 * @param name is the charbuf containing the name of the sync slice to be read.
 * @param slice is a pointer to a ccns_slice object which will be filled in
 *  on successful return.
 * @returns 0 on success, -1 otherwise.
 */
int
ccns_read_slice(struct ccn *h, struct ccn_charbuf *name,
                struct ccns_slice *slice) {
    struct ccn_parsed_ContentObject pco_space = { 0 };
    struct ccn_parsed_ContentObject *pco = &pco_space;
    struct ccn_charbuf *nc = ccn_charbuf_create_n(name->length);
    struct ccn_charbuf *cob = ccn_charbuf_create();
    const unsigned char *content;
    size_t content_length;
    int res = -1;

    if (nc == NULL || cob == NULL)
        goto Cleanup;

    ccn_charbuf_append_charbuf(nc, name);
    res = ccn_resolve_version(h, nc,  CCN_V_HIGHEST, 100); // XXX: timeout
    if (res < 0)
        goto Cleanup;
    if (res == 0) {
        // TODO: check if the last component is a segment number, chop it off, try again.
    }
    res = ccn_get(h, nc, NULL, 100, cob, pco, NULL, 0);
    if (res < 0)
        goto Cleanup;
    if (pco->type != CCN_CONTENT_DATA) {
        res = -1;
        goto Cleanup;
    }
    res = ccn_content_get_value(cob->buf, cob->length, pco,
                                &content, &content_length);
    if (res < 0)
        goto Cleanup;
    res = slice_parse(slice, content, content_length);

Cleanup:
    ccn_charbuf_destroy(&nc);
    ccn_charbuf_destroy(&cob);
    return (res);
}
Пример #3
0
/**
 * Process options and then loop through command line CCNx URIs retrieving
 * the data and writing it to stdout.
 */
int
main(int argc, char **argv)
{
    struct ccn *ccn = NULL;
    struct ccn_charbuf *name = NULL;
    struct ccn_charbuf *templ = NULL;
    struct ccn_closure *incoming = NULL;
    const char *arg = NULL;
    int i;
    int res;
    int opt;
    struct mydata *mydata;
    int allow_stale = 0;
    int *done;
    int exit_status = 0;
    
    done = calloc(1, sizeof(*done));
    
    while ((opt = getopt(argc, argv, "ha")) != -1) {
        switch (opt) {
            case 'a':
                allow_stale = 1;
                break;
            case 'h':
            default:
                usage(argv[0]);
        }
    }
    arg = argv[optind];
    if (arg == NULL)
        usage(argv[0]);
    name = ccn_charbuf_create();
    /* Check the args first */
    for (i = optind; argv[i] != NULL; i++) {
        name->length = 0;
        res = ccn_name_from_uri(name, argv[i]);
        if (res < 0) {
            fprintf(stderr, "%s: bad ccn URI: %s\n", argv[0], argv[i]);
            exit(1);
        }
    }
    for (i = optind; (arg = argv[i]) != NULL; i++) {
        *done = 0;
        name->length = 0;
        res = ccn_name_from_uri(name, arg);
        ccn = ccn_create();
        if (ccn_connect(ccn, NULL) == -1) {
            perror("Could not connect to ccnd");
            exit(1);
        }
        ccn_resolve_version(ccn, name, CCN_V_HIGHEST, 50);
        ccn_name_append_numeric(name, CCN_MARKER_SEQNUM, 0);
        incoming = calloc(1, sizeof(*incoming));
        incoming->p = &incoming_content;
        mydata = calloc(1, sizeof(*mydata));
        mydata->allow_stale = allow_stale;
        mydata->done = done;
        incoming->data = mydata;
        templ = make_template(mydata, NULL);
        ccn_express_interest(ccn, name, incoming, templ);
        ccn_charbuf_destroy(&templ);
        /* Run a little while to see if there is anything there */
        res = ccn_run(ccn, 200);
        if ((!*done) && incoming->intdata == 0) {
            fprintf(stderr, "%s: not found: %s\n", argv[0], arg);
            res = -1;
        }
        /* We got something; run until end of data or somebody kills us */
        while (res >= 0 && !*done) {
            fflush(stdout);
            res = ccn_run(ccn, 333);
        }
        if (res < 0)
            exit_status = 1;
        ccn_destroy(&ccn);
        fflush(stdout);
        free(incoming);
        incoming = NULL;
    }
    ccn_charbuf_destroy(&name);
    free(done);
    exit(exit_status);
}
Пример #4
0
/**
 * Creates a stream for a named interest.
 * The name should be a ccnb encoded interest.
 * If resolveVersion, then we assume that the version is unresolved, 
 * and an attempt is made to determine the version number using the highest
 * version.
 * The number of buffers (nBufs) may be silently limited.
 * @returns NULL if the stream creation failed,
 * otherwise returns the new stream.
 */
extern struct ccn_fetch_stream *
ccn_fetch_open(struct ccn_fetch *f,
			   struct ccn_charbuf *name,
			   const char *id,
			   struct ccn_charbuf *interestTemplate,
			   int maxBufs,
			   int resolveVersion,
			   int assumeFixed) {
	// returns a new ccn_fetch_stream object based on the arguments
	// returns NULL if not successful
    if (maxBufs <= 0) return NULL;
	if (maxBufs > 16) maxBufs = 16;
	int res = 0;
	FILE *debug = f->debug;
	ccn_fetch_flags flags = f->debugFlags;
    
	// first, resolve the version
	struct ccn_fetch_stream *fs = calloc(1, sizeof(*fs));
	fs->segSize = (assumeFixed ? 0 : -1);
	fs->name = ccn_charbuf_create();
	fs->id = newStringCopy(id);
	ccn_charbuf_append_charbuf(fs->name, name);
	if (resolveVersion) {
		int tmInc = 40; // TBD: need better strategy for version timeout
		int tm = 0;
		while (tm < CCN_VERSION_TIMEOUT) {
			res = ccn_resolve_version(f->h, fs->name, resolveVersion, tmInc);
			if (res >= 0) break;
			tm = tm + tmInc;
		}
		if (res < 0) {
			// could not resolve version for this name
			// get rid of allocations so far and bail out
			if (debug != NULL && (flags & ccn_fetch_flags_NoteOpenClose)) {
				fprintf(debug, 
						"-- ccn_fetch open, %s, failed to resolve version\n",
						fs->id);
				fflush(debug);
			}
			ccn_charbuf_destroy(&fs->name);
			freeString(fs->id);
			free(fs);
			return NULL;
		}
	}
	fs->maxBufs = maxBufs;
	fs->segsAhead = 0;
	fs->fileSize = -1;
	fs->finalSeg = -1;
	fs->timeoutSeg = -1;
	fs->zeroLenSeg = -1;
	fs->parent = f;
	fs->timeoutUSecs = CCN_INTEREST_TIMEOUT_USECS;  // TBD: how to get better timeout?
	
	// use the supplied template or the default
	if (interestTemplate != NULL) {
		struct ccn_charbuf *cb = ccn_charbuf_create();
		ccn_charbuf_append_charbuf(cb, interestTemplate);
		fs->interest = cb;
	} else
		fs->interest = make_data_template(MaxSuffixDefault);
	
	
	// remember the stream in the parent
	int ns = f->nStreams;
	int max = f->maxStreams;
	if (ns >= max) {
		// extend the vector
		int nMax = max+max/2+4;
        f->streams = realloc(f->streams, sizeof(*(f->streams)) * nMax);
		f->maxStreams = nMax;
	}
	// guaranteed room to add at the end
	f->streams[ns] = fs;
	f->nStreams = ns+1;
	
	if (debug != NULL && (flags & ccn_fetch_flags_NoteOpenClose)) {
		fprintf(debug, 
				"-- ccn_fetch open, %s\n",
				fs->id);
		fflush(debug);
	}
	// prep for the first segment
	NeedSegment(fs, 0);
	return fs;
}
Пример #5
0
/**
 * Tell the GST source element it is time to prepare to do work
 *
 * This is one of the last functions GStreamer will call when the pipeline
 * is being put together. It is the last place the element has a chance to
 * allocate resources and in our case startup our background task for network
 * connectivity.
 * After this function returns, we are ready to start processing data from the pipeliine.
 *
 * We allocate some of the last minute buffers, and setup a connection to the network;
 * this is used primarily by the background task, but we need access to it for name initialization.
 *
 * Next we initialize our fifo queue, and startup the background task.
 *
 * Lastly we return to the GST to begin processing information.
 *
 * \param bsrc		-> to the context source element
 * \return true if the initialization went well and we are ready to process data, false otherwise
 */
static gboolean
gst_ccnxsrc_start (GstBaseSrc * bsrc)
{
  Gstccnxsrc *src;
  CcnxInterestState *istate;

  struct ccn_charbuf *p_name = NULL;
  uintmax_t *p_seg = NULL;
  gint i_ret = 0;
  gboolean b_ret = FALSE;

  src = GST_CCNXSRC (bsrc);
  GST_DEBUG ("starting, getting connections");

  /* setup the connection to ccnx */
  if ((src->ccn = ccn_create ()) == NULL) {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), ("ccn_create failed"));
    return FALSE;
  }
  if (-1 == ccn_connect (src->ccn, ccndHost ())) {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), ("ccn_connect failed to %s",
            ccndHost ()));
    return FALSE;
  }
  loadKey (src->ccn, &src->sp);

  /* A closure is what defines what to do when an inbound interest or data arrives */
  if ((src->ccn_closure = calloc (1, sizeof (struct ccn_closure))) == NULL) {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), ("closure alloc failed"));
    return FALSE;
  }

  /* We setup the closure to keep our context [src] and to call the incoming_content() function */
  src->ccn_closure->data = src;
  src->ccn_closure->p = incoming_content;

  /* Allocate buffers and construct the name from the uri the user gave us */
  GST_INFO ("step 1");
  if ((p_name = ccn_charbuf_create ()) == NULL) {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), ("p_name alloc failed"));
    return FALSE;
  }
  if ((src->p_name = ccn_charbuf_create ()) == NULL) {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
        ("src->p_name alloc failed"));
    return FALSE;
  }
  if ((i_ret = ccn_name_from_uri (p_name, src->uri)) < 0) {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
        ("name from uri failed for \"%s\"", src->uri));
    return FALSE;
  }

  /* Find out what the latest one of these is called, and keep it in our context */
  ccn_charbuf_append (src->p_name, p_name->buf, p_name->length);
  i_ret = ccn_resolve_version (src->ccn, src->p_name, CCN_V_HIGHEST,
      CCN_VERSION_TIMEOUT);

  GST_INFO ("step 20 - name so far...");
  // hDump(src->p_name->buf, src->p_name->length);
  src->i_seg = 0;
  if (i_ret == 0) {             /* name is versioned, so get the meta data to obtain the length */
    p_seg = get_segment (src->ccn, src->p_name, CCN_HEADER_TIMEOUT);
    if (p_seg != NULL) {
      src->i_seg = *p_seg;
      GST_INFO ("step 25 - next seg: %d", src->i_seg);
      free (p_seg);
    }
  }
  ccn_charbuf_destroy (&p_name);

  /* Even though the recent segment published is likely to be >> 0, we still need to ask for segment 0 */
  /* because it seems to contain valuable stream information. Attempts to skip segment 0 resulted in no */
  /* proper rendering of the stream on my screen during testing */
  i_ret = request_segment (src, 0);
  if (i_ret < 0) {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
        ("interest sending failed"));
    return FALSE;
  }
  src->post_seg = 0;
  istate = allocInterestState (src);
  if (!istate) {                // This should not happen, but maybe
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
        ("trouble allocating interest state structure"));
    return FALSE;
  }
  istate->seg = 0;
  istate->state = OInterest_waiting;

  /* Now start up the background work which will fetch all the rest of the R/T segments */
  eventTask = gst_task_create (ccn_event_thread, src);
  if (NULL == eventTask) {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
        ("creating event thread failed"));
    return FALSE;
  }
  src->fifo_cond = g_cond_new ();
  src->fifo_lock = g_mutex_new ();
  gst_task_set_lock (eventTask, &task_mutex);
  eventCond = g_cond_new ();
  eventLock = g_mutex_new ();
  b_ret = gst_task_start (eventTask);
  if (FALSE == b_ret) {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
        ("starting event thread failed"));
    return FALSE;
  }
  GST_DEBUG ("event thread started");

  /* Done! */
  return TRUE;
}