blob: 284edc419f838dbf07a82d3fab68307988c599ad [file] [log] [blame]
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001/*****************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 *
9 * A multi-threaded example that uses pthreads and fetches 4 remote files at
10 * once over HTTPS. The lock callbacks and stuff assume OpenSSL or GnuTLS
11 * (libgcrypt) so far.
12 *
13 * OpenSSL docs for this:
14 * http://www.openssl.org/docs/crypto/threads.html
15 * gcrypt docs for this:
16 * http://gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html
17 */
18
19#define USE_OPENSSL /* or USE_GNUTLS accordingly */
20
21#include <stdio.h>
22#include <pthread.h>
23#include <curl/curl.h>
24
25#define NUMT 4
26
27/* we have this global to let the callback get easy access to it */
28static pthread_mutex_t *lockarray;
29
30#ifdef USE_OPENSSL
31#include <openssl/crypto.h>
32static void lock_callback(int mode, int type, char *file, int line)
33{
34 (void)file;
35 (void)line;
36 if (mode & CRYPTO_LOCK) {
37 pthread_mutex_lock(&(lockarray[type]));
38 }
39 else {
40 pthread_mutex_unlock(&(lockarray[type]));
41 }
42}
43
44static unsigned long thread_id(void)
45{
46 unsigned long ret;
47
48 ret=(unsigned long)pthread_self();
49 return(ret);
50}
51
52static void init_locks(void)
53{
54 int i;
55
56 lockarray=(pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() *
57 sizeof(pthread_mutex_t));
58 for (i=0; i<CRYPTO_num_locks(); i++) {
59 pthread_mutex_init(&(lockarray[i]),NULL);
60 }
61
62 CRYPTO_set_id_callback((unsigned long (*)())thread_id);
63 CRYPTO_set_locking_callback((void (*)())lock_callback);
64}
65
66static void kill_locks(void)
67{
68 int i;
69
70 CRYPTO_set_locking_callback(NULL);
71 for (i=0; i<CRYPTO_num_locks(); i++)
72 pthread_mutex_destroy(&(lockarray[i]));
73
74 OPENSSL_free(lockarray);
75}
76#endif
77
78#ifdef USE_GNUTLS
79#include <gcrypt.h>
80#include <errno.h>
81
82GCRY_THREAD_OPTION_PTHREAD_IMPL;
83
84void init_locks(void)
85{
86 gcry_control(GCRYCTL_SET_THREAD_CBS);
87}
88
89#define kill_locks()
90#endif
91
92/* List of URLs to fetch.*/
93const char * const urls[]= {
94 "https://www.example.com/",
95 "https://www2.example.com/",
96 "https://www3.example.com/",
97 "https://www4.example.com/",
98};
99
100static void *pull_one_url(void *url)
101{
102 CURL *curl;
103
104 curl = curl_easy_init();
105 curl_easy_setopt(curl, CURLOPT_URL, url);
106 /* this example doesn't 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
113 return NULL;
114}
115
116int main(int argc, char **argv)
117{
118 pthread_t tid[NUMT];
119 int i;
120 int error;
121 (void)argc; /* we don't use any arguments in this example */
122 (void)argv;
123
124 /* Must initialize libcurl before any threads are started */
125 curl_global_init(CURL_GLOBAL_ALL);
126
127 init_locks();
128
129 for(i=0; i< NUMT; i++) {
130 error = pthread_create(&tid[i],
131 NULL, /* default attributes please */
132 pull_one_url,
133 (void *)urls[i]);
134 if(0 != error)
135 fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error);
136 else
137 fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]);
138 }
139
140 /* now wait for all threads to terminate */
141 for(i=0; i< NUMT; i++) {
142 error = pthread_join(tid[i], NULL);
143 fprintf(stderr, "Thread %d terminated\n", i);
144 }
145
146 kill_locks();
147
148 return 0;
149}