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 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
00124
00125
00126
00127
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
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
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
00225
00226
00227
00228
00229
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
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
00254
00255
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
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 }