00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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 int blockminsize;
00040 int blockmaxsize;
00041 unsigned char interests_possibly_pending;
00042 unsigned char closed;
00043 };
00044
00045 static struct ccn_charbuf *
00046 seqw_next_cob(struct ccn_seqwriter *w)
00047 {
00048 struct ccn_charbuf *cob = ccn_charbuf_create();
00049 struct ccn_charbuf *name = ccn_charbuf_create();
00050 struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
00051 int res;
00052
00053 if (w->closed)
00054 sp.sp_flags |= CCN_SP_FINAL_BLOCK;
00055 ccn_charbuf_append(name, w->nv->buf, w->nv->length);
00056 ccn_name_append_numeric(name, CCN_MARKER_SEQNUM, w->seqnum);
00057 res = ccn_sign_content(w->h, cob, name, &sp, w->buffer->buf, w->buffer->length);
00058 if (res < 0)
00059 ccn_charbuf_destroy(&cob);
00060 ccn_charbuf_destroy(&name);
00061 return(cob);
00062 }
00063
00064 static enum ccn_upcall_res
00065 seqw_incoming_interest(
00066 struct ccn_closure *selfp,
00067 enum ccn_upcall_kind kind,
00068 struct ccn_upcall_info *info)
00069 {
00070 int res;
00071 struct ccn_charbuf *cob = NULL;
00072 struct ccn_seqwriter *w = selfp->data;
00073
00074 if (w == NULL || selfp != &(w->cl))
00075 abort();
00076 switch (kind) {
00077 case CCN_UPCALL_FINAL:
00078 ccn_charbuf_destroy(&w->nb);
00079 ccn_charbuf_destroy(&w->nv);
00080 ccn_charbuf_destroy(&w->buffer);
00081 ccn_charbuf_destroy(&w->cob0);
00082 free(w);
00083 break;
00084 case CCN_UPCALL_INTEREST:
00085 if (w->closed || w->buffer->length > w->blockminsize) {
00086 cob = seqw_next_cob(w);
00087 if (cob == NULL)
00088 return(CCN_UPCALL_RESULT_OK);
00089 if (ccn_content_matches_interest(cob->buf, cob->length,
00090 1, NULL,
00091 info->interest_ccnb,
00092 info->pi->offset[CCN_PI_E],
00093 info->pi)) {
00094 w->interests_possibly_pending = 0;
00095 res = ccn_put(info->h, cob->buf, cob->length);
00096 if (res >= 0) {
00097 w->buffer->length = 0;
00098 w->seqnum++;
00099 return(CCN_UPCALL_RESULT_INTEREST_CONSUMED);
00100 }
00101 }
00102 ccn_charbuf_destroy(&cob);
00103 }
00104 if (w->cob0 != NULL) {
00105 cob = w->cob0;
00106 if (ccn_content_matches_interest(cob->buf, cob->length,
00107 1, NULL,
00108 info->interest_ccnb,
00109 info->pi->offset[CCN_PI_E],
00110 info->pi)) {
00111 w->interests_possibly_pending = 0;
00112 ccn_put(info->h, cob->buf, cob->length);
00113 return(CCN_UPCALL_RESULT_INTEREST_CONSUMED);
00114 }
00115 }
00116 w->interests_possibly_pending = 1;
00117 break;
00118 default:
00119 break;
00120 }
00121 return(CCN_UPCALL_RESULT_OK);
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131 struct ccn_seqwriter *
00132 ccn_seqw_create(struct ccn *h, struct ccn_charbuf *name)
00133 {
00134 struct ccn_seqwriter *w = NULL;
00135 struct ccn_charbuf *nb = NULL;
00136 struct ccn_charbuf *nv = NULL;
00137 int res;
00138
00139 w = calloc(1, sizeof(*w));
00140 if (w == NULL)
00141 return(NULL);
00142 nb = ccn_charbuf_create();
00143 ccn_charbuf_append(nb, name->buf, name->length);
00144 nv = ccn_charbuf_create();
00145 ccn_charbuf_append(nv, name->buf, name->length);
00146 res = ccn_create_version(h, nv, CCN_V_NOW, 0, 0);
00147 if (res < 0 || nb == NULL) {
00148 ccn_charbuf_destroy(&nv);
00149 ccn_charbuf_destroy(&nb);
00150 free(w);
00151 return(NULL);
00152 }
00153
00154 w->cl.p = &seqw_incoming_interest;
00155 w->cl.data = w;
00156 w->nb = nb;
00157 w->nv = nv;
00158 w->buffer = ccn_charbuf_create();
00159 w->h = h;
00160 w->seqnum = 0;
00161 w->interests_possibly_pending = 1;
00162 w->blockminsize = 0;
00163 w->blockmaxsize = MAX_DATA_SIZE;
00164 res = ccn_set_interest_filter(h, nb, &(w->cl));
00165 if (res < 0) {
00166 ccn_charbuf_destroy(&w->nb);
00167 ccn_charbuf_destroy(&w->nv);
00168 ccn_charbuf_destroy(&w->buffer);
00169 free(w);
00170 return(NULL);
00171 }
00172 return(w);
00173 }
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183 int
00184 ccn_seqw_get_name(struct ccn_seqwriter *w, struct ccn_charbuf *nv)
00185 {
00186 if (nv == NULL || w == NULL)
00187 return (-1);
00188 return (ccn_charbuf_append_charbuf(nv, w->nv));
00189 }
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207 int
00208 ccn_seqw_write(struct ccn_seqwriter *w, const void *buf, size_t size)
00209 {
00210 struct ccn_charbuf *cob = NULL;
00211 int res;
00212 int ans;
00213
00214 if (w == NULL || w->cl.data != w)
00215 return(-1);
00216 if (w->buffer == NULL || size > w->blockmaxsize)
00217 return(ccn_seterror(w->h, EINVAL));
00218 ans = size;
00219 if (size + w->buffer->length > w->blockmaxsize)
00220 ans = ccn_seterror(w->h, EAGAIN);
00221 else if (size != 0)
00222 ccn_charbuf_append(w->buffer, buf, size);
00223 if (w->interests_possibly_pending &&
00224 (w->closed || w->buffer->length >= w->blockminsize) &&
00225 (w->batching == 0 || ans == -1)) {
00226 cob = seqw_next_cob(w);
00227 if (cob != NULL) {
00228 res = ccn_put(w->h, cob->buf, cob->length);
00229 if (res >= 0) {
00230 if (w->seqnum == 0) {
00231 w->cob0 = cob;
00232 cob = NULL;
00233 }
00234 w->buffer->length = 0;
00235 w->seqnum++;
00236 w->interests_possibly_pending = 0;
00237 }
00238 ccn_charbuf_destroy(&cob);
00239 }
00240 }
00241 return(ans);
00242 }
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252 int
00253 ccn_seqw_batch_start(struct ccn_seqwriter *w)
00254 {
00255 if (w == NULL || w->cl.data != w || w->closed)
00256 return(-1);
00257 return(++(w->batching));
00258 }
00259
00260
00261
00262
00263 int
00264 ccn_seqw_batch_end(struct ccn_seqwriter *w)
00265 {
00266 if (w == NULL || w->cl.data != w || w->batching == 0)
00267 return(-1);
00268 if (--(w->batching) == 0)
00269 ccn_seqw_write(w, NULL, 0);
00270 return(w->batching);
00271 }
00272 int
00273 ccn_seqw_set_block_limits(struct ccn_seqwriter *w, int l, int h)
00274 {
00275 if (w == NULL || w->cl.data != w || w->closed)
00276 return(-1);
00277 if (l < 0 || l > MAX_DATA_SIZE || h < 0 || h > MAX_DATA_SIZE || l > h)
00278 return(-1);
00279 w->blockminsize = l;
00280 w->blockmaxsize = h;
00281 return(0);
00282 }
00283
00284
00285
00286
00287
00288 int
00289 ccn_seqw_possible_interest(struct ccn_seqwriter *w)
00290 {
00291 if (w == NULL || w->cl.data != w)
00292 return(-1);
00293 w->interests_possibly_pending = 1;
00294 ccn_seqw_write(w, NULL, 0);
00295 return(0);
00296 }
00297
00298
00299
00300
00301 int
00302 ccn_seqw_close(struct ccn_seqwriter *w)
00303 {
00304 if (w == NULL || w->cl.data != w)
00305 return(-1);
00306 w->closed = 1;
00307 w->interests_possibly_pending = 1;
00308 w->batching = 0;
00309 ccn_seqw_write(w, NULL, 0);
00310 ccn_set_interest_filter(w->h, w->nb, NULL);
00311 return(0);
00312 }