lib3207.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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. #include "testutil.h"
  26. #include "memdebug.h"
  27. #include <stdio.h>
  28. #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
  29. #if defined(USE_THREADS_POSIX)
  30. #include <pthread.h>
  31. #endif
  32. #include "curl_threads.h"
  33. #endif
  34. #define CAINFO libtest_arg2
  35. #define THREAD_SIZE 16
  36. #define PER_THREAD_SIZE 8
  37. struct Ctx {
  38. const char *URL;
  39. CURLSH *share;
  40. int result;
  41. int thread_id;
  42. struct curl_slist *contents;
  43. };
  44. static size_t write_memory_callback(char *contents, size_t size,
  45. size_t nmemb, void *userp)
  46. {
  47. /* append the data to contents */
  48. size_t realsize = size * nmemb;
  49. struct Ctx *mem = (struct Ctx *)userp;
  50. char *data = (char *)malloc(realsize + 1);
  51. struct curl_slist *item_append = NULL;
  52. if(!data) {
  53. printf("not enough memory (malloc returned NULL)\n");
  54. return 0;
  55. }
  56. memcpy(data, contents, realsize);
  57. data[realsize] = '\0';
  58. item_append = curl_slist_append(mem->contents, data);
  59. free(data);
  60. if(item_append) {
  61. mem->contents = item_append;
  62. }
  63. else {
  64. printf("not enough memory (curl_slist_append returned NULL)\n");
  65. return 0;
  66. }
  67. return realsize;
  68. }
  69. static
  70. #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
  71. #if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
  72. DWORD
  73. #else
  74. unsigned int
  75. #endif
  76. CURL_STDCALL
  77. #else
  78. unsigned int
  79. #endif
  80. test_thread(void *ptr)
  81. {
  82. struct Ctx *ctx = (struct Ctx *)ptr;
  83. CURLcode res = CURLE_OK;
  84. int i;
  85. /* Loop the transfer and cleanup the handle properly every lap. This will
  86. still reuse ssl session since the pool is in the shared object! */
  87. for(i = 0; i < PER_THREAD_SIZE; i++) {
  88. CURL *curl = curl_easy_init();
  89. if(curl) {
  90. curl_easy_setopt(curl, CURLOPT_URL, (char *)ctx->URL);
  91. /* use the share object */
  92. curl_easy_setopt(curl, CURLOPT_SHARE, ctx->share);
  93. curl_easy_setopt(curl, CURLOPT_CAINFO, CAINFO);
  94. curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_memory_callback);
  95. curl_easy_setopt(curl, CURLOPT_WRITEDATA, ptr);
  96. curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
  97. /* Perform the request, res will get the return code */
  98. res = curl_easy_perform(curl);
  99. /* always cleanup */
  100. curl_easy_cleanup(curl);
  101. /* Check for errors */
  102. if(res != CURLE_OK) {
  103. fprintf(stderr, "curl_easy_perform() failed: %s\n",
  104. curl_easy_strerror(res));
  105. goto test_cleanup;
  106. }
  107. }
  108. }
  109. test_cleanup:
  110. ctx->result = (int)res;
  111. return 0;
  112. }
  113. #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
  114. static void test_lock(CURL *handle, curl_lock_data data,
  115. curl_lock_access laccess, void *useptr)
  116. {
  117. curl_mutex_t *mutexes = (curl_mutex_t*) useptr;
  118. (void)handle;
  119. (void)laccess;
  120. Curl_mutex_acquire(&mutexes[data]);
  121. }
  122. static void test_unlock(CURL *handle, curl_lock_data data, void *useptr)
  123. {
  124. curl_mutex_t *mutexes = (curl_mutex_t*) useptr;
  125. (void)handle;
  126. Curl_mutex_release(&mutexes[data]);
  127. }
  128. static void execute(CURLSH *share, struct Ctx *ctx)
  129. {
  130. int i;
  131. curl_mutex_t mutexes[CURL_LOCK_DATA_LAST - 1];
  132. curl_thread_t thread[THREAD_SIZE];
  133. for(i = 0; i < CURL_LOCK_DATA_LAST - 1; i++) {
  134. Curl_mutex_init(&mutexes[i]);
  135. }
  136. curl_share_setopt(share, CURLSHOPT_LOCKFUNC, test_lock);
  137. curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, test_unlock);
  138. curl_share_setopt(share, CURLSHOPT_USERDATA, (void *)mutexes);
  139. curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);
  140. for(i = 0; i < THREAD_SIZE; i++) {
  141. thread[i] = Curl_thread_create(test_thread, (void *)&ctx[i]);
  142. }
  143. for(i = 0; i < THREAD_SIZE; i++) {
  144. if(thread[i]) {
  145. Curl_thread_join(&thread[i]);
  146. Curl_thread_destroy(thread[i]);
  147. }
  148. }
  149. curl_share_setopt(share, CURLSHOPT_LOCKFUNC, NULL);
  150. curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, NULL);
  151. for(i = 0; i < CURL_LOCK_DATA_LAST - 1; i++) {
  152. Curl_mutex_destroy(&mutexes[i]);
  153. }
  154. }
  155. #else /* without pthread, run serially */
  156. static void execute(CURLSH *share, struct Ctx *ctx)
  157. {
  158. int i;
  159. (void) share;
  160. for(i = 0; i < THREAD_SIZE; i++) {
  161. test_thread((void *)&ctx[i]);
  162. }
  163. }
  164. #endif
  165. CURLcode test(char *URL)
  166. {
  167. int res = 0;
  168. int i;
  169. CURLSH* share;
  170. struct Ctx ctx[THREAD_SIZE];
  171. curl_global_init(CURL_GLOBAL_ALL);
  172. share = curl_share_init();
  173. if(!share) {
  174. fprintf(stderr, "curl_share_init() failed\n");
  175. goto test_cleanup;
  176. }
  177. for(i = 0; i < THREAD_SIZE; i++) {
  178. ctx[i].share = share;
  179. ctx[i].URL = URL;
  180. ctx[i].thread_id = i;
  181. ctx[i].result = 0;
  182. ctx[i].contents = NULL;
  183. }
  184. execute(share, ctx);
  185. for(i = 0; i < THREAD_SIZE; i++) {
  186. if(ctx[i].result) {
  187. res = ctx[i].result;
  188. }
  189. else {
  190. struct curl_slist *item = ctx[i].contents;
  191. while(item) {
  192. printf("%s", item->data);
  193. item = item->next;
  194. }
  195. }
  196. curl_slist_free_all(ctx[i].contents);
  197. }
  198. test_cleanup:
  199. if(share)
  200. curl_share_cleanup(share);
  201. curl_global_cleanup();
  202. return (CURLcode)res;
  203. }