xref: /curl/tests/libtest/lib1565.c (revision 25cbc2f7)
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 CURLcode test_failure = CURLE_OK;
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   CURLcode res = CURLE_OK;
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 CURLcode test(char *URL)
93 {
94   int still_running;
95   int num;
96   int i;
97   int result;
98   CURLcode res = CURLE_OK;
99   CURL *started_handles[CONN_NUM];
100   int started_num = 0;
101   int finished_num = 0;
102   pthread_t tid;
103   bool tid_valid = false;
104   struct CURLMsg *message;
105 
106   start_test_timing();
107 
108   global_init(CURL_GLOBAL_ALL);
109 
110   multi_init(multi);
111 
112   url = URL;
113 
114   result = pthread_create(&tid, NULL, run_thread, NULL);
115   if(!result)
116     tid_valid = true;
117   else {
118     fprintf(stderr, "%s:%d Couldn't create thread, errno %d\n",
119             __FILE__, __LINE__, result);
120     goto test_cleanup;
121   }
122 
123   while(1) {
124     multi_perform(multi, &still_running);
125 
126     abort_on_test_timeout();
127 
128     while((message = curl_multi_info_read(multi, &num))) {
129       if(message->msg == CURLMSG_DONE) {
130         res = message->data.result;
131         if(res)
132           goto test_cleanup;
133         multi_remove_handle(multi, message->easy_handle);
134         finished_num++;
135       }
136       else {
137         fprintf(stderr, "%s:%d Got an unexpected message from curl: %i\n",
138               __FILE__, __LINE__, (int)message->msg);
139         res = TEST_ERR_MAJOR_BAD;
140         goto test_cleanup;
141       }
142 
143       abort_on_test_timeout();
144     }
145 
146     if(CONN_NUM == finished_num)
147       break;
148 
149     multi_poll(multi, NULL, 0, TEST_HANG_TIMEOUT, &num);
150 
151     abort_on_test_timeout();
152 
153     pthread_mutex_lock(&lock);
154 
155     while(pending_num > 0) {
156       res_multi_add_handle(multi, pending_handles[pending_num - 1]);
157       if(res) {
158         pthread_mutex_unlock(&lock);
159         goto test_cleanup;
160       }
161 
162       started_handles[started_num] = pending_handles[pending_num - 1];
163       started_num++;
164       pending_num--;
165     }
166 
167     pthread_mutex_unlock(&lock);
168 
169     abort_on_test_timeout();
170   }
171 
172   if(CONN_NUM != started_num) {
173     fprintf(stderr, "%s:%d Not all connections started: %d of %d\n",
174             __FILE__, __LINE__, started_num, CONN_NUM);
175     goto test_cleanup;
176   }
177 
178   if(CONN_NUM != finished_num) {
179     fprintf(stderr, "%s:%d Not all connections finished: %d of %d\n",
180             __FILE__, __LINE__, started_num, CONN_NUM);
181     goto test_cleanup;
182   }
183 
184 test_cleanup:
185 
186   pthread_mutex_lock(&lock);
187   if(!test_failure)
188     test_failure = res;
189   pthread_mutex_unlock(&lock);
190 
191   if(tid_valid)
192     pthread_join(tid, NULL);
193 
194   curl_multi_cleanup(multi);
195   for(i = 0; i < pending_num; i++)
196     curl_easy_cleanup(pending_handles[i]);
197   for(i = 0; i < started_num; i++)
198     curl_easy_cleanup(started_handles[i]);
199   curl_global_cleanup();
200 
201   return test_failure;
202 }
203 
204 #else /* without pthread, this test doesn't work */
test(char * URL)205 CURLcode test(char *URL)
206 {
207   (void)URL;
208   return 0;
209 }
210 #endif
211