📄 curl.c
字号:
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <time.h>#include <errno.h>#include <sys/select.h>#include <curl/curl.h>#include <curl/easy.h>#include "curl.h"/* curl globals */static CURLM *curlm;static fd_set rd, wr, ex;/* my globals */static int url_debug = 0;static int url_timeout = 30;/* my structs */struct iobuf { off_t start; size_t size; char *data;};struct url_state { char *path; CURL *curl; char errmsg[CURL_ERROR_SIZE]; off_t curl_pos; off_t buf_pos; struct iobuf buf; int eof;};/* ---------------------------------------------------------------------- *//* curl stuff */static void __attribute__ ((constructor)) curl_init(void){ curl_global_init(CURL_GLOBAL_ALL); curlm = curl_multi_init();}static void __attribute__ ((destructor)) curl_fini(void){ curl_multi_cleanup(curlm); curl_global_cleanup();}static void curl_free_buffer(struct iobuf *buf){ if (buf->data) { free(buf->data); memset(buf,0,sizeof(*buf)); }}/* CURLOPT_WRITEFUNCTION */static int curl_write(void *data, size_t size, size_t nmemb, void *handle){ struct url_state *h = handle; curl_free_buffer(&h->buf); h->buf.start = h->curl_pos; h->buf.size = size * nmemb; h->buf.data = malloc(h->buf.size); memcpy(h->buf.data, data, h->buf.size); if (url_debug) fprintf(stderr," put %5d @ %5d\n", (int)h->buf.size, (int)h->buf.start); h->curl_pos += h->buf.size; return h->buf.size;}/* do transfers */static int curl_xfer(struct url_state *h){ CURLMcode rc; struct timeval tv; int count, maxfd; FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&ex); maxfd = -1; rc = curl_multi_fdset(curlm, &rd, &wr, &ex, &maxfd); if (CURLM_OK != rc) { fprintf(stderr,"curl_multi_fdset: %d %s\n",rc,h->errmsg); return -1; } if (-1 == maxfd) { /* wait 0.1 sec */ if (url_debug) fprintf(stderr,"wait 0.01 sec\n"); tv.tv_sec = 0; tv.tv_usec = 100000; } else { /* wait for data */ if (url_debug) fprintf(stderr,"select for data [maxfd=%d]\n",maxfd); tv.tv_sec = url_timeout; tv.tv_usec = 0; } switch (select(maxfd+1, &rd, &wr, &ex, &tv)) { case -1: /* Huh? */ perror("select"); exit(1); case 0: /* timeout */ return -1; } for (;;) { rc = curl_multi_perform(curlm,&count); if (CURLM_CALL_MULTI_PERFORM == rc) continue; if (CURLM_OK != rc) { fprintf(stderr,"curl_multi_perform: %d %s\n",rc,h->errmsg); return -1; } if (0 == count) h->eof = 1; break; } return 0;}/* curl setup */static int curl_setup(struct url_state *h){ if (h->curl) { curl_multi_remove_handle(curlm,h->curl); curl_easy_cleanup(h->curl); } h->curl = curl_easy_init(); curl_easy_setopt(h->curl, CURLOPT_URL, h->path); curl_easy_setopt(h->curl, CURLOPT_ERRORBUFFER, h->errmsg); curl_easy_setopt(h->curl, CURLOPT_WRITEFUNCTION, curl_write); curl_easy_setopt(h->curl, CURLOPT_WRITEDATA, h); curl_multi_add_handle(curlm, h->curl); h->buf_pos = 0; h->curl_pos = 0; h->eof = 0; return 0;}/* ---------------------------------------------------------------------- *//* GNU glibc custom stream interface */static ssize_t url_read(void *handle, char *buf, size_t size){ struct url_state *h = handle; size_t bytes, total; off_t off; int count; if (url_debug) fprintf(stderr,"url_read(size=%d)\n",(int)size); for (total = 0; size > 0;) { if (h->buf.start <= h->buf_pos && h->buf.start + h->buf.size > h->buf_pos) { /* can satisfy from current buffer */ bytes = h->buf.start + h->buf.size - h->buf_pos; off = h->buf_pos - h->buf.start; if (bytes > size) bytes = size; memcpy(buf+total, h->buf.data + off, bytes); if (url_debug) fprintf(stderr," get %5d @ %5d [%5d]\n", (int)bytes, (int)h->buf_pos, (int)off); size -= bytes; total += bytes; h->buf_pos += bytes; continue; } if (h->buf_pos < h->buf.start) { /* seeking backwards -- restart transfer */ if (url_debug) fprintf(stderr," rewind\n"); curl_free_buffer(&h->buf); curl_setup(h); while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curlm,&count)) /* nothing */; } if (h->eof) /* stop on eof */ break; /* fetch more data */ if (-1 == curl_xfer(h)) { if (0 == total) return -1; break; } } return total;}#if 0static ssize_t url_write(void *handle, const char *buf, size_t size){ //struct url_state *h = handle; if (url_debug) fprintf(stderr,"url_write(size=%d)\n",(int)size); return -1;}#endifstatic int url_seek(void *handle, off64_t *pos, int whence){ struct url_state *h = handle; int rc = 0; if (url_debug) fprintf(stderr,"url_seek(pos=%d,whence=%d)\n", (int)(*pos), whence); switch (whence) { case SEEK_SET: h->buf_pos = *pos; break; case SEEK_CUR: h->buf_pos += *pos; break; case SEEK_END: rc = -1; } *pos = h->buf_pos; return rc;}static int url_close(void *handle){ struct url_state *h = handle; if (url_debug) fprintf(stderr,"url_close()\n"); curl_multi_remove_handle(curlm,h->curl); curl_easy_cleanup(h->curl); if (h->buf.data) free(h->buf.data); free(h->path); free(h); return 0;}static cookie_io_functions_t url_hooks = { .read = url_read,#if 0 .write = url_write,#endif .seek = url_seek, .close = url_close,};static FILE *url_open(const char *path, const char *mode){ FILE *fp; struct url_state *h; int count; if (url_debug) fprintf(stderr,"url_open(%s,%s)\n",path,mode); h = malloc(sizeof(*h)); if (NULL == h) goto err; memset(h,0,sizeof(*h)); h->path = strdup(path); if (NULL == h->path) goto err; /* setup */ curl_setup(h); fp = fopencookie(h, mode, url_hooks); if (NULL == fp) goto err; /* connect + start fetching */ while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curlm,&count)) /* nothing */; /* check for errors */ if (0 == count && NULL == h->buf.data) { errno = ENOENT; goto fetch_err; } /* all done */ return fp; fetch_err: curl_multi_remove_handle(curlm,h->curl); err: if (h->curl) curl_easy_cleanup(h->curl); if (h->path) free(h->path); if (h) free(h); return NULL;}/* ---------------------------------------------------------------------- *//* hook into fopen using GNU ld's --wrap */int curl_is_url(const char *url){ static char *protocols[] = { "ftp://", "http://", NULL, }; int i; for (i = 0; protocols[i] != NULL; i++) if (0 == strncasecmp(url, protocols[i], strlen(protocols[i]))) return 1; return 0;}FILE *__wrap_fopen(const char *path, const char *mode);FILE *__real_fopen(const char *path, const char *mode);FILE *__wrap_fopen(const char *path, const char *mode){ if (url_debug) fprintf(stderr,"fopen(%s,%s)\n",path,mode); /* catch URLs */ if (curl_is_url(path)) { if (strchr(mode,'w')) { fprintf(stderr,"write access over ftp/http is not supported, sorry\n"); return NULL; } return url_open(path,mode); } /* files passed to the real fopen */ return __real_fopen(path,mode);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -