1 | /*************************************************************************** |
2 | * _ _ ____ _ |
3 | * Project ___| | | | _ \| | |
4 | * / __| | | | |_) | | |
5 | * | (__| |_| | _ <| |___ |
6 | * \___|\___/|_| \_\_____| |
7 | * |
8 | * Copyright (C) 2013 - 2019, Linus Nielsen Feltzing, <linus@haxx.se> |
9 | * |
10 | * This software is licensed as described in the file COPYING, which |
11 | * you should have received as part of this distribution. The terms |
12 | * are also available at https://curl.haxx.se/docs/copyright.html. |
13 | * |
14 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
15 | * copies of the Software, and permit persons to whom the Software is |
16 | * furnished to do so, under the terms of the COPYING file. |
17 | * |
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
19 | * KIND, either express or implied. |
20 | * |
21 | ***************************************************************************/ |
22 | #include "test.h" |
23 | |
24 | #include "testutil.h" |
25 | #include "warnless.h" |
26 | #include "memdebug.h" |
27 | |
28 | #define TEST_HANG_TIMEOUT 60 * 1000 |
29 | #define MAX_URLS 200 |
30 | #define MAX_BLACKLIST 20 |
31 | |
32 | static int urltime[MAX_URLS]; |
33 | static char *urlstring[MAX_URLS]; |
34 | static CURL *handles[MAX_URLS]; |
35 | static char *site_blacklist[MAX_BLACKLIST]; |
36 | static char *server_blacklist[MAX_BLACKLIST]; |
37 | static int num_handles; |
38 | static int blacklist_num_servers; |
39 | static int blacklist_num_sites; |
40 | |
41 | static size_t |
42 | write_callback(void *contents, size_t size, size_t nmemb, void *userp) |
43 | { |
44 | size_t realsize = size * nmemb; |
45 | (void)contents; |
46 | (void)userp; |
47 | |
48 | return realsize; |
49 | } |
50 | |
51 | static int parse_url_file(const char *filename) |
52 | { |
53 | FILE *f; |
54 | int filetime; |
55 | char buf[200]; |
56 | |
57 | num_handles = 0; |
58 | blacklist_num_sites = 0; |
59 | blacklist_num_servers = 0; |
60 | |
61 | f = fopen(filename, "rb" ); |
62 | if(!f) |
63 | return 0; |
64 | |
65 | while(!feof(f)) { |
66 | if(fscanf(f, "%d %199s\n" , &filetime, buf)) { |
67 | urltime[num_handles] = filetime; |
68 | urlstring[num_handles] = strdup(buf); |
69 | num_handles++; |
70 | continue; |
71 | } |
72 | |
73 | if(fscanf(f, "blacklist_site %199s\n" , buf)) { |
74 | site_blacklist[blacklist_num_sites] = strdup(buf); |
75 | blacklist_num_sites++; |
76 | continue; |
77 | } |
78 | |
79 | break; |
80 | } |
81 | fclose(f); |
82 | |
83 | site_blacklist[blacklist_num_sites] = NULL; |
84 | server_blacklist[blacklist_num_servers] = NULL; |
85 | return num_handles; |
86 | } |
87 | |
88 | static void free_urls(void) |
89 | { |
90 | int i; |
91 | for(i = 0; i < num_handles; i++) { |
92 | Curl_safefree(urlstring[i]); |
93 | } |
94 | for(i = 0; i < blacklist_num_servers; i++) { |
95 | Curl_safefree(server_blacklist[i]); |
96 | } |
97 | for(i = 0; i < blacklist_num_sites; i++) { |
98 | Curl_safefree(site_blacklist[i]); |
99 | } |
100 | } |
101 | |
102 | static int create_handles(void) |
103 | { |
104 | int i; |
105 | |
106 | for(i = 0; i < num_handles; i++) { |
107 | handles[i] = curl_easy_init(); |
108 | } |
109 | return 0; |
110 | } |
111 | |
112 | static void setup_handle(char *base_url, CURLM *m, int handlenum) |
113 | { |
114 | char urlbuf[256]; |
115 | |
116 | msnprintf(urlbuf, sizeof(urlbuf), "%s%s" , base_url, urlstring[handlenum]); |
117 | curl_easy_setopt(handles[handlenum], CURLOPT_URL, urlbuf); |
118 | curl_easy_setopt(handles[handlenum], CURLOPT_VERBOSE, 1L); |
119 | curl_easy_setopt(handles[handlenum], CURLOPT_FAILONERROR, 1L); |
120 | curl_easy_setopt(handles[handlenum], CURLOPT_WRITEFUNCTION, write_callback); |
121 | curl_easy_setopt(handles[handlenum], CURLOPT_WRITEDATA, NULL); |
122 | curl_multi_add_handle(m, handles[handlenum]); |
123 | } |
124 | |
125 | static void remove_handles(void) |
126 | { |
127 | int i; |
128 | |
129 | for(i = 0; i < num_handles; i++) { |
130 | if(handles[i]) |
131 | curl_easy_cleanup(handles[i]); |
132 | } |
133 | } |
134 | |
135 | int test(char *URL) |
136 | { |
137 | int res = 0; |
138 | CURLM *m = NULL; |
139 | CURLMsg *msg; /* for picking up messages with the transfer status */ |
140 | int msgs_left; /* how many messages are left */ |
141 | int running = 0; |
142 | int handlenum = 0; |
143 | struct timeval last_handle_add; |
144 | |
145 | if(parse_url_file(libtest_arg2) <= 0) |
146 | goto test_cleanup; |
147 | |
148 | start_test_timing(); |
149 | |
150 | curl_global_init(CURL_GLOBAL_ALL); |
151 | |
152 | multi_init(m); |
153 | |
154 | create_handles(); |
155 | |
156 | multi_setopt(m, CURLMOPT_PIPELINING, 1L); |
157 | multi_setopt(m, CURLMOPT_MAX_HOST_CONNECTIONS, 2L); |
158 | multi_setopt(m, CURLMOPT_MAX_PIPELINE_LENGTH, 3L); |
159 | multi_setopt(m, CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, 15000L); |
160 | multi_setopt(m, CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, 10000L); |
161 | |
162 | multi_setopt(m, CURLMOPT_PIPELINING_SITE_BL, site_blacklist); |
163 | multi_setopt(m, CURLMOPT_PIPELINING_SERVER_BL, server_blacklist); |
164 | |
165 | last_handle_add = tutil_tvnow(); |
166 | |
167 | for(;;) { |
168 | struct timeval interval; |
169 | struct timeval now; |
170 | fd_set rd, wr, exc; |
171 | int maxfd = -99; |
172 | long timeout; |
173 | |
174 | interval.tv_sec = 1; |
175 | interval.tv_usec = 0; |
176 | |
177 | if(handlenum < num_handles) { |
178 | now = tutil_tvnow(); |
179 | if(tutil_tvdiff(now, last_handle_add) >= urltime[handlenum]) { |
180 | fprintf(stdout, "Adding handle %d\n" , handlenum); |
181 | setup_handle(URL, m, handlenum); |
182 | last_handle_add = now; |
183 | handlenum++; |
184 | } |
185 | } |
186 | |
187 | curl_multi_perform(m, &running); |
188 | |
189 | abort_on_test_timeout(); |
190 | |
191 | /* See how the transfers went */ |
192 | do { |
193 | msg = curl_multi_info_read(m, &msgs_left); |
194 | if(msg && msg->msg == CURLMSG_DONE) { |
195 | int i; |
196 | |
197 | /* Find out which handle this message is about */ |
198 | for(i = 0; i < num_handles; i++) { |
199 | int found = (msg->easy_handle == handles[i]); |
200 | if(found) |
201 | break; |
202 | } |
203 | |
204 | printf("Handle %d Completed with status %d\n" , i, msg->data.result); |
205 | curl_multi_remove_handle(m, handles[i]); |
206 | } |
207 | } while(msg); |
208 | |
209 | if(handlenum == num_handles && !running) { |
210 | break; /* done */ |
211 | } |
212 | |
213 | FD_ZERO(&rd); |
214 | FD_ZERO(&wr); |
215 | FD_ZERO(&exc); |
216 | |
217 | curl_multi_fdset(m, &rd, &wr, &exc, &maxfd); |
218 | |
219 | /* At this point, maxfd is guaranteed to be greater or equal than -1. */ |
220 | |
221 | curl_multi_timeout(m, &timeout); |
222 | |
223 | if(timeout < 0) |
224 | timeout = 1; |
225 | |
226 | interval.tv_sec = timeout / 1000; |
227 | interval.tv_usec = (timeout % 1000) * 1000; |
228 | |
229 | interval.tv_sec = 0; |
230 | interval.tv_usec = 1000; |
231 | |
232 | select_test(maxfd + 1, &rd, &wr, &exc, &interval); |
233 | |
234 | abort_on_test_timeout(); |
235 | } |
236 | |
237 | test_cleanup: |
238 | |
239 | remove_handles(); |
240 | |
241 | /* undocumented cleanup sequence - type UB */ |
242 | |
243 | curl_multi_cleanup(m); |
244 | curl_global_cleanup(); |
245 | |
246 | free_urls(); |
247 | return res; |
248 | } |
249 | |