lib3207.c 5.9 KB

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