0418b6ba20945b895c763b867b5bcb318d4d21ce
[external/curl.git] / tests / libtest / lib526.c
1 /*****************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  */
9
10 /*
11  * This code sets up multiple easy handles that transfer a single file from
12  * the same URL, in a serial manner after each other. Due to the connection
13  * sharing within the multi handle all transfers are performed on the same
14  * persistent connection.
15  *
16  * This source code is used for lib526, lib527 and lib532 with only #ifdefs
17  * controlling the small differences.
18  *
19  * - lib526 closes all easy handles after
20  *   they all have transfered the file over the single connection
21  * - lib527 closes each easy handle after each single transfer.
22  * - lib532 uses only a single easy handle that is removed, reset and then
23  *   re-added for each transfer
24  *
25  * Test case 526, 527 and 532 use FTP, while test 528 uses the lib526 tool but
26  * with HTTP.
27  */
28
29 #include "test.h"
30
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34
35 #include "testutil.h"
36 #include "memdebug.h"
37
38 #define MAIN_LOOP_HANG_TIMEOUT     90 * 1000
39 #define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000
40
41 #define NUM_HANDLES 4
42
43 int test(char *URL)
44 {
45   int res = 0;
46   CURL *curl[NUM_HANDLES];
47   int running;
48   char done=FALSE;
49   CURLM *m = NULL;
50   int current=0;
51   int i, j;
52   struct timeval ml_start;
53   struct timeval mp_start;
54   char ml_timedout = FALSE;
55   char mp_timedout = FALSE;
56
57   if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
58     fprintf(stderr, "curl_global_init() failed\n");
59     return TEST_ERR_MAJOR_BAD;
60   }
61
62   /* get NUM_HANDLES easy handles */
63   for(i=0; i < NUM_HANDLES; i++) {
64     curl[i] = curl_easy_init();
65     if(!curl[i]) {
66       fprintf(stderr, "curl_easy_init() failed "
67               "on handle #%d\n", i);
68       for (j=i-1; j >= 0; j--) {
69         curl_easy_cleanup(curl[j]);
70       }
71       curl_global_cleanup();
72       return TEST_ERR_MAJOR_BAD + i;
73     }
74     res = curl_easy_setopt(curl[i], CURLOPT_URL, URL);
75     if(res) {
76       fprintf(stderr, "curl_easy_setopt() failed "
77               "on handle #%d\n", i);
78       for (j=i; j >= 0; j--) {
79         curl_easy_cleanup(curl[j]);
80       }
81       curl_global_cleanup();
82       return TEST_ERR_MAJOR_BAD + i;
83     }
84
85     /* go verbose */
86     res = curl_easy_setopt(curl[i], CURLOPT_VERBOSE, 1L);
87     if(res) {
88       fprintf(stderr, "curl_easy_setopt() failed "
89               "on handle #%d\n", i);
90       for (j=i; j >= 0; j--) {
91         curl_easy_cleanup(curl[j]);
92       }
93       curl_global_cleanup();
94       return TEST_ERR_MAJOR_BAD + i;
95     }
96   }
97
98   if ((m = curl_multi_init()) == NULL) {
99     fprintf(stderr, "curl_multi_init() failed\n");
100     for(i=0; i < NUM_HANDLES; i++) {
101       curl_easy_cleanup(curl[i]);
102     }
103     curl_global_cleanup();
104     return TEST_ERR_MAJOR_BAD;
105   }
106
107   if ((res = (int)curl_multi_add_handle(m, curl[current])) != CURLM_OK) {
108     fprintf(stderr, "curl_multi_add_handle() failed, "
109             "with code %d\n", res);
110     curl_multi_cleanup(m);
111     for(i=0; i < NUM_HANDLES; i++) {
112       curl_easy_cleanup(curl[i]);
113     }
114     curl_global_cleanup();
115     return TEST_ERR_MAJOR_BAD;
116   }
117
118   ml_timedout = FALSE;
119   ml_start = tutil_tvnow();
120
121   fprintf(stderr, "Start at URL 0\n");
122
123   while (!done) {
124     fd_set rd, wr, exc;
125     int max_fd;
126     struct timeval interval;
127
128     interval.tv_sec = 1;
129     interval.tv_usec = 0;
130
131     if (tutil_tvdiff(tutil_tvnow(), ml_start) >
132         MAIN_LOOP_HANG_TIMEOUT) {
133       ml_timedout = TRUE;
134       break;
135     }
136     mp_timedout = FALSE;
137     mp_start = tutil_tvnow();
138
139     while (res == CURLM_CALL_MULTI_PERFORM) {
140       res = (int)curl_multi_perform(m, &running);
141       if (tutil_tvdiff(tutil_tvnow(), mp_start) >
142           MULTI_PERFORM_HANG_TIMEOUT) {
143         mp_timedout = TRUE;
144         break;
145       }
146       if (running <= 0) {
147 #ifdef LIB527
148         /* NOTE: this code does not remove the handle from the multi handle
149            here, which would be the nice, sane and documented way of working.
150            This however tests that the API survives this abuse gracefully. */
151         curl_easy_cleanup(curl[current]);
152 #endif
153         if(++current < NUM_HANDLES) {
154           fprintf(stderr, "Advancing to URL %d\n", current);
155 #ifdef LIB532
156           /* first remove the only handle we use */
157           curl_multi_remove_handle(m, curl[0]);
158
159           /* make us re-use the same handle all the time, and try resetting
160              the handle first too */
161           curl_easy_reset(curl[0]);
162           test_setopt(curl[0], CURLOPT_URL, URL);
163           test_setopt(curl[0], CURLOPT_VERBOSE, 1L);
164
165           /* re-add it */
166           res = (int)curl_multi_add_handle(m, curl[0]);
167 #else
168           res = (int)curl_multi_add_handle(m, curl[current]);
169 #endif
170           if(res) {
171             fprintf(stderr, "add handle failed: %d.\n", res);
172             res = 243;
173             break;
174           }
175         }
176         else
177           done = TRUE; /* bail out */
178         break;
179       }
180     }
181     if (mp_timedout || done)
182       break;
183
184     if (res != CURLM_OK) {
185       fprintf(stderr, "not okay???\n");
186       break;
187     }
188
189     FD_ZERO(&rd);
190     FD_ZERO(&wr);
191     FD_ZERO(&exc);
192     max_fd = 0;
193
194     if (curl_multi_fdset(m, &rd, &wr, &exc, &max_fd) != CURLM_OK) {
195       fprintf(stderr, "unexpected failured of fdset.\n");
196       res = 189;
197       break;
198     }
199
200     if (select_test(max_fd+1, &rd, &wr, &exc, &interval) == -1) {
201       fprintf(stderr, "bad select??\n");
202       res = 195;
203       break;
204     }
205
206     res = CURLM_CALL_MULTI_PERFORM;
207   }
208
209   if (ml_timedout || mp_timedout) {
210     if (ml_timedout) fprintf(stderr, "ml_timedout\n");
211     if (mp_timedout) fprintf(stderr, "mp_timedout\n");
212     fprintf(stderr, "ABORTING TEST, since it seems "
213             "that it would have run forever.\n");
214     res = TEST_ERR_RUNS_FOREVER;
215   }
216
217 #ifdef LIB532
218 test_cleanup:
219 #endif
220
221 #ifndef LIB527
222   /* get NUM_HANDLES easy handles */
223   for(i=0; i < NUM_HANDLES; i++) {
224 #ifdef LIB526
225     if(m)
226       curl_multi_remove_handle(m, curl[i]);
227 #endif
228     curl_easy_cleanup(curl[i]);
229   }
230 #endif
231   if(m)
232     curl_multi_cleanup(m);
233
234   curl_global_cleanup();
235   return res;
236 }