83
87
CURLM *multi_handle;
85
89
/* curl calls this routine to get more data */
87
write_callback(char *buffer,
90
static size_t write_callback(char *buffer,
95
URL_FILE *url = (URL_FILE *)userp;
98
rembuff=url->buffer_len - url->buffer_pos; /* remaining space in buffer */
102
/* not enough space in buffer */
103
newbuff=realloc(url->buffer,url->buffer_len + (size - rembuff));
106
fprintf(stderr,"callback buffer grow failed\n");
111
/* realloc suceeded increase buffer size*/
112
url->buffer_len+=size - rembuff;
115
/*printf("Callback buffer grown to %d bytes\n",url->buffer_len);*/
119
memcpy(&url->buffer[url->buffer_pos], buffer, size);
120
url->buffer_pos += size;
122
/*fprintf(stderr, "callback %d size bytes\n", size);*/
98
URL_FILE *url = (URL_FILE *)userp;
101
rembuff=url->buffer_len - url->buffer_pos; /* remaining space in buffer */
104
/* not enough space in buffer */
105
newbuff=realloc(url->buffer,url->buffer_len + (size - rembuff));
107
fprintf(stderr,"callback buffer grow failed\n");
111
/* realloc suceeded increase buffer size*/
112
url->buffer_len+=size - rembuff;
117
memcpy(&url->buffer[url->buffer_pos], buffer, size);
118
url->buffer_pos += size;
127
123
/* use to attempt to fill the read buffer up to requested number of bytes */
129
fill_buffer(URL_FILE *file,int want,int waittime)
124
static int fill_buffer(URL_FILE *file,int want,int waittime)
134
struct timeval timeout;
137
/* only attempt to fill buffer if transactions still running and buffer
138
* doesnt exceed required size already
140
if((!file->still_running) || (file->buffer_pos > want))
143
/* attempt to fill buffer */
147
long curl_timeo = -1;
153
/* set a suitable timeout to fail on */
154
timeout.tv_sec = 60; /* 1 minute */
157
curl_multi_timeout(multi_handle, &curl_timeo);
158
if(curl_timeo >= 0) {
159
timeout.tv_sec = curl_timeo / 1000;
160
if(timeout.tv_sec > 1)
163
timeout.tv_usec = (curl_timeo % 1000) * 1000;
166
/* get file descriptors from the transfers */
167
curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
169
/* In a real-world program you OF COURSE check the return code of the
170
function calls. On success, the value of maxfd is guaranteed to be
171
greater or equal than -1. We call select(maxfd + 1, ...), specially
172
in case of (maxfd == -1), we call select(0, ...), which is basically
175
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
186
/* timeout or readable/writable sockets */
187
curl_multi_perform(multi_handle, &file->still_running);
190
} while(file->still_running && (file->buffer_pos < want));
129
struct timeval timeout;
132
/* only attempt to fill buffer if transactions still running and buffer
133
* doesnt exceed required size already
135
if((!file->still_running) || (file->buffer_pos > want))
138
/* attempt to fill buffer */
141
long curl_timeo = -1;
147
/* set a suitable timeout to fail on */
148
timeout.tv_sec = 60; /* 1 minute */
151
curl_multi_timeout(multi_handle, &curl_timeo);
152
if(curl_timeo >= 0) {
153
timeout.tv_sec = curl_timeo / 1000;
154
if(timeout.tv_sec > 1)
157
timeout.tv_usec = (curl_timeo % 1000) * 1000;
160
/* get file descriptors from the transfers */
161
curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
163
/* In a real-world program you OF COURSE check the return code of the
164
function calls. On success, the value of maxfd is guaranteed to be
165
greater or equal than -1. We call select(maxfd + 1, ...), specially
166
in case of (maxfd == -1), we call select(0, ...), which is basically
169
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
178
/* timeout or readable/writable sockets */
179
curl_multi_perform(multi_handle, &file->still_running);
182
} while(file->still_running && (file->buffer_pos < want));
194
186
/* use to remove want bytes from the front of a files buffer */
196
use_buffer(URL_FILE *file,int want)
198
/* sort out buffer */
199
if((file->buffer_pos - want) <=0)
201
/* ditch buffer - write will recreate */
211
/* move rest down make it available for later */
212
memmove(file->buffer,
214
(file->buffer_pos - want));
216
file->buffer_pos -= want;
224
url_fopen(const char *url,const char *operation)
226
/* this code could check for URLs or types in the 'url' and
227
basicly use the real fopen() for standard files */
232
file = malloc(sizeof(URL_FILE));
236
memset(file, 0, sizeof(URL_FILE));
238
if((file->handle.file=fopen(url,operation)))
240
file->type = CFTYPE_FILE; /* marked as URL */
244
file->type = CFTYPE_CURL; /* marked as URL */
245
file->handle.curl = curl_easy_init();
247
curl_easy_setopt(file->handle.curl, CURLOPT_URL, url);
248
curl_easy_setopt(file->handle.curl, CURLOPT_WRITEDATA, file);
249
curl_easy_setopt(file->handle.curl, CURLOPT_VERBOSE, 0L);
250
curl_easy_setopt(file->handle.curl, CURLOPT_WRITEFUNCTION, write_callback);
253
multi_handle = curl_multi_init();
255
curl_multi_add_handle(multi_handle, file->handle.curl);
257
/* lets start the fetch */
258
curl_multi_perform(multi_handle, &file->still_running);
260
if((file->buffer_pos == 0) && (!file->still_running))
262
/* if still_running is 0 now, we should return NULL */
264
/* make sure the easy handle is not in the multi handle anymore */
265
curl_multi_remove_handle(multi_handle, file->handle.curl);
268
curl_easy_cleanup(file->handle.curl);
279
url_fclose(URL_FILE *file)
281
int ret=0;/* default is good return */
286
ret=fclose(file->handle.file); /* passthrough */
290
/* make sure the easy handle is not in the multi handle anymore */
291
curl_multi_remove_handle(multi_handle, file->handle.curl);
294
curl_easy_cleanup(file->handle.curl);
297
default: /* unknown or supported type - oh dear */
305
free(file->buffer);/* free any allocated buffer space */
313
url_feof(URL_FILE *file)
320
ret=feof(file->handle.file);
324
if((file->buffer_pos == 0) && (!file->still_running))
327
default: /* unknown or supported type - oh dear */
336
url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file)
343
want=fread(ptr,size,nmemb,file->handle.file);
349
fill_buffer(file,want,1);
351
/* check if theres data in the buffer - if not fill_buffer()
352
* either errored or EOF */
353
if(!file->buffer_pos)
356
/* ensure only available data is considered */
357
if(file->buffer_pos < want)
358
want = file->buffer_pos;
360
/* xfer data to caller */
361
memcpy(ptr, file->buffer, want);
363
use_buffer(file,want);
365
want = want / size; /* number of items - nb correct op - checked
368
/*printf("(fread) return %d bytes %d left\n", want,file->buffer_pos);*/
371
default: /* unknown or supported type - oh dear */
381
url_fgets(char *ptr, int size, URL_FILE *file)
383
int want = size - 1;/* always need to leave room for zero termination */
389
ptr = fgets(ptr,size,file->handle.file);
393
fill_buffer(file,want,1);
395
/* check if theres data in the buffer - if not fill either errored or
397
if(!file->buffer_pos)
400
/* ensure only available data is considered */
401
if(file->buffer_pos < want)
402
want = file->buffer_pos;
404
/*buffer contains data */
405
/* look for newline or eof */
406
for(loop=0;loop < want;loop++)
408
if(file->buffer[loop] == '\n')
410
want=loop+1;/* include newline */
415
/* xfer data to caller */
416
memcpy(ptr, file->buffer, want);
417
ptr[want]=0;/* allways null terminate */
419
use_buffer(file,want);
421
/*printf("(fgets) return %d bytes %d left\n", want,file->buffer_pos);*/
424
default: /* unknown or supported type - oh dear */
430
return ptr;/*success */
434
url_rewind(URL_FILE *file)
439
rewind(file->handle.file); /* passthrough */
443
/* halt transaction */
444
curl_multi_remove_handle(multi_handle, file->handle.curl);
447
curl_multi_add_handle(multi_handle, file->handle.curl);
449
/* ditch buffer - write will recreate - resets stream pos*/
459
default: /* unknown or supported type - oh dear */
187
static int use_buffer(URL_FILE *file,int want)
189
/* sort out buffer */
190
if((file->buffer_pos - want) <=0) {
191
/* ditch buffer - write will recreate */
200
/* move rest down make it available for later */
201
memmove(file->buffer,
203
(file->buffer_pos - want));
205
file->buffer_pos -= want;
210
URL_FILE *url_fopen(const char *url,const char *operation)
212
/* this code could check for URLs or types in the 'url' and
213
basicly use the real fopen() for standard files */
218
file = malloc(sizeof(URL_FILE));
222
memset(file, 0, sizeof(URL_FILE));
224
if((file->handle.file=fopen(url,operation)))
225
file->type = CFTYPE_FILE; /* marked as URL */
228
file->type = CFTYPE_CURL; /* marked as URL */
229
file->handle.curl = curl_easy_init();
231
curl_easy_setopt(file->handle.curl, CURLOPT_URL, url);
232
curl_easy_setopt(file->handle.curl, CURLOPT_WRITEDATA, file);
233
curl_easy_setopt(file->handle.curl, CURLOPT_VERBOSE, 0L);
234
curl_easy_setopt(file->handle.curl, CURLOPT_WRITEFUNCTION, write_callback);
237
multi_handle = curl_multi_init();
239
curl_multi_add_handle(multi_handle, file->handle.curl);
241
/* lets start the fetch */
242
curl_multi_perform(multi_handle, &file->still_running);
244
if((file->buffer_pos == 0) && (!file->still_running)) {
245
/* if still_running is 0 now, we should return NULL */
247
/* make sure the easy handle is not in the multi handle anymore */
248
curl_multi_remove_handle(multi_handle, file->handle.curl);
251
curl_easy_cleanup(file->handle.curl);
261
int url_fclose(URL_FILE *file)
263
int ret=0;/* default is good return */
267
ret=fclose(file->handle.file); /* passthrough */
271
/* make sure the easy handle is not in the multi handle anymore */
272
curl_multi_remove_handle(multi_handle, file->handle.curl);
275
curl_easy_cleanup(file->handle.curl);
278
default: /* unknown or supported type - oh dear */
285
free(file->buffer);/* free any allocated buffer space */
292
int url_feof(URL_FILE *file)
298
ret=feof(file->handle.file);
302
if((file->buffer_pos == 0) && (!file->still_running))
306
default: /* unknown or supported type - oh dear */
314
size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file)
320
want=fread(ptr,size,nmemb,file->handle.file);
326
fill_buffer(file,want,1);
328
/* check if theres data in the buffer - if not fill_buffer()
329
* either errored or EOF */
330
if(!file->buffer_pos)
333
/* ensure only available data is considered */
334
if(file->buffer_pos < want)
335
want = file->buffer_pos;
337
/* xfer data to caller */
338
memcpy(ptr, file->buffer, want);
340
use_buffer(file,want);
342
want = want / size; /* number of items */
345
default: /* unknown or supported type - oh dear */
354
char *url_fgets(char *ptr, int size, URL_FILE *file)
356
int want = size - 1;/* always need to leave room for zero termination */
361
ptr = fgets(ptr,size,file->handle.file);
365
fill_buffer(file,want,1);
367
/* check if theres data in the buffer - if not fill either errored or
369
if(!file->buffer_pos)
372
/* ensure only available data is considered */
373
if(file->buffer_pos < want)
374
want = file->buffer_pos;
376
/*buffer contains data */
377
/* look for newline or eof */
378
for(loop=0;loop < want;loop++) {
379
if(file->buffer[loop] == '\n') {
380
want=loop+1;/* include newline */
385
/* xfer data to caller */
386
memcpy(ptr, file->buffer, want);
387
ptr[want]=0;/* allways null terminate */
389
use_buffer(file,want);
393
default: /* unknown or supported type - oh dear */
399
return ptr;/*success */
402
void url_rewind(URL_FILE *file)
406
rewind(file->handle.file); /* passthrough */
410
/* halt transaction */
411
curl_multi_remove_handle(multi_handle, file->handle.curl);
414
curl_multi_add_handle(multi_handle, file->handle.curl);
416
/* ditch buffer - write will recreate - resets stream pos*/
426
default: /* unknown or supported type - oh dear */
467
431
/* Small main program to retrive from a url using fgets and fread saving the
468
432
* output to two test files (note the fgets method will corrupt binary files if
469
433
* they contain 0 chars */
471
main(int argc, char *argv[])
434
int main(int argc, char *argv[])
482
url="http://192.168.7.3/testfile";/* default to testurl */
486
url=argv[1];/* use passed url */
489
/* copy from url line by line with fgets */
490
outf=fopen("fgets.test","w+");
493
perror("couldn't open fgets output file\n");
497
handle = url_fopen(url, "r");
500
printf("couldn't url_fopen() %s\n", url);
505
while(!url_feof(handle))
507
url_fgets(buffer,sizeof(buffer),handle);
508
fwrite(buffer,1,strlen(buffer),outf);
516
/* Copy from url with fread */
517
outf=fopen("fread.test","w+");
520
perror("couldn't open fread output file\n");
524
handle = url_fopen("testfile", "r");
526
printf("couldn't url_fopen() testfile\n");
532
nread = url_fread(buffer, 1,sizeof(buffer), handle);
533
fwrite(buffer,1,nread,outf);
542
outf=fopen("rewind.test","w+");
545
perror("couldn't open fread output file\n");
549
handle = url_fopen("testfile", "r");
551
printf("couldn't url_fopen() testfile\n");
556
nread = url_fread(buffer, 1,sizeof(buffer), handle);
557
fwrite(buffer,1,nread,outf);
561
fwrite(buffer,1,1,outf);
563
nread = url_fread(buffer, 1,sizeof(buffer), handle);
564
fwrite(buffer,1,nread,outf);
572
return 0;/* all done */
444
url="http://192.168.7.3/testfile";/* default to testurl */
446
url=argv[1];/* use passed url */
448
/* copy from url line by line with fgets */
449
outf=fopen("fgets.test","w+");
451
perror("couldn't open fgets output file\n");
455
handle = url_fopen(url, "r");
457
printf("couldn't url_fopen() %s\n", url);
462
while(!url_feof(handle)) {
463
url_fgets(buffer,sizeof(buffer),handle);
464
fwrite(buffer,1,strlen(buffer),outf);
472
/* Copy from url with fread */
473
outf=fopen("fread.test","w+");
475
perror("couldn't open fread output file\n");
479
handle = url_fopen("testfile", "r");
481
printf("couldn't url_fopen() testfile\n");
487
nread = url_fread(buffer, 1,sizeof(buffer), handle);
488
fwrite(buffer,1,nread,outf);
497
outf=fopen("rewind.test","w+");
499
perror("couldn't open fread output file\n");
503
handle = url_fopen("testfile", "r");
505
printf("couldn't url_fopen() testfile\n");
510
nread = url_fread(buffer, 1,sizeof(buffer), handle);
511
fwrite(buffer,1,nread,outf);
515
fwrite(buffer,1,1,outf);
517
nread = url_fread(buffer, 1,sizeof(buffer), handle);
518
fwrite(buffer,1,nread,outf);
526
return 0;/* all done */