1 | /*************************************************************************** |
2 | * _ _ ____ _ |
3 | * Project ___| | | | _ \| | |
4 | * / __| | | | |_) | | |
5 | * | (__| |_| | _ <| |___ |
6 | * \___|\___/|_| \_\_____| |
7 | * |
8 | * Copyright (C) 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 https://curl.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 | * SPDX-License-Identifier: curl |
22 | * |
23 | ***************************************************************************/ |
24 | |
25 | #include "curl_setup.h" |
26 | |
27 | #ifdef USE_NGHTTP2 |
28 | #include <nghttp2/nghttp2.h> |
29 | #endif |
30 | |
31 | #include <curl/curl.h> |
32 | #include "urldata.h" |
33 | #include "vtls/vtls.h" |
34 | #include "http2.h" |
35 | #include "vssh/ssh.h" |
36 | #include "vquic/vquic.h" |
37 | #include "curl_printf.h" |
38 | #include "easy_lock.h" |
39 | |
40 | #ifdef USE_ARES |
41 | # if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ |
42 | defined(WIN32) |
43 | # define CARES_STATICLIB |
44 | # endif |
45 | # include <ares.h> |
46 | #endif |
47 | |
48 | #ifdef USE_LIBIDN2 |
49 | #include <idn2.h> |
50 | #endif |
51 | |
52 | #ifdef USE_LIBPSL |
53 | #include <libpsl.h> |
54 | #endif |
55 | |
56 | #ifdef USE_LIBRTMP |
57 | #include <librtmp/rtmp.h> |
58 | #endif |
59 | |
60 | #ifdef HAVE_LIBZ |
61 | #include <zlib.h> |
62 | #endif |
63 | |
64 | #ifdef HAVE_BROTLI |
65 | #if defined(__GNUC__) |
66 | /* Ignore -Wvla warnings in brotli headers */ |
67 | #pragma GCC diagnostic push |
68 | #pragma GCC diagnostic ignored "-Wvla" |
69 | #endif |
70 | #include <brotli/decode.h> |
71 | #if defined(__GNUC__) |
72 | #pragma GCC diagnostic pop |
73 | #endif |
74 | #endif |
75 | |
76 | #ifdef HAVE_ZSTD |
77 | #include <zstd.h> |
78 | #endif |
79 | |
80 | #ifdef USE_GSASL |
81 | #include <gsasl.h> |
82 | #endif |
83 | |
84 | #ifdef USE_OPENLDAP |
85 | #include <ldap.h> |
86 | #endif |
87 | |
88 | #ifdef HAVE_BROTLI |
89 | static void brotli_version(char *buf, size_t bufsz) |
90 | { |
91 | uint32_t brotli_version = BrotliDecoderVersion(); |
92 | unsigned int major = brotli_version >> 24; |
93 | unsigned int minor = (brotli_version & 0x00FFFFFF) >> 12; |
94 | unsigned int patch = brotli_version & 0x00000FFF; |
95 | (void)msnprintf(buf, bufsz, "%u.%u.%u" , major, minor, patch); |
96 | } |
97 | #endif |
98 | |
99 | #ifdef HAVE_ZSTD |
100 | static void zstd_version(char *buf, size_t bufsz) |
101 | { |
102 | unsigned long zstd_version = (unsigned long)ZSTD_versionNumber(); |
103 | unsigned int major = (unsigned int)(zstd_version / (100 * 100)); |
104 | unsigned int minor = (unsigned int)((zstd_version - |
105 | (major * 100 * 100)) / 100); |
106 | unsigned int patch = (unsigned int)(zstd_version - |
107 | (major * 100 * 100) - (minor * 100)); |
108 | (void)msnprintf(buf, bufsz, "%u.%u.%u" , major, minor, patch); |
109 | } |
110 | #endif |
111 | |
112 | /* |
113 | * curl_version() returns a pointer to a static buffer. |
114 | * |
115 | * It is implemented to work multi-threaded by making sure repeated invokes |
116 | * generate the exact same string and never write any temporary data like |
117 | * zeros in the data. |
118 | */ |
119 | |
120 | #define VERSION_PARTS 16 /* number of substrings we can concatenate */ |
121 | |
122 | char *curl_version(void) |
123 | { |
124 | static char out[300]; |
125 | char *outp; |
126 | size_t outlen; |
127 | const char *src[VERSION_PARTS]; |
128 | #ifdef USE_SSL |
129 | char ssl_version[200]; |
130 | #endif |
131 | #ifdef HAVE_LIBZ |
132 | char z_version[40]; |
133 | #endif |
134 | #ifdef HAVE_BROTLI |
135 | char br_version[40] = "brotli/" ; |
136 | #endif |
137 | #ifdef HAVE_ZSTD |
138 | char zst_version[40] = "zstd/" ; |
139 | #endif |
140 | #ifdef USE_ARES |
141 | char cares_version[40]; |
142 | #endif |
143 | #if defined(USE_LIBIDN2) |
144 | char idn_version[40]; |
145 | #endif |
146 | #ifdef USE_LIBPSL |
147 | char psl_version[40]; |
148 | #endif |
149 | #ifdef USE_SSH |
150 | char ssh_version[40]; |
151 | #endif |
152 | #ifdef USE_NGHTTP2 |
153 | char h2_version[40]; |
154 | #endif |
155 | #ifdef ENABLE_QUIC |
156 | char h3_version[40]; |
157 | #endif |
158 | #ifdef USE_LIBRTMP |
159 | char rtmp_version[40]; |
160 | #endif |
161 | #ifdef USE_HYPER |
162 | char hyper_buf[30]; |
163 | #endif |
164 | #ifdef USE_GSASL |
165 | char gsasl_buf[30]; |
166 | #endif |
167 | #ifdef USE_OPENLDAP |
168 | char ldap_buf[30]; |
169 | #endif |
170 | int i = 0; |
171 | int j; |
172 | |
173 | #ifdef DEBUGBUILD |
174 | /* Override version string when environment variable CURL_VERSION is set */ |
175 | const char *debugversion = getenv("CURL_VERSION" ); |
176 | if(debugversion) { |
177 | strncpy(out, debugversion, sizeof(out)-1); |
178 | out[sizeof(out)-1] = '\0'; |
179 | return out; |
180 | } |
181 | #endif |
182 | |
183 | src[i++] = LIBCURL_NAME "/" LIBCURL_VERSION; |
184 | #ifdef USE_SSL |
185 | Curl_ssl_version(buffer: ssl_version, size: sizeof(ssl_version)); |
186 | src[i++] = ssl_version; |
187 | #endif |
188 | #ifdef HAVE_LIBZ |
189 | msnprintf(buffer: z_version, maxlength: sizeof(z_version), format: "zlib/%s" , zlibVersion()); |
190 | src[i++] = z_version; |
191 | #endif |
192 | #ifdef HAVE_BROTLI |
193 | brotli_version(&br_version[7], sizeof(br_version) - 7); |
194 | src[i++] = br_version; |
195 | #endif |
196 | #ifdef HAVE_ZSTD |
197 | zstd_version(&zst_version[5], sizeof(zst_version) - 5); |
198 | src[i++] = zst_version; |
199 | #endif |
200 | #ifdef USE_ARES |
201 | msnprintf(cares_version, sizeof(cares_version), |
202 | "c-ares/%s" , ares_version(NULL)); |
203 | src[i++] = cares_version; |
204 | #endif |
205 | #ifdef USE_LIBIDN2 |
206 | msnprintf(idn_version, sizeof(idn_version), |
207 | "libidn2/%s" , idn2_check_version(NULL)); |
208 | src[i++] = idn_version; |
209 | #elif defined(USE_WIN32_IDN) |
210 | src[i++] = (char *)"WinIDN" ; |
211 | #endif |
212 | |
213 | #ifdef USE_LIBPSL |
214 | msnprintf(psl_version, sizeof(psl_version), "libpsl/%s" , psl_get_version()); |
215 | src[i++] = psl_version; |
216 | #endif |
217 | |
218 | #ifdef USE_SSH |
219 | Curl_ssh_version(ssh_version, sizeof(ssh_version)); |
220 | src[i++] = ssh_version; |
221 | #endif |
222 | #ifdef USE_NGHTTP2 |
223 | Curl_http2_ver(h2_version, sizeof(h2_version)); |
224 | src[i++] = h2_version; |
225 | #endif |
226 | #ifdef ENABLE_QUIC |
227 | Curl_quic_ver(h3_version, sizeof(h3_version)); |
228 | src[i++] = h3_version; |
229 | #endif |
230 | #ifdef USE_LIBRTMP |
231 | { |
232 | char suff[2]; |
233 | if(RTMP_LIB_VERSION & 0xff) { |
234 | suff[0] = (RTMP_LIB_VERSION & 0xff) + 'a' - 1; |
235 | suff[1] = '\0'; |
236 | } |
237 | else |
238 | suff[0] = '\0'; |
239 | |
240 | msnprintf(rtmp_version, sizeof(rtmp_version), "librtmp/%d.%d%s" , |
241 | RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff, |
242 | suff); |
243 | src[i++] = rtmp_version; |
244 | } |
245 | #endif |
246 | #ifdef USE_HYPER |
247 | msnprintf(hyper_buf, sizeof(hyper_buf), "Hyper/%s" , hyper_version()); |
248 | src[i++] = hyper_buf; |
249 | #endif |
250 | #ifdef USE_GSASL |
251 | msnprintf(gsasl_buf, sizeof(gsasl_buf), "libgsasl/%s" , |
252 | gsasl_check_version(NULL)); |
253 | src[i++] = gsasl_buf; |
254 | #endif |
255 | #ifdef USE_OPENLDAP |
256 | { |
257 | LDAPAPIInfo api; |
258 | api.ldapai_info_version = LDAP_API_INFO_VERSION; |
259 | |
260 | if(ldap_get_option(NULL, LDAP_OPT_API_INFO, &api) == LDAP_OPT_SUCCESS) { |
261 | unsigned int patch = api.ldapai_vendor_version % 100; |
262 | unsigned int major = api.ldapai_vendor_version / 10000; |
263 | unsigned int minor = |
264 | ((api.ldapai_vendor_version - major * 10000) - patch) / 100; |
265 | msnprintf(ldap_buf, sizeof(ldap_buf), "%s/%u.%u.%u" , |
266 | api.ldapai_vendor_name, major, minor, patch); |
267 | src[i++] = ldap_buf; |
268 | ldap_memfree(api.ldapai_vendor_name); |
269 | ber_memvfree((void **)api.ldapai_extensions); |
270 | } |
271 | } |
272 | #endif |
273 | |
274 | DEBUGASSERT(i <= VERSION_PARTS); |
275 | |
276 | outp = &out[0]; |
277 | outlen = sizeof(out); |
278 | for(j = 0; j < i; j++) { |
279 | size_t n = strlen(s: src[j]); |
280 | /* we need room for a space, the string and the final zero */ |
281 | if(outlen <= (n + 2)) |
282 | break; |
283 | if(j) { |
284 | /* prepend a space if not the first */ |
285 | *outp++ = ' '; |
286 | outlen--; |
287 | } |
288 | memcpy(dest: outp, src: src[j], n: n); |
289 | outp += n; |
290 | outlen -= n; |
291 | } |
292 | *outp = 0; |
293 | |
294 | return out; |
295 | } |
296 | |
297 | /* data for curl_version_info |
298 | |
299 | Keep the list sorted alphabetically. It is also written so that each |
300 | protocol line has its own #if line to make things easier on the eye. |
301 | */ |
302 | |
303 | static const char * const supported_protocols[] = { |
304 | #ifndef CURL_DISABLE_DICT |
305 | "dict" , |
306 | #endif |
307 | #ifndef CURL_DISABLE_FILE |
308 | "file" , |
309 | #endif |
310 | #ifndef CURL_DISABLE_FTP |
311 | "ftp" , |
312 | #endif |
313 | #if defined(USE_SSL) && !defined(CURL_DISABLE_FTP) |
314 | "ftps" , |
315 | #endif |
316 | #ifndef CURL_DISABLE_GOPHER |
317 | "gopher" , |
318 | #endif |
319 | #if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER) |
320 | "gophers" , |
321 | #endif |
322 | #ifndef CURL_DISABLE_HTTP |
323 | "http" , |
324 | #endif |
325 | #if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP) |
326 | "https" , |
327 | #endif |
328 | #ifndef CURL_DISABLE_IMAP |
329 | "imap" , |
330 | #endif |
331 | #if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP) |
332 | "imaps" , |
333 | #endif |
334 | #ifndef CURL_DISABLE_LDAP |
335 | "ldap" , |
336 | #if !defined(CURL_DISABLE_LDAPS) && \ |
337 | ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \ |
338 | (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL))) |
339 | "ldaps" , |
340 | #endif |
341 | #endif |
342 | #ifndef CURL_DISABLE_MQTT |
343 | "mqtt" , |
344 | #endif |
345 | #ifndef CURL_DISABLE_POP3 |
346 | "pop3" , |
347 | #endif |
348 | #if defined(USE_SSL) && !defined(CURL_DISABLE_POP3) |
349 | "pop3s" , |
350 | #endif |
351 | #ifdef USE_LIBRTMP |
352 | "rtmp" , |
353 | "rtmpe" , |
354 | "rtmps" , |
355 | "rtmpt" , |
356 | "rtmpte" , |
357 | "rtmpts" , |
358 | #endif |
359 | #ifndef CURL_DISABLE_RTSP |
360 | "rtsp" , |
361 | #endif |
362 | #if defined(USE_SSH) && !defined(USE_WOLFSSH) |
363 | "scp" , |
364 | #endif |
365 | #ifdef USE_SSH |
366 | "sftp" , |
367 | #endif |
368 | #if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) |
369 | "smb" , |
370 | # ifdef USE_SSL |
371 | "smbs" , |
372 | # endif |
373 | #endif |
374 | #ifndef CURL_DISABLE_SMTP |
375 | "smtp" , |
376 | #endif |
377 | #if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP) |
378 | "smtps" , |
379 | #endif |
380 | #ifndef CURL_DISABLE_TELNET |
381 | "telnet" , |
382 | #endif |
383 | #ifndef CURL_DISABLE_TFTP |
384 | "tftp" , |
385 | #endif |
386 | #ifdef USE_WEBSOCKETS |
387 | "ws" , |
388 | #endif |
389 | #if defined(USE_SSL) && defined(USE_WEBSOCKETS) |
390 | "wss" , |
391 | #endif |
392 | |
393 | NULL |
394 | }; |
395 | |
396 | /* |
397 | * Feature presence run-time check functions. |
398 | * |
399 | * Warning: the value returned by these should not change between |
400 | * curl_global_init() and curl_global_cleanup() calls. |
401 | */ |
402 | |
403 | #if defined(USE_LIBIDN2) |
404 | static int idn_present(curl_version_info_data *info) |
405 | { |
406 | return info->libidn != NULL; |
407 | } |
408 | #else |
409 | #define idn_present NULL |
410 | #endif |
411 | |
412 | #if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY) |
413 | static int https_proxy_present(curl_version_info_data *info) |
414 | { |
415 | (void) info; |
416 | return Curl_ssl_supports(NULL, SSLSUPP_HTTPS_PROXY); |
417 | } |
418 | #endif |
419 | |
420 | /* |
421 | * Features table. |
422 | * |
423 | * Keep the features alphabetically sorted. |
424 | * Use FEATURE() macro to define an entry: this allows documentation check. |
425 | */ |
426 | |
427 | #define FEATURE(name, present, bitmask) {(name), (present), (bitmask)} |
428 | |
429 | struct feat { |
430 | const char *name; |
431 | int (*present)(curl_version_info_data *info); |
432 | int bitmask; |
433 | }; |
434 | |
435 | static const struct feat features_table[] = { |
436 | #ifndef CURL_DISABLE_ALTSVC |
437 | FEATURE("alt-svc" , NULL, CURL_VERSION_ALTSVC), |
438 | #endif |
439 | #ifdef CURLRES_ASYNCH |
440 | FEATURE("AsynchDNS" , NULL, CURL_VERSION_ASYNCHDNS), |
441 | #endif |
442 | #ifdef HAVE_BROTLI |
443 | FEATURE("brotli" , NULL, CURL_VERSION_BROTLI), |
444 | #endif |
445 | #ifdef DEBUGBUILD |
446 | FEATURE("Debug" , NULL, CURL_VERSION_DEBUG), |
447 | #endif |
448 | #ifdef USE_GSASL |
449 | FEATURE("gsasl" , NULL, CURL_VERSION_GSASL), |
450 | #endif |
451 | #ifdef HAVE_GSSAPI |
452 | FEATURE("GSS-API" , NULL, CURL_VERSION_GSSAPI), |
453 | #endif |
454 | #ifndef CURL_DISABLE_HSTS |
455 | FEATURE("HSTS" , NULL, CURL_VERSION_HSTS), |
456 | #endif |
457 | #if defined(USE_NGHTTP2) || defined(USE_HYPER) |
458 | FEATURE("HTTP2" , NULL, CURL_VERSION_HTTP2), |
459 | #endif |
460 | #if defined(ENABLE_QUIC) |
461 | FEATURE("HTTP3" , NULL, CURL_VERSION_HTTP3), |
462 | #endif |
463 | #if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY) |
464 | FEATURE("HTTPS-proxy" , https_proxy_present, CURL_VERSION_HTTPS_PROXY), |
465 | #endif |
466 | #if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) |
467 | FEATURE("IDN" , idn_present, CURL_VERSION_IDN), |
468 | #endif |
469 | #ifdef ENABLE_IPV6 |
470 | FEATURE("IPv6" , NULL, CURL_VERSION_IPV6), |
471 | #endif |
472 | #ifdef USE_KERBEROS5 |
473 | FEATURE("Kerberos" , NULL, CURL_VERSION_KERBEROS5), |
474 | #endif |
475 | #if (SIZEOF_CURL_OFF_T > 4) && \ |
476 | ( (SIZEOF_OFF_T > 4) || defined(USE_WIN32_LARGE_FILES) ) |
477 | FEATURE("Largefile" , NULL, CURL_VERSION_LARGEFILE), |
478 | #endif |
479 | #ifdef HAVE_LIBZ |
480 | FEATURE("libz" , NULL, CURL_VERSION_LIBZ), |
481 | #endif |
482 | #ifdef CURL_WITH_MULTI_SSL |
483 | FEATURE("MultiSSL" , NULL, CURL_VERSION_MULTI_SSL), |
484 | #endif |
485 | #ifdef USE_NTLM |
486 | FEATURE("NTLM" , NULL, CURL_VERSION_NTLM), |
487 | #endif |
488 | #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ |
489 | defined(NTLM_WB_ENABLED) |
490 | FEATURE("NTLM_WB" , NULL, CURL_VERSION_NTLM_WB), |
491 | #endif |
492 | #if defined(USE_LIBPSL) |
493 | FEATURE("PSL" , NULL, CURL_VERSION_PSL), |
494 | #endif |
495 | #ifdef USE_SPNEGO |
496 | FEATURE("SPNEGO" , NULL, CURL_VERSION_SPNEGO), |
497 | #endif |
498 | #ifdef USE_SSL |
499 | FEATURE("SSL" , NULL, CURL_VERSION_SSL), |
500 | #endif |
501 | #ifdef USE_WINDOWS_SSPI |
502 | FEATURE("SSPI" , NULL, CURL_VERSION_SSPI), |
503 | #endif |
504 | #ifdef GLOBAL_INIT_IS_THREADSAFE |
505 | FEATURE("threadsafe" , NULL, CURL_VERSION_THREADSAFE), |
506 | #endif |
507 | #ifdef USE_TLS_SRP |
508 | FEATURE("TLS-SRP" , NULL, CURL_VERSION_TLSAUTH_SRP), |
509 | #endif |
510 | #ifdef CURLDEBUG |
511 | FEATURE("TrackMemory" , NULL, CURL_VERSION_CURLDEBUG), |
512 | #endif |
513 | #if defined(WIN32) && defined(UNICODE) && defined(_UNICODE) |
514 | FEATURE("Unicode" , NULL, CURL_VERSION_UNICODE), |
515 | #endif |
516 | #ifdef USE_UNIX_SOCKETS |
517 | FEATURE("UnixSockets" , NULL, CURL_VERSION_UNIX_SOCKETS), |
518 | #endif |
519 | #ifdef HAVE_ZSTD |
520 | FEATURE("zstd" , NULL, CURL_VERSION_ZSTD), |
521 | #endif |
522 | {NULL, NULL, .bitmask: 0} |
523 | }; |
524 | |
525 | static const char *feature_names[sizeof(features_table) / |
526 | sizeof(features_table[0])] = {NULL}; |
527 | |
528 | |
529 | static curl_version_info_data version_info = { |
530 | CURLVERSION_NOW, |
531 | LIBCURL_VERSION, |
532 | LIBCURL_VERSION_NUM, |
533 | OS, /* as found by configure or set by hand at build-time */ |
534 | 0, /* features bitmask is built at run-time */ |
535 | NULL, /* ssl_version */ |
536 | 0, /* ssl_version_num, this is kept at zero */ |
537 | NULL, /* zlib_version */ |
538 | supported_protocols, |
539 | NULL, /* c-ares version */ |
540 | 0, /* c-ares version numerical */ |
541 | NULL, /* libidn version */ |
542 | 0, /* iconv version */ |
543 | NULL, /* ssh lib version */ |
544 | 0, /* brotli_ver_num */ |
545 | NULL, /* brotli version */ |
546 | 0, /* nghttp2 version number */ |
547 | NULL, /* nghttp2 version string */ |
548 | NULL, /* quic library string */ |
549 | #ifdef CURL_CA_BUNDLE |
550 | CURL_CA_BUNDLE, /* cainfo */ |
551 | #else |
552 | NULL, |
553 | #endif |
554 | #ifdef CURL_CA_PATH |
555 | CURL_CA_PATH, /* capath */ |
556 | #else |
557 | NULL, |
558 | #endif |
559 | 0, /* zstd_ver_num */ |
560 | NULL, /* zstd version */ |
561 | NULL, /* Hyper version */ |
562 | NULL, /* gsasl version */ |
563 | feature_names |
564 | }; |
565 | |
566 | curl_version_info_data *curl_version_info(CURLversion stamp) |
567 | { |
568 | size_t n; |
569 | const struct feat *p; |
570 | int features = 0; |
571 | |
572 | #if defined(USE_SSH) |
573 | static char ssh_buffer[80]; |
574 | #endif |
575 | #ifdef USE_SSL |
576 | #ifdef CURL_WITH_MULTI_SSL |
577 | static char ssl_buffer[200]; |
578 | #else |
579 | static char ssl_buffer[80]; |
580 | #endif |
581 | #endif |
582 | #ifdef HAVE_BROTLI |
583 | static char brotli_buffer[80]; |
584 | #endif |
585 | #ifdef HAVE_ZSTD |
586 | static char zstd_buffer[80]; |
587 | #endif |
588 | |
589 | (void)stamp; /* avoid compiler warnings, we don't use this */ |
590 | |
591 | #ifdef USE_SSL |
592 | Curl_ssl_version(buffer: ssl_buffer, size: sizeof(ssl_buffer)); |
593 | version_info.ssl_version = ssl_buffer; |
594 | #endif |
595 | |
596 | #ifdef HAVE_LIBZ |
597 | version_info.libz_version = zlibVersion(); |
598 | /* libz left NULL if non-existing */ |
599 | #endif |
600 | #ifdef USE_ARES |
601 | { |
602 | int aresnum; |
603 | version_info.ares = ares_version(&aresnum); |
604 | version_info.ares_num = aresnum; |
605 | } |
606 | #endif |
607 | #ifdef USE_LIBIDN2 |
608 | /* This returns a version string if we use the given version or later, |
609 | otherwise it returns NULL */ |
610 | version_info.libidn = idn2_check_version(IDN2_VERSION); |
611 | #endif |
612 | |
613 | #if defined(USE_SSH) |
614 | Curl_ssh_version(ssh_buffer, sizeof(ssh_buffer)); |
615 | version_info.libssh_version = ssh_buffer; |
616 | #endif |
617 | |
618 | #ifdef HAVE_BROTLI |
619 | version_info.brotli_ver_num = BrotliDecoderVersion(); |
620 | brotli_version(brotli_buffer, sizeof(brotli_buffer)); |
621 | version_info.brotli_version = brotli_buffer; |
622 | #endif |
623 | |
624 | #ifdef HAVE_ZSTD |
625 | version_info.zstd_ver_num = (unsigned int)ZSTD_versionNumber(); |
626 | zstd_version(zstd_buffer, sizeof(zstd_buffer)); |
627 | version_info.zstd_version = zstd_buffer; |
628 | #endif |
629 | |
630 | #ifdef USE_NGHTTP2 |
631 | { |
632 | nghttp2_info *h2 = nghttp2_version(0); |
633 | version_info.nghttp2_ver_num = h2->version_num; |
634 | version_info.nghttp2_version = h2->version_str; |
635 | } |
636 | #endif |
637 | |
638 | #ifdef ENABLE_QUIC |
639 | { |
640 | static char quicbuffer[80]; |
641 | Curl_quic_ver(quicbuffer, sizeof(quicbuffer)); |
642 | version_info.quic_version = quicbuffer; |
643 | } |
644 | #endif |
645 | |
646 | #ifdef USE_HYPER |
647 | { |
648 | static char hyper_buffer[30]; |
649 | msnprintf(hyper_buffer, sizeof(hyper_buffer), "Hyper/%s" , hyper_version()); |
650 | version_info.hyper_version = hyper_buffer; |
651 | } |
652 | #endif |
653 | |
654 | #ifdef USE_GSASL |
655 | { |
656 | version_info.gsasl_version = gsasl_check_version(NULL); |
657 | } |
658 | #endif |
659 | |
660 | /* Get available features, build bitmask and names array. */ |
661 | n = 0; |
662 | for(p = features_table; p->name; p++) |
663 | if(!p->present || p->present(&version_info)) { |
664 | features |= p->bitmask; |
665 | feature_names[n++] = p->name; |
666 | } |
667 | |
668 | feature_names[n] = NULL; /* Terminate array. */ |
669 | version_info.features = features; |
670 | |
671 | return &version_info; |
672 | } |
673 | |