a7e9c2de1674482a9ca6d4645d34a26e4d1ae604
[platform/upstream/curl.git] / docs / examples / threaded-ssl.c
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>
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
57 static unsigned long thread_id(void)
58 {
59   unsigned long ret;
60
61   ret=(unsigned long)pthread_self();
62   return(ret);
63 }
64
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
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
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
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
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 }