00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "test.h"
00023
00024 #ifdef HAVE_LIMITS_H
00025 #include <limits.h>
00026 #endif
00027 #include <assert.h>
00028
00029 #include "testutil.h"
00030 #include "warnless.h"
00031 #include "memdebug.h"
00032
00033 #define TEST_HANG_TIMEOUT 5 * 1000
00034 #define MAX_EASY_HANDLES 3
00035
00036 static CURL *easy[MAX_EASY_HANDLES];
00037 static curl_socket_t sockets[MAX_EASY_HANDLES];
00038 static int res = 0;
00039
00040 static size_t callback(char *ptr, size_t size, size_t nmemb, void *data)
00041 {
00042 ssize_t idx = ((CURL **) data) - easy;
00043 curl_socket_t sock;
00044 long longdata;
00045 CURLcode code;
00046
00047 const size_t failure = (size * nmemb) ? 0 : 1;
00048
00049 char *output = malloc(size * nmemb + 1);
00050 if(!output) {
00051 fprintf(stderr, "output, malloc() failed\n");
00052 res = TEST_ERR_MAJOR_BAD;
00053 return failure;
00054 }
00055
00056 memcpy(output, ptr, size * nmemb);
00057 output[size * nmemb] = '\0';
00058 fprintf(stdout, "%s", output);
00059 free(output);
00060
00061
00062 code = curl_easy_getinfo(easy[idx], CURLINFO_LASTSOCKET, &longdata);
00063 if(CURLE_OK != code) {
00064 fprintf(stderr, "%s:%d curl_easy_getinfo() failed, "
00065 "with code %d (%s)\n",
00066 __FILE__, __LINE__, (int)code, curl_easy_strerror(code));
00067 res = TEST_ERR_MAJOR_BAD;
00068 return failure;
00069 }
00070 if(longdata == -1L)
00071 sock = CURL_SOCKET_BAD;
00072 else
00073 sock = (curl_socket_t)longdata;
00074
00075 if(sock != CURL_SOCKET_BAD) {
00076
00077 if(sockets[idx] == CURL_SOCKET_BAD) {
00078
00079 sockets[idx] = sock;
00080 }
00081 else if(sock != sockets[idx]) {
00082
00083
00084 fprintf(stderr, "Handle %d started on socket %d and moved to %d\n",
00085 curlx_sztosi(idx), (int)sockets[idx], (int)sock);
00086 res = TEST_ERR_MAJOR_BAD;
00087 return failure;
00088 }
00089 }
00090 return size * nmemb;
00091 }
00092
00093 enum HandleState {
00094 ReadyForNewHandle,
00095 NeedSocketForNewHandle,
00096 NoMoreHandles
00097 };
00098
00099 int test(char *url)
00100 {
00101 CURLM *multi = NULL;
00102 int running;
00103 int i, j;
00104 int num_handles = 0;
00105 enum HandleState state = ReadyForNewHandle;
00106 size_t urllen = strlen(url) + 4 + 1;
00107 char *full_url = malloc(urllen);
00108
00109 start_test_timing();
00110
00111 if(!full_url) {
00112 fprintf(stderr, "Not enough memory for full url\n");
00113 return TEST_ERR_MAJOR_BAD;
00114 }
00115
00116 for(i = 0; i < MAX_EASY_HANDLES; ++i) {
00117 easy[i] = NULL;
00118 sockets[i] = CURL_SOCKET_BAD;
00119 }
00120
00121 res_global_init(CURL_GLOBAL_ALL);
00122 if(res) {
00123 free(full_url);
00124 return res;
00125 }
00126
00127 multi_init(multi);
00128
00129 #ifdef USE_PIPELINING
00130 multi_setopt(multi, CURLMOPT_PIPELINING, 1L);
00131 multi_setopt(multi, CURLMOPT_MAX_HOST_CONNECTIONS, 5L);
00132 multi_setopt(multi, CURLMOPT_MAX_TOTAL_CONNECTIONS, 10L);
00133 #endif
00134
00135 for(;;) {
00136 struct timeval interval;
00137 fd_set fdread;
00138 fd_set fdwrite;
00139 fd_set fdexcep;
00140 long timeout = -99;
00141 int maxfd = -99;
00142 bool found_new_socket = FALSE;
00143
00144
00145 if(state == ReadyForNewHandle) {
00146 easy_init(easy[num_handles]);
00147
00148 if(num_handles % 3 == 2) {
00149 snprintf(full_url, urllen, "%s0200", url);
00150 easy_setopt(easy[num_handles], CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
00151 }
00152 else {
00153 snprintf(full_url, urllen, "%s0100", url);
00154 easy_setopt(easy[num_handles], CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
00155 }
00156 easy_setopt(easy[num_handles], CURLOPT_FRESH_CONNECT, 1L);
00157 easy_setopt(easy[num_handles], CURLOPT_URL, full_url);
00158 easy_setopt(easy[num_handles], CURLOPT_VERBOSE, 1L);
00159 easy_setopt(easy[num_handles], CURLOPT_HTTPGET, 1L);
00160 easy_setopt(easy[num_handles], CURLOPT_USERPWD, "testuser:testpass");
00161 easy_setopt(easy[num_handles], CURLOPT_WRITEFUNCTION, callback);
00162 easy_setopt(easy[num_handles], CURLOPT_WRITEDATA, easy + num_handles);
00163 easy_setopt(easy[num_handles], CURLOPT_HEADER, 1L);
00164
00165 multi_add_handle(multi, easy[num_handles]);
00166 num_handles += 1;
00167 state = NeedSocketForNewHandle;
00168 }
00169
00170 multi_perform(multi, &running);
00171
00172 abort_on_test_timeout();
00173
00174 if(!running && state == NoMoreHandles)
00175 break;
00176
00177 FD_ZERO(&fdread);
00178 FD_ZERO(&fdwrite);
00179 FD_ZERO(&fdexcep);
00180
00181 multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd);
00182
00183
00184
00185
00186 for(i = 0; i <= maxfd; ++i) {
00187 bool socket_exists = FALSE;
00188 curl_socket_t curfd = (curl_socket_t)i;
00189
00190 if(!FD_ISSET(curfd, &fdread)) {
00191 continue;
00192 }
00193
00194
00195
00196 for(j = 0; j < num_handles; ++j) {
00197 if(sockets[j] == curfd) {
00198 socket_exists = TRUE;
00199 break;
00200 }
00201 }
00202 if(socket_exists) {
00203 continue;
00204 }
00205
00206 if(found_new_socket || state != NeedSocketForNewHandle) {
00207 fprintf(stderr, "Unexpected new socket\n");
00208 res = TEST_ERR_MAJOR_BAD;
00209 goto test_cleanup;
00210 }
00211
00212
00213 if(sockets[num_handles-1] != CURL_SOCKET_BAD) {
00214
00215
00216 assert(curfd != sockets[num_handles-1]);
00217 fprintf(stderr, "Handle %d wrote to socket %d then detected on %d\n",
00218 num_handles-1, (int)sockets[num_handles-1], (int)curfd);
00219 res = TEST_ERR_MAJOR_BAD;
00220 goto test_cleanup;
00221 }
00222 else {
00223 sockets[num_handles-1] = curfd;
00224 found_new_socket = TRUE;
00225
00226 }
00227 }
00228
00229 if(state == NeedSocketForNewHandle) {
00230 if(maxfd != -1 && !found_new_socket) {
00231 fprintf(stderr, "Warning: socket did not open immediately for new "
00232 "handle (trying again)\n");
00233 continue;
00234 }
00235 state = num_handles < MAX_EASY_HANDLES ? ReadyForNewHandle
00236 : NoMoreHandles;
00237 }
00238
00239 multi_timeout(multi, &timeout);
00240
00241
00242
00243 fprintf(stderr, "%s:%d num_handles %d timeout %ld\n",
00244 __FILE__, __LINE__, num_handles, timeout);
00245
00246 if(timeout != -1L) {
00247 int itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout;
00248 interval.tv_sec = itimeout/1000;
00249 interval.tv_usec = (itimeout%1000)*1000;
00250 }
00251 else {
00252 interval.tv_sec = TEST_HANG_TIMEOUT/1000+1;
00253 interval.tv_usec = 0;
00254
00255
00256
00257
00258 if(!running && num_handles == MAX_EASY_HANDLES) {
00259 break;
00260 }
00261 }
00262
00263 select_test(maxfd+1, &fdread, &fdwrite, &fdexcep, &interval);
00264
00265 abort_on_test_timeout();
00266 }
00267
00268 test_cleanup:
00269
00270
00271
00272 for(i = 0; i < MAX_EASY_HANDLES; i++) {
00273 curl_multi_remove_handle(multi, easy[i]);
00274 curl_easy_cleanup(easy[i]);
00275 }
00276
00277 curl_multi_cleanup(multi);
00278 curl_global_cleanup();
00279
00280 free(full_url);
00281
00282 return res;
00283 }