ccn_seqwriter.c

Go to the documentation of this file.
00001 /**
00002  * @file ccn_seqwriter.c
00003  * @brief
00004  * 
00005  * Part of the CCNx C Library.
00006  *
00007  * Copyright (C) 2010 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 
00021 #include <stddef.h>
00022 #include <stdint.h>
00023 #include <stdlib.h>
00024 #include <errno.h>
00025 #include <ccn/ccn.h>
00026 #include <ccn/seqwriter.h>
00027 
00028 #define MAX_DATA_SIZE 4096
00029 
00030 struct ccn_seqwriter {
00031     struct ccn_closure cl;
00032     struct ccn *h;
00033     struct ccn_charbuf *nb;
00034     struct ccn_charbuf *nv;
00035     struct ccn_charbuf *buffer;
00036     struct ccn_charbuf *cob0;
00037     uintmax_t seqnum;
00038     int batching;
00039     unsigned char interests_possibly_pending;
00040     unsigned char closed;
00041 };
00042 
00043 static struct ccn_charbuf *
00044 seqw_next_cob(struct ccn_seqwriter *w)
00045 {
00046     struct ccn_charbuf *cob = ccn_charbuf_create();
00047     struct ccn_charbuf *name = ccn_charbuf_create();
00048     struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
00049     int res;
00050     
00051     if (w->closed)
00052         sp.sp_flags |= CCN_SP_FINAL_BLOCK;
00053     ccn_charbuf_append(name, w->nv->buf, w->nv->length);
00054     ccn_name_append_numeric(name, CCN_MARKER_SEQNUM, w->seqnum);
00055     res = ccn_sign_content(w->h, cob, name, &sp, w->buffer->buf, w->buffer->length);
00056     if (res < 0)
00057         ccn_charbuf_destroy(&cob);
00058     ccn_charbuf_destroy(&name);
00059     return(cob);
00060 }
00061 
00062 static enum ccn_upcall_res
00063 seqw_incoming_interest(
00064                        struct ccn_closure *selfp,
00065                        enum ccn_upcall_kind kind,
00066                        struct ccn_upcall_info *info)
00067 {
00068     int res;
00069     struct ccn_charbuf *cob = NULL;
00070     struct ccn_seqwriter *w = selfp->data;
00071     
00072     if (w == NULL || selfp != &(w->cl))
00073         abort();
00074     switch (kind) {
00075         case CCN_UPCALL_FINAL:
00076             ccn_charbuf_destroy(&w->nb);
00077             ccn_charbuf_destroy(&w->nv);
00078             ccn_charbuf_destroy(&w->buffer);
00079             ccn_charbuf_destroy(&w->cob0);
00080             free(w);
00081             break;
00082         case CCN_UPCALL_INTEREST:
00083             if (w->closed || w->buffer->length > 0) {
00084                 cob = seqw_next_cob(w);
00085                 if (cob == NULL)
00086                     return(CCN_UPCALL_RESULT_OK);
00087                 if (ccn_content_matches_interest(cob->buf, cob->length,
00088                                                  1, NULL,
00089                                                  info->interest_ccnb,
00090                                                  info->pi->offset[CCN_PI_E],
00091                                                  info->pi)) {
00092                     w->interests_possibly_pending = 0;
00093                     res = ccn_put(info->h, cob->buf, cob->length);
00094                     if (res >= 0) {
00095                         w->buffer->length = 0;
00096                         w->seqnum++;
00097                         return(CCN_UPCALL_RESULT_INTEREST_CONSUMED);
00098                     }
00099                 }
00100                 ccn_charbuf_destroy(&cob);
00101             }
00102             if (w->cob0 != NULL) {
00103                 cob = w->cob0;
00104                 if (ccn_content_matches_interest(cob->buf, cob->length,
00105                                                  1, NULL,
00106                                                  info->interest_ccnb,
00107                                                  info->pi->offset[CCN_PI_E],
00108                                                  info->pi)) {
00109                     w->interests_possibly_pending = 0;
00110                     ccn_put(info->h, cob->buf, cob->length);
00111                     return(CCN_UPCALL_RESULT_INTEREST_CONSUMED);
00112                 }
00113             }
00114             w->interests_possibly_pending = 1;
00115             break;
00116         default:
00117             break;
00118     }
00119     return(CCN_UPCALL_RESULT_OK);
00120 }
00121 
00122 /**
00123  * Create a seqwriter for writing data to a versioned, segmented stream.
00124  *
00125  * @param name is a ccnb-encoded Name.  It will be provided with a version
00126  *        based on the current time unless it already ends in a version
00127  *        component.
00128  */
00129 struct ccn_seqwriter *
00130 ccn_seqw_create(struct ccn *h, struct ccn_charbuf *name)
00131 {
00132     struct ccn_seqwriter *w = NULL;
00133     struct ccn_charbuf *nb = NULL;
00134     struct ccn_charbuf *nv = NULL;
00135     int res;
00136     
00137     w = calloc(1, sizeof(*w));
00138     if (w == NULL)
00139         return(NULL);
00140     nb = ccn_charbuf_create();
00141     ccn_charbuf_append(nb, name->buf, name->length);
00142     nv = ccn_charbuf_create();
00143     ccn_charbuf_append(nv, name->buf, name->length);
00144     res = ccn_create_version(h, nv, CCN_V_NOW, 0, 0);
00145     if (res < 0 || nb == NULL) {
00146         ccn_charbuf_destroy(&nv);
00147         ccn_charbuf_destroy(&nb);
00148         free(w);
00149         return(NULL);
00150     }
00151     
00152     w->cl.p = &seqw_incoming_interest;
00153     w->cl.data = w;
00154     w->nb = nb;
00155     w->nv = nv;
00156     w->buffer = ccn_charbuf_create();
00157     w->h = h;
00158     w->seqnum = 0;
00159     w->interests_possibly_pending = 1;
00160     res = ccn_set_interest_filter(h, nb, &(w->cl));
00161     if (res < 0) {
00162         ccn_charbuf_destroy(&w->nb);
00163         ccn_charbuf_destroy(&w->nv);
00164         ccn_charbuf_destroy(&w->buffer);
00165         free(w);
00166         return(NULL);
00167     }
00168     return(w);
00169 }
00170 
00171 /**
00172  * Write some data to a seqwriter.
00173  *
00174  * This is roughly analogous to a write(2) call in non-blocking mode.
00175  *
00176  * The current implementation returns an error and refuses the new data if
00177  * it does not fit in the current buffer.
00178  * That is, there are no partial writes.
00179  * In this case, the caller should ccn_run() for a little while and retry.
00180  * 
00181  * It is also an error to attempt to write more than 4096 bytes.
00182  *
00183  * @returns the size written, or -1 for an error.  In case of an error,
00184  *          the caller may test ccn_geterror() for values of EAGAIN or
00185  *          EINVAL from errno.h.
00186  */
00187 int
00188 ccn_seqw_write(struct ccn_seqwriter *w, const void *buf, size_t size)
00189 {
00190     struct ccn_charbuf *cob = NULL;
00191     int res;
00192     int ans;
00193     
00194     if (w == NULL || w->cl.data != w)
00195         return(-1);
00196     if (w->buffer == NULL || size > MAX_DATA_SIZE)
00197         return(ccn_seterror(w->h, EINVAL));
00198     ans = size;
00199     if (size + w->buffer->length > MAX_DATA_SIZE)
00200         ans = ccn_seterror(w->h, EAGAIN);
00201     else if (size != 0)
00202         ccn_charbuf_append(w->buffer, buf, size);
00203     if (w->interests_possibly_pending &&
00204         (w->batching == 0 || ans == -1)) {
00205         cob = seqw_next_cob(w);
00206         if (cob != NULL) {
00207             res = ccn_put(w->h, cob->buf, cob->length);
00208             if (res >= 0) {
00209                 if (w->seqnum == 0) {
00210                     w->cob0 = cob;
00211                     cob = NULL;
00212                 }
00213                 w->buffer->length = 0;
00214                 w->seqnum++;
00215                 w->interests_possibly_pending = 0;
00216             }
00217             ccn_charbuf_destroy(&cob);
00218         }
00219     }
00220     return(ans);
00221 }
00222 
00223 /**
00224  * Start a batch of writes.
00225  *
00226  * This will delay the signing of content objects until the batch ends,
00227  * producing a more efficient result.
00228  * Must have a matching ccn_seqw_batch_end() call.
00229  * Batching may be nested.
00230  */
00231 int
00232 ccn_seqw_batch_start(struct ccn_seqwriter *w)
00233 {
00234     if (w == NULL || w->cl.data != w || w->closed)
00235         return(-1);
00236     return(++(w->batching));
00237 }
00238 
00239 /**
00240  * End a batch of writes.
00241  */
00242 int
00243 ccn_seqw_batch_end(struct ccn_seqwriter *w)
00244 {
00245     if (w == NULL || w->cl.data != w || w->batching == 0)
00246         return(-1);
00247     if (--(w->batching) == 0)
00248         ccn_seqw_write(w, NULL, 0);
00249     return(w->batching);
00250 }
00251 
00252 /**
00253  * Assert that an interest has possibly been expressed that matches
00254  * the seqwriter's data.  This is useful, for example, if the seqwriter
00255  * was created in response to an interest.
00256  */
00257 int
00258 ccn_seqw_possible_interest(struct ccn_seqwriter *w)
00259 {
00260     if (w == NULL || w->cl.data != w)
00261         return(-1);
00262     w->interests_possibly_pending = 1;
00263     ccn_seqw_write(w, NULL, 0);
00264     return(0);
00265 }
00266 
00267 /**
00268  * Close the seqwriter, which will be freed.
00269  */
00270 int
00271 ccn_seqw_close(struct ccn_seqwriter *w)
00272 {
00273     if (w == NULL || w->cl.data != w)
00274         return(-1);
00275     w->closed = 1;
00276     w->interests_possibly_pending = 1;
00277     w->batching = 0;
00278     ccn_seqw_write(w, NULL, 0);
00279     ccn_set_interest_filter(w->h, w->nb, NULL);
00280     return(0);
00281 }
Generated on Fri May 13 16:27:03 2011 for Content-Centric Networking in C by  doxygen 1.6.3