threaded-ssl.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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. /* <DESC>
  25. * Show the required mutex callback setups for GnuTLS and OpenSSL when using
  26. * libcurl multi-threaded.
  27. * </DESC>
  28. */
  29. /* A multi-threaded example that uses pthreads and fetches 4 remote files at
  30. * once over HTTPS. The lock callbacks and stuff assume OpenSSL <1.1 or GnuTLS
  31. * (libgcrypt) so far.
  32. *
  33. * OpenSSL docs for this:
  34. * https://www.openssl.org/docs/man1.0.2/man3/CRYPTO_num_locks.html
  35. * gcrypt docs for this:
  36. * https://gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html
  37. */
  38. #define USE_OPENSSL /* or USE_GNUTLS accordingly */
  39. #include <stdio.h>
  40. #include <pthread.h>
  41. #include <curl/curl.h>
  42. #define NUMT 4
  43. /* we have this global to let the callback get easy access to it */
  44. static pthread_mutex_t *lockarray;
  45. #ifdef USE_OPENSSL
  46. #include <openssl/crypto.h>
  47. static void lock_callback(int mode, int type, char *file, int line)
  48. {
  49. (void)file;
  50. (void)line;
  51. if(mode & CRYPTO_LOCK) {
  52. pthread_mutex_lock(&(lockarray[type]));
  53. }
  54. else {
  55. pthread_mutex_unlock(&(lockarray[type]));
  56. }
  57. }
  58. static unsigned long thread_id(void)
  59. {
  60. unsigned long ret;
  61. ret = (unsigned long)pthread_self();
  62. return ret;
  63. }
  64. static void init_locks(void)
  65. {
  66. int i;
  67. lockarray = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() *
  68. sizeof(pthread_mutex_t));
  69. for(i = 0; i<CRYPTO_num_locks(); i++) {
  70. pthread_mutex_init(&(lockarray[i]), NULL);
  71. }
  72. CRYPTO_set_id_callback((unsigned long (*)())thread_id);
  73. CRYPTO_set_locking_callback((void (*)())lock_callback);
  74. }
  75. static void kill_locks(void)
  76. {
  77. int i;
  78. CRYPTO_set_locking_callback(NULL);
  79. for(i = 0; i<CRYPTO_num_locks(); i++)
  80. pthread_mutex_destroy(&(lockarray[i]));
  81. OPENSSL_free(lockarray);
  82. }
  83. #endif
  84. #ifdef USE_GNUTLS
  85. #include <gcrypt.h>
  86. #include <errno.h>
  87. GCRY_THREAD_OPTION_PTHREAD_IMPL;
  88. void init_locks(void)
  89. {
  90. gcry_control(GCRYCTL_SET_THREAD_CBS);
  91. }
  92. #define kill_locks()
  93. #endif
  94. /* List of URLs to fetch.*/
  95. const char * const urls[]= {
  96. "https://www.example.com/",
  97. "https://www2.example.com/",
  98. "https://www3.example.com/",
  99. "https://www4.example.com/",
  100. };
  101. static void *pull_one_url(void *url)
  102. {
  103. CURL *curl;
  104. curl = curl_easy_init();
  105. curl_easy_setopt(curl, CURLOPT_URL, url);
  106. /* this example does not verify the server's certificate, which means we
  107. might be downloading stuff from an impostor */
  108. curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
  109. curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
  110. curl_easy_perform(curl); /* ignores error */
  111. curl_easy_cleanup(curl);
  112. return NULL;
  113. }
  114. int main(int argc, char **argv)
  115. {
  116. pthread_t tid[NUMT];
  117. int i;
  118. (void)argc; /* we do not use any arguments in this example */
  119. (void)argv;
  120. /* Must initialize libcurl before any threads are started */
  121. curl_global_init(CURL_GLOBAL_ALL);
  122. init_locks();
  123. for(i = 0; i< NUMT; i++) {
  124. int error = pthread_create(&tid[i],
  125. NULL, /* default attributes please */
  126. pull_one_url,
  127. (void *)urls[i]);
  128. if(0 != error)
  129. fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error);
  130. else
  131. fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]);
  132. }
  133. /* now wait for all threads to terminate */
  134. for(i = 0; i< NUMT; i++) {
  135. pthread_join(tid[i], NULL);
  136. fprintf(stderr, "Thread %d terminated\n", i);
  137. }
  138. kill_locks();
  139. return 0;
  140. }