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