Viewing file: fopen.c (5.32 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/***************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * $Id: fopen.c,v 1.1 2002/05/13 07:28:10 bagder Exp $ * * This example source code introduces an fopen()/fread()/fclose() emulation * for URL reads. Using an approach similar to this, you could replace your * program's fopen() with this url_fopen() and fread() with url_fread() and * it should be possible to read remote streams instead of (only) local files. * * See the main() function at the bottom that shows a tiny app in action. * * This source code is a proof of concept. It will need further attention to * become production-use useful and solid. * * This example requires libcurl 7.9.7 or later. */ #include <stdio.h> #include <string.h> #include <sys/time.h>
#include <curl/curl.h> #include <curl/types.h> #include <curl/easy.h>
struct data { int type; union { CURL *curl; FILE *file; } handle;
/* TODO: We should perhaps document the biggest possible buffer chunk we can get from libcurl in one single callback... */ char buffer[CURL_MAX_WRITE_SIZE];
char *readptr; /* read from here */ int bytes; /* bytes available from read pointer */
CURLMcode m; /* stored from a previous url_fread() */ };
typedef struct data URL_FILE;
/* we use a global one for convenience */ CURLM *multi_handle;
static size_t write_callback(char *buffer, size_t size, size_t nitems, void *userp) { URL_FILE *url = (URL_FILE *)userp; size *= nitems;
memcpy(url->readptr, buffer, size); url->readptr += size; url->bytes += size;
return size; }
URL_FILE *url_fopen(char *url, char *operation) { /* this code could check for URLs or types in the 'url' and basicly use the real fopen() for standard files */
URL_FILE *file; int still_running;
file = (URL_FILE *)malloc(sizeof(URL_FILE)); if(!file) return NULL;
memset(file, 0, sizeof(URL_FILE));
file->type = 1; /* marked as URL, use 0 for plain file */ file->handle.curl = curl_easy_init();
curl_easy_setopt(file->handle.curl, CURLOPT_URL, url); curl_easy_setopt(file->handle.curl, CURLOPT_FILE, file); curl_easy_setopt(file->handle.curl, CURLOPT_VERBOSE, FALSE); curl_easy_setopt(file->handle.curl, CURLOPT_WRITEFUNCTION, write_callback);
if(!multi_handle) multi_handle = curl_multi_init();
curl_multi_add_handle(multi_handle, file->handle.curl);
while(CURLM_CALL_MULTI_PERFORM == curl_multi_perform(multi_handle, &still_running));
/* if still_running would be 0 now, we should return NULL */
return file; }
void url_fclose(URL_FILE *file) { /* make sure the easy handle is not in the multi handle anymore */ curl_multi_remove_handle(multi_handle, file->handle.curl);
/* cleanup */ curl_easy_cleanup(file->handle.curl); }
size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file) { fd_set fdread; fd_set fdwrite; fd_set fdexcep; int maxfd; struct timeval timeout; int rc; int still_running = 0;
if(!file->bytes) { /* no data available at this point */
file->readptr = file->buffer; /* reset read pointer */
if(CURLM_CALL_MULTI_PERFORM == file->m) { while(CURLM_CALL_MULTI_PERFORM == curl_multi_perform(multi_handle, &still_running)) { if(file->bytes) { printf("(fread) WOAH! THis happened!\n"); break; } } if(!still_running) { printf("NO MORE RUNNING AROUND!\n"); return 0; } }
FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* set a suitable timeout to fail on */ timeout.tv_sec = 500; /* 5 minutes */ timeout.tv_usec = 0;
/* get file descriptors from the transfers */ curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
switch(rc) { case -1: /* select error */ break; case 0: break; default: /* timeout or readable/writable sockets */ do { file->m = curl_multi_perform(multi_handle, &still_running);
if(file->bytes) /* we have received data, return that now */ break;
} while(CURLM_CALL_MULTI_PERFORM == file->m);
if(!still_running) printf("NO MORE RUNNING AROUND!\n");
break; } } else printf("(fread) Skip network read\n");
if(file->bytes) { /* data already available, return that */ int want = size * nmemb;
if(file->bytes < want) want = file->bytes;
memcpy(ptr, file->readptr, want); file->readptr += want; file->bytes -= want;
printf("(fread) return %d bytes\n", want);
return want; } return 0; /* no data available to return */ }
int main(int argc, char *argv[]) { URL_FILE *handle; int nread; char buffer[256];
handle = url_fopen("http://www.haxx.se", "r");
if(!handle) { printf("couldn't url_fopen()\n"); }
do { nread = url_fread(buffer, sizeof(buffer), 1, handle);
printf("We got: %d bytes\n", nread); } while(nread);
url_fclose(handle);
return 0; }
|