113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci/* <DESC> 2513498266Sopenharmony_ci * Show the required mutex callback setups for GnuTLS and OpenSSL when using 2613498266Sopenharmony_ci * libcurl multi-threaded. 2713498266Sopenharmony_ci * </DESC> 2813498266Sopenharmony_ci */ 2913498266Sopenharmony_ci/* A multi-threaded example that uses pthreads and fetches 4 remote files at 3013498266Sopenharmony_ci * once over HTTPS. The lock callbacks and stuff assume OpenSSL <1.1 or GnuTLS 3113498266Sopenharmony_ci * (libgcrypt) so far. 3213498266Sopenharmony_ci * 3313498266Sopenharmony_ci * OpenSSL docs for this: 3413498266Sopenharmony_ci * https://www.openssl.org/docs/man1.0.2/man3/CRYPTO_num_locks.html 3513498266Sopenharmony_ci * gcrypt docs for this: 3613498266Sopenharmony_ci * https://gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html 3713498266Sopenharmony_ci */ 3813498266Sopenharmony_ci 3913498266Sopenharmony_ci#define USE_OPENSSL /* or USE_GNUTLS accordingly */ 4013498266Sopenharmony_ci 4113498266Sopenharmony_ci#include <stdio.h> 4213498266Sopenharmony_ci#include <pthread.h> 4313498266Sopenharmony_ci#include <curl/curl.h> 4413498266Sopenharmony_ci 4513498266Sopenharmony_ci#define NUMT 4 4613498266Sopenharmony_ci 4713498266Sopenharmony_ci/* we have this global to let the callback get easy access to it */ 4813498266Sopenharmony_cistatic pthread_mutex_t *lockarray; 4913498266Sopenharmony_ci 5013498266Sopenharmony_ci#ifdef USE_OPENSSL 5113498266Sopenharmony_ci#include <openssl/crypto.h> 5213498266Sopenharmony_cistatic void lock_callback(int mode, int type, char *file, int line) 5313498266Sopenharmony_ci{ 5413498266Sopenharmony_ci (void)file; 5513498266Sopenharmony_ci (void)line; 5613498266Sopenharmony_ci if(mode & CRYPTO_LOCK) { 5713498266Sopenharmony_ci pthread_mutex_lock(&(lockarray[type])); 5813498266Sopenharmony_ci } 5913498266Sopenharmony_ci else { 6013498266Sopenharmony_ci pthread_mutex_unlock(&(lockarray[type])); 6113498266Sopenharmony_ci } 6213498266Sopenharmony_ci} 6313498266Sopenharmony_ci 6413498266Sopenharmony_cistatic unsigned long thread_id(void) 6513498266Sopenharmony_ci{ 6613498266Sopenharmony_ci unsigned long ret; 6713498266Sopenharmony_ci 6813498266Sopenharmony_ci ret = (unsigned long)pthread_self(); 6913498266Sopenharmony_ci return ret; 7013498266Sopenharmony_ci} 7113498266Sopenharmony_ci 7213498266Sopenharmony_cistatic void init_locks(void) 7313498266Sopenharmony_ci{ 7413498266Sopenharmony_ci int i; 7513498266Sopenharmony_ci 7613498266Sopenharmony_ci lockarray = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() * 7713498266Sopenharmony_ci sizeof(pthread_mutex_t)); 7813498266Sopenharmony_ci for(i = 0; i<CRYPTO_num_locks(); i++) { 7913498266Sopenharmony_ci pthread_mutex_init(&(lockarray[i]), NULL); 8013498266Sopenharmony_ci } 8113498266Sopenharmony_ci 8213498266Sopenharmony_ci CRYPTO_set_id_callback((unsigned long (*)())thread_id); 8313498266Sopenharmony_ci CRYPTO_set_locking_callback((void (*)())lock_callback); 8413498266Sopenharmony_ci} 8513498266Sopenharmony_ci 8613498266Sopenharmony_cistatic void kill_locks(void) 8713498266Sopenharmony_ci{ 8813498266Sopenharmony_ci int i; 8913498266Sopenharmony_ci 9013498266Sopenharmony_ci CRYPTO_set_locking_callback(NULL); 9113498266Sopenharmony_ci for(i = 0; i<CRYPTO_num_locks(); i++) 9213498266Sopenharmony_ci pthread_mutex_destroy(&(lockarray[i])); 9313498266Sopenharmony_ci 9413498266Sopenharmony_ci OPENSSL_free(lockarray); 9513498266Sopenharmony_ci} 9613498266Sopenharmony_ci#endif 9713498266Sopenharmony_ci 9813498266Sopenharmony_ci#ifdef USE_GNUTLS 9913498266Sopenharmony_ci#include <gcrypt.h> 10013498266Sopenharmony_ci#include <errno.h> 10113498266Sopenharmony_ci 10213498266Sopenharmony_ciGCRY_THREAD_OPTION_PTHREAD_IMPL; 10313498266Sopenharmony_ci 10413498266Sopenharmony_civoid init_locks(void) 10513498266Sopenharmony_ci{ 10613498266Sopenharmony_ci gcry_control(GCRYCTL_SET_THREAD_CBS); 10713498266Sopenharmony_ci} 10813498266Sopenharmony_ci 10913498266Sopenharmony_ci#define kill_locks() 11013498266Sopenharmony_ci#endif 11113498266Sopenharmony_ci 11213498266Sopenharmony_ci/* List of URLs to fetch.*/ 11313498266Sopenharmony_ciconst char * const urls[]= { 11413498266Sopenharmony_ci "https://www.example.com/", 11513498266Sopenharmony_ci "https://www2.example.com/", 11613498266Sopenharmony_ci "https://www3.example.com/", 11713498266Sopenharmony_ci "https://www4.example.com/", 11813498266Sopenharmony_ci}; 11913498266Sopenharmony_ci 12013498266Sopenharmony_cistatic void *pull_one_url(void *url) 12113498266Sopenharmony_ci{ 12213498266Sopenharmony_ci CURL *curl; 12313498266Sopenharmony_ci 12413498266Sopenharmony_ci curl = curl_easy_init(); 12513498266Sopenharmony_ci curl_easy_setopt(curl, CURLOPT_URL, url); 12613498266Sopenharmony_ci /* this example does not verify the server's certificate, which means we 12713498266Sopenharmony_ci might be downloading stuff from an impostor */ 12813498266Sopenharmony_ci curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 12913498266Sopenharmony_ci curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); 13013498266Sopenharmony_ci curl_easy_perform(curl); /* ignores error */ 13113498266Sopenharmony_ci curl_easy_cleanup(curl); 13213498266Sopenharmony_ci 13313498266Sopenharmony_ci return NULL; 13413498266Sopenharmony_ci} 13513498266Sopenharmony_ci 13613498266Sopenharmony_ciint main(int argc, char **argv) 13713498266Sopenharmony_ci{ 13813498266Sopenharmony_ci pthread_t tid[NUMT]; 13913498266Sopenharmony_ci int i; 14013498266Sopenharmony_ci (void)argc; /* we do not use any arguments in this example */ 14113498266Sopenharmony_ci (void)argv; 14213498266Sopenharmony_ci 14313498266Sopenharmony_ci /* Must initialize libcurl before any threads are started */ 14413498266Sopenharmony_ci curl_global_init(CURL_GLOBAL_ALL); 14513498266Sopenharmony_ci 14613498266Sopenharmony_ci init_locks(); 14713498266Sopenharmony_ci 14813498266Sopenharmony_ci for(i = 0; i< NUMT; i++) { 14913498266Sopenharmony_ci int error = pthread_create(&tid[i], 15013498266Sopenharmony_ci NULL, /* default attributes please */ 15113498266Sopenharmony_ci pull_one_url, 15213498266Sopenharmony_ci (void *)urls[i]); 15313498266Sopenharmony_ci if(0 != error) 15413498266Sopenharmony_ci fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error); 15513498266Sopenharmony_ci else 15613498266Sopenharmony_ci fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]); 15713498266Sopenharmony_ci } 15813498266Sopenharmony_ci 15913498266Sopenharmony_ci /* now wait for all threads to terminate */ 16013498266Sopenharmony_ci for(i = 0; i< NUMT; i++) { 16113498266Sopenharmony_ci pthread_join(tid[i], NULL); 16213498266Sopenharmony_ci fprintf(stderr, "Thread %d terminated\n", i); 16313498266Sopenharmony_ci } 16413498266Sopenharmony_ci 16513498266Sopenharmony_ci kill_locks(); 16613498266Sopenharmony_ci 16713498266Sopenharmony_ci return 0; 16813498266Sopenharmony_ci} 169