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_KEYMISSING:
00531 return (CCN_UPCALL_RESULT_FETCHKEY);
00532 case CCN_UPCALL_CONTENT:
00533 case CCN_UPCALL_CONTENT_RAW:
00534 if (fs->timeoutSeg >= 0 && fs->timeoutSeg <= thisSeg)
00535
00536 return(CCN_UPCALL_RESULT_OK);
00537 break;
00538 default:
00539
00540 return(CCN_UPCALL_RESULT_ERR);
00541 }
00542
00543 struct ccn_fetch_buffer *fb = FindBufferForSeg(fs, thisSeg);
00544 if (fb == NULL) {
00545
00546 const unsigned char *data = NULL;
00547 size_t dataLen = 0;
00548 size_t ccnb_size = info->pco->offset[CCN_PCO_E];
00549 const unsigned char *ccnb = info->content_ccnb;
00550 int res = ccn_content_get_value(ccnb, ccnb_size, info->pco,
00551 &data, &dataLen);
00552
00553 if (res < 0 || (thisSeg != finalSeg && dataLen == 0)) {
00554
00555 if (debug != NULL && (flags & ccn_fetch_flags_NoteAddRem)) {
00556 fprintf(debug,
00557 "-- ccn_fetch no data, %s, seg %jd, final %jd",
00558 fs->id, thisSeg, finalSeg);
00559 ShowDelta(debug, req->startClock);
00560 }
00561 if (fs->zeroLenSeg < 0 || thisSeg < fs->zeroLenSeg)
00562
00563 fs->zeroLenSeg = thisSeg;
00564 } else if (thisSeg == finalSeg && dataLen == 0) {
00565
00566 if (fs->fileSize < 0)
00567 fs->fileSize = InferPosition(fs, thisSeg);
00568 fs->finalSeg = finalSeg-1;
00569 if (debug != NULL && (flags & ccn_fetch_flags_NoteFinal)) {
00570 fprintf(debug,
00571 "-- ccn_fetch EOF, %s, seg %jd, len %d, fs %jd",
00572 fs->id, thisSeg,
00573 (int) dataLen,
00574 fs->fileSize);
00575 ShowDelta(debug, req->startClock);
00576 }
00577
00578 } else {
00579
00580
00581 if (fs->segSize == 0) {
00582
00583
00584 if (thisSeg == 0 || thisSeg < finalSeg)
00585 fs->segSize = dataLen;
00586 }
00587 if (thisSeg == finalSeg) fs->finalSegLen = dataLen;
00588 struct ccn_fetch_buffer *fb = NewBufferForSeg(fs, thisSeg, dataLen);
00589 memcpy(fb->buf, data, dataLen);
00590 if (debug != NULL && (flags & ccn_fetch_flags_NoteFill)) {
00591 fprintf(debug,
00592 "-- ccn_fetch FillSeg, %s, seg %jd, len %d, nbuf %d",
00593 fs->id, thisSeg, (int) dataLen, (int) fs->nBufs);
00594 ShowDelta(debug, req->startClock);
00595 }
00596 if (thisSeg == finalSeg) {
00597
00598 if (fs->segSize <= 0) {
00599
00600 if (fb->pos >= 0) {
00601 fs->fileSize = fb->pos + dataLen;
00602 }
00603 } else {
00604
00605 fs->fileSize = thisSeg * fs->segSize + dataLen;
00606 }
00607 if (debug != NULL && (flags & ccn_fetch_flags_NoteFinal)) {
00608 fprintf(debug,
00609 "-- ccn_fetch EOF, %s, seg %jd, len %d, fs %jd",
00610 fs->id, thisSeg, (int) dataLen, fs->fileSize);
00611 ShowDelta(debug, req->startClock);
00612 }
00613 }
00614 fs->segsRead++;
00615 }
00616 }
00617
00618 ccn_set_run_timeout(fs->parent->h, 0);
00619 return(CCN_UPCALL_RESULT_OK);
00620 }
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632 extern struct ccn_fetch *
00633 ccn_fetch_new(struct ccn *h) {
00634 struct ccn_fetch *f = calloc(1, sizeof(*f));
00635 if (h == NULL) {
00636 h = ccn_create();
00637 int connRes = ccn_connect(h, NULL);
00638 if (connRes < 0) {
00639 ccn_destroy(&h);
00640 free(f);
00641 return NULL;
00642 }
00643 f->localConnect = 1;
00644 }
00645 f->h = h;
00646 return f;
00647 }
00648
00649 void
00650 ccn_fetch_set_debug(struct ccn_fetch *f, FILE *debug, ccn_fetch_flags flags) {
00651 f->debug = debug;
00652 f->debugFlags = flags;
00653 }
00654
00655
00656
00657
00658
00659
00660
00661 extern struct ccn_fetch *
00662 ccn_fetch_destroy(struct ccn_fetch *f) {
00663
00664
00665
00666
00667 if (f != NULL) {
00668 struct ccn *h = f->h;
00669 if (h != NULL && f->localConnect) {
00670 ccn_disconnect(h);
00671 ccn_destroy(&f->h);
00672 }
00673
00674 while (f->nStreams > 0) {
00675 struct ccn_fetch_stream *fs = f->streams[0];
00676 if (fs == NULL) break;
00677 ccn_fetch_close(fs);
00678 }
00679 free(f);
00680 }
00681 return NULL;
00682 }
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695 extern int
00696 ccn_fetch_poll(struct ccn_fetch *f) {
00697 int i;
00698 int count = 0;
00699 int ns = f->nStreams;
00700 for (i = 0; i < ns; i++) {
00701 struct ccn_fetch_stream *fs = f->streams[i];
00702 if (fs != NULL) {
00703 intmax_t avail = ccn_fetch_avail(fs);
00704 if (avail >= 0) count++;
00705 }
00706 }
00707
00708 ccn_run(f->h, 0);
00709 return count;
00710 }
00711
00712
00713
00714
00715
00716
00717
00718
00719 extern struct ccn_fetch_stream *
00720 ccn_fetch_next(struct ccn_fetch *f, struct ccn_fetch_stream *fs) {
00721 int i;
00722 int ns = f->nStreams;
00723 struct ccn_fetch_stream *lag = NULL;
00724 for (i = 0; i < ns; i++) {
00725 struct ccn_fetch_stream *tfs = f->streams[i];
00726 if (tfs != NULL) {
00727 if (lag == fs) return tfs;
00728 lag = tfs;
00729 }
00730 }
00731 return NULL;
00732 }
00733
00734
00735
00736
00737 extern struct ccn *
00738 ccn_fetch_get_ccn(struct ccn_fetch *f) {
00739 return f->h;
00740 }
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752 extern struct ccn_fetch_stream *
00753 ccn_fetch_open(struct ccn_fetch *f,
00754 struct ccn_charbuf *name,
00755 const char *id,
00756 struct ccn_charbuf *interestTemplate,
00757 int maxBufs,
00758 int resolveVersion,
00759 int assumeFixed) {
00760
00761
00762 if (maxBufs <= 0) return NULL;
00763 if (maxBufs > 16) maxBufs = 16;
00764 int res = 0;
00765 FILE *debug = f->debug;
00766 ccn_fetch_flags flags = f->debugFlags;
00767
00768
00769 struct ccn_fetch_stream *fs = calloc(1, sizeof(*fs));
00770 fs->segSize = (assumeFixed ? 0 : -1);
00771 fs->name = ccn_charbuf_create();
00772 fs->id = newStringCopy(id);
00773 ccn_charbuf_append_charbuf(fs->name, name);
00774 if (resolveVersion) {
00775 int tmInc = 40;
00776 int tm = 0;
00777 while (tm < CCN_VERSION_TIMEOUT) {
00778 res = ccn_resolve_version(f->h, fs->name, resolveVersion, tmInc);
00779 if (res >= 0) break;
00780 tm = tm + tmInc;
00781 }
00782 if (res < 0) {
00783
00784
00785 if (debug != NULL && (flags & ccn_fetch_flags_NoteOpenClose)) {
00786 fprintf(debug,
00787 "-- ccn_fetch open, %s, failed to resolve version\n",
00788 fs->id);
00789 fflush(debug);
00790 }
00791 ccn_charbuf_destroy(&fs->name);
00792 freeString(fs->id);
00793 free(fs);
00794 return NULL;
00795 }
00796 }
00797 fs->maxBufs = maxBufs;
00798 fs->segsAhead = 0;
00799 fs->fileSize = -1;
00800 fs->finalSeg = -1;
00801 fs->timeoutSeg = -1;
00802 fs->zeroLenSeg = -1;
00803 fs->parent = f;
00804 fs->timeoutUSecs = CCN_INTEREST_TIMEOUT_USECS;
00805
00806
00807 if (interestTemplate != NULL) {
00808 struct ccn_charbuf *cb = ccn_charbuf_create();
00809 ccn_charbuf_append_charbuf(cb, interestTemplate);
00810 fs->interest = cb;
00811 } else
00812 fs->interest = make_data_template(MaxSuffixDefault);
00813
00814
00815
00816 int ns = f->nStreams;
00817 int max = f->maxStreams;
00818 if (ns >= max) {
00819
00820 int nMax = max+max/2+4;
00821 f->streams = realloc(f->streams, sizeof(*(f->streams)) * nMax);
00822 f->maxStreams = nMax;
00823 }
00824
00825 f->streams[ns] = fs;
00826 f->nStreams = ns+1;
00827
00828 if (debug != NULL && (flags & ccn_fetch_flags_NoteOpenClose)) {
00829 fprintf(debug,
00830 "-- ccn_fetch open, %s\n",
00831 fs->id);
00832 fflush(debug);
00833 }
00834
00835 NeedSegment(fs, 0);
00836 return fs;
00837 }
00838
00839
00840
00841
00842
00843
00844 extern struct ccn_fetch_stream *
00845 ccn_fetch_close(struct ccn_fetch_stream *fs) {
00846
00847
00848
00849 int i;
00850 FILE *debug = fs->parent->debug;
00851 ccn_fetch_flags flags = fs->parent->debugFlags;
00852
00853
00854
00855 struct localClosure * this = fs->requests;
00856 fs->requests = NULL;
00857 while (this != NULL) {
00858 this->fs = NULL;
00859 this = this->next;
00860 }
00861
00862 fs->maxBufs = 0;
00863 PruneSegments(fs);
00864
00865 if (fs->name != NULL)
00866 ccn_charbuf_destroy(&fs->name);
00867 if (fs->interest != NULL)
00868 ccn_charbuf_destroy(&fs->interest);
00869 struct ccn_fetch *f = fs->parent;
00870 if (f != NULL) {
00871 int ns = f->nStreams;
00872 fs->parent = NULL;
00873 for (i = 0; i < ns; i++) {
00874 struct ccn_fetch_stream *tfs = f->streams[i];
00875 if (tfs == fs) {
00876
00877 ns--;
00878 f->nStreams = ns;
00879 f->streams[i] = NULL;
00880 f->streams[i] = f->streams[ns];
00881 f->streams[ns] = NULL;
00882 break;
00883 }
00884 }
00885 }
00886 if (debug != NULL && (flags & ccn_fetch_flags_NoteOpenClose)) {
00887 fprintf(debug,
00888 "-- ccn_fetch close, %s, segReq %jd, segsRead %jd, timeouts %jd\n",
00889 fs->id,
00890 fs->segsRequested,
00891 fs->segsRead,
00892 fs->timeoutsSeen);
00893 fflush(debug);
00894 }
00895
00896 freeString(fs->id);
00897 free(fs);
00898 return NULL;
00899 }
00900
00901
00902
00903
00904 extern intmax_t
00905 ccn_fetch_avail(struct ccn_fetch_stream *fs) {
00906 intmax_t pos = fs->readPosition;
00907 if (fs->fileSize >= 0 && pos >= fs->fileSize) {
00908
00909 return CCN_FETCH_READ_END;
00910 }
00911 intmax_t avail = 0;
00912 seg_t seg = fs->readSeg;
00913 if (fs->timeoutSeg >= 0 && seg >= fs->timeoutSeg)
00914
00915 return CCN_FETCH_READ_TIMEOUT;
00916 if (fs->zeroLenSeg >= 0 && seg >= fs->zeroLenSeg)
00917
00918 return CCN_FETCH_READ_ZERO;
00919 seg_t finalSeg = fs->finalSeg;
00920 if (seg > finalSeg && fs->finalSeg >= 0)
00921
00922 return CCN_FETCH_READ_NONE;
00923
00924 for (;;) {
00925 struct ccn_fetch_buffer *fb = FindBufferForSeg(fs, seg);
00926 if (fb == NULL) break;
00927 if (fb->pos < 0) fb->pos = pos;
00928 int len = fb->len;
00929 if (seg == fs->readSeg) {
00930
00931 intmax_t off = pos - fb->pos;
00932 if (off > 0) len = len - off;
00933 }
00934 avail = avail + len;
00935 pos = pos + len;
00936 seg++;
00937 }
00938 if (avail == 0)
00939
00940 return CCN_FETCH_READ_NONE;
00941 return avail;
00942 }
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956 extern intmax_t
00957 ccn_fetch_read(struct ccn_fetch_stream *fs,
00958 void *buf,
00959 intmax_t len) {
00960 if (len < 0 || buf == NULL) {
00961 return CCN_FETCH_READ_NONE;
00962 }
00963 intmax_t off = 0;
00964 intmax_t pos = fs->readPosition;
00965 if (fs->fileSize >= 0 && pos >= fs->fileSize) {
00966
00967 return CCN_FETCH_READ_END;
00968 }
00969 intmax_t nr = 0;
00970 unsigned char *dst = (unsigned char *) buf;
00971 seg_t seg = fs->readSeg;
00972
00973 if (fs->timeoutSeg >= 0 && seg >= fs->timeoutSeg)
00974
00975 return CCN_FETCH_READ_TIMEOUT;
00976 if (fs->zeroLenSeg >= 0 && seg >= fs->zeroLenSeg)
00977
00978 return CCN_FETCH_READ_ZERO;
00979 while (len > 0) {
00980 struct ccn_fetch_buffer *fb = FindBufferForSeg(fs, seg);
00981 if (fb == NULL) break;
00982 unsigned char *src = fb->buf;
00983 intmax_t start = fb->pos;
00984 intmax_t lo = start;
00985 if (lo < 0) {
00986
00987 lo = pos;
00988 fb->pos = pos;
00989 }
00990 intmax_t hi = lo + fb->len;
00991 if (pos < lo || pos >= hi || seg != fb->seg) {
00992
00993 FILE *debug = fs->parent->debug;
00994 if (debug != NULL) {
00995 fprintf(debug,
00996 "** ccn_fetch read, %s, seg %jd, pos %jd, lo %jd, hi %jd\n",
00997 fs->id, seg, pos, (intmax_t) lo, (intmax_t) hi);
00998 fflush(debug);
00999 }
01000 break;
01001 }
01002 intmax_t d = hi - pos;
01003 if (d > len) d = len;
01004 memcpy(dst+off, src+(pos-lo), d);
01005 nr = nr + d;
01006 pos = pos + d;
01007 off = off + d;
01008 len = len - d;
01009 fs->readPosition = pos;
01010 fs->readStart = start;
01011 if (pos == hi) {
01012
01013 seg++;
01014 fs->readSeg = seg;
01015 fs->readStart = pos;
01016 }
01017 }
01018 NeedSegments(fs);
01019 PruneSegments(fs);
01020 if (nr == 0) {
01021 return CCN_FETCH_READ_NONE;
01022 }
01023 return nr;
01024 }
01025
01026
01027
01028
01029 extern void
01030 ccn_reset_timeout(struct ccn_fetch_stream *fs) {
01031 fs->timeoutSeg = -1;
01032 fs->segsAhead = 0;
01033 }
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043 extern int
01044 ccn_fetch_seek(struct ccn_fetch_stream *fs, intmax_t pos) {
01045
01046 seg_t seg = 0;
01047 intmax_t start = 0;
01048 if (pos == 0) {
01049
01050
01051 fs->timeoutSeg = -1;
01052 fs->zeroLenSeg = -1;
01053 fs->segsAhead = 0;
01054 } else if (pos == fs->readPosition) {
01055
01056 return 0;
01057 } else {
01058
01059 struct ccn_fetch_buffer *fb = FindBufferForPosition(fs, pos);
01060 if (fb != NULL) {
01061
01062 seg = fb->seg;
01063 start = fb->pos;
01064 } else {
01065 int ss = fs->segSize;
01066 if (pos < 0 || ss <= 0)
01067
01068 return -1;
01069 intmax_t fileSize = fs->fileSize;
01070 if (fileSize >= 0 && pos > fileSize) {
01071
01072 return -1;
01073 }
01074
01075 seg = pos / ss;
01076 start = seg * ss;
01077 }
01078 }
01079 fs->readPosition = pos;
01080 fs->readStart = start;
01081 fs->readSeg = seg;
01082 NeedSegment(fs, seg);
01083 PruneSegments(fs);
01084
01085 return 0;
01086 }
01087
01088
01089
01090
01091 extern intmax_t
01092 ccn_fetch_position(struct ccn_fetch_stream *fs) {
01093 return fs->readPosition;
01094 }
01095
01096