xref: /third_party/curl/tests/libtest/lib1565.c (revision 13498266)
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
38static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
39static CURL *pending_handles[CONN_NUM];
40static int pending_num = 0;
41static int test_failure = 0;
42
43static CURLM *multi = NULL;
44static const char *url;
45
46static 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
78test_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
92int 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
183test_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 */
204int test(char *URL)
205{
206  (void)URL;
207  return 0;
208}
209#endif
210