KiCad PCB EDA Suite
kicad_curl.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015 Mark Roszko <mark.roszko@gmail.com>
5  * Copyright (C) 2016 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 2015 KiCad Developers, see CHANGELOG.TXT for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 3
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 // kicad_curl.h must be included before wx headers, to avoid
27 // conflicts for some defines, at least on Windows
28 #include <kicad_curl/kicad_curl.h>
29 
30 #include <mutex>
31 #include <ki_exception.h> // THROW_IO_ERROR
32 
33 
34 
35 // These are even more private than class members, and since there is only
36 // one instance of KICAD_CURL ever, these statics are hidden here to simplify the
37 // client (API) header file.
38 static volatile bool s_initialized;
39 
40 static std::mutex s_lock; // for s_initialized
41 
42 // Assume that on these platforms libcurl uses OpenSSL
43 #if defined(__linux__) || defined(__MINGW32__)
44 
45 #include <openssl/crypto.h>
46 
47 static std::mutex* s_crypto_locks;
48 
49 /*
50  * From OpenSSL v1.1.0, the CRYPTO_set_locking_callback macro is a no-op.
51  *
52  * Once this is the minimum OpenSSL version, the entire s_crypto_locks
53  * system and related functions can be removed.
54  *
55  * In the meantime, use this macro to determine when to use the callback.
56  * Keep them compiling until then to prevent accidentally breaking older
57  * version builds.
58  *
59  * https://github.com/openssl/openssl/issues/1260
60  */
61 #if OPENSSL_VERSION_NUMBER < 0x10100000L
62 #define USE_OPENSSL_LOCKING_CALLBACKS
63 #endif
64 
65 
66 static void lock_callback( int mode, int type, const char* file, int line )
67 {
68  (void)file;
69  (void)line;
70 
71  wxASSERT( s_crypto_locks && unsigned( type ) < unsigned( CRYPTO_num_locks() ) );
72 
73  if( mode & CRYPTO_LOCK )
74  {
75  s_crypto_locks[ type ].lock();
76  }
77  else
78  {
79  s_crypto_locks[ type ].unlock();
80  }
81 }
82 
83 
84 static void init_locks()
85 {
86  s_crypto_locks = new std::mutex[ CRYPTO_num_locks() ];
87 
88  // From http://linux.die.net/man/3/crypto_set_id_callback:
89 
90  /*
91 
92  OpenSSL can safely be used in multi-threaded applications provided that at
93  least two callback functions are set, locking_function and threadid_func.
94 
95  locking_function(int mode, int n, const char *file, int line) is needed to
96  perform locking on shared data structures. (Note that OpenSSL uses a number
97  of global data structures that will be implicitly shared whenever multiple
98  threads use OpenSSL.) Multi-threaded applications will crash at random if it
99  is not set.
100 
101  threadid_func( CRYPTO_THREADID *id) is needed to record the
102  currently-executing thread's identifier into id. The implementation of this
103  callback should not fill in id directly, but should use
104  CRYPTO_THREADID_set_numeric() if thread IDs are numeric, or
105  CRYPTO_THREADID_set_pointer() if they are pointer-based. If the application
106  does not register such a callback using CRYPTO_THREADID_set_callback(), then
107  a default implementation is used - on Windows and BeOS this uses the
108  system's default thread identifying APIs, and on all other platforms it uses
109  the address of errno. The latter is satisfactory for thread-safety if and
110  only if the platform has a thread-local error number facility.
111 
112  Dick: "sounds like CRYPTO_THREADID_set_callback() is not mandatory on our
113  2 OpenSSL platforms."
114 
115  */
116 
117  CRYPTO_set_locking_callback( &lock_callback );
118 
119 #ifndef USE_OPENSSL_LOCKING_CALLBACKS
120  // Ignore the unused function (the above macro didn't use it)
121  (void) &lock_callback;
122 #endif
123 }
124 
125 
126 static void kill_locks()
127 {
128  CRYPTO_set_locking_callback( NULL );
129 
130  delete[] s_crypto_locks;
131 
132  s_crypto_locks = NULL;
133 }
134 
135 #else
136 
137 inline void init_locks() { /* dummy */ }
138 inline void kill_locks() { /* dummy */ }
139 
140 #endif
141 
144 static void at_terminate()
145 {
147 }
148 
149 
151 {
152  // We test s_initialized twice in an effort to avoid
153  // unnecessarily locking s_lock. This understands that the common case
154  // will not need to lock.
155  if( !s_initialized )
156  {
157  std::lock_guard<std::mutex> lock( s_lock );
158 
159  if( !s_initialized )
160  {
161  if( curl_global_init( CURL_GLOBAL_ALL ) != CURLE_OK )
162  {
163  THROW_IO_ERROR( "curl_global_init() failed." );
164  }
165 
166  init_locks();
167 
168  //wxLogDebug( "Using %s", GetVersion() );
169 
170  s_initialized = true;
171  }
172  }
173 }
174 
175 
177 {
178  /*
179 
180  Calling lock_guard() from a static destructor will typically be bad, since the
181  s_lock may already have been statically destroyed itself leading to a boost
182  exception. (Remember C++ does not provide certain sequencing of static
183  destructor invocation.)
184 
185  To prevent this we test s_initialized twice, which ensures that the lock_guard
186  is only instantiated on the first call, which should be from
187  PGM_BASE::destroy() which is first called earlier than static destruction.
188  Then when called again from the actual PGM_BASE::~PGM_BASE() function,
189  lock_guard will not be instantiated because s_initialized will be false.
190 
191  */
192 
193  if( s_initialized )
194  {
195  std::lock_guard<std::mutex> lock( s_lock );
196 
197  if( s_initialized )
198  {
199  curl_global_cleanup();
200 
201  kill_locks();
202 
203  atexit( &at_terminate );
204 
205  s_initialized = false;
206  }
207  }
208 }
209 
210 
212 {
213  if( !s_initialized )
214  Init();
215 
216  curl_version_info_data* info = curl_version_info( CURLVERSION_NOW );
217 
218  std::string res;
219 
220  if( info->version )
221  {
222  res += "libcurl version: " + std::string( info->version );
223  }
224 
225  res += " (";
226 
227  if( info->features & CURL_VERSION_SSL )
228  {
229  res += "with SSL - ";
230  res += std::string( info->ssl_version );
231  }
232  else
233  {
234  res += "without SSL";
235  }
236  res += ")";
237 
238  return res;
239 }
240 
241 std::string GetKicadCurlVersion()
242 {
243  return KICAD_CURL::GetVersion();
244 }
245 
246 std::string GetCurlLibVersion()
247 {
248  return LIBCURL_VERSION;
249 }
static std::mutex s_lock
Definition: kicad_curl.cpp:40
static void Cleanup()
Function Cleanup calls curl_global_cleanup for the application.
Definition: kicad_curl.cpp:176
static void Init()
Function Init calls curl_global_init for the application.
Definition: kicad_curl.cpp:150
static void at_terminate()
At process termination, using atexit() keeps the CURL stuff out of the singletops and PGM_BASE.
Definition: kicad_curl.cpp:144
std::string GetKicadCurlVersion()
Definition: kicad_curl.cpp:241
#define THROW_IO_ERROR(msg)
std::string GetCurlLibVersion()
Definition: kicad_curl.cpp:246
static volatile bool s_initialized
Definition: kicad_curl.cpp:38
void kill_locks()
Definition: kicad_curl.cpp:138
static const char * GetVersion()
Function GetVersion wrapper for curl_version().
Definition: kicad_curl.h:93
void init_locks()
Definition: kicad_curl.cpp:137
static std::string GetSimpleVersion()
Function GetSimpleVersion Reports back curl version only and SSL library support.
Definition: kicad_curl.cpp:211