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