ccn_bulkdata.c

Go to the documentation of this file.
00001 /**
00002  * @file ccn_bulkdata.c
00003  * @brief (INCOMPLETE)Support for transport of bulk data.
00004  * 
00005  * Part of the CCNx C Library.
00006  *
00007  * Copyright (C) 2008, 2009 Palo Alto Research Center, Inc.
00008  *
00009  * This library is free software; you can redistribute it and/or modify it
00010  * under the terms of the GNU Lesser General Public License version 2.1
00011  * as published by the Free Software Foundation.
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00015  * Lesser General Public License for more details. You should have received
00016  * a copy of the GNU Lesser General Public License along with this library;
00017  * if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
00018  * Fifth Floor, Boston, MA 02110-1301 USA.
00019  */
00020 #include <assert.h>
00021 #include <stdint.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 
00025 #include <ccn/bloom.h>
00026 #include <ccn/ccn.h>
00027 
00028 /************ Candidate API stuff - was in ccn/ccn.h for a while ******/
00029 /***********************************
00030  * Bulk data
00031  */
00032 
00033 /*
00034  * The client provides a ccn_seqfunc * (and perhaps a matching param)
00035  * to specify the scheme for naming the content items in the sequence.
00036  * Given the sequence number x, it should place in resultbuf the
00037  * corresponding blob that that will be used in the final explicit
00038  * Component of the Name of item x in the sequence.  This should
00039  * act as a mathematical function, returning the same answer for a given x.
00040  * (Ususally param will be NULL, but is provided in case it is needed.)
00041  */
00042 typedef void ccn_seqfunc(uintmax_t x, void *param,
00043                          struct ccn_charbuf *resultbuf);
00044 
00045 /*
00046  * Ready-to-use sequencing functions
00047  */
00048 extern ccn_seqfunc ccn_decimal_seqfunc;
00049 extern ccn_seqfunc ccn_binary_seqfunc;
00050 /**********************************************************************/
00051 
00052 /*
00053  * Encode the number in decimal ascii
00054  */
00055 void
00056 ccn_decimal_seqfunc(uintmax_t x, void *param, struct ccn_charbuf *resultbuf)
00057 {
00058     (void)param; /* unused */
00059     assert(resultbuf->length == 0);
00060     ccn_charbuf_putf(resultbuf, "%ju", x);
00061 }
00062 
00063 /*
00064  * Encode the number in big-endian binary, using one more than the
00065  * minimum number of bytes (that is, the first byte is always zero).
00066  */
00067 void
00068 ccn_binary_seqfunc(uintmax_t x, void *param, struct ccn_charbuf *resultbuf)
00069 {
00070     uintmax_t m;
00071     int n;
00072     unsigned char *b;
00073     (void)param; /* unused */
00074     for (n = 0, m = 0; x < m; n++)
00075         m = (m << 8) | 0xff;
00076     b = ccn_charbuf_reserve(resultbuf, n + 1);
00077     resultbuf->length = n + 1;
00078     for (; n >= 0; n--, x >>= 8)
00079         b[n] = x & 0xff;
00080 }
00081 
00082 /*
00083  * Our private record of the state of the bulk data reception
00084  */
00085 struct bulkdata {
00086     ccn_seqfunc *seqfunc;           /* the sequence number scheme */
00087     void *seqfunc_param;            /* parameters thereto, if needed */
00088     struct pending *first;          /* start of list of pending items */
00089     struct ccn_closure *client;     /* client-supplied upcall for delivery */
00090     uintmax_t next_expected;        /* smallest undelivered sequence number */
00091     struct ccn_charbuf *name_prefix;
00092     int prefix_comps;
00093     /* pubid, etc? */
00094 };
00095 
00096 struct pending {
00097     struct pending *prev;           /* links for doubly-linked list */
00098     struct pending *next;
00099     struct bulkdata *parent;
00100     uintmax_t x;                    /* sequence number for this item */
00101     struct ccn_closure closure;     /* our closure for getting matching data */
00102     unsigned char *content_ccnb;    /* the content that has arrived */
00103     size_t content_size;
00104 };
00105 
00106 static enum ccn_upcall_res deliver_content(struct ccn *h, struct bulkdata *b);
00107 static void express_bulkdata_interest(struct ccn *h, struct pending *b);
00108 // XXX - missing a way to create a struct bulkdata *
00109 // XXX - missing code to create new pendings
00110 
00111 
00112 /*static*/ enum ccn_upcall_res
00113 imcoming_bulkdata(struct ccn_closure *selfp,
00114                   enum ccn_upcall_kind kind,
00115                   struct ccn_upcall_info *info)
00116 {
00117     struct bulkdata *b;
00118     struct pending *p = selfp->data;
00119     enum ccn_upcall_res res = CCN_UPCALL_RESULT_ERR;
00120 
00121     assert(selfp == &p->closure);
00122     b = p->parent;
00123     
00124     switch (kind) {
00125         case CCN_UPCALL_FINAL:
00126             p->prev->next = p->next->prev;
00127             p->next->prev = p->prev->next;
00128             if (b != NULL && p == b->first)
00129                 b->first = (p == p->next) ? NULL : p->next;
00130             if (p->content_ccnb != NULL)
00131                 free(p->content_ccnb);
00132             free(p);
00133             return(CCN_UPCALL_RESULT_OK);
00134         case CCN_UPCALL_CONTENT:
00135         case CCN_UPCALL_CONTENT_UNVERIFIED:
00136         case CCN_UPCALL_CONTENT_BAD:
00137             /* XXX - should we be returning bad (signature failed) content */
00138             break;
00139         case CCN_UPCALL_INTEREST_TIMED_OUT:
00140             /* XXX - may want to give client a chance to decide */ 
00141             return(CCN_UPCALL_RESULT_REEXPRESS);
00142         default:
00143             return(CCN_UPCALL_RESULT_ERR);
00144     }
00145     /* XXX - check to see if seq comp matches, if not we have a hole to fill */
00146     
00147     if (p->content_ccnb == NULL) {
00148     if (p->x == b->next_expected) {
00149         /* Good, we have in-order data to deliver to the caller */
00150         res = (*b->client->p)(b->client, kind, info);
00151         if (res == CCN_UPCALL_RESULT_OK) {
00152             b->next_expected += 1;
00153             b->first = (p == p->next) ? NULL : p->next;
00154             p->prev->next = p->next->prev;
00155             p->next->prev = p->prev->next;
00156             p->next = p->prev = p;
00157             p->parent = NULL;
00158         }
00159         // else ...
00160     }
00161     else if (p->content_ccnb == NULL) {
00162         /* Out-of-order data, save it for later */
00163         size_t size = info->pco->offset[CCN_PCO_E];
00164         selfp->refcount++; /* don't call FINAL just yet */
00165         p->content_ccnb = malloc(size);
00166         memcpy(p->content_ccnb, info->content_ccnb, size);
00167         p->content_size = size;
00168     }
00169     }
00170     while (b->first != NULL && b->first->x == b->next_expected &&
00171            b->first->content_ccnb != NULL) {
00172         res = deliver_content(info->h, b);
00173         if (res != CCN_UPCALL_RESULT_OK)
00174             break;
00175     }
00176     if (b->first == NULL) {
00177         // XXX 
00178         return(CCN_UPCALL_RESULT_OK);
00179     }
00180     for (p = b->first; p->x >= b->next_expected; p = p->next) {
00181         // XXX - this is not really right ...
00182         if (p->content_ccnb == NULL)
00183             express_bulkdata_interest(info->h, p);
00184     }
00185     return(CCN_UPCALL_RESULT_OK);
00186 }
00187 
00188 static void
00189 express_bulkdata_interest(struct ccn *h, struct pending *p)
00190 {
00191     int res;
00192     struct bulkdata *b = NULL;
00193     int prefix_comps = -1;
00194     int addl_comps = -1;
00195     struct ccn_charbuf *name = NULL;
00196     struct ccn_charbuf *templ = NULL;
00197     struct ccn_charbuf *seq = NULL;
00198     
00199     b = p->parent;
00200     if (b == NULL)
00201         return;
00202     name = ccn_charbuf_create();
00203     templ = ccn_charbuf_create();
00204     seq = ccn_charbuf_create();
00205 
00206     ccn_charbuf_append(name, b->name_prefix->buf, b->name_prefix->length);
00207     
00208     seq->length = 0;
00209     (*b->seqfunc)(p->x, b->seqfunc_param, seq);
00210     ccn_name_append(name, seq->buf, seq->length);
00211     prefix_comps = -1;
00212     addl_comps = 1;
00213     
00214     ccn_charbuf_append_tt(templ, CCN_DTAG_Interest, CCN_DTAG);
00215 
00216     ccn_charbuf_append_tt(templ, CCN_DTAG_Name, CCN_DTAG);
00217     ccn_charbuf_append_closer(templ); /* </Name> */
00218 
00219     // XXX - may want to set Min/MaxSuffixComponents
00220     
00221     ccn_charbuf_append_closer(templ); /* </Interest> */
00222     res = ccn_express_interest(h, name, &p->closure, templ);
00223     assert(res >= 0); // XXX - handle this better
00224     ccn_charbuf_destroy(&name);
00225     ccn_charbuf_destroy(&templ);
00226     ccn_charbuf_destroy(&seq);
00227 }
00228 
00229 /*
00230  * deliver_content is used to deliver a previously-buffered
00231  * ContentObject to the client.
00232  */
00233 static enum ccn_upcall_res
00234 deliver_content(struct ccn *h, struct bulkdata *b)
00235 {
00236     struct ccn_upcall_info info = {0};
00237     struct ccn_parsed_ContentObject obj = {0};
00238     struct pending *p = b->first;
00239     int res;
00240     enum ccn_upcall_res ans;
00241     assert(p != NULL && p->x == b->next_expected && p->content_ccnb != NULL);
00242     info.pco = &obj;
00243     info.content_comps = ccn_indexbuf_create();
00244     res = ccn_parse_ContentObject(p->content_ccnb, p->content_size,
00245                                   &obj, info.content_comps);
00246     assert(res >= 0);
00247     info.content_ccnb = p->content_ccnb;
00248     info.matched_comps = info.content_comps->n - 2;
00249     /* XXX - we have no matched interest to present */
00250     ans = (*b->client->p)(b->client, CCN_UPCALL_CONTENT, &info);
00251     // XXX - check for refusal
00252     info.content_ccnb = NULL;
00253     free(p->content_ccnb);
00254     p->content_ccnb = NULL;
00255     p->content_size = 0;
00256     ccn_indexbuf_destroy(&info.content_comps);
00257     if (ans == CCN_UPCALL_RESULT_OK) {
00258         struct ccn_closure *old = &p->closure;
00259         if ((--(old->refcount)) == 0) {
00260             info.pco = NULL;
00261             (old->p)(old, CCN_UPCALL_FINAL, &info);
00262         }
00263     }
00264     return(ans);
00265 }
Generated on Fri May 13 16:27:02 2011 for Content-Centric Networking in C by  doxygen 1.6.3