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 <stdio.h>
00036 #include <stdlib.h>
00037 #include <uv.h>
00038 #include <curl/curl.h>
00039
00040 uv_loop_t *loop;
00041 CURLM *curl_handle;
00042 uv_timer_t timeout;
00043
00044 typedef struct curl_context_s {
00045 uv_poll_t poll_handle;
00046 curl_socket_t sockfd;
00047 } curl_context_t;
00048
00049 curl_context_t* create_curl_context(curl_socket_t sockfd)
00050 {
00051 curl_context_t *context;
00052
00053 context = (curl_context_t *) malloc(sizeof *context);
00054
00055 context->sockfd = sockfd;
00056
00057 uv_poll_init_socket(loop, &context->poll_handle, sockfd);
00058 context->poll_handle.data = context;
00059
00060 return context;
00061 }
00062
00063 void curl_close_cb(uv_handle_t *handle)
00064 {
00065 curl_context_t *context = (curl_context_t *) handle->data;
00066 free(context);
00067 }
00068
00069 void destroy_curl_context(curl_context_t *context)
00070 {
00071 uv_close((uv_handle_t *) &context->poll_handle, curl_close_cb);
00072 }
00073
00074 void add_download(const char *url, int num)
00075 {
00076 char filename[50];
00077 FILE *file;
00078 CURL *handle;
00079
00080 snprintf(filename, 50, "%d.download", num);
00081
00082 file = fopen(filename, "wb");
00083 if(!file) {
00084 fprintf(stderr, "Error opening %s\n", filename);
00085 return;
00086 }
00087
00088 handle = curl_easy_init();
00089 curl_easy_setopt(handle, CURLOPT_WRITEDATA, file);
00090 curl_easy_setopt(handle, CURLOPT_PRIVATE, file);
00091 curl_easy_setopt(handle, CURLOPT_URL, url);
00092 curl_multi_add_handle(curl_handle, handle);
00093 fprintf(stderr, "Added download %s -> %s\n", url, filename);
00094 }
00095
00096 static void check_multi_info(void)
00097 {
00098 char *done_url;
00099 CURLMsg *message;
00100 int pending;
00101 CURL *easy_handle;
00102 FILE *file;
00103
00104 while((message = curl_multi_info_read(curl_handle, &pending))) {
00105 switch(message->msg) {
00106 case CURLMSG_DONE:
00107
00108
00109
00110
00111
00112 easy_handle = message->easy_handle;
00113
00114 curl_easy_getinfo(easy_handle, CURLINFO_EFFECTIVE_URL, &done_url);
00115 curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, &file);
00116 printf("%s DONE\n", done_url);
00117
00118 curl_multi_remove_handle(curl_handle, easy_handle);
00119 curl_easy_cleanup(easy_handle);
00120 if(file) {
00121 fclose(file);
00122 }
00123 break;
00124
00125 default:
00126 fprintf(stderr, "CURLMSG default\n");
00127 break;
00128 }
00129 }
00130 }
00131
00132 void curl_perform(uv_poll_t *req, int status, int events)
00133 {
00134 int running_handles;
00135 int flags = 0;
00136 curl_context_t *context;
00137
00138 uv_timer_stop(&timeout);
00139
00140 if(events & UV_READABLE)
00141 flags |= CURL_CSELECT_IN;
00142 if(events & UV_WRITABLE)
00143 flags |= CURL_CSELECT_OUT;
00144
00145 context = (curl_context_t *) req->data;
00146
00147 curl_multi_socket_action(curl_handle, context->sockfd, flags,
00148 &running_handles);
00149
00150 check_multi_info();
00151 }
00152
00153 void on_timeout(uv_timer_t *req, int status)
00154 {
00155 int running_handles;
00156 curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0,
00157 &running_handles);
00158 check_multi_info();
00159 }
00160
00161 void start_timeout(CURLM *multi, long timeout_ms, void *userp)
00162 {
00163 if(timeout_ms <= 0)
00164 timeout_ms = 1;
00165
00166 uv_timer_start(&timeout, on_timeout, timeout_ms, 0);
00167 }
00168
00169 int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp,
00170 void *socketp)
00171 {
00172 curl_context_t *curl_context;
00173 int events = 0;
00174
00175 switch(action) {
00176 case CURL_POLL_IN:
00177 case CURL_POLL_OUT:
00178 case CURL_POLL_INOUT:
00179 curl_context = socketp ?
00180 (curl_context_t *) socketp : create_curl_context(s);
00181
00182 curl_multi_assign(curl_handle, s, (void *) curl_context);
00183
00184 if(action != CURL_POLL_IN)
00185 events |= UV_WRITABLE;
00186 if(action != CURL_POLL_OUT)
00187 events |= UV_READABLE;
00188
00189 uv_poll_start(&curl_context->poll_handle, events, curl_perform);
00190 break;
00191 case CURL_POLL_REMOVE:
00192 if(socketp) {
00193 uv_poll_stop(&((curl_context_t*)socketp)->poll_handle);
00194 destroy_curl_context((curl_context_t*) socketp);
00195 curl_multi_assign(curl_handle, s, NULL);
00196 }
00197 break;
00198 default:
00199 abort();
00200 }
00201
00202 return 0;
00203 }
00204
00205 int main(int argc, char **argv)
00206 {
00207 loop = uv_default_loop();
00208
00209 if(argc <= 1)
00210 return 0;
00211
00212 if(curl_global_init(CURL_GLOBAL_ALL)) {
00213 fprintf(stderr, "Could not init curl\n");
00214 return 1;
00215 }
00216
00217 uv_timer_init(loop, &timeout);
00218
00219 curl_handle = curl_multi_init();
00220 curl_multi_setopt(curl_handle, CURLMOPT_SOCKETFUNCTION, handle_socket);
00221 curl_multi_setopt(curl_handle, CURLMOPT_TIMERFUNCTION, start_timeout);
00222
00223 while(argc-- > 1) {
00224 add_download(argv[argc], argc);
00225 }
00226
00227 uv_run(loop, UV_RUN_DEFAULT);
00228 curl_multi_cleanup(curl_handle);
00229
00230 return 0;
00231 }