• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 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 https://curl.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  * SPDX-License-Identifier: curl
22  *
23  ***************************************************************************/
24 #include "test.h"
25 
26 #include "testutil.h"
27 #include "warnless.h"
28 #include "memdebug.h"
29 
30 #ifdef HAVE_PTHREAD_H
31 #include <pthread.h>
32 #include <unistd.h>
33 
34 #define TEST_HANG_TIMEOUT 60 * 1000
35 #define CONN_NUM 3
36 #define TIME_BETWEEN_START_SECS 2
37 
38 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
39 static CURL *pending_handles[CONN_NUM];
40 static int pending_num = 0;
41 static int test_failure = 0;
42 
43 static CURLM *multi = NULL;
44 static const char *url;
45 
run_thread(void * ptr)46 static void *run_thread(void *ptr)
47 {
48   CURL *easy = NULL;
49   int res = 0;
50   int i;
51 
52   (void)ptr;
53 
54   for(i = 0; i < CONN_NUM; i++) {
55     wait_ms(TIME_BETWEEN_START_SECS * 1000);
56 
57     easy_init(easy);
58 
59     easy_setopt(easy, CURLOPT_URL, url);
60     easy_setopt(easy, CURLOPT_VERBOSE, 0L);
61 
62     pthread_mutex_lock(&lock);
63 
64     if(test_failure) {
65       pthread_mutex_unlock(&lock);
66       goto test_cleanup;
67     }
68 
69     pending_handles[pending_num] = easy;
70     pending_num++;
71     easy = NULL;
72 
73     pthread_mutex_unlock(&lock);
74 
75     res_multi_wakeup(multi);
76   }
77 
78 test_cleanup:
79 
80   curl_easy_cleanup(easy);
81 
82   pthread_mutex_lock(&lock);
83 
84   if(!test_failure)
85     test_failure = res;
86 
87   pthread_mutex_unlock(&lock);
88 
89   return NULL;
90 }
91 
test(char * URL)92 int test(char *URL)
93 {
94   int still_running;
95   int num;
96   int i;
97   int res = 0;
98   CURL *started_handles[CONN_NUM];
99   int started_num = 0;
100   int finished_num = 0;
101   pthread_t tid;
102   bool tid_valid = false;
103   struct CURLMsg *message;
104 
105   start_test_timing();
106 
107   global_init(CURL_GLOBAL_ALL);
108 
109   multi_init(multi);
110 
111   url = URL;
112 
113   res = pthread_create(&tid, NULL, run_thread, NULL);
114   if(!res)
115     tid_valid = true;
116   else {
117     fprintf(stderr, "%s:%d Couldn't create thread, errno %d\n",
118             __FILE__, __LINE__, res);
119     goto test_cleanup;
120   }
121 
122   while(1) {
123     multi_perform(multi, &still_running);
124 
125     abort_on_test_timeout();
126 
127     while((message = curl_multi_info_read(multi, &num))) {
128       if(message->msg == CURLMSG_DONE) {
129         res = message->data.result;
130         if(res)
131           goto test_cleanup;
132         multi_remove_handle(multi, message->easy_handle);
133         finished_num++;
134       }
135       else {
136         fprintf(stderr, "%s:%d Got an unexpected message from curl: %i\n",
137               __FILE__, __LINE__, (int)message->msg);
138         res = TEST_ERR_MAJOR_BAD;
139         goto test_cleanup;
140       }
141 
142       abort_on_test_timeout();
143     }
144 
145     if(CONN_NUM == finished_num)
146       break;
147 
148     multi_poll(multi, NULL, 0, TEST_HANG_TIMEOUT, &num);
149 
150     abort_on_test_timeout();
151 
152     pthread_mutex_lock(&lock);
153 
154     while(pending_num > 0) {
155       res_multi_add_handle(multi, pending_handles[pending_num - 1]);
156       if(res) {
157         pthread_mutex_unlock(&lock);
158         goto test_cleanup;
159       }
160 
161       started_handles[started_num] = pending_handles[pending_num - 1];
162       started_num++;
163       pending_num--;
164     }
165 
166     pthread_mutex_unlock(&lock);
167 
168     abort_on_test_timeout();
169   }
170 
171   if(CONN_NUM != started_num) {
172     fprintf(stderr, "%s:%d Not all connections started: %d of %d\n",
173             __FILE__, __LINE__, started_num, CONN_NUM);
174     goto test_cleanup;
175   }
176 
177   if(CONN_NUM != finished_num) {
178     fprintf(stderr, "%s:%d Not all connections finished: %d of %d\n",
179             __FILE__, __LINE__, started_num, CONN_NUM);
180     goto test_cleanup;
181   }
182 
183 test_cleanup:
184 
185   pthread_mutex_lock(&lock);
186   if(!test_failure)
187     test_failure = res;
188   pthread_mutex_unlock(&lock);
189 
190   if(tid_valid)
191     pthread_join(tid, NULL);
192 
193   curl_multi_cleanup(multi);
194   for(i = 0; i < pending_num; i++)
195     curl_easy_cleanup(pending_handles[i]);
196   for(i = 0; i < started_num; i++)
197     curl_easy_cleanup(started_handles[i]);
198   curl_global_cleanup();
199 
200   return test_failure;
201 }
202 
203 #else /* without pthread, this test doesn't work */
test(char * URL)204 int test(char *URL)
205 {
206   (void)URL;
207   return 0;
208 }
209 #endif
210