00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <ccn/fetch.h>
00036
00037 #include <sys/types.h>
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <errno.h>
00041 #include <string.h>
00042 #include <time.h>
00043 #include <unistd.h>
00044
00045 #include <sys/time.h>
00046
00047
00048 #define CCN_VERSION_TIMEOUT 8000
00049 #define CCN_INTEREST_TIMEOUT_USECS 15000000
00050 #define MaxSuffixDefault 4
00051
00052 typedef intmax_t seg_t;
00053
00054 typedef uint64_t TimeMarker;
00055
00056 static TimeMarker
00057 GetCurrentTimeUSecs(void) {
00058 const TimeMarker M = 1000*1000;
00059 struct timeval now = {0};
00060 gettimeofday(&now, 0);
00061 return now.tv_sec*M+now.tv_usec;
00062 }
00063
00064 static intmax_t
00065 DeltaTime(TimeMarker mt1, TimeMarker mt2) {
00066 return(mt2-mt1);
00067 }
00068
00069
00070
00071 struct ccn_fetch {
00072 struct ccn *h;
00073 FILE *debug;
00074 ccn_fetch_flags debugFlags;
00075 int localConnect;
00076 int nStreams;
00077 int maxStreams;
00078 struct ccn_fetch_stream **streams;
00079 };
00080
00081 struct ccn_fetch_buffer {
00082 struct ccn_fetch_buffer *next;
00083 seg_t seg;
00084 intmax_t pos;
00085 int len;
00086 int max;
00087 unsigned char *buf;
00088 };
00089
00090 struct localClosure {
00091 struct ccn_fetch_stream *fs;
00092 struct localClosure *next;
00093 seg_t reqSeg;
00094 TimeMarker startClock;
00095 };
00096
00097 struct ccn_fetch_stream {
00098 struct ccn_fetch *parent;
00099 struct localClosure *requests;
00100 int reqBusy;
00101 int maxBufs;
00102 int nBufs;
00103 struct ccn_fetch_buffer *bufList;
00104 char *id;
00105 struct ccn_charbuf *name;
00106 struct ccn_charbuf *interest;
00107 int segSize;
00108 int segsAhead;
00109 intmax_t fileSize;
00110 intmax_t readPosition;
00111 intmax_t readStart;
00112 seg_t readSeg;
00113 seg_t timeoutSeg;
00114 seg_t zeroLenSeg;
00115 seg_t finalSeg;
00116 int finalSegLen;
00117 intmax_t timeoutUSecs;
00118 intmax_t timeoutsSeen;
00119 seg_t segsRead;
00120 seg_t segsRequested;
00121 };
00122
00123
00124 static enum ccn_upcall_res
00125 CallMe(struct ccn_closure *selfp,
00126 enum ccn_upcall_kind kind,
00127 struct ccn_upcall_info *info);
00128
00129
00130
00131
00132
00133 static char *globalNullString = "";
00134 static char *
00135 newStringCopy(const char *src) {
00136 int n = ((src == NULL) ? 0 : strlen(src));
00137 if (n <= 0 || src == globalNullString) return globalNullString;
00138 char *s = calloc(n+1, sizeof(*s));
00139 strncpy(s, src, n);
00140 return s;
00141 }
00142
00143 static char *
00144 freeString(char * s) {
00145 if (s != NULL && s != globalNullString)
00146 free(s);
00147 return NULL;
00148 }
00149
00150 static struct ccn_charbuf *
00151 sequenced_name(struct ccn_charbuf *basename, seg_t seq) {
00152
00153 struct ccn_charbuf *name = ccn_charbuf_create();
00154 ccn_charbuf_append_charbuf(name, basename);
00155 if (seq >= 0)
00156 ccn_name_append_numeric(name, CCN_MARKER_SEQNUM, seq);
00157 return(name);
00158 }
00159
00160 static struct ccn_charbuf *
00161 make_data_template(int maxSuffix) {
00162
00163
00164 struct ccn_charbuf *cb = ccn_charbuf_create();
00165 ccn_charbuf_append_tt(cb, CCN_DTAG_Interest, CCN_DTAG);
00166 ccn_charbuf_append_tt(cb, CCN_DTAG_Name, CCN_DTAG);
00167 ccn_charbuf_append_closer(cb);
00168 ccn_charbuf_append_tt(cb, CCN_DTAG_MaxSuffixComponents, CCN_DTAG);
00169 ccnb_append_number(cb, maxSuffix);
00170 ccn_charbuf_append_closer(cb);
00171 ccn_charbuf_append_closer(cb);
00172 return(cb);
00173 }
00174
00175 static seg_t
00176 GetNumberFromInfo(const unsigned char *ccnb,
00177 enum ccn_dtag tt, size_t start, size_t stop) {
00178
00179
00180
00181
00182 if (start < stop) {
00183 size_t len = 0;
00184 const unsigned char *data = NULL;
00185 ccn_ref_tagged_BLOB(tt, ccnb, start, stop, &data, &len);
00186 if (len > 0 && data != NULL) {
00187
00188 seg_t n = 0;
00189 size_t i;
00190 for (i = 0; i < len; i++) {
00191 n = n * 256 + data[i];
00192 }
00193 return n;
00194 }
00195 }
00196 return -1;
00197 }
00198
00199 static seg_t
00200 GetFinalSegment(struct ccn_upcall_info *info) {
00201
00202
00203
00204 if (info == NULL) return -1;
00205 const unsigned char *ccnb = info->content_ccnb;
00206 if (ccnb == NULL || info->pco == NULL) return -1;
00207 int start = info->pco->offset[CCN_PCO_B_FinalBlockID];
00208 int stop = info->pco->offset[CCN_PCO_E_FinalBlockID];
00209 return GetNumberFromInfo(ccnb, CCN_DTAG_FinalBlockID, start, stop);
00210 }
00211
00212 static struct localClosure *
00213 AddSegRequest(struct ccn_fetch_stream *fs, seg_t seg) {
00214
00215
00216
00217 FILE *debug = fs->parent->debug;
00218 ccn_fetch_flags flags = fs->parent->debugFlags;
00219 if (seg < 0) return NULL;
00220 if (fs->finalSeg >= 0 && seg > fs->finalSeg) return NULL;
00221 struct localClosure *req = fs->requests;
00222 while (req != NULL) {
00223 if (req->reqSeg == seg) return NULL;
00224 req = req->next;
00225 }
00226 req = calloc(1, sizeof(*req));
00227 req->fs = fs;
00228 req->reqSeg = seg;
00229 req->startClock = GetCurrentTimeUSecs();
00230 req->next = fs->requests;
00231 fs->requests = req;
00232 if (debug != NULL && (flags & ccn_fetch_flags_NoteAddRem)) {
00233 fprintf(debug, "-- ccn_fetch AddSegRequest %s, seg %jd\n",
00234 fs->id, seg);
00235 fflush(debug);
00236 }
00237 return req;
00238 }
00239
00240 static struct localClosure *
00241 RemSegRequest(struct ccn_fetch_stream *fs, struct localClosure *req) {
00242
00243
00244
00245 FILE *debug = fs->parent->debug;
00246 ccn_fetch_flags flags = fs->parent->debugFlags;
00247 struct localClosure *this = fs->requests;
00248 struct localClosure *lag = NULL;
00249 seg_t seg = req->reqSeg;
00250 while (this != NULL) {
00251 struct localClosure *next = this->next;
00252 if (this == req) {
00253 if (lag == NULL) {
00254 fs->requests = next;
00255 } else {
00256 lag->next = next;
00257 }
00258 req->fs = NULL;
00259 if (debug != NULL && (flags & ccn_fetch_flags_NoteAddRem)) {
00260 fprintf(debug, "-- ccn_fetch RemSegRequest %s, seg %jd\n",
00261 fs->id, seg);
00262 fflush(debug);
00263 }
00264 return NULL;
00265 }
00266 lag = this;
00267 this = next;
00268 }
00269 if (debug != NULL && (flags & ccn_fetch_flags_NoteAddRem)) {
00270 fprintf(debug, "-- ccn_fetch RemSegRequest %s, seg %jd, NOT FOUND!\n",
00271 fs->id, seg);
00272 fflush(debug);
00273 }
00274 return req;
00275 }
00276
00277 static struct ccn_fetch_buffer *
00278 FindBufferForSeg(struct ccn_fetch_stream *fs, seg_t seg) {
00279
00280 struct ccn_fetch_buffer *fb = fs->bufList;
00281 for (;;) {
00282 if (fb == NULL) break;
00283 if (fb->seg == seg) break;
00284 fb = fb->next;
00285 }
00286 return fb;
00287 }
00288
00289 static struct ccn_fetch_buffer *
00290 FindBufferForPosition(struct ccn_fetch_stream *fs, intmax_t pos) {
00291
00292 struct ccn_fetch_buffer *fb = fs->bufList;
00293 for (;;) {
00294 if (fb == NULL) break;
00295 intmax_t fp = fb->pos;
00296 if (fp >= 0 && pos >= fp && pos < fp+fb->len) break;
00297 fb = fb->next;
00298 }
00299 return fb;
00300 }
00301
00302 static intmax_t
00303 InferPosition(struct ccn_fetch_stream *fs, seg_t seg) {
00304 intmax_t pos = -1;
00305 if (seg == 0) {
00306
00307 pos = 0;
00308 } else if (fs->segSize > 0) {
00309
00310 pos = seg*fs->segSize;
00311 } else if (seg == fs->readSeg) {
00312
00313 pos = fs->readStart;
00314 } else {
00315
00316 struct ccn_fetch_buffer *ofb = FindBufferForSeg(fs, seg-1);
00317 if (ofb != NULL && ofb->pos >= 0)
00318 pos = ofb->pos+ofb->len;
00319 }
00320 return pos;
00321 }
00322
00323 static struct ccn_fetch_buffer *
00324 NewBufferForSeg(struct ccn_fetch_stream *fs, seg_t seg, size_t len) {
00325
00326 struct ccn_fetch_buffer *fb = calloc(1, sizeof(*fb));
00327 if (len > 0) fb->buf = calloc(len, sizeof(unsigned char));
00328 fb->seg = seg;
00329 intmax_t pos = InferPosition(fs, seg);
00330 fb->pos = pos;
00331 fb->len = len;
00332 fs->nBufs++;
00333 fb->next = fs->bufList;
00334 fs->bufList = fb;
00335 fs->segsAhead++;
00336 if (fs->segsAhead >= fs->maxBufs) fs->segsAhead = fs->maxBufs-1;
00337 if (fs->segSize <= 0 && pos >= 0) {
00338
00339
00340 for (;;) {
00341 if (fs->fileSize < 0) {
00342
00343 if (seg == fs->finalSeg
00344 || (seg+1 == fs->finalSeg && fs->finalSegLen == 0))
00345 fs->fileSize = pos+len;
00346 }
00347 seg++;
00348 struct ccn_fetch_buffer *ofb = FindBufferForSeg(fs, seg);
00349 if (ofb == NULL || ofb->pos >= 0) break;
00350 pos = pos + len;
00351 ofb->pos = pos;
00352 len = ofb->len;
00353 }
00354 }
00355 return fb;
00356 }
00357
00358 static void
00359 PruneSegments(struct ccn_fetch_stream *fs) {
00360 intmax_t start = fs->readStart;
00361 struct ccn_fetch_buffer *lag = NULL;
00362 struct ccn_fetch_buffer *fb = fs->bufList;
00363 while (fb != NULL && fs->nBufs > fs->maxBufs) {
00364 struct ccn_fetch_buffer *next = fb->next;
00365 if (fs->maxBufs == 0 || (fb->pos >= 0 && start > (fb->pos + fb->len))) {
00366
00367
00368 if (lag == NULL) {
00369 fs->bufList = next;
00370 } else {
00371 lag->next = next;
00372 }
00373 if (fb->buf != NULL) free(fb->buf);
00374 free(fb);
00375 fs->nBufs--;
00376 } else {
00377
00378 lag = fb;
00379 }
00380 fb = next;
00381 }
00382 }
00383
00384 static void
00385 NeedSegment(struct ccn_fetch_stream *fs, seg_t seg) {
00386
00387
00388
00389 struct ccn_fetch_buffer *fb = FindBufferForSeg(fs, seg);
00390 if (fb != NULL)
00391
00392 return;
00393 if (fs->finalSeg >= 0 && seg > fs->finalSeg)
00394
00395 return;
00396 if (fs->timeoutSeg > 0 && seg >= fs->timeoutSeg)
00397
00398 return;
00399 if (fs->zeroLenSeg > 0 && seg >= fs->zeroLenSeg)
00400
00401 return;
00402 struct localClosure *req = AddSegRequest(fs, seg);
00403 if (req != NULL) {
00404 FILE *debug = fs->parent->debug;
00405 ccn_fetch_flags flags = fs->parent->debugFlags;
00406 struct ccn_charbuf *temp = sequenced_name(fs->name, seg);
00407 struct ccn *h = fs->parent->h;
00408 struct ccn_closure *action = calloc(1, sizeof(*action));
00409 action->data = req;
00410 action->p = &CallMe;
00411 int res = ccn_express_interest(h, temp, action, fs->interest);
00412 ccn_charbuf_destroy(&temp);
00413 if (res >= 0) {
00414
00415 fs->reqBusy++;
00416 fs->segsRequested++;
00417 if (debug != NULL && (flags & ccn_fetch_flags_NoteNeed)) {
00418 fprintf(debug,
00419 "-- ccn_fetch NeedSegment %s, seg %jd",
00420 fs->id, seg);
00421 if (fs->finalSeg >= 0)
00422 fprintf(debug, ", final %jd", fs->finalSeg);
00423 fprintf(debug, "\n");
00424 fflush(debug);
00425 }
00426 return;
00427 }
00428
00429
00430 if (debug != NULL && (flags & ccn_fetch_flags_NoteNeed)) {
00431 fprintf(debug,
00432 "** ccn_fetch NeedSegment failed, %s, seg %jd\n",
00433 fs->id, seg);
00434 fflush(debug);
00435 }
00436 RemSegRequest(fs, req);
00437 free(req);
00438 free(action);
00439
00440 }
00441 }
00442
00443 static void
00444 NeedSegments(struct ccn_fetch_stream *fs) {
00445
00446
00447 seg_t loSeg = fs->readSeg;
00448 seg_t hiSeg = loSeg+fs->segsAhead;
00449 seg_t finalSeg = fs->finalSeg;
00450 if (finalSeg >= 0 && hiSeg > finalSeg) hiSeg = finalSeg;
00451 if (loSeg > hiSeg) hiSeg = loSeg;
00452 while (loSeg <= hiSeg) {
00453
00454 NeedSegment(fs, loSeg);
00455 loSeg++;
00456 }
00457 }
00458
00459 static void
00460 ShowDelta(FILE *f, TimeMarker from) {
00461 intmax_t dt = DeltaTime(from, GetCurrentTimeUSecs());
00462 fprintf(f, ", dt %jd.%06d\n", dt / 1000000, (int) (dt % 1000000));
00463 fflush(f);
00464 }
00465
00466 static enum ccn_upcall_res
00467 CallMe(struct ccn_closure *selfp,
00468 enum ccn_upcall_kind kind,
00469 struct ccn_upcall_info *info) {
00470
00471
00472 struct localClosure *req = (struct localClosure *)selfp->data;
00473 seg_t thisSeg = req->reqSeg;
00474 struct ccn_fetch_stream *fs = (struct ccn_fetch_stream *) req->fs;
00475 if (fs == NULL) {
00476 if (kind == CCN_UPCALL_FINAL) {
00477
00478 free(req);
00479 free(selfp);
00480 }
00481 return(CCN_UPCALL_RESULT_OK);
00482 }
00483 FILE *debug = fs->parent->debug;
00484 seg_t finalSeg = fs->finalSeg;
00485 ccn_fetch_flags flags = fs->parent->debugFlags;
00486 if (finalSeg < 0) {
00487
00488 finalSeg = GetFinalSegment(info);
00489 fs->finalSeg = finalSeg;
00490 }
00491
00492 switch (kind) {
00493 case CCN_UPCALL_FINAL:
00494
00495 req = RemSegRequest(fs, req);
00496 if (fs->reqBusy > 0) fs->reqBusy--;
00497 free(selfp);
00498 return(CCN_UPCALL_RESULT_OK);
00499 case CCN_UPCALL_INTEREST_TIMED_OUT: {
00500 if (finalSeg >= 0 && thisSeg > finalSeg)
00501
00502 return(CCN_UPCALL_RESULT_OK);
00503 intmax_t dt = DeltaTime(req->startClock, GetCurrentTimeUSecs());
00504 if (dt >= fs->timeoutUSecs) {
00505
00506
00507 seg_t timeoutSeg = fs->timeoutSeg;
00508 fs->timeoutsSeen++;
00509 fs->segsAhead = 0;
00510 if (timeoutSeg < 0 || thisSeg < timeoutSeg) {
00511
00512 fs->timeoutSeg = thisSeg;
00513 }
00514 if (debug != NULL && (flags & ccn_fetch_flags_NoteTimeout)) {
00515 fprintf(debug,
00516 "** ccn_fetch timeout, %s, seg %jd",
00517 fs->id, thisSeg);
00518 fprintf(debug,
00519 ", dt %jd us, timeoutUSecs %jd\n",
00520 dt, fs->timeoutUSecs);
00521 fflush(debug);
00522 }
00523 return(CCN_UPCALL_RESULT_OK);
00524 }
00525
00526 return(CCN_UPCALL_RESULT_REEXPRESS);
00527 }
00528 case CCN_UPCALL_CONTENT_UNVERIFIED:
00529 return (CCN_UPCALL_RESULT_VERIFY);
00530 case CCN_UPCALL_CONTENT:
00531 if (fs->timeoutSeg >= 0 && fs->timeoutSeg <= thisSeg)
00532
00533 return(CCN_UPCALL_RESULT_OK);
00534 break;
00535 default:
00536
00537 return(CCN_UPCALL_RESULT_ERR);
00538 }
00539
00540 struct ccn_fetch_buffer *fb = FindBufferForSeg(fs, thisSeg);
00541 if (fb == NULL) {
00542
00543 const unsigned char *data = NULL;
00544 size_t dataLen = 0;
00545 size_t ccnb_size = info->pco->offset[CCN_PCO_E];
00546 const unsigned char *ccnb = info->content_ccnb;
00547 int res = ccn_content_get_value(ccnb, ccnb_size, info->pco,
00548 &data, &dataLen);
00549
00550 if (res < 0 || (thisSeg != finalSeg && dataLen == 0)) {
00551
00552 if (debug != NULL && (flags & ccn_fetch_flags_NoteAddRem)) {
00553 fprintf(debug,
00554 "-- ccn_fetch no data, %s, seg %jd, final %jd",
00555 fs->id, thisSeg, finalSeg);
00556 ShowDelta(debug, req->startClock);
00557 }
00558 if (fs->zeroLenSeg < 0 || thisSeg < fs->zeroLenSeg)
00559
00560 fs->zeroLenSeg = thisSeg;
00561 } else if (thisSeg == finalSeg && dataLen == 0) {
00562
00563 if (fs->fileSize < 0)
00564 fs->fileSize = InferPosition(fs, thisSeg);
00565 fs->finalSeg = finalSeg-1;
00566 if (debug != NULL && (flags & ccn_fetch_flags_NoteFinal)) {
00567 fprintf(debug,
00568 "-- ccn_fetch EOF, %s, seg %jd, len %d, fs %jd",
00569 fs->id, thisSeg,
00570 (int) dataLen,
00571 fs->fileSize);
00572 ShowDelta(debug, req->startClock);
00573 }
00574
00575 } else {
00576
00577
00578 if (fs->segSize == 0) {
00579
00580
00581 if (thisSeg == 0 || thisSeg < finalSeg)
00582 fs->segSize = dataLen;
00583 }
00584 if (thisSeg == finalSeg) fs->finalSegLen = dataLen;
00585 struct ccn_fetch_buffer *fb = NewBufferForSeg(fs, thisSeg, dataLen);
00586 memcpy(fb->buf, data, dataLen);
00587 if (debug != NULL && (flags & ccn_fetch_flags_NoteFill)) {
00588 fprintf(debug,
00589 "-- ccn_fetch FillSeg, %s, seg %jd, len %d, nbuf %d",
00590 fs->id, thisSeg, (int) dataLen, (int) fs->nBufs);
00591 ShowDelta(debug, req->startClock);
00592 }
00593 if (thisSeg == finalSeg) {
00594
00595 if (fs->segSize <= 0) {
00596
00597 if (fb->pos >= 0) {
00598 fs->fileSize = fb->pos + dataLen;
00599 }
00600 } else {
00601
00602 fs->fileSize = thisSeg * fs->segSize + dataLen;
00603 }
00604 if (debug != NULL && (flags & ccn_fetch_flags_NoteFinal)) {
00605 fprintf(debug,
00606 "-- ccn_fetch EOF, %s, seg %jd, len %d, fs %jd",
00607 fs->id, thisSeg, (int) dataLen, fs->fileSize);
00608 ShowDelta(debug, req->startClock);
00609 }
00610 }
00611 fs->segsRead++;
00612 }
00613 }
00614
00615 ccn_set_run_timeout(fs->parent->h, 0);
00616 return(CCN_UPCALL_RESULT_OK);
00617 }
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629 extern struct ccn_fetch *
00630 ccn_fetch_new(struct ccn *h) {
00631 struct ccn_fetch *f = calloc(1, sizeof(*f));
00632 if (h == NULL) {
00633 h = ccn_create();
00634 int connRes = ccn_connect(h, NULL);
00635 if (connRes < 0) {
00636 ccn_destroy(&h);
00637 free(f);
00638 return NULL;
00639 }
00640 f->localConnect = 1;
00641 }
00642 f->h = h;
00643 return f;
00644 }
00645
00646 void
00647 ccn_fetch_set_debug(struct ccn_fetch *f, FILE *debug, ccn_fetch_flags flags) {
00648 f->debug = debug;
00649 f->debugFlags = flags;
00650 }
00651
00652
00653
00654
00655
00656
00657
00658 extern struct ccn_fetch *
00659 ccn_fetch_destroy(struct ccn_fetch *f) {
00660
00661
00662
00663
00664 if (f != NULL) {
00665 struct ccn *h = f->h;
00666 if (h != NULL && f->localConnect) {
00667 ccn_disconnect(h);
00668 ccn_destroy(&f->h);
00669 }
00670
00671 while (f->nStreams > 0) {
00672 struct ccn_fetch_stream *fs = f->streams[0];
00673 if (fs == NULL) break;
00674 ccn_fetch_close(fs);
00675 }
00676 free(f);
00677 }
00678 return NULL;
00679 }
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692 extern int
00693 ccn_fetch_poll(struct ccn_fetch *f) {
00694 int i;
00695 int count = 0;
00696 int ns = f->nStreams;
00697 for (i = 0; i < ns; i++) {
00698 struct ccn_fetch_stream *fs = f->streams[i];
00699 if (fs != NULL) {
00700 intmax_t avail = ccn_fetch_avail(fs);
00701 if (avail >= 0) count++;
00702 }
00703 }
00704
00705 ccn_run(f->h, 0);
00706 return count;
00707 }
00708
00709
00710
00711
00712
00713
00714
00715
00716 extern struct ccn_fetch_stream *
00717 ccn_fetch_next(struct ccn_fetch *f, struct ccn_fetch_stream *fs) {
00718 int i;
00719 int ns = f->nStreams;
00720 struct ccn_fetch_stream *lag = NULL;
00721 for (i = 0; i < ns; i++) {
00722 struct ccn_fetch_stream *tfs = f->streams[i];
00723 if (tfs != NULL) {
00724 if (lag == fs) return tfs;
00725 lag = tfs;
00726 }
00727 }
00728 return NULL;
00729 }
00730
00731
00732
00733
00734 extern struct ccn *
00735 ccn_fetch_get_ccn(struct ccn_fetch *f) {
00736 return f->h;
00737 }
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749 extern struct ccn_fetch_stream *
00750 ccn_fetch_open(struct ccn_fetch *f,
00751 struct ccn_charbuf *name,
00752 const char *id,
00753 struct ccn_charbuf *interestTemplate,
00754 int maxBufs,
00755 int resolveVersion,
00756 int assumeFixed) {
00757
00758
00759 if (maxBufs <= 0) return NULL;
00760 if (maxBufs > 16) maxBufs = 16;
00761 int res = 0;
00762 FILE *debug = f->debug;
00763 ccn_fetch_flags flags = f->debugFlags;
00764
00765
00766 struct ccn_fetch_stream *fs = calloc(1, sizeof(*fs));
00767 fs->segSize = (assumeFixed ? 0 : -1);
00768 fs->name = ccn_charbuf_create();
00769 fs->id = newStringCopy(id);
00770 ccn_charbuf_append_charbuf(fs->name, name);
00771 if (resolveVersion) {
00772 int tmInc = 40;
00773 int tm = 0;
00774 while (tm < CCN_VERSION_TIMEOUT) {
00775 res = ccn_resolve_version(f->h, fs->name, resolveVersion, tmInc);
00776 if (res >= 0) break;
00777 tm = tm + tmInc;
00778 }
00779 if (res < 0) {
00780
00781
00782 if (debug != NULL && (flags & ccn_fetch_flags_NoteOpenClose)) {
00783 fprintf(debug,
00784 "-- ccn_fetch open, %s, failed to resolve version\n",
00785 fs->id);
00786 fflush(debug);
00787 }
00788 ccn_charbuf_destroy(&fs->name);
00789 freeString(fs->id);
00790 free(fs);
00791 return NULL;
00792 }
00793 }
00794 fs->maxBufs = maxBufs;
00795 fs->segsAhead = 0;
00796 fs->fileSize = -1;
00797 fs->finalSeg = -1;
00798 fs->timeoutSeg = -1;
00799 fs->zeroLenSeg = -1;
00800 fs->parent = f;
00801 fs->timeoutUSecs = CCN_INTEREST_TIMEOUT_USECS;
00802
00803
00804 if (interestTemplate != NULL) {
00805 struct ccn_charbuf *cb = ccn_charbuf_create();
00806 ccn_charbuf_append_charbuf(cb, interestTemplate);
00807 fs->interest = cb;
00808 } else
00809 fs->interest = make_data_template(MaxSuffixDefault);
00810
00811
00812
00813 int ns = f->nStreams;
00814 int max = f->maxStreams;
00815 if (ns >= max) {
00816
00817 int nMax = max+max/2+4;
00818 f->streams = realloc(f->streams, sizeof(*(f->streams)) * nMax);
00819 f->maxStreams = nMax;
00820 }
00821
00822 f->streams[ns] = fs;
00823 f->nStreams = ns+1;
00824
00825 if (debug != NULL && (flags & ccn_fetch_flags_NoteOpenClose)) {
00826 fprintf(debug,
00827 "-- ccn_fetch open, %s\n",
00828 fs->id);
00829 fflush(debug);
00830 }
00831
00832 NeedSegment(fs, 0);
00833 return fs;
00834 }
00835
00836
00837
00838
00839
00840
00841 extern struct ccn_fetch_stream *
00842 ccn_fetch_close(struct ccn_fetch_stream *fs) {
00843
00844
00845
00846 int i;
00847 FILE *debug = fs->parent->debug;
00848 ccn_fetch_flags flags = fs->parent->debugFlags;
00849
00850
00851
00852 struct localClosure * this = fs->requests;
00853 fs->requests = NULL;
00854 while (this != NULL) {
00855 this->fs = NULL;
00856 this = this->next;
00857 }
00858
00859 fs->maxBufs = 0;
00860 PruneSegments(fs);
00861
00862 if (fs->name != NULL)
00863 ccn_charbuf_destroy(&fs->name);
00864 if (fs->interest != NULL)
00865 ccn_charbuf_destroy(&fs->interest);
00866 struct ccn_fetch *f = fs->parent;
00867 if (f != NULL) {
00868 int ns = f->nStreams;
00869 fs->parent = NULL;
00870 for (i = 0; i < ns; i++) {
00871 struct ccn_fetch_stream *tfs = f->streams[i];
00872 if (tfs == fs) {
00873
00874 ns--;
00875 f->nStreams = ns;
00876 f->streams[i] = NULL;
00877 f->streams[i] = f->streams[ns];
00878 f->streams[ns] = NULL;
00879 break;
00880 }
00881 }
00882 }
00883 if (debug != NULL && (flags & ccn_fetch_flags_NoteOpenClose)) {
00884 fprintf(debug,
00885 "-- ccn_fetch close, %s, segReq %jd, segsRead %jd, timeouts %jd\n",
00886 fs->id,
00887 fs->segsRequested,
00888 fs->segsRead,
00889 fs->timeoutsSeen);
00890 fflush(debug);
00891 }
00892
00893 freeString(fs->id);
00894 free(fs);
00895 return NULL;
00896 }
00897
00898
00899
00900
00901 extern intmax_t
00902 ccn_fetch_avail(struct ccn_fetch_stream *fs) {
00903 intmax_t pos = fs->readPosition;
00904 if (fs->fileSize >= 0 && pos >= fs->fileSize) {
00905
00906 return CCN_FETCH_READ_END;
00907 }
00908 intmax_t avail = 0;
00909 seg_t seg = fs->readSeg;
00910 if (fs->timeoutSeg >= 0 && seg >= fs->timeoutSeg)
00911
00912 return CCN_FETCH_READ_TIMEOUT;
00913 if (fs->zeroLenSeg >= 0 && seg >= fs->zeroLenSeg)
00914
00915 return CCN_FETCH_READ_ZERO;
00916 seg_t finalSeg = fs->finalSeg;
00917 if (seg > finalSeg && fs->finalSeg >= 0)
00918
00919 return CCN_FETCH_READ_NONE;
00920
00921 for (;;) {
00922 struct ccn_fetch_buffer *fb = FindBufferForSeg(fs, seg);
00923 if (fb == NULL) break;
00924 if (fb->pos < 0) fb->pos = pos;
00925 int len = fb->len;
00926 if (seg == fs->readSeg) {
00927
00928 intmax_t off = pos - fb->pos;
00929 if (off > 0) len = len - off;
00930 }
00931 avail = avail + len;
00932 pos = pos + len;
00933 seg++;
00934 }
00935 if (avail == 0)
00936
00937 return CCN_FETCH_READ_NONE;
00938 return avail;
00939 }
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953 extern intmax_t
00954 ccn_fetch_read(struct ccn_fetch_stream *fs,
00955 void *buf,
00956 intmax_t len) {
00957 if (len < 0 || buf == NULL) {
00958 return CCN_FETCH_READ_NONE;
00959 }
00960 intmax_t off = 0;
00961 intmax_t pos = fs->readPosition;
00962 if (fs->fileSize >= 0 && pos >= fs->fileSize) {
00963
00964 return CCN_FETCH_READ_END;
00965 }
00966 intmax_t nr = 0;
00967 unsigned char *dst = (unsigned char *) buf;
00968 seg_t seg = fs->readSeg;
00969
00970 if (fs->timeoutSeg >= 0 && seg >= fs->timeoutSeg)
00971
00972 return CCN_FETCH_READ_TIMEOUT;
00973 if (fs->zeroLenSeg >= 0 && seg >= fs->zeroLenSeg)
00974
00975 return CCN_FETCH_READ_ZERO;
00976 while (len > 0) {
00977 struct ccn_fetch_buffer *fb = FindBufferForSeg(fs, seg);
00978 if (fb == NULL) break;
00979 unsigned char *src = fb->buf;
00980 intmax_t start = fb->pos;
00981 intmax_t lo = start;
00982 if (lo < 0) {
00983
00984 lo = pos;
00985 fb->pos = pos;
00986 }
00987 intmax_t hi = lo + fb->len;
00988 if (pos < lo || pos >= hi || seg != fb->seg) {
00989
00990 FILE *debug = fs->parent->debug;
00991 if (debug != NULL) {
00992 fprintf(debug,
00993 "** ccn_fetch read, %s, seg %jd, pos %jd, lo %jd, hi %jd\n",
00994 fs->id, seg, pos, (intmax_t) lo, (intmax_t) hi);
00995 fflush(debug);
00996 }
00997 break;
00998 }
00999 intmax_t d = hi - pos;
01000 if (d > len) d = len;
01001 memcpy(dst+off, src+(pos-lo), d);
01002 nr = nr + d;
01003 pos = pos + d;
01004 off = off + d;
01005 len = len - d;
01006 fs->readPosition = pos;
01007 fs->readStart = start;
01008 if (pos == hi) {
01009
01010 seg++;
01011 fs->readSeg = seg;
01012 fs->readStart = pos;
01013 }
01014 }
01015 NeedSegments(fs);
01016 PruneSegments(fs);
01017 if (nr == 0) {
01018 return CCN_FETCH_READ_NONE;
01019 }
01020 return nr;
01021 }
01022
01023
01024
01025
01026 extern void
01027 ccn_reset_timeout(struct ccn_fetch_stream *fs) {
01028 fs->timeoutSeg = -1;
01029 fs->segsAhead = 0;
01030 }
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040 extern int
01041 ccn_fetch_seek(struct ccn_fetch_stream *fs, intmax_t pos) {
01042
01043 seg_t seg = 0;
01044 intmax_t start = 0;
01045 if (pos == 0) {
01046
01047
01048 fs->timeoutSeg = -1;
01049 fs->zeroLenSeg = -1;
01050 fs->segsAhead = 0;
01051 } else if (pos == fs->readPosition) {
01052
01053 return 0;
01054 } else {
01055
01056 struct ccn_fetch_buffer *fb = FindBufferForPosition(fs, pos);
01057 if (fb != NULL) {
01058
01059 seg = fb->seg;
01060 start = fb->pos;
01061 } else {
01062 int ss = fs->segSize;
01063 if (pos < 0 || ss <= 0)
01064
01065 return -1;
01066 intmax_t fileSize = fs->fileSize;
01067 if (fileSize >= 0 && pos > fileSize) {
01068
01069 return -1;
01070 }
01071
01072 seg = pos / ss;
01073 start = seg * ss;
01074 }
01075 }
01076 fs->readPosition = pos;
01077 fs->readStart = start;
01078 fs->readSeg = seg;
01079 NeedSegment(fs, seg);
01080 PruneSegments(fs);
01081
01082 return 0;
01083 }
01084
01085
01086
01087
01088 extern intmax_t
01089 ccn_fetch_position(struct ccn_fetch_stream *fs) {
01090 return fs->readPosition;
01091 }
01092
01093