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
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 #include <stdio.h>
00051 #include <string.h>
00052 #ifndef WIN32
00053 # include <sys/time.h>
00054 #endif
00055 #include <stdlib.h>
00056 #include <errno.h>
00057
00058 #include <curl/curl.h>
00059
00060 enum fcurl_type_e {
00061 CFTYPE_NONE=0,
00062 CFTYPE_FILE=1,
00063 CFTYPE_CURL=2
00064 };
00065
00066 struct fcurl_data
00067 {
00068 enum fcurl_type_e type;
00069 union {
00070 CURL *curl;
00071 FILE *file;
00072 } handle;
00073
00074 char *buffer;
00075 size_t buffer_len;
00076 size_t buffer_pos;
00077 int still_running;
00078 };
00079
00080 typedef struct fcurl_data URL_FILE;
00081
00082
00083 URL_FILE *url_fopen(const char *url, const char *operation);
00084 int url_fclose(URL_FILE *file);
00085 int url_feof(URL_FILE *file);
00086 size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file);
00087 char *url_fgets(char *ptr, size_t size, URL_FILE *file);
00088 void url_rewind(URL_FILE *file);
00089
00090
00091 CURLM *multi_handle;
00092
00093
00094 static size_t write_callback(char *buffer,
00095 size_t size,
00096 size_t nitems,
00097 void *userp)
00098 {
00099 char *newbuff;
00100 size_t rembuff;
00101
00102 URL_FILE *url = (URL_FILE *)userp;
00103 size *= nitems;
00104
00105 rembuff=url->buffer_len - url->buffer_pos;
00106
00107 if(size > rembuff) {
00108
00109 newbuff=realloc(url->buffer, url->buffer_len + (size - rembuff));
00110 if(newbuff==NULL) {
00111 fprintf(stderr, "callback buffer grow failed\n");
00112 size=rembuff;
00113 }
00114 else {
00115
00116 url->buffer_len+=size - rembuff;
00117 url->buffer=newbuff;
00118 }
00119 }
00120
00121 memcpy(&url->buffer[url->buffer_pos], buffer, size);
00122 url->buffer_pos += size;
00123
00124 return size;
00125 }
00126
00127
00128 static int fill_buffer(URL_FILE *file, size_t want)
00129 {
00130 fd_set fdread;
00131 fd_set fdwrite;
00132 fd_set fdexcep;
00133 struct timeval timeout;
00134 int rc;
00135 CURLMcode mc;
00136
00137
00138
00139
00140 if((!file->still_running) || (file->buffer_pos > want))
00141 return 0;
00142
00143
00144 do {
00145 int maxfd = -1;
00146 long curl_timeo = -1;
00147
00148 FD_ZERO(&fdread);
00149 FD_ZERO(&fdwrite);
00150 FD_ZERO(&fdexcep);
00151
00152
00153 timeout.tv_sec = 60;
00154 timeout.tv_usec = 0;
00155
00156 curl_multi_timeout(multi_handle, &curl_timeo);
00157 if(curl_timeo >= 0) {
00158 timeout.tv_sec = curl_timeo / 1000;
00159 if(timeout.tv_sec > 1)
00160 timeout.tv_sec = 1;
00161 else
00162 timeout.tv_usec = (curl_timeo % 1000) * 1000;
00163 }
00164
00165
00166 mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
00167
00168 if(mc != CURLM_OK) {
00169 fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
00170 break;
00171 }
00172
00173
00174
00175
00176
00177
00178
00179 if(maxfd == -1) {
00180 #ifdef _WIN32
00181 Sleep(100);
00182 rc = 0;
00183 #else
00184
00185 struct timeval wait = { 0, 100 * 1000 };
00186 rc = select(0, NULL, NULL, NULL, &wait);
00187 #endif
00188 }
00189 else {
00190
00191
00192 rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
00193 }
00194
00195 switch(rc) {
00196 case -1:
00197
00198 break;
00199
00200 case 0:
00201 default:
00202
00203 curl_multi_perform(multi_handle, &file->still_running);
00204 break;
00205 }
00206 } while(file->still_running && (file->buffer_pos < want));
00207 return 1;
00208 }
00209
00210
00211 static int use_buffer(URL_FILE *file, size_t want)
00212 {
00213
00214 if((file->buffer_pos - want) <=0) {
00215
00216 free(file->buffer);
00217 file->buffer=NULL;
00218 file->buffer_pos=0;
00219 file->buffer_len=0;
00220 }
00221 else {
00222
00223 memmove(file->buffer,
00224 &file->buffer[want],
00225 (file->buffer_pos - want));
00226
00227 file->buffer_pos -= want;
00228 }
00229 return 0;
00230 }
00231
00232 URL_FILE *url_fopen(const char *url, const char *operation)
00233 {
00234
00235
00236
00237 URL_FILE *file;
00238 (void)operation;
00239
00240 file = malloc(sizeof(URL_FILE));
00241 if(!file)
00242 return NULL;
00243
00244 memset(file, 0, sizeof(URL_FILE));
00245
00246 if((file->handle.file=fopen(url, operation)))
00247 file->type = CFTYPE_FILE;
00248
00249 else {
00250 file->type = CFTYPE_CURL;
00251 file->handle.curl = curl_easy_init();
00252
00253 curl_easy_setopt(file->handle.curl, CURLOPT_URL, url);
00254 curl_easy_setopt(file->handle.curl, CURLOPT_WRITEDATA, file);
00255 curl_easy_setopt(file->handle.curl, CURLOPT_VERBOSE, 0L);
00256 curl_easy_setopt(file->handle.curl, CURLOPT_WRITEFUNCTION, write_callback);
00257
00258 if(!multi_handle)
00259 multi_handle = curl_multi_init();
00260
00261 curl_multi_add_handle(multi_handle, file->handle.curl);
00262
00263
00264 curl_multi_perform(multi_handle, &file->still_running);
00265
00266 if((file->buffer_pos == 0) && (!file->still_running)) {
00267
00268
00269
00270 curl_multi_remove_handle(multi_handle, file->handle.curl);
00271
00272
00273 curl_easy_cleanup(file->handle.curl);
00274
00275 free(file);
00276
00277 file = NULL;
00278 }
00279 }
00280 return file;
00281 }
00282
00283 int url_fclose(URL_FILE *file)
00284 {
00285 int ret=0;
00286
00287 switch(file->type) {
00288 case CFTYPE_FILE:
00289 ret=fclose(file->handle.file);
00290 break;
00291
00292 case CFTYPE_CURL:
00293
00294 curl_multi_remove_handle(multi_handle, file->handle.curl);
00295
00296
00297 curl_easy_cleanup(file->handle.curl);
00298 break;
00299
00300 default:
00301 ret=EOF;
00302 errno=EBADF;
00303 break;
00304 }
00305
00306 free(file->buffer);
00307 free(file);
00308
00309 return ret;
00310 }
00311
00312 int url_feof(URL_FILE *file)
00313 {
00314 int ret=0;
00315
00316 switch(file->type) {
00317 case CFTYPE_FILE:
00318 ret=feof(file->handle.file);
00319 break;
00320
00321 case CFTYPE_CURL:
00322 if((file->buffer_pos == 0) && (!file->still_running))
00323 ret = 1;
00324 break;
00325
00326 default:
00327 ret=-1;
00328 errno=EBADF;
00329 break;
00330 }
00331 return ret;
00332 }
00333
00334 size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file)
00335 {
00336 size_t want;
00337
00338 switch(file->type) {
00339 case CFTYPE_FILE:
00340 want=fread(ptr, size, nmemb, file->handle.file);
00341 break;
00342
00343 case CFTYPE_CURL:
00344 want = nmemb * size;
00345
00346 fill_buffer(file, want);
00347
00348
00349
00350 if(!file->buffer_pos)
00351 return 0;
00352
00353
00354 if(file->buffer_pos < want)
00355 want = file->buffer_pos;
00356
00357
00358 memcpy(ptr, file->buffer, want);
00359
00360 use_buffer(file, want);
00361
00362 want = want / size;
00363 break;
00364
00365 default:
00366 want=0;
00367 errno=EBADF;
00368 break;
00369
00370 }
00371 return want;
00372 }
00373
00374 char *url_fgets(char *ptr, size_t size, URL_FILE *file)
00375 {
00376 size_t want = size - 1;
00377 size_t loop;
00378
00379 switch(file->type) {
00380 case CFTYPE_FILE:
00381 ptr = fgets(ptr, (int)size, file->handle.file);
00382 break;
00383
00384 case CFTYPE_CURL:
00385 fill_buffer(file, want);
00386
00387
00388
00389 if(!file->buffer_pos)
00390 return NULL;
00391
00392
00393 if(file->buffer_pos < want)
00394 want = file->buffer_pos;
00395
00396
00397
00398 for(loop=0;loop < want;loop++) {
00399 if(file->buffer[loop] == '\n') {
00400 want=loop+1;
00401 break;
00402 }
00403 }
00404
00405
00406 memcpy(ptr, file->buffer, want);
00407 ptr[want]=0;
00408
00409 use_buffer(file, want);
00410
00411 break;
00412
00413 default:
00414 ptr=NULL;
00415 errno=EBADF;
00416 break;
00417 }
00418
00419 return ptr;
00420 }
00421
00422 void url_rewind(URL_FILE *file)
00423 {
00424 switch(file->type) {
00425 case CFTYPE_FILE:
00426 rewind(file->handle.file);
00427 break;
00428
00429 case CFTYPE_CURL:
00430
00431 curl_multi_remove_handle(multi_handle, file->handle.curl);
00432
00433
00434 curl_multi_add_handle(multi_handle, file->handle.curl);
00435
00436
00437 free(file->buffer);
00438 file->buffer=NULL;
00439 file->buffer_pos=0;
00440 file->buffer_len=0;
00441
00442 break;
00443
00444 default:
00445 break;
00446 }
00447 }
00448
00449 #define FGETSFILE "fgets.test"
00450 #define FREADFILE "fread.test"
00451 #define REWINDFILE "rewind.test"
00452
00453
00454
00455
00456 int main(int argc, char *argv[])
00457 {
00458 URL_FILE *handle;
00459 FILE *outf;
00460
00461 size_t nread;
00462 char buffer[256];
00463 const char *url;
00464
00465 if(argc < 2)
00466 url="http://192.168.7.3/testfile";
00467 else
00468 url=argv[1];
00469
00470
00471 outf=fopen(FGETSFILE, "wb+");
00472 if(!outf) {
00473 perror("couldn't open fgets output file\n");
00474 return 1;
00475 }
00476
00477 handle = url_fopen(url, "r");
00478 if(!handle) {
00479 printf("couldn't url_fopen() %s\n", url);
00480 fclose(outf);
00481 return 2;
00482 }
00483
00484 while(!url_feof(handle)) {
00485 url_fgets(buffer, sizeof(buffer), handle);
00486 fwrite(buffer, 1, strlen(buffer), outf);
00487 }
00488
00489 url_fclose(handle);
00490
00491 fclose(outf);
00492
00493
00494
00495 outf=fopen(FREADFILE, "wb+");
00496 if(!outf) {
00497 perror("couldn't open fread output file\n");
00498 return 1;
00499 }
00500
00501 handle = url_fopen("testfile", "r");
00502 if(!handle) {
00503 printf("couldn't url_fopen() testfile\n");
00504 fclose(outf);
00505 return 2;
00506 }
00507
00508 do {
00509 nread = url_fread(buffer, 1, sizeof(buffer), handle);
00510 fwrite(buffer, 1, nread, outf);
00511 } while(nread);
00512
00513 url_fclose(handle);
00514
00515 fclose(outf);
00516
00517
00518
00519 outf=fopen(REWINDFILE, "wb+");
00520 if(!outf) {
00521 perror("couldn't open fread output file\n");
00522 return 1;
00523 }
00524
00525 handle = url_fopen("testfile", "r");
00526 if(!handle) {
00527 printf("couldn't url_fopen() testfile\n");
00528 fclose(outf);
00529 return 2;
00530 }
00531
00532 nread = url_fread(buffer, 1, sizeof(buffer), handle);
00533 fwrite(buffer, 1, nread, outf);
00534 url_rewind(handle);
00535
00536 buffer[0]='\n';
00537 fwrite(buffer, 1, 1, outf);
00538
00539 nread = url_fread(buffer, 1, sizeof(buffer), handle);
00540 fwrite(buffer, 1, nread, outf);
00541
00542 url_fclose(handle);
00543
00544 fclose(outf);
00545
00546 return 0;
00547 }