9 #include <sys/select.h>
11 #include <sys/types.h>
19 * fix connect-timeouts
23 static int cb_write(char *data
, size_t size
, size_t nmemb
, struct grow
*gr
)
25 /* printf("zapisuju %d do %d, %d\n", (int) (size * nmemb), gr->ptr, gr->size); */
26 return grow_append(gr
, data
, size
*nmemb
);
29 /* Date: Tue, 23 Oct 2007 23:42:30 GMT */
30 /* Last-Modified: Mon, 22 Oct 2007 03:25:53 GMT */
32 #define DATE_HDR "Date: "
33 #define LASM_HDR "Last-Modified: "
34 #define CONL_HDR "Content-length: "
35 #define SCC(s,q) !strncasecmp(s,q,strlen(q))
37 static int cb_stat(char *data
, size_t size
, size_t nmemb
, struct stat
*st
)
39 size_t sz
= size
* nmemb
;
41 /* XXX buffer not ended with 0 */
42 if (SCC(data
, DATE_HDR
)) {
44 st
->st_mtime
= curl_getdate(data
+strlen(DATE_HDR
), NULL
);
45 } else if (SCC(data
, LASM_HDR
)) {
46 st
->st_mtime
= curl_getdate(data
+strlen(LASM_HDR
), NULL
);
47 } else if (SCC(data
, CONL_HDR
)) {
48 st
->st_size
= (long long) atol(data
+strlen(CONL_HDR
));
54 static inline int unixerr(CURLcode ret
, long errcode
, int data
)
59 case CURLE_COULDNT_RESOLVE_HOST
:
61 case CURLE_OPERATION_TIMEDOUT
:
63 /* case CURLE_RANGE_ERROR: */
72 case 404: return -ENOENT
;
73 case 403: return -EPERM
;
74 case 301: return -EMLINK
;
76 case 206: return data
;
77 default: return -EBUSY
;
83 void wait(CURLM
*handle
)
92 dbg("fetch: waiting\n");
93 curl_multi_fdset(handle
, &r
, &w
, &e
, &maxfd
);
94 select(maxfd
, &r
, &w
, &e
, &tv
);
97 #define CH(s) { CURLcode _code; _code = s; if (_code != CURLE_OK) { fprintf(stderr, "Error: %s\n%s\n", #s, errbuf); return -EIO; } }
99 int request(CURL
*conn
, char *url
, int head
, struct stat
*st
, struct grow
*data
, size_t size
, off_t offset
)
102 char errbuf
[CURL_ERROR_SIZE
];
106 dbg("fetch url:\"%s\" head:%d st:%p data:%p size:%lu off:%ld\n", url
, head
, st
, data
, size
, offset
);
108 /* CH(curl_easy_setopt(conn, CURLOPT_VERBOSE, 1)); */
109 CH(curl_easy_setopt(conn
, CURLOPT_ERRORBUFFER
, errbuf
));
110 CH(curl_easy_setopt(conn
, CURLOPT_URL
, url
));
111 CH(curl_easy_setopt(conn
, CURLOPT_WRITEFUNCTION
, data
? cb_write
: NULL
));
112 CH(curl_easy_setopt(conn
, CURLOPT_WRITEDATA
, data
? data
: NULL
));
113 CH(curl_easy_setopt(conn
, CURLOPT_HEADERFUNCTION
, st
? cb_stat
: NULL
));
114 CH(curl_easy_setopt(conn
, CURLOPT_HEADERDATA
, st
? st
: NULL
));
115 CH(curl_easy_setopt(conn
, CURLOPT_NOBODY
, head
));
116 /* CH(curl_easy_setopt(conn, CURLOPT_TIMEOUT, 30)); */
118 CH(curl_easy_setopt(conn
, CURLOPT_CUSTOMREQUEST
, "HEAD"));
120 CH(curl_easy_setopt(conn
, CURLOPT_CUSTOMREQUEST
, NULL
));
121 CH(curl_easy_setopt(conn
, CURLOPT_HTTPGET
, 1));
125 /* FIXME: may overflow when downloading larger files (eg iso images) */
126 snprintf(range
, 32, "%ld-%ld", (long) offset
, (long) (offset
+size
-1));
127 dbg("range: \"%s\"\n", range
);
128 CH(curl_easy_setopt(conn
, CURLOPT_RANGE
, range
));
130 CH(curl_easy_setopt(conn
, CURLOPT_RANGE
, NULL
));
133 ret
= curl_easy_perform(conn
);
134 curl_easy_getinfo(conn
, CURLINFO_RESPONSE_CODE
, &errcode
);
136 dbg("fetch done, ret:%d code: %ld\n", ret
, errcode
);
137 return unixerr(ret
, errcode
, data
?data
->ptr
:0);
140 /* nebylo by treba storovat tady i CURL */
141 int request_open_async(struct handle
*h
, off_t offset
, size_t size
)
143 char errbuf
[CURL_ERROR_SIZE
];
147 dbg("setupuju async\n");
149 mult
= curl_multi_init();
153 conn
= curl_easy_init();
155 curl_multi_cleanup(mult
);
159 CH(curl_easy_setopt(conn
, CURLOPT_ERRORBUFFER
, errbuf
));
160 CH(curl_easy_setopt(conn
, CURLOPT_VERBOSE
, 1));
161 CH(curl_easy_setopt(conn
, CURLOPT_URL
, h
->url
.s
));
162 CH(curl_easy_setopt(conn
, CURLOPT_WRITEFUNCTION
, cb_write
));
163 CH(curl_easy_setopt(conn
, CURLOPT_WRITEDATA
, &h
->lover
));
164 /* CH(curl_easy_setopt(conn, CURLOPT_TIMEOUT, 30)); */
166 snprintf(h
->range
, 32, "%ld-%ld", (long) offset
, (long) (offset
+size
-1));
167 dbg("range: \"%s\"\n", h
->range
);
168 CH(curl_easy_setopt(conn
, CURLOPT_RANGE
, h
->range
));
171 CH(curl_multi_add_handle(mult
, conn
));
178 void request_close_async(struct handle
*h
)
180 dbg("async; cleanup\n");
181 if (!request_done(h
)) {
182 curl_multi_remove_handle(h
->mult
, h
->conn
);
183 curl_easy_cleanup(h
->conn
);
184 curl_multi_cleanup(h
->mult
);
190 int request_perf_async(struct handle
*h
, size_t todo
, int *done
)
196 dbg("async: todo: %d, ctu %p %p, mam precist %d\n", todo
, h
->conn
, h
->mult
, h
->lover
.size
);
197 while (h
->lover
.ptr
< todo
) {
201 ret
= curl_multi_perform(h
->mult
, &left
);
204 dbg("--- MULTI PERFORM ERROR %d ---\n", ret
);
208 while((msg
= curl_multi_info_read(h
->mult
, &left
))) {
209 curl_easy_getinfo(msg
->easy_handle
, CURLINFO_RESPONSE_CODE
, &code
);
210 if (msg
->msg
== CURLMSG_DONE
) {
211 int ret
= unixerr(msg
->data
.result
, code
, h
->lover
.ptr
);
212 dbg("async: konec %d %d\n", msg
->data
.result
, code
);
219 dbg("async: vracim %d\n", h
->lover
.ptr
);